From ae48763d8dc968f51f12dab28f92bcc07a94b406 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 10:13:36 -0500 Subject: [PATCH 001/188] phase2 r0: numbers design, site inventory and test map (#1758) Round 0 of #1758 (exact int64 kind and IEEE doubles): the design a blind critic reviews before round 1 builds. No src/ change. - tools/phase2_inventory.py classifies every numeric site in src/*.c and src/*.h (comments and literals stripped) into one of the ten categories and writes docs/design/phase2-inventory.txt: examined=1773 classified=1773 unclassified=0. Two derived checks keep "unclassified" live: a new double-returning payload accessor, or a VAL_NUM in an unrecognized position, is unclassified. It also derives the builtin registration table (311 names; equal to `eigenscript --api --json` both ways) and checks the design doc's classification table against the 229 numeric builtins, both directions, with closed class and loss tokens. - docs/design/phase2-numbers.md chooses Alt 1R: VAL_INT beside a renamed VAL_FLOAT, with the ambiguous accessors deleted, so 1,488 of 1,773 sites stop compiling until visited. A shared-tag subtype (Lua's TValue shape) or a double shadow leaves 445 type tests and 484 checked reads compiling with a widened or lossy meaning, and three JIT emitters that would misread a boxed int. Also: the JIT guard table (every consuming guard bails on 0xFFFA; four producer emitters must change), the N12/SMI NaN-space argument, the builtin table (39 LOSS rows), the semantics-to-sites map, the round 1/2 plan, the check/plant/Lua-diff tool designs, and six open questions left to the owner. - tests/phase2/MAP.md maps N1-N14, N4b, (A), (B), T1 and O1-O4 to 78 tag-failing rows, 5 controls and 2 oracle gates. Measured prototype (standalone C, callgrind Ir/op): today's double ADD 38; float-first SMI arm 40 on floats, 44 on ints (shifted add); boxing every int 77. The interpreter spends 685 Ir per counter-loop iteration and the JIT 402, so int loops bailing in round 1 cost up to ~1.7x until round 5. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 2102 ++++++++++++++++++++++++++++++ docs/design/phase2-numbers.md | 1272 ++++++++++++++++++ tests/phase2/MAP.md | 348 +++++ tools/phase2_inventory.py | 687 ++++++++++ 4 files changed, 4409 insertions(+) create mode 100644 docs/design/phase2-inventory.txt create mode 100644 docs/design/phase2-numbers.md create mode 100644 tests/phase2/MAP.md create mode 100755 tools/phase2_inventory.py diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt new file mode 100644 index 000000000..1526cda9e --- /dev/null +++ b/docs/design/phase2-inventory.txt @@ -0,0 +1,2102 @@ +# docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. +# Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. +examined=1773 classified=1773 unclassified=0 +files=64 tokens=39 role_rules=8 derived_accessors=17 wrappers=6 + +## Per category +(a) type tests 384 CASE=52 DATA=3 TEST=327 YIELD=2 +(b) payload reads 505 RAW=113 READ=392 +(c) producers 472 GUARD=71 PARSE=3 PRODUCE=373 TAGSET=3 WRITE=22 +(d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 +(e) number formatting 14 CASE=1 FORMAT=3 PARSE=1 RAW=2 READ=3 TEST=4 +(f) equality, ordering and hashing 27 CASE=1 PRODUCE=4 RAW=5 READ=9 TEST=8 +(g) tape encode and decode 20 CASE=2 DATA=2 PARSE=7 PRODUCE=5 RAW=3 TEST=1 +(h) JSON, store and db encoders 70 CASE=2 FORMAT=3 PARSE=5 PRODUCE=19 READ=24 TEST=17 +(i) observer numeric paths 90 CASE=4 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=5 TEST=22 +(j) embed API 64 CASE=1 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 + +## Per token +make_num 368 +VAL_NUM 329 +eigs_num_arg 145 +eigs_list_num 130 +SLOT_NUM_RAW 94 +VAL_NUM_RAW 92 +slot_is_num 62 +num_guard 60 +AST_NUM 52 +eigs_slot_num 52 +eigs_value_as_num 48 +slot_from_num 41 +buffer_read_num 38 +list_set_num 22 +slot_as_double 16 +strtod 16 +NUM_REUSE 15 +eigs_slot_opt_num 12 +eigs_num_arg_slow 9 +EIGS_NUM_MAX 8 +finite_num_to_byte 8 +eigs_num_text 7 +eigs_opt_num 6 +eigs_slot_elem_num 6 +num_guard_named 6 +num_to_i64_exact 6 +num_val 5 +VAL_NUM_OFFSET 4 +buf_num_arg 4 +dict_value_rewrite_num 4 +list_rewrite_num 3 +eigs_elem_num 2 +list_append_num 2 +make_num_permanent 2 +atof 1 +dict_value_get_num 1 +dict_value_set_num 1 +list_get_num 1 +slot_is_numeric 1 +data.num (AST) 7 + +## Per file (category counts) +builtins.c 319 a=74 b=94 c=111 e=6 f=8 h=15 i=11 +vm.c 304 a=78 b=105 c=72 f=6 i=43 +ext_gfx.c 229 a=56 b=103 c=70 +builtins_tensor.c 184 a=39 b=59 c=86 +builtins_buf.c 97 a=21 b=37 c=39 +jit.c 96 d=96 +eigenscript.c 83 a=13 b=13 c=12 e=5 f=7 i=33 +container.h 72 a=23 b=24 c=25 +embed_smoke.c 50 j=50 +ext_store.c 50 h=50 +builtins_host.c 47 a=11 b=24 c=12 +jit_smoke.c 31 d=31 +eigenscript.h 30 a=3 b=15 c=11 e=1 +lint.c 29 a=29 +compiler.c 21 a=13 b=5 c=1 i=2 +ext_net.c 19 a=5 b=7 c=7 +model_infer.c 16 a=1 b=6 c=9 +trace.c 15 g=15 +ext_http.c 14 a=3 b=4 c=7 +chunk.c 11 a=3 e=2 f=6 +value_slot.h 8 a=4 b=2 c=2 +eigs_embed.c 7 j=7 +model_train.c 7 a=1 b=4 c=1 i=1 +embed_concurrent.c 6 j=6 +parser.c 5 a=2 b=1 c=2 +tape_read.c 5 g=5 +ext_db.c 4 h=4 +task.c 4 c=4 +lexer.c 3 b=2 c=1 +lint_host.c 3 a=3 +eigenlsp.c 2 a=2 +eigs_embed.h 1 j=1 +model_io.c 1 h=1 + +## Builtins +registered=311 numeric=229 classified=229 unclassified=0 stale=0 +classes: float-producing=58 int-preserving=37 int-requiring=67 other=67 +LOSS (39): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_query store_update subtract sum task_sched_seed +abs builtin_abs int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +acos builtin_acos float-producing - VAL_NUM,eigs_num_arg,make_num +add builtin_tensor_add int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard +append builtin_append other - VAL_NUM +asin builtin_asin float-producing - VAL_NUM,eigs_num_arg,make_num +assert builtin_assert other - eigs_num_text +atan builtin_atan float-producing - VAL_NUM,eigs_num_arg,make_num +atan2 builtin_atan2 float-producing - VAL_NUM,eigs_num_arg,make_num +audio_capture_open builtin_audio_capture_open other - VAL_NUM,eigs_list_num,make_num +audio_envelope builtin_audio_envelope float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num +audio_gain builtin_audio_gain float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num +audio_mix builtin_audio_mix float-producing - VAL_NUM,eigs_slot_num,make_num +audio_music_play builtin_audio_music_play other - VAL_NUM,eigs_list_num +audio_music_volume builtin_audio_music_volume other - VAL_NUM,eigs_list_num,eigs_num_arg +audio_noise builtin_audio_noise float-producing - VAL_NUM,eigs_list_num,make_num +audio_open builtin_audio_open other - VAL_NUM,eigs_list_num,make_num +audio_pause builtin_audio_pause other - VAL_NUM,eigs_num_arg +audio_play builtin_audio_play other - VAL_NUM,buffer_read_num,eigs_slot_num,make_num +audio_play_loop builtin_audio_play_loop other - VAL_NUM,buffer_read_num,eigs_list_num,eigs_slot_num,make_num +audio_queue_size builtin_audio_queue_size int-preserving - make_num +audio_saw builtin_audio_saw float-producing - VAL_NUM,eigs_list_num,make_num +audio_sine builtin_audio_sine float-producing - VAL_NUM,eigs_list_num,make_num +audio_square builtin_audio_square float-producing - VAL_NUM,eigs_list_num,make_num +audio_stop builtin_audio_stop int-requiring - VAL_NUM,eigs_num_arg,make_num +audio_stream_open builtin_audio_stream_open other - VAL_NUM,eigs_list_num,make_num +audio_stream_push builtin_audio_stream_push other - VAL_NUM,buffer_read_num,eigs_slot_num +audio_stream_queued builtin_audio_stream_queued int-preserving - make_num +audio_sweep builtin_audio_sweep float-producing - VAL_NUM,eigs_list_num,make_num +audio_volume builtin_audio_volume other - VAL_NUM,eigs_slot_num,make_num +bit_and builtin_bit_and int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_not builtin_bit_not int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_or builtin_bit_or int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_shl builtin_bit_shift_left int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_shr builtin_bit_shift_right int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_xor builtin_bit_xor int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +buf_copy builtin_buf_copy int-requiring - VAL_NUM,eigs_slot_num +buf_deinterleave builtin_buf_deinterleave int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_num +buf_dot builtin_buf_dot float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,make_num,num_guard +buf_fill builtin_buf_fill float-producing - VAL_NUM,buf_num_arg,eigs_slot_num +buf_from_list builtin_buf_from_list float-producing - VAL_NUM,eigs_slot_num +buf_from_pcm16le builtin_buf_from_pcm16le float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,num_guard +buf_get builtin_buf_get int-requiring - buffer_read_num,eigs_list_num,make_num +buf_len builtin_buf_len int-preserving - make_num +buf_mix builtin_buf_mix float-producing - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard +buf_peak builtin_buf_peak float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,make_num +buf_resample_linear builtin_buf_resample_linear float-producing - VAL_NUM,eigs_slot_num,num_guard +buf_scale_range builtin_buf_scale_range float-producing - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard +buf_set builtin_buf_set int-requiring - VAL_NUM,eigs_list_num +buf_to_pcm16le builtin_buf_to_pcm16le other - VAL_NUM,buffer_read_num,eigs_slot_num,num_guard +buffer builtin_buffer int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg +build_corpus builtin_build_corpus int-requiring - VAL_NUM,eigs_num_arg,eigs_opt_num,make_num,num_val +ceil builtin_ceil int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +channel builtin_channel int-preserving - make_num +channel_closed builtin_channel_closed int-requiring - VAL_NUM,eigs_num_arg +char_at builtin_char_at int-requiring - VAL_NUM,eigs_num_arg +chr builtin_chr int-requiring - VAL_NUM,eigs_num_arg +clock_unix builtin_clock_unix float-producing - make_num +close_channel builtin_close_channel int-requiring - VAL_NUM,eigs_num_arg +copy_into builtin_copy_into int-requiring - VAL_NUM,eigs_num_arg +cos builtin_cos float-producing - VAL_NUM,eigs_num_arg,make_num +db_execute builtin_db_execute other - VAL_NUM,eigs_num_arg +db_query_json builtin_db_query_json other - VAL_NUM,eigs_num_arg +db_query_value builtin_db_query_value other LOSS VAL_NUM,eigs_num_arg,make_num,strtod +dispatch builtin_dispatch int-requiring - VAL_NUM,eigs_num_arg,make_num +divide builtin_tensor_divide float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard +dot builtin_dot float-producing - buffer_read_num,make_num,num_guard +eigen_eval_loss builtin_eigen_eval_loss float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num +eigen_generate builtin_eigen_generate other - eigs_slot_num,eigs_slot_opt_num,make_num +eigen_model_load builtin_eigen_model_load other - strtod +exec_capture builtin_exec_capture other - VAL_NUM,eigs_list_num,list_append_num +exit builtin_exit int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg +exp builtin_tensor_exp float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard +f64_from_bytes builtin_f64_from_bytes other - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named +f64_to_bytes builtin_f64_to_bytes other - VAL_NUM,eigs_num_arg,make_num +fill builtin_fill int-requiring - eigs_list_num +floor builtin_floor int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +gather builtin_tensor_gather int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num +get_at builtin_get_at int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,make_num +get_observer_thresholds builtin_get_observer_thresholds float-producing - make_num +gfx_circle builtin_gfx_circle other - VAL_NUM,eigs_list_num +gfx_clear builtin_gfx_clear other - VAL_NUM,eigs_list_num +gfx_clip builtin_gfx_clip other - VAL_NUM,eigs_list_num +gfx_delay builtin_gfx_delay other - VAL_NUM,eigs_num_arg +gfx_fb builtin_gfx_fb other - VAL_NUM,eigs_list_num +gfx_line builtin_gfx_line other - VAL_NUM,eigs_list_num +gfx_open builtin_gfx_open other - VAL_NUM,eigs_list_num +gfx_point builtin_gfx_point other - VAL_NUM,eigs_list_num +gfx_poll builtin_gfx_poll int-preserving - make_num +gfx_read builtin_gfx_read other - VAL_NUM,eigs_list_num,make_num +gfx_rect builtin_gfx_rect other - VAL_NUM,eigs_list_num +gfx_rrect builtin_gfx_rrect other - VAL_NUM,eigs_list_num +gfx_text builtin_gfx_text other - VAL_NUM,eigs_list_num +gfx_text_height builtin_gfx_text_height int-preserving - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +gfx_text_width builtin_gfx_text_width int-preserving - VAL_NUM,eigs_list_num,make_num +gfx_ticks builtin_gfx_ticks int-preserving - make_num +hex builtin_hex int-requiring LOSS VAL_NUM,eigs_list_num,eigs_num_arg +http_early_bind builtin_http_early_bind int-requiring - VAL_NUM,eigs_opt_num +http_post builtin_http_post other - eigs_num_text +http_route builtin_http_route other - eigs_num_text +http_route_authed builtin_http_route_authed other - eigs_num_text +http_serve builtin_http_serve int-requiring - eigs_num_text,eigs_opt_num +http_static builtin_http_static other - eigs_num_text +index_of builtin_index_of int-preserving - make_num +inflate builtin_inflate other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num +join builtin_join other - eigs_num_text +json_build builtin_json_build other LOSS VAL_NUM,eigs_num_arg,eigs_num_text +json_decode builtin_json_decode other LOSS make_num,strtod +json_encode builtin_json_encode other LOSS VAL_NUM,eigs_num_arg,eigs_num_text +json_path builtin_json_path other LOSS VAL_NUM,eigs_num_arg,eigs_num_text,make_num,strtod +leaky_relu builtin_tensor_leaky_relu float-producing - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num +len builtin_len int-preserving - make_num +list_contains builtin_list_contains other - values_equal +list_index_of builtin_list_index_of int-preserving - make_num,values_equal +list_insert_at builtin_list_insert_at int-requiring - VAL_NUM,eigs_num_arg +list_remove_at builtin_list_remove_at int-requiring - VAL_NUM,eigs_num_arg +list_slice builtin_list_slice int-requiring - VAL_NUM,eigs_num_arg +list_truncate builtin_list_truncate int-requiring - VAL_NUM,eigs_num_arg +log builtin_tensor_log float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard +log_softmax builtin_tensor_log_softmax float-producing - VAL_NUM,eigs_slot_num,make_num +matmul builtin_tensor_matmul float-producing - SLOT_NUM_RAW,VAL_NUM,eigs_slot_num,make_num,num_guard_named +matmul_at builtin_tensor_matmul_at float-producing - VAL_NUM,eigs_slot_num,make_num +matmul_bt builtin_tensor_matmul_bt float-producing - VAL_NUM,eigs_slot_num,make_num +max builtin_max int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +mean builtin_tensor_mean float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +min builtin_min int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +model_load_weights builtin_eigen_model_load other - strtod +monotonic_ms builtin_monotonic_ms float-producing - make_num +monotonic_ns builtin_monotonic_ns int-preserving LOSS make_num +multiply builtin_tensor_multiply int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard +native_train_step_builtin builtin_native_train_step other - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod +nearest_in_range builtin_nearest_in_range float-producing - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num +nearest_in_range_all builtin_nearest_in_range_all float-producing - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num +negative builtin_tensor_negative int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +net_accept builtin_net_accept int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_opt_num,make_num +net_close builtin_net_close int-requiring - VAL_NUM,eigs_num_arg +net_dial builtin_net_dial int-requiring - eigs_slot_opt_num,make_num +net_listen builtin_net_listen int-requiring - VAL_NUM,eigs_num_arg,make_num +net_port builtin_net_port int-requiring - VAL_NUM,eigs_num_arg,make_num +net_recv builtin_net_recv int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_opt_num +net_send builtin_net_send other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +norm builtin_tensor_norm float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +num builtin_num other LOSS VAL_NUM,make_num,num_guard_named,strtod +num_copy builtin_num_copy int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +numerical_grad builtin_numerical_grad float-producing - VAL_NUM,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +numerical_grad_cols builtin_numerical_grad_cols float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +numerical_grad_rows builtin_numerical_grad_rows float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +observe builtin_observe other - make_num +ord builtin_ord int-preserving - make_num +pi builtin_pi float-producing - make_num +pow builtin_tensor_pow float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard_named +print builtin_print other - eigs_num_text +proc_read_buf builtin_proc_read_buf int-requiring - VAL_NUM,eigs_num_arg +random builtin_random float-producing - make_num +random_hex builtin_random_hex int-requiring - VAL_NUM,eigs_num_arg +random_int builtin_random_int int-requiring LOSS VAL_NUM,eigs_num_arg,make_num +random_normal builtin_random_normal float-producing - eigs_list_num,make_num +range builtin_range int-preserving - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +read_bytes builtin_read_bytes int-preserving - make_num +read_bytes_buf builtin_read_bytes_buf int-requiring - VAL_NUM,eigs_num_arg,make_num +record_history builtin_record_history other - VAL_NUM,eigs_num_arg,make_num +recv builtin_recv int-requiring - VAL_NUM,eigs_num_arg +recv_timeout builtin_recv_timeout other - VAL_NUM,eigs_num_arg +relu builtin_tensor_relu float-producing - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num +reshape builtin_reshape int-requiring - VAL_NUM,eigs_list_num +round builtin_round int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +sandbox_run builtin_sandbox_run int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +scan_int_tokens builtin_scan_int_tokens int-preserving LOSS make_num +scan_ints builtin_scan_ints int-preserving LOSS make_num +scatter_add builtin_tensor_scatter_add float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard +seed_random builtin_seed_random int-requiring LOSS VAL_NUM,eigs_num_arg +send builtin_send int-requiring - VAL_NUM,eigs_num_arg +set_at builtin_set_at int-requiring - VAL_NUM,eigs_num_arg +sgd_update builtin_sgd_update float-producing - VAL_NUM,eigs_slot_num,eigs_slot_opt_num,list_set_num +sgd_update_cols builtin_sgd_update_cols float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num +sgd_update_rows builtin_sgd_update_rows float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num +shape builtin_tensor_shape int-preserving - VAL_NUM,make_num +shared_delete builtin_shared_delete int-preserving - make_num +shared_incr builtin_shared_incr int-preserving LOSS VAL_NUM,eigs_num_arg,make_num +shared_size builtin_shared_size int-preserving - make_num +sign_extend builtin_sign_extend int-requiring LOSS VAL_NUM,eigs_num_arg,make_num +sin builtin_sin float-producing - VAL_NUM,eigs_num_arg,make_num +softmax builtin_tensor_softmax float-producing - VAL_NUM,eigs_slot_num,make_num +sort builtin_sort other LOSS VAL_NUM,eigs_slot_num +sort_by builtin_sort_by other LOSS VAL_NUM,eigs_num_arg +spawn builtin_spawn int-preserving - make_num +sqrt builtin_tensor_sqrt float-producing - VAL_NUM,eigs_num_arg,make_num +state_at builtin_state_at int-requiring - VAL_NUM,eigs_num_arg +store_close builtin_store_close int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num +store_collections builtin_store_collections int-requiring - VAL_NUM,eigs_num_arg +store_count builtin_store_count int-requiring - VAL_NUM,eigs_num_arg,make_num +store_delete builtin_store_delete int-requiring LOSS VAL_NUM,eigs_num_arg +store_drop builtin_store_drop int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num +store_get builtin_store_get int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,strtod +store_open builtin_store_open int-preserving - VAL_NUM,eigs_num_arg,make_num,strtod +store_put builtin_store_put other - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num +store_query builtin_store_query other LOSS VAL_NUM,eigs_num_arg,make_num,strtod +store_update builtin_store_update other LOSS VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num +str builtin_str other - eigs_num_text +str_from_bytes builtin_str_from_bytes other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte +stream_open builtin_stream_open int-requiring - VAL_NUM,eigs_num_arg +stream_write builtin_stream_write float-producing - VAL_NUM,eigs_num_arg +substr builtin_substr int-requiring - VAL_NUM,eigs_num_arg +subtract builtin_tensor_subtract int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard +sum builtin_tensor_sum int-preserving LOSS VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +tan builtin_tan float-producing - VAL_NUM,eigs_num_arg,make_num +task_alive builtin_task_alive int-requiring - VAL_NUM,eigs_num_arg +task_detach builtin_task_detach int-requiring - VAL_NUM,eigs_num_arg,make_num +task_join builtin_task_join int-requiring - VAL_NUM,eigs_num_arg +task_kill builtin_task_kill int-requiring - VAL_NUM,eigs_num_arg +task_sched_seed builtin_task_sched_seed int-requiring LOSS VAL_NUM,eigs_num_arg +task_self builtin_task_self int-preserving - make_num +task_send builtin_task_send int-requiring - VAL_NUM,eigs_num_arg +task_sleep builtin_task_sleep other - VAL_NUM,eigs_num_arg +task_spawn builtin_task_spawn int-preserving - make_num +tensor_load builtin_tensor_load float-producing - VAL_NUM,eigs_list_num,make_num,num_guard_named +tensor_save builtin_tensor_save float-producing - VAL_NUM,eigs_slot_num +text_builder_append builtin_text_builder_append other - eigs_num_text +text_builder_append_line builtin_text_builder_append_line other - eigs_num_text +thread_join builtin_thread_join int-requiring - VAL_NUM,eigs_num_arg +throw builtin_throw other - eigs_num_text +token_name builtin_token_name int-requiring - VAL_NUM,eigs_num_arg +try_recv builtin_try_recv int-requiring - VAL_NUM,eigs_num_arg +type builtin_type other - VAL_NUM +usleep builtin_usleep other - VAL_NUM,eigs_num_arg +vm_run_bytecode builtin_vm_run_bytecode int-requiring - VAL_NUM,eigs_num_arg +write builtin_write other - eigs_num_text +write_bytes builtin_write_bytes other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +zeros builtin_tensor_zeros int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +zeros_like builtin_tensor_zeros_like float-producing - VAL_NUM,make_num + +## Sites (file:line scope token kind category) +builtins.c:164 builtin_usleep VAL_NUM TEST a +builtins.c:165 builtin_usleep eigs_num_arg READ b +builtins.c:350 bit_int num_to_i64_exact READ b +builtins.c:361 bit_pair VAL_NUM TEST a +builtins.c:361 bit_pair VAL_NUM TEST a +builtins.c:362 bit_pair eigs_num_arg READ b +builtins.c:363 bit_pair eigs_num_arg READ b +builtins.c:372 builtin_bit_and make_num PRODUCE c +builtins.c:380 builtin_bit_or make_num PRODUCE c +builtins.c:388 builtin_bit_xor make_num PRODUCE c +builtins.c:392 builtin_bit_not VAL_NUM TEST a +builtins.c:394 builtin_bit_not eigs_num_arg READ b +builtins.c:395 builtin_bit_not make_num PRODUCE c +builtins.c:403 builtin_bit_shift_left make_num PRODUCE c +builtins.c:414 builtin_bit_shift_right make_num PRODUCE c +builtins.c:422 builtin_monotonic_ns make_num PRODUCE c +builtins.c:430 builtin_monotonic_ms make_num PRODUCE c +builtins.c:441 builtin_clock_unix make_num PRODUCE c +builtins.c:446 builtin_len make_num PRODUCE c +builtins.c:448 builtin_len make_num PRODUCE c +builtins.c:451 builtin_len make_num PRODUCE c +builtins.c:454 builtin_len make_num PRODUCE c +builtins.c:456 builtin_len make_num PRODUCE c +builtins.c:466 builtin_len make_num PRODUCE c +builtins.c:495 builtin_num make_num PRODUCE c +builtins.c:496 builtin_num VAL_NUM TEST a +builtins.c:503 builtin_num make_num PRODUCE c +builtins.c:522 builtin_num make_num PRODUCE c +builtins.c:530 builtin_num make_num PRODUCE c +builtins.c:535 builtin_num make_num PRODUCE c +builtins.c:535 builtin_num num_guard_named GUARD c +builtins.c:535 builtin_num strtod PARSE c +builtins.c:537 builtin_num make_num PRODUCE c +builtins.c:538 builtin_num make_num PRODUCE c +builtins.c:557 builtin_append VAL_NUM YIELD a +builtins.c:591 builtin_get_observer_thresholds make_num PRODUCE i +builtins.c:592 builtin_get_observer_thresholds make_num PRODUCE i +builtins.c:593 builtin_get_observer_thresholds make_num PRODUCE i +builtins.c:643 builtin_exit VAL_NUM TEST a +builtins.c:644 builtin_exit eigs_num_arg READ b +builtins.c:647 builtin_exit VAL_NUM TEST a +builtins.c:648 builtin_exit eigs_list_num READ b +builtins.c:783 builtin_observe make_num PRODUCE i +builtins.c:784 builtin_observe make_num PRODUCE i +builtins.c:785 builtin_observe make_num PRODUCE i +builtins.c:867 builtin_type VAL_NUM CASE a +builtins.c:915 eigs_json_encode_value VAL_NUM CASE h +builtins.c:922 eigs_json_encode_value eigs_num_arg READ h +builtins.c:922 eigs_json_encode_value eigs_num_text FORMAT h +builtins.c:1278 eigs_json_parse_number make_num PRODUCE h +builtins.c:1285 eigs_json_parse_number make_num PRODUCE h +builtins.c:1294 eigs_json_parse_number make_num PRODUCE h +builtins.c:1299 eigs_json_parse_number strtod PARSE h +builtins.c:1309 eigs_json_parse_number strtod PARSE h +builtins.c:1313 eigs_json_parse_number make_num PRODUCE h +builtins.c:1484 builtin_json_build VAL_NUM TEST h +builtins.c:1486 builtin_json_build eigs_num_arg READ h +builtins.c:1486 builtin_json_build eigs_num_text FORMAT h +builtins.c:1672 builtin_scan_ints make_num PRODUCE c +builtins.c:1786 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1787 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1788 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1789 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1790 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1791 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1894 builtin_char_at VAL_NUM TEST a +builtins.c:1896 builtin_char_at eigs_num_arg READ b +builtins.c:1930 builtin_substr VAL_NUM TEST a +builtins.c:1931 builtin_substr VAL_NUM TEST a +builtins.c:1933 builtin_substr eigs_num_arg READ b +builtins.c:1934 builtin_substr eigs_num_arg READ b +builtins.c:1964 builtin_index_of make_num PRODUCE c +builtins.c:1971 builtin_index_of make_num PRODUCE c +builtins.c:1976 builtin_index_of make_num PRODUCE c +builtins.c:1977 builtin_index_of make_num PRODUCE c +builtins.c:1985 builtin_sin VAL_NUM TEST a +builtins.c:1985 builtin_sin make_num PRODUCE c +builtins.c:1986 builtin_sin eigs_num_arg READ b +builtins.c:1986 builtin_sin make_num PRODUCE c +builtins.c:1990 builtin_cos VAL_NUM TEST a +builtins.c:1990 builtin_cos make_num PRODUCE c +builtins.c:1991 builtin_cos eigs_num_arg READ b +builtins.c:1991 builtin_cos make_num PRODUCE c +builtins.c:1995 builtin_tan VAL_NUM TEST a +builtins.c:1995 builtin_tan make_num PRODUCE c +builtins.c:1996 builtin_tan eigs_num_arg READ b +builtins.c:1996 builtin_tan make_num PRODUCE c +builtins.c:2000 builtin_asin VAL_NUM TEST a +builtins.c:2000 builtin_asin make_num PRODUCE c +builtins.c:2001 builtin_asin eigs_num_arg READ b +builtins.c:2006 builtin_asin make_num PRODUCE c +builtins.c:2010 builtin_asin make_num PRODUCE c +builtins.c:2014 builtin_acos VAL_NUM TEST a +builtins.c:2014 builtin_acos make_num PRODUCE c +builtins.c:2015 builtin_acos eigs_num_arg READ b +builtins.c:2020 builtin_acos make_num PRODUCE c +builtins.c:2024 builtin_acos make_num PRODUCE c +builtins.c:2028 builtin_atan VAL_NUM TEST a +builtins.c:2028 builtin_atan make_num PRODUCE c +builtins.c:2029 builtin_atan eigs_num_arg READ b +builtins.c:2029 builtin_atan make_num PRODUCE c +builtins.c:2034 builtin_atan2 make_num PRODUCE c +builtins.c:2037 builtin_atan2 VAL_NUM TEST a +builtins.c:2037 builtin_atan2 VAL_NUM TEST a +builtins.c:2037 builtin_atan2 make_num PRODUCE c +builtins.c:2038 builtin_atan2 eigs_num_arg READ b +builtins.c:2038 builtin_atan2 eigs_num_arg READ b +builtins.c:2038 builtin_atan2 make_num PRODUCE c +builtins.c:2042 builtin_floor VAL_NUM TEST a +builtins.c:2042 builtin_floor make_num PRODUCE c +builtins.c:2043 builtin_floor eigs_num_arg READ b +builtins.c:2043 builtin_floor make_num PRODUCE c +builtins.c:2047 builtin_ceil VAL_NUM TEST a +builtins.c:2047 builtin_ceil make_num PRODUCE c +builtins.c:2048 builtin_ceil eigs_num_arg READ b +builtins.c:2048 builtin_ceil make_num PRODUCE c +builtins.c:2052 builtin_round VAL_NUM TEST a +builtins.c:2052 builtin_round make_num PRODUCE c +builtins.c:2053 builtin_round eigs_num_arg READ b +builtins.c:2053 builtin_round make_num PRODUCE c +builtins.c:2057 builtin_abs VAL_NUM TEST a +builtins.c:2057 builtin_abs make_num PRODUCE c +builtins.c:2058 builtin_abs eigs_num_arg READ b +builtins.c:2058 builtin_abs make_num PRODUCE c +builtins.c:2067 minmax_reduce VAL_NUM TEST a +builtins.c:2067 minmax_reduce eigs_num_arg READ b +builtins.c:2067 minmax_reduce make_num PRODUCE c +builtins.c:2072 minmax_reduce make_num PRODUCE c +builtins.c:2075 minmax_reduce make_num PRODUCE c +builtins.c:2079 minmax_reduce VAL_NUM TEST a +builtins.c:2079 minmax_reduce make_num PRODUCE c +builtins.c:2080 minmax_reduce eigs_num_arg READ b +builtins.c:2080 minmax_reduce eigs_num_arg READ b +builtins.c:2081 minmax_reduce eigs_num_arg READ b +builtins.c:2083 minmax_reduce make_num PRODUCE c +builtins.c:2092 builtin_pi make_num PRODUCE c +builtins.c:2148 builtin_random make_num PRODUCE c +builtins.c:2157 builtin_random_int make_num PRODUCE c +builtins.c:2160 builtin_random_int VAL_NUM TEST a +builtins.c:2160 builtin_random_int VAL_NUM TEST a +builtins.c:2161 builtin_random_int make_num PRODUCE c +builtins.c:2165 builtin_random_int eigs_num_arg READ b +builtins.c:2166 builtin_random_int eigs_num_arg READ b +builtins.c:2176 builtin_random_int make_num PRODUCE c +builtins.c:2188 builtin_random_int make_num PRODUCE c +builtins.c:2193 builtin_seed_random VAL_NUM TEST a +builtins.c:2195 builtin_seed_random eigs_num_arg READ b +builtins.c:2423 builtin_json_path VAL_NUM TEST h +builtins.c:2425 builtin_json_path eigs_num_arg READ h +builtins.c:2425 builtin_json_path eigs_num_text FORMAT h +builtins.c:2529 builtin_token_name VAL_NUM TEST a +builtins.c:2530 builtin_token_name eigs_num_arg READ b +builtins.c:2566 builtin_state_at VAL_NUM TEST i +builtins.c:2567 builtin_state_at eigs_num_arg READ i +builtins.c:2613 builtin_chr VAL_NUM TEST a +builtins.c:2617 builtin_chr eigs_num_arg READ b +builtins.c:2641 builtin_hex VAL_NUM TEST e +builtins.c:2642 builtin_hex eigs_num_arg READ e +builtins.c:2644 builtin_hex VAL_NUM TEST e +builtins.c:2645 builtin_hex VAL_NUM TEST e +builtins.c:2646 builtin_hex eigs_list_num READ e +builtins.c:2647 builtin_hex eigs_list_num READ e +builtins.c:2674 builtin_ord make_num PRODUCE c +builtins.c:2677 builtin_ord make_num PRODUCE c +builtins.c:2678 builtin_ord make_num PRODUCE c +builtins.c:2795 vm_desc_abi_error VAL_NUM TEST a +builtins.c:2803 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2808 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2904 desc_isolate_const VAL_NUM CASE a +builtins.c:3022 vm_build_chunk_desc_body VAL_NUM TEST a +builtins.c:3027 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3083 vm_build_chunk_desc_body VAL_NUM TEST a +builtins.c:3084 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3401 builtin_sandbox_run VAL_NUM TEST a +builtins.c:3402 builtin_sandbox_run eigs_list_num READ b +builtins.c:3408 builtin_sandbox_run VAL_NUM TEST a +builtins.c:3409 builtin_sandbox_run eigs_list_num READ b +builtins.c:3410 builtin_sandbox_run eigs_list_num READ b +builtins.c:3417 builtin_sandbox_run VAL_NUM TEST a +builtins.c:3418 builtin_sandbox_run eigs_list_num READ b +builtins.c:3460 builtin_sandbox_run make_num PRODUCE c +builtins.c:3641 builtin_sandbox_run make_num PRODUCE c +builtins.c:3653 builtin_sandbox_run make_num PRODUCE c +builtins.c:3667 builtin_sandbox_run make_num PRODUCE c +builtins.c:3701 builtin_sandbox_run make_num PRODUCE c +builtins.c:3727 builtin_record_history VAL_NUM TEST i +builtins.c:3733 builtin_record_history eigs_num_arg READ i +builtins.c:3738 builtin_record_history make_num PRODUCE i +builtins.c:3766 builtin_copy_into VAL_NUM TEST a +builtins.c:3771 builtin_copy_into eigs_num_arg READ b +builtins.c:3783 builtin_copy_into VAL_NUM TEST a +builtins.c:3788 builtin_copy_into eigs_num_arg READ b +builtins.c:3821 builtin_list_slice VAL_NUM TEST a +builtins.c:3821 builtin_list_slice VAL_NUM TEST a +builtins.c:3824 builtin_list_slice eigs_num_arg READ b +builtins.c:3825 builtin_list_slice eigs_num_arg READ b +builtins.c:3847 builtin_num_copy VAL_NUM TEST a +builtins.c:3848 builtin_num_copy eigs_num_arg READ b +builtins.c:3848 builtin_num_copy make_num PRODUCE c +builtins.c:3892 builtin_range VAL_NUM TEST a +builtins.c:3894 builtin_range eigs_num_arg READ b +builtins.c:3901 builtin_range VAL_NUM TEST a +builtins.c:3909 builtin_range eigs_list_num READ b +builtins.c:3912 builtin_range eigs_list_num READ b +builtins.c:3916 builtin_range eigs_list_num READ b +builtins.c:3960 builtin_range make_num PRODUCE c +builtins.c:3976 builtin_fill eigs_list_num READ b +builtins.c:3998 at_index VAL_NUM TEST a +builtins.c:4002 at_index eigs_num_arg READ b +builtins.c:4006 at_index eigs_num_arg READ b +builtins.c:4017 buf_at_index VAL_NUM TEST a +builtins.c:4022 buf_at_index eigs_num_arg READ b +builtins.c:4026 buf_at_index eigs_num_arg READ b +builtins.c:4067 builtin_set_at VAL_NUM TEST a +builtins.c:4072 builtin_set_at eigs_num_arg READ b +builtins.c:4133 builtin_get_at buffer_read_num READ b +builtins.c:4133 builtin_get_at make_num PRODUCE c +builtins.c:4141 builtin_get_at buffer_read_num READ b +builtins.c:4141 builtin_get_at make_num PRODUCE c +builtins.c:4503 builtin_spawn make_num PRODUCE c +builtins.c:4509 builtin_spawn make_num PRODUCE c +builtins.c:4510 builtin_spawn make_num PRODUCE c +builtins.c:4535 builtin_thread_join VAL_NUM TEST a +builtins.c:4539 builtin_thread_join eigs_num_arg READ b +builtins.c:4540 builtin_thread_join VAL_NUM TEST a +builtins.c:4540 builtin_thread_join eigs_num_arg READ b +builtins.c:4620 get_channel_why VAL_NUM TEST a +builtins.c:4621 get_channel_why eigs_num_arg READ b +builtins.c:4623 get_channel_why VAL_NUM TEST a +builtins.c:4623 get_channel_why eigs_num_arg READ b +builtins.c:4688 builtin_channel make_num PRODUCE c +builtins.c:4689 builtin_channel make_num PRODUCE c +builtins.c:4791 builtin_recv_timeout VAL_NUM TEST a +builtins.c:4795 builtin_recv_timeout eigs_num_arg READ b +builtins.c:4977 builtin_task_spawn make_num PRODUCE c +builtins.c:4987 task_handle_resolve VAL_NUM TEST a +builtins.c:4988 task_handle_resolve eigs_num_arg READ b +builtins.c:5039 builtin_task_join VAL_NUM TEST a +builtins.c:5081 builtin_task_send VAL_NUM TEST a +builtins.c:5089 builtin_task_send eigs_num_arg READ b +builtins.c:5112 builtin_task_kill VAL_NUM TEST a +builtins.c:5124 builtin_task_alive VAL_NUM TEST a +builtins.c:5146 builtin_task_sleep VAL_NUM TEST a +builtins.c:5152 builtin_task_sleep eigs_num_arg READ b +builtins.c:5184 builtin_task_self make_num PRODUCE c +builtins.c:5196 builtin_task_detach VAL_NUM TEST a +builtins.c:5201 builtin_task_detach make_num PRODUCE c +builtins.c:5202 builtin_task_detach make_num PRODUCE c +builtins.c:5213 builtin_task_sched_seed VAL_NUM TEST a +builtins.c:5217 builtin_task_sched_seed eigs_num_arg READ b +builtins.c:5366 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5367 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5368 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5369 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5370 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5426 builtin_nearest_in_range VAL_NUM TEST a +builtins.c:5426 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5450 builtin_nearest_in_range eigs_num_arg_slow READ b +builtins.c:5453 builtin_nearest_in_range VAL_NUM TEST a +builtins.c:5453 builtin_nearest_in_range VAL_NUM TEST a +builtins.c:5455 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5456 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5470 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5471 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5472 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5473 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5498 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5499 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5500 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5555 builtin_nearest_in_range_all VAL_NUM TEST a +builtins.c:5555 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5575 builtin_nearest_in_range_all eigs_num_arg_slow READ b +builtins.c:5578 builtin_nearest_in_range_all VAL_NUM TEST a +builtins.c:5578 builtin_nearest_in_range_all VAL_NUM TEST a +builtins.c:5582 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5583 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5624 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5625 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5626 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5627 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5650 builtin_sign_extend make_num PRODUCE c +builtins.c:5660 builtin_sign_extend VAL_NUM TEST a +builtins.c:5660 builtin_sign_extend VAL_NUM TEST a +builtins.c:5660 builtin_sign_extend make_num PRODUCE c +builtins.c:5661 builtin_sign_extend eigs_num_arg READ b +builtins.c:5662 builtin_sign_extend eigs_num_arg READ b +builtins.c:5663 builtin_sign_extend make_num PRODUCE c +builtins.c:5666 builtin_sign_extend make_num PRODUCE c +builtins.c:5667 builtin_sign_extend make_num PRODUCE c +builtins.c:5684 builtin_list_truncate VAL_NUM TEST a +builtins.c:5688 builtin_list_truncate eigs_num_arg READ b +builtins.c:5714 builtin_list_remove_at VAL_NUM TEST a +builtins.c:5715 builtin_list_remove_at eigs_num_arg READ b +builtins.c:5736 builtin_list_insert_at VAL_NUM TEST a +builtins.c:5737 builtin_list_insert_at eigs_num_arg READ b +builtins.c:5764 builtin_list_index_of make_num PRODUCE f +builtins.c:5768 builtin_list_index_of make_num PRODUCE f +builtins.c:5774 builtin_list_index_of make_num PRODUCE f +builtins.c:5778 builtin_list_index_of make_num PRODUCE f +builtins.c:5841 builtin_sort_by VAL_NUM TEST f +builtins.c:5850 builtin_sort_by eigs_num_arg READ f +builtins.c:5869 sort_cmp_num eigs_slot_num READ b +builtins.c:5870 sort_cmp_num eigs_slot_num READ b +builtins.c:5888 builtin_sort VAL_NUM TEST f +builtins.c:5895 builtin_sort VAL_NUM TEST f +builtins.c:5916 builtin_dispatch VAL_NUM TEST a +builtins.c:5920 builtin_dispatch eigs_num_arg READ b +builtins.c:5921 builtin_dispatch eigs_num_arg READ b +builtins.c:5923 builtin_dispatch eigs_num_arg READ b +builtins.c:5946 builtin_dispatch VAL_NUM TEST a +builtins.c:5947 builtin_dispatch eigs_num_arg READ b +builtins.c:5947 builtin_dispatch make_num PRODUCE c +builtins.c:6023 builtin_dot make_num PRODUCE c +builtins.c:6026 builtin_dot make_num PRODUCE c +builtins.c:6031 builtin_dot buffer_read_num READ b +builtins.c:6033 builtin_dot buffer_read_num READ b +builtins.c:6035 builtin_dot num_guard GUARD c +builtins.c:6035 builtin_dot num_guard GUARD c +builtins.c:6037 builtin_dot make_num PRODUCE c +builtins_buf.c:35 builtin_buffer VAL_NUM TEST a +builtins_buf.c:36 builtin_buffer VAL_NUM TEST a +builtins_buf.c:37 builtin_buffer eigs_list_num READ b +builtins_buf.c:38 builtin_buffer eigs_list_num READ b +builtins_buf.c:56 builtin_buffer VAL_NUM TEST a +builtins_buf.c:57 builtin_buffer VAL_NUM TEST a +builtins_buf.c:57 builtin_buffer eigs_num_arg READ b +builtins_buf.c:78 builtin_reshape VAL_NUM TEST a +builtins_buf.c:79 builtin_reshape VAL_NUM TEST a +builtins_buf.c:80 builtin_reshape eigs_list_num READ b +builtins_buf.c:81 builtin_reshape eigs_list_num READ b +builtins_buf.c:105 builtin_buf_get make_num PRODUCE c +builtins_buf.c:112 builtin_buf_get make_num PRODUCE c +builtins_buf.c:114 builtin_buf_get eigs_list_num READ b +builtins_buf.c:115 builtin_buf_get make_num PRODUCE c +builtins_buf.c:120 builtin_buf_get make_num PRODUCE c +builtins_buf.c:122 builtin_buf_get buffer_read_num READ b +builtins_buf.c:122 builtin_buf_get make_num PRODUCE c +builtins_buf.c:141 builtin_buf_set VAL_NUM TEST a +builtins_buf.c:145 builtin_buf_set VAL_NUM TEST a +builtins_buf.c:149 builtin_buf_set eigs_list_num READ b +builtins_buf.c:150 builtin_buf_set eigs_list_num READ b +builtins_buf.c:163 builtin_buf_len make_num PRODUCE c +builtins_buf.c:164 builtin_buf_len make_num PRODUCE c +builtins_buf.c:184 builtin_buf_from_list VAL_NUM TEST a +builtins_buf.c:185 builtin_buf_from_list eigs_slot_num READ b +builtins_buf.c:206 strict_numeric_byte_list VAL_NUM TEST a +builtins_buf.c:213 strict_numeric_byte_list VAL_NUM TEST a +builtins_buf.c:214 strict_numeric_byte_list eigs_num_arg READ b +builtins_buf.c:214 strict_numeric_byte_list finite_num_to_byte READ b +builtins_buf.c:239 builtin_str_from_bytes VAL_NUM TEST a +builtins_buf.c:239 builtin_str_from_bytes eigs_slot_num READ b +builtins_buf.c:240 builtin_str_from_bytes buffer_read_num READ b +builtins_buf.c:242 builtin_str_from_bytes finite_num_to_byte READ b +builtins_buf.c:260 builtin_f64_to_bytes VAL_NUM TEST a +builtins_buf.c:261 builtin_f64_to_bytes VAL_NUM TEST a +builtins_buf.c:261 builtin_f64_to_bytes eigs_num_arg READ b +builtins_buf.c:267 builtin_f64_to_bytes make_num PRODUCE c +builtins_buf.c:279 builtin_f64_from_bytes VAL_NUM TEST a +builtins_buf.c:280 builtin_f64_from_bytes eigs_slot_num READ b +builtins_buf.c:284 builtin_f64_from_bytes buffer_read_num READ b +builtins_buf.c:288 builtin_f64_from_bytes make_num PRODUCE c +builtins_buf.c:292 builtin_f64_from_bytes finite_num_to_byte READ b +builtins_buf.c:297 builtin_f64_from_bytes make_num PRODUCE c +builtins_buf.c:297 builtin_f64_from_bytes num_guard_named GUARD c +builtins_buf.c:350 zlib_bytes_arg VAL_NUM TEST a +builtins_buf.c:350 zlib_bytes_arg eigs_slot_num READ b +builtins_buf.c:351 zlib_bytes_arg buffer_read_num READ b +builtins_buf.c:353 zlib_bytes_arg finite_num_to_byte READ b +builtins_buf.c:374 zlib_bytes_result make_num PRODUCE c +builtins_buf.c:493 buf_count_arg VAL_NUM TEST a +builtins_buf.c:497 buf_count_arg eigs_slot_num READ b +builtins_buf.c:507 buf_num_arg READ b +builtins_buf.c:509 buf_num_arg VAL_NUM TEST a +builtins_buf.c:513 buf_num_arg eigs_slot_num READ b +builtins_buf.c:526 buf_window_arg VAL_NUM TEST a +builtins_buf.c:530 buf_window_arg eigs_slot_num READ b +builtins_buf.c:590 builtin_buf_mix buf_num_arg READ b +builtins_buf.c:595 builtin_buf_mix num_guard GUARD c +builtins_buf.c:595 builtin_buf_mix num_guard GUARD c +builtins_buf.c:614 builtin_buf_scale_range buf_num_arg READ b +builtins_buf.c:618 builtin_buf_scale_range num_guard GUARD c +builtins_buf.c:637 builtin_buf_fill buf_num_arg READ b +builtins_buf.c:652 builtin_buf_peak make_num PRODUCE c +builtins_buf.c:660 builtin_buf_peak make_num PRODUCE c +builtins_buf.c:663 builtin_buf_peak buffer_read_num READ b +builtins_buf.c:668 builtin_buf_peak make_num PRODUCE c +builtins_buf.c:682 builtin_buf_dot make_num PRODUCE c +builtins_buf.c:693 builtin_buf_dot make_num PRODUCE c +builtins_buf.c:696 builtin_buf_dot buffer_read_num READ b +builtins_buf.c:698 builtin_buf_dot buffer_read_num READ b +builtins_buf.c:700 builtin_buf_dot num_guard GUARD c +builtins_buf.c:700 builtin_buf_dot num_guard GUARD c +builtins_buf.c:702 builtin_buf_dot make_num PRODUCE c +builtins_buf.c:754 builtin_buf_from_pcm16le buffer_read_num READ b +builtins_buf.c:756 builtin_buf_from_pcm16le buffer_read_num READ b +builtins_buf.c:758 builtin_buf_from_pcm16le num_guard GUARD c +builtins_buf.c:758 builtin_buf_from_pcm16le num_guard GUARD c +builtins_buf.c:760 builtin_buf_from_pcm16le num_guard GUARD c +builtins_buf.c:761 builtin_buf_from_pcm16le num_guard GUARD c +builtins_buf.c:794 builtin_buf_to_pcm16le buffer_read_num READ b +builtins_buf.c:798 builtin_buf_to_pcm16le num_guard GUARD c +builtins_buf.c:799 builtin_buf_to_pcm16le num_guard GUARD c +builtins_buf.c:800 builtin_buf_to_pcm16le num_guard GUARD c +builtins_buf.c:801 builtin_buf_to_pcm16le num_guard GUARD c +builtins_buf.c:801 builtin_buf_to_pcm16le num_guard GUARD c +builtins_buf.c:827 builtin_buf_deinterleave VAL_NUM TEST a +builtins_buf.c:827 builtin_buf_deinterleave VAL_NUM TEST a +builtins_buf.c:831 builtin_buf_deinterleave eigs_num_arg READ b +builtins_buf.c:832 builtin_buf_deinterleave eigs_num_arg READ b +builtins_buf.c:909 builtin_buf_resample_linear num_guard GUARD c +builtins_buf.c:909 builtin_buf_resample_linear num_guard GUARD c +builtins_buf.c:923 builtin_buf_resample_linear num_guard GUARD c +builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c +builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c +builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c +builtins_buf.c:925 builtin_buf_resample_linear num_guard GUARD c +builtins_host.c:218 builtin_stream_open VAL_NUM TEST a +builtins_host.c:220 builtin_stream_open eigs_num_arg READ b +builtins_host.c:221 builtin_stream_open eigs_num_arg READ b +builtins_host.c:222 builtin_stream_open eigs_num_arg READ b +builtins_host.c:222 builtin_stream_open eigs_num_arg READ b +builtins_host.c:225 builtin_stream_open eigs_num_arg READ b +builtins_host.c:236 builtin_stream_open eigs_num_arg READ b +builtins_host.c:255 builtin_stream_write VAL_NUM TEST a +builtins_host.c:260 builtin_stream_write eigs_num_arg READ b +builtins_host.c:413 builtin_build_corpus VAL_NUM TEST a +builtins_host.c:417 builtin_build_corpus eigs_num_arg READ b +builtins_host.c:449 builtin_build_corpus eigs_opt_num READ b +builtins_host.c:478 builtin_build_corpus eigs_opt_num READ b +builtins_host.c:707 builtin_build_corpus num_val RAW b +builtins_host.c:808 builtin_build_corpus make_num PRODUCE c +builtins_host.c:809 builtin_build_corpus make_num PRODUCE c +builtins_host.c:810 builtin_build_corpus make_num PRODUCE c +builtins_host.c:1055 builtin_read_bytes make_num PRODUCE c +builtins_host.c:1106 builtin_read_bytes_buf VAL_NUM TEST a +builtins_host.c:1110 builtin_read_bytes_buf eigs_num_arg READ b +builtins_host.c:1111 builtin_read_bytes_buf eigs_num_arg READ b +builtins_host.c:1114 builtin_read_bytes_buf eigs_num_arg READ b +builtins_host.c:1117 builtin_read_bytes_buf eigs_num_arg READ b +builtins_host.c:1131 builtin_read_bytes_buf VAL_NUM TEST a +builtins_host.c:1132 builtin_read_bytes_buf eigs_num_arg READ b +builtins_host.c:1152 builtin_read_bytes_buf make_num PRODUCE c +builtins_host.c:1263 exec_capture_result list_append_num PRODUCE c +builtins_host.c:1290 builtin_exec_capture VAL_NUM TEST a +builtins_host.c:1292 builtin_exec_capture eigs_list_num READ b +builtins_host.c:1441 builtin_proc_read_buf VAL_NUM TEST a +builtins_host.c:1441 builtin_proc_read_buf VAL_NUM TEST a +builtins_host.c:1443 builtin_proc_read_buf eigs_num_arg READ b +builtins_host.c:1444 builtin_proc_read_buf eigs_num_arg READ b +builtins_host.c:1475 builtin_random_hex VAL_NUM TEST a +builtins_host.c:1476 builtin_random_hex VAL_NUM TEST a +builtins_host.c:1476 builtin_random_hex eigs_num_arg READ b +builtins_host.c:1502 builtin_write_bytes make_num PRODUCE c +builtins_host.c:1508 builtin_write_bytes make_num PRODUCE c +builtins_host.c:1516 builtin_write_bytes eigs_num_arg READ b +builtins_host.c:1517 builtin_write_bytes make_num PRODUCE c +builtins_host.c:1530 builtin_write_bytes make_num PRODUCE c +builtins_host.c:1540 builtin_write_bytes VAL_NUM TEST a +builtins_host.c:1547 builtin_write_bytes eigs_slot_elem_num READ b +builtins_host.c:1548 builtin_write_bytes buffer_read_num READ b +builtins_host.c:1550 builtin_write_bytes finite_num_to_byte READ b +builtins_host.c:1556 builtin_write_bytes make_num PRODUCE c +builtins_host.c:1560 builtin_write_bytes make_num PRODUCE c +builtins_tensor.c:229 tensor_dims VAL_NUM TEST a +builtins_tensor.c:257 #define FLAT_BAD VAL_NUM TEST a +builtins_tensor.c:292 tensor_to_flat VAL_NUM TEST a +builtins_tensor.c:292 tensor_to_flat eigs_slot_num READ b +builtins_tensor.c:299 tensor_to_flat VAL_NUM TEST a +builtins_tensor.c:299 tensor_to_flat eigs_slot_num READ b +builtins_tensor.c:311 flat_to_tensor_2d make_num PRODUCE c +builtins_tensor.c:327 flat_to_tensor_1d make_num PRODUCE c +builtins_tensor.c:359 tensor_total VAL_NUM TEST a +builtins_tensor.c:380 tensor_flatten_recursive VAL_NUM TEST a +builtins_tensor.c:380 tensor_flatten_recursive eigs_num_arg READ b +builtins_tensor.c:383 tensor_flatten_recursive buffer_read_num READ b +builtins_tensor.c:399 op_add num_guard GUARD c +builtins_tensor.c:400 op_sub num_guard GUARD c +builtins_tensor.c:401 op_mul num_guard GUARD c +builtins_tensor.c:408 op_div num_guard GUARD c +builtins_tensor.c:412 op_pow num_guard_named GUARD c +builtins_tensor.c:488 tensor_elementwise make_num PRODUCE c +builtins_tensor.c:491 tensor_elementwise VAL_NUM TEST a +builtins_tensor.c:491 tensor_elementwise VAL_NUM TEST a +builtins_tensor.c:492 tensor_elementwise eigs_num_arg READ b +builtins_tensor.c:492 tensor_elementwise eigs_num_arg READ b +builtins_tensor.c:492 tensor_elementwise make_num PRODUCE c +builtins_tensor.c:500 tensor_elementwise VAL_NUM TEST a +builtins_tensor.c:501 tensor_elementwise eigs_num_arg READ b +builtins_tensor.c:502 tensor_elementwise VAL_NUM TEST a +builtins_tensor.c:503 tensor_elementwise eigs_num_arg READ b +builtins_tensor.c:520 tensor_elementwise VAL_NUM TEST a +builtins_tensor.c:531 tensor_elementwise VAL_NUM TEST a +builtins_tensor.c:629 tensor_elementwise make_num PRODUCE c +builtins_tensor.c:683 tensor_unary VAL_NUM TEST a +builtins_tensor.c:683 tensor_unary eigs_num_arg READ b +builtins_tensor.c:683 tensor_unary make_num PRODUCE c +builtins_tensor.c:705 tensor_unary make_num PRODUCE c +builtins_tensor.c:718 op_exp num_guard GUARD c +builtins_tensor.c:732 op_log_safe num_guard GUARD c +builtins_tensor.c:734 op_log_safe num_guard GUARD c +builtins_tensor.c:797 builtin_tensor_matmul SLOT_NUM_RAW RAW b +builtins_tensor.c:828 builtin_tensor_matmul num_guard_named GUARD c +builtins_tensor.c:995 builtin_tensor_scatter_add VAL_NUM TEST a +builtins_tensor.c:1026 builtin_tensor_scatter_add VAL_NUM TEST a +builtins_tensor.c:1030 builtin_tensor_scatter_add eigs_slot_num READ b +builtins_tensor.c:1036 builtin_tensor_scatter_add buffer_read_num READ b +builtins_tensor.c:1041 builtin_tensor_scatter_add VAL_NUM TEST a +builtins_tensor.c:1045 builtin_tensor_scatter_add eigs_slot_num READ b +builtins_tensor.c:1049 builtin_tensor_scatter_add eigs_num_arg READ b +builtins_tensor.c:1077 builtin_tensor_scatter_add num_guard GUARD c +builtins_tensor.c:1080 builtin_tensor_scatter_add num_guard GUARD c +builtins_tensor.c:1091 builtin_tensor_softmax VAL_NUM TEST a +builtins_tensor.c:1091 builtin_tensor_softmax make_num PRODUCE c +builtins_tensor.c:1125 builtin_tensor_log_softmax VAL_NUM TEST a +builtins_tensor.c:1131 builtin_tensor_log_softmax VAL_NUM TEST a +builtins_tensor.c:1131 builtin_tensor_log_softmax make_num PRODUCE c +builtins_tensor.c:1165 builtin_tensor_relu VAL_NUM TEST a +builtins_tensor.c:1166 builtin_tensor_relu eigs_num_arg READ b +builtins_tensor.c:1167 builtin_tensor_relu make_num PRODUCE c +builtins_tensor.c:1186 builtin_tensor_leaky_relu VAL_NUM TEST a +builtins_tensor.c:1187 builtin_tensor_leaky_relu eigs_num_arg READ b +builtins_tensor.c:1188 builtin_tensor_leaky_relu make_num PRODUCE c +builtins_tensor.c:1219 builtin_tensor_mean make_num PRODUCE c +builtins_tensor.c:1222 builtin_tensor_mean buffer_read_num READ b +builtins_tensor.c:1224 builtin_tensor_mean num_guard GUARD c +builtins_tensor.c:1226 builtin_tensor_mean make_num PRODUCE c +builtins_tensor.c:1236 builtin_tensor_mean VAL_NUM TEST a +builtins_tensor.c:1238 builtin_tensor_mean make_num PRODUCE c +builtins_tensor.c:1243 builtin_tensor_mean make_num PRODUCE c +builtins_tensor.c:1253 builtin_tensor_mean make_num PRODUCE c +builtins_tensor.c:1265 builtin_tensor_sum buffer_read_num READ b +builtins_tensor.c:1267 builtin_tensor_sum num_guard GUARD c +builtins_tensor.c:1269 builtin_tensor_sum make_num PRODUCE c +builtins_tensor.c:1279 builtin_tensor_sum VAL_NUM TEST a +builtins_tensor.c:1281 builtin_tensor_sum make_num PRODUCE c +builtins_tensor.c:1286 builtin_tensor_sum make_num PRODUCE c +builtins_tensor.c:1294 builtin_tensor_sum num_guard GUARD c +builtins_tensor.c:1296 builtin_tensor_sum make_num PRODUCE c +builtins_tensor.c:1305 builtin_tensor_norm buffer_read_num READ b +builtins_tensor.c:1307 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1307 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1309 builtin_tensor_norm make_num PRODUCE c +builtins_tensor.c:1309 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1319 builtin_tensor_norm VAL_NUM TEST a +builtins_tensor.c:1321 builtin_tensor_norm make_num PRODUCE c +builtins_tensor.c:1325 builtin_tensor_norm make_num PRODUCE c +builtins_tensor.c:1333 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1333 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1335 builtin_tensor_norm make_num PRODUCE c +builtins_tensor.c:1335 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1356 builtin_tensor_zeros VAL_NUM TEST a +builtins_tensor.c:1357 builtin_tensor_zeros eigs_num_arg READ b +builtins_tensor.c:1365 builtin_tensor_zeros VAL_NUM TEST a +builtins_tensor.c:1366 builtin_tensor_zeros VAL_NUM TEST a +builtins_tensor.c:1367 builtin_tensor_zeros eigs_list_num READ b +builtins_tensor.c:1368 builtin_tensor_zeros eigs_list_num READ b +builtins_tensor.c:1381 builtin_tensor_zeros make_num PRODUCE c +builtins_tensor.c:1396 builtin_tensor_zeros_like VAL_NUM TEST a +builtins_tensor.c:1396 builtin_tensor_zeros_like make_num PRODUCE c +builtins_tensor.c:1413 builtin_tensor_zeros_like make_num PRODUCE c +builtins_tensor.c:1430 flat_index_at VAL_NUM TEST a +builtins_tensor.c:1431 flat_index_at eigs_slot_num READ b +builtins_tensor.c:1436 flat_index_at buffer_read_num READ b +builtins_tensor.c:1445 flat_index_is_num VAL_NUM TEST a +builtins_tensor.c:1488 builtin_tensor_gather VAL_NUM TEST a +builtins_tensor.c:1489 builtin_tensor_gather eigs_num_arg READ b +builtins_tensor.c:1495 builtin_tensor_gather buffer_read_num READ b +builtins_tensor.c:1495 builtin_tensor_gather make_num PRODUCE c +builtins_tensor.c:1538 builtin_tensor_gather eigs_num_arg_slow READ b +builtins_tensor.c:1541 builtin_tensor_gather make_num PRODUCE c +builtins_tensor.c:1545 builtin_tensor_gather VAL_NUM TEST a +builtins_tensor.c:1551 builtin_tensor_gather eigs_slot_num READ b +builtins_tensor.c:1561 builtin_tensor_gather eigs_slot_elem_num READ b +builtins_tensor.c:1563 builtin_tensor_gather make_num PRODUCE c +builtins_tensor.c:1568 builtin_tensor_gather VAL_NUM TEST a +builtins_tensor.c:1569 builtin_tensor_gather eigs_num_arg READ b +builtins_tensor.c:1575 builtin_tensor_gather eigs_slot_elem_num READ b +builtins_tensor.c:1577 builtin_tensor_gather make_num PRODUCE c +builtins_tensor.c:1586 builtin_tensor_gather make_num PRODUCE c +builtins_tensor.c:1686 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1687 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1688 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1698 builtin_random_normal make_num PRODUCE c +builtins_tensor.c:1706 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1707 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1713 builtin_random_normal make_num PRODUCE c +builtins_tensor.c:1724 builtin_tensor_shape VAL_NUM TEST a +builtins_tensor.c:1732 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1733 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1737 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1743 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1751 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1752 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1757 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1766 numerical_loss VAL_NUM TEST a +builtins_tensor.c:1767 numerical_loss eigs_num_arg READ b +builtins_tensor.c:1802 tensor_cells_numeric VAL_NUM TEST a +builtins_tensor.c:1803 tensor_cells_numeric eigs_slot_num READ b +builtins_tensor.c:1806 tensor_cells_numeric VAL_NUM TEST a +builtins_tensor.c:1807 tensor_cells_numeric eigs_slot_num READ b +builtins_tensor.c:1824 builtin_numerical_grad eigs_slot_opt_num READ b +builtins_tensor.c:1860 builtin_numerical_grad eigs_slot_num READ b +builtins_tensor.c:1861 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1863 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1865 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1867 builtin_numerical_grad make_num PRODUCE c +builtins_tensor.c:1883 builtin_numerical_grad eigs_slot_num READ b +builtins_tensor.c:1884 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1886 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1888 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1889 builtin_numerical_grad make_num PRODUCE c +builtins_tensor.c:1910 builtin_sgd_update eigs_slot_opt_num READ b +builtins_tensor.c:1931 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1932 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1933 builtin_sgd_update list_set_num PRODUCE c +builtins_tensor.c:1946 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1947 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1948 builtin_sgd_update list_set_num PRODUCE c +builtins_tensor.c:1972 builtin_numerical_grad_rows eigs_slot_opt_num READ b +builtins_tensor.c:2023 builtin_numerical_grad_rows make_num PRODUCE c +builtins_tensor.c:2042 builtin_numerical_grad_rows eigs_slot_num READ b +builtins_tensor.c:2043 builtin_numerical_grad_rows list_set_num PRODUCE c +builtins_tensor.c:2045 builtin_numerical_grad_rows list_set_num PRODUCE c +builtins_tensor.c:2047 builtin_numerical_grad_rows list_set_num PRODUCE c +builtins_tensor.c:2049 builtin_numerical_grad_rows list_set_num PRODUCE c +builtins_tensor.c:2072 builtin_sgd_update_rows eigs_slot_opt_num READ b +builtins_tensor.c:2109 builtin_sgd_update_rows eigs_slot_num READ b +builtins_tensor.c:2110 builtin_sgd_update_rows eigs_slot_num READ b +builtins_tensor.c:2111 builtin_sgd_update_rows list_set_num PRODUCE c +builtins_tensor.c:2134 builtin_numerical_grad_cols eigs_slot_opt_num READ b +builtins_tensor.c:2183 builtin_numerical_grad_cols make_num PRODUCE c +builtins_tensor.c:2201 builtin_numerical_grad_cols eigs_slot_num READ b +builtins_tensor.c:2203 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2206 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2209 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2212 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2235 builtin_sgd_update_cols eigs_slot_opt_num READ b +builtins_tensor.c:2273 builtin_sgd_update_cols eigs_slot_num READ b +builtins_tensor.c:2274 builtin_sgd_update_cols eigs_slot_num READ b +builtins_tensor.c:2275 builtin_sgd_update_cols list_set_num PRODUCE c +builtins_tensor.c:2385 tensor_load_record_verdict make_num PRODUCE c +builtins_tensor.c:2386 tensor_load_record_verdict make_num PRODUCE c +builtins_tensor.c:2403 builtin_tensor_load VAL_NUM TEST a +builtins_tensor.c:2404 builtin_tensor_load VAL_NUM TEST a +builtins_tensor.c:2405 builtin_tensor_load eigs_list_num READ b +builtins_tensor.c:2406 builtin_tensor_load eigs_list_num READ b +builtins_tensor.c:2483 builtin_tensor_load num_guard_named GUARD c +chunk.c:194 const_hash_value VAL_NUM TEST f +chunk.c:195 const_hash_value VAL_NUM_RAW RAW f +chunk.c:213 const_equal VAL_NUM TEST f +chunk.c:213 const_equal VAL_NUM TEST f +chunk.c:214 const_equal VAL_NUM_RAW RAW f +chunk.c:214 const_equal VAL_NUM_RAW RAW f +chunk.c:234 const_dedup_grow VAL_NUM TEST a +chunk.c:243 chunk_add_constant_ex VAL_NUM TEST a +chunk.c:421 chunk_disassemble VAL_NUM TEST e +chunk.c:422 chunk_disassemble VAL_NUM_RAW RAW e +chunk.c:1090 chunk_scan_leaf_accessor VAL_NUM TEST a +compiler.c:582 add_num_constant make_num PRODUCE c +compiler.c:791 collect_referenced_names_skip AST_NUM CASE a +compiler.c:935 collect_referenced_names AST_NUM CASE a +compiler.c:1074 scan_for_captures AST_NUM CASE a +compiler.c:1181 ast_has_closure AST_NUM CASE a +compiler.c:1259 subtree_overwrite_safe AST_NUM CASE a +compiler.c:1469 scan_for_interrogated AST_NUM CASE a +compiler.c:1591 scan_for_env_bound AST_NUM CASE a +compiler.c:1658 collect_module_names_walk AST_NUM CASE a +compiler.c:1796 scan_dispatch_rebind AST_NUM CASE a +compiler.c:1983 cond_is_observer_based AST_NUM CASE i +compiler.c:2071 compile_node_inner AST_NUM CASE a +compiler.c:2072 compile_node_inner data.num RAW b +compiler.c:2090 compile_node_inner data.num RAW b +compiler.c:2929 compile_node_inner AST_NUM TEST a +compiler.c:2930 compile_node_inner data.num RAW b +compiler.c:2985 compile_node_inner AST_NUM TEST a +compiler.c:2986 compile_node_inner data.num RAW b +compiler.c:3030 compile_node_inner AST_NUM TEST a +compiler.c:3031 compile_node_inner data.num RAW b +compiler.c:3844 obs_ast_scan_d AST_NUM CASE i +container.h:26 eigs_container_slot VAL_NUM TEST a +container.h:26 eigs_container_slot VAL_NUM_RAW RAW b +container.h:26 eigs_container_slot num_guard GUARD c +container.h:26 eigs_container_slot slot_from_num PRODUCE c +container.h:42 eigs_slot_store_owned SLOT_NUM_RAW RAW b +container.h:42 eigs_slot_store_owned num_guard GUARD c +container.h:42 eigs_slot_store_owned slot_from_num PRODUCE c +container.h:42 eigs_slot_store_owned slot_is_num TEST a +container.h:45 eigs_slot_store_owned VAL_NUM TEST a +container.h:51 eigs_slot_store_borrow SLOT_NUM_RAW RAW b +container.h:51 eigs_slot_store_borrow num_guard GUARD c +container.h:51 eigs_slot_store_borrow slot_from_num PRODUCE c +container.h:51 eigs_slot_store_borrow slot_is_num TEST a +container.h:78 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c +container.h:80 dict_value_rewrite_num slot_from_num PRODUCE c +container.h:84 list_rewrite_num list_rewrite_num PRODUCE c +container.h:86 list_rewrite_num slot_from_num PRODUCE c +container.h:93 slot_type VAL_NUM YIELD a +container.h:93 slot_type slot_is_num TEST a +container.h:114 list_get_ref slot_is_num TEST a +container.h:118 dict_value_get_ref slot_is_num TEST a +container.h:125 eigs_slot_num eigs_slot_num READ b +container.h:126 eigs_slot_num SLOT_NUM_RAW RAW b +container.h:126 eigs_slot_num slot_is_num TEST a +container.h:127 eigs_slot_num VAL_NUM TEST a +container.h:128 eigs_slot_num eigs_num_arg READ b +container.h:129 eigs_slot_num eigs_num_arg_slow READ b +container.h:131 eigs_slot_elem_num eigs_slot_elem_num READ b +container.h:132 eigs_slot_elem_num SLOT_NUM_RAW RAW b +container.h:132 eigs_slot_elem_num slot_is_num TEST a +container.h:134 eigs_slot_elem_num VAL_NUM TEST a +container.h:134 eigs_slot_elem_num eigs_num_arg READ b +container.h:135 eigs_slot_elem_num eigs_num_arg_slow READ b +container.h:138 eigs_slot_opt_num eigs_slot_opt_num READ b +container.h:140 eigs_slot_opt_num SLOT_NUM_RAW RAW b +container.h:140 eigs_slot_opt_num slot_is_num TEST a +container.h:141 eigs_slot_opt_num VAL_NUM TEST a +container.h:142 eigs_slot_opt_num eigs_num_arg READ b +container.h:144 eigs_slot_opt_num eigs_num_arg_slow READ b +container.h:152 slot_view VAL_NUM TEST a +container.h:152 slot_view slot_is_num TEST a +container.h:153 slot_view VAL_NUM TAGSET c +container.h:154 slot_view SLOT_NUM_RAW RAW b +container.h:154 slot_view VAL_NUM_RAW WRITE c +container.h:154 slot_view slot_is_num TEST a +container.h:155 slot_view eigs_num_arg READ b +container.h:166 eigs_view_check VAL_NUM TEST a +container.h:191 list_get_return SLOT_NUM_RAW RAW b +container.h:191 list_get_return make_num PRODUCE c +container.h:191 list_get_return slot_is_num TEST a +container.h:198 dict_value_get_return SLOT_NUM_RAW RAW b +container.h:198 dict_value_get_return make_num PRODUCE c +container.h:198 dict_value_get_return slot_is_num TEST a +container.h:228 eigs_slot_box SLOT_NUM_RAW RAW b +container.h:228 eigs_slot_box make_num PRODUCE c +container.h:228 eigs_slot_box num_guard GUARD c +container.h:228 eigs_slot_box slot_is_num TEST a +container.h:250 list_set_num list_set_num PRODUCE c +container.h:251 list_set_num list_rewrite_num PRODUCE c +container.h:251 list_set_num num_guard GUARD c +container.h:253 list_append_num list_append_num PRODUCE c +container.h:254 list_append_num num_guard GUARD c +container.h:256 list_append_num slot_from_num PRODUCE c +container.h:258 dict_value_set_num dict_value_set_num PRODUCE c +container.h:259 dict_value_set_num dict_value_rewrite_num PRODUCE c +container.h:259 dict_value_set_num num_guard GUARD c +container.h:286 list_get_num list_get_num READ b +container.h:288 list_get_num slot_is_num TEST a +container.h:289 list_get_num SLOT_NUM_RAW RAW b +container.h:292 dict_value_get_num dict_value_get_num READ b +container.h:294 dict_value_get_num slot_is_num TEST a +container.h:295 dict_value_get_num SLOT_NUM_RAW RAW b +eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a +eigenlsp.c:637 collect_references AST_NUM CASE a +eigenscript.c:309 val_type_name VAL_NUM CASE a +eigenscript.c:431 ent_child_slot SLOT_NUM_RAW RAW i +eigenscript.c:431 ent_child_slot slot_is_num TEST i +eigenscript.c:439 compute_entropy_impl VAL_NUM CASE i +eigenscript.c:439 compute_entropy_impl VAL_NUM_RAW RAW i +eigenscript.c:788 observer_slot_update VAL_NUM TEST i +eigenscript.c:790 observer_slot_update VAL_NUM_RAW RAW i +eigenscript.c:852 observer_slot_sample_gated VAL_NUM TEST i +eigenscript.c:853 observer_slot_sample_gated VAL_NUM_RAW RAW i +eigenscript.c:936 observer_slot_saturated EIGS_NUM_MAX GUARD i +eigenscript.c:1384 observer_entropy_now slot_is_num TEST i +eigenscript.c:1386 observer_entropy_now SLOT_NUM_RAW RAW i +eigenscript.c:1431 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1432 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1435 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1439 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1440 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1441 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1442 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1448 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1480 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1480 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1481 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1481 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1481 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1483 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1497 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1497 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1502 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1503 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1512 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1517 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1530 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1535 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1638 free_value VAL_NUM TEST a +eigenscript.c:1720 free_value VAL_NUM CASE a +eigenscript.c:1729 make_num make_num PRODUCE c +eigenscript.c:1730 make_num num_guard GUARD c +eigenscript.c:1746 make_num VAL_NUM TAGSET c +eigenscript.c:1747 make_num VAL_NUM_RAW WRITE c +eigenscript.c:1753 recycle_intermediate VAL_NUM TEST a +eigenscript.c:1775 make_num_permanent make_num_permanent PRODUCE c +eigenscript.c:1776 make_num_permanent num_guard GUARD c +eigenscript.c:1778 make_num_permanent VAL_NUM TAGSET c +eigenscript.c:1779 make_num_permanent VAL_NUM_RAW WRITE c +eigenscript.c:1808 eigs_num_arg_slow eigs_num_arg_slow READ b +eigenscript.c:1809 eigs_num_arg_slow VAL_NUM TEST a +eigenscript.c:1809 eigs_num_arg_slow VAL_NUM_RAW RAW b +eigenscript.c:1816 eigs_list_num eigs_list_num READ b +eigenscript.c:1823 eigs_list_num eigs_slot_num READ b +eigenscript.c:1826 eigs_elem_num eigs_elem_num READ b +eigenscript.c:1827 eigs_elem_num eigs_slot_elem_num READ b +eigenscript.c:1830 eigs_opt_num eigs_opt_num READ b +eigenscript.c:1831 eigs_opt_num eigs_slot_opt_num READ b +eigenscript.c:1867 slot_from_value VAL_NUM TEST a +eigenscript.c:1871 slot_from_value VAL_NUM_RAW RAW b +eigenscript.c:1873 slot_from_value slot_from_num PRODUCE c +eigenscript.c:1886 slot_to_value SLOT_NUM_RAW RAW b +eigenscript.c:1886 slot_to_value make_num PRODUCE c +eigenscript.c:1886 slot_to_value slot_is_num TEST a +eigenscript.c:2380 module_ns_project slot_is_num TEST a +eigenscript.c:2380 module_ns_project slot_is_num TEST a +eigenscript.c:2383 module_ns_project SLOT_NUM_RAW RAW b +eigenscript.c:2383 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2628 chan_clone_rec VAL_NUM TEST a +eigenscript.c:2631 chan_clone_rec VAL_NUM CASE a +eigenscript.c:2631 chan_clone_rec VAL_NUM_RAW RAW b +eigenscript.c:2631 chan_clone_rec make_num PRODUCE c +eigenscript.c:2819 is_truthy VAL_NUM CASE a +eigenscript.c:2819 is_truthy VAL_NUM_RAW RAW b +eigenscript.c:2855 values_equal_impl VAL_NUM TEST f +eigenscript.c:2856 values_equal_impl VAL_NUM TEST f +eigenscript.c:2870 values_equal_impl VAL_NUM CASE f +eigenscript.c:2870 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2870 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2900 values_equal_impl buffer_read_num READ f +eigenscript.c:2902 values_equal_impl buffer_read_num READ f +eigenscript.c:2938 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:2953 eigs_num_text strtod PARSE e +eigenscript.c:2963 value_to_string VAL_NUM CASE e +eigenscript.c:2964 value_to_string VAL_NUM_RAW RAW e +eigenscript.c:2964 value_to_string eigs_num_text FORMAT e +eigenscript.c:4186 gc_value_is_node VAL_NUM CASE a +eigenscript.h:188 num_val RAW b +eigenscript.h:206 AST_NUM DATA a +eigenscript.h:270 VAL_NUM DATA a +eigenscript.h:285 #define VAL_NUM_RAW VAL_NUM_RAW RAW b +eigenscript.h:286 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b +eigenscript.h:1390 eigs_num_arg_slow READ b +eigenscript.h:1391 eigs_num_arg eigs_num_arg READ b +eigenscript.h:1392 eigs_num_arg VAL_NUM TEST a +eigenscript.h:1392 eigs_num_arg VAL_NUM_RAW RAW b +eigenscript.h:1393 eigs_num_arg eigs_num_arg_slow READ b +eigenscript.h:1395 eigs_list_num READ b +eigenscript.h:1400 eigs_elem_num READ b +eigenscript.h:1401 eigs_opt_num READ b +eigenscript.h:1772 make_num PRODUCE c +eigenscript.h:1782 make_num_permanent PRODUCE c +eigenscript.h:1834 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1876 num_guard num_guard GUARD c +eigenscript.h:1884 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1884 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1885 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1885 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1894 buffer_read_num buffer_read_num READ b +eigenscript.h:1895 buffer_read_num num_guard GUARD c +eigenscript.h:1901 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1910 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1920 buffer_read_byte buffer_read_num READ b +eigenscript.h:1922 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1933 num_guard_named num_guard_named GUARD c +eigenscript.h:1939 num_guard_named num_guard GUARD c +eigenscript.h:2251 eigs_num_text FORMAT e +eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j +eigs_embed.c:314 eigs_value_type VAL_NUM CASE j +eigs_embed.c:339 eigs_value_as_num eigs_value_as_num READ j +eigs_embed.c:341 eigs_value_as_num VAL_NUM TEST j +eigs_embed.c:341 eigs_value_as_num VAL_NUM_RAW RAW j +eigs_embed.c:394 eigs_value_buffer_get buffer_read_num READ j +eigs_embed.c:433 eigs_trace_declare_kind VAL_NUM DATA j +eigs_embed.h:171 eigs_value_as_num READ j +embed_concurrent.c:106 global_worker eigs_value_as_num READ j +embed_concurrent.c:768 take_drain eigs_value_as_num READ j +embed_concurrent.c:1268 test_sink_only_buffer_bounded eigs_value_as_num READ j +embed_concurrent.c:1763 fu_worker eigs_value_as_num READ j +embed_concurrent.c:1830 test_register_while_workers_read eigs_value_as_num READ j +embed_concurrent.c:1834 test_register_while_workers_read eigs_value_as_num READ j +embed_smoke.c:190 test_worker_exit_lifecycle eigs_value_as_num READ j +embed_smoke.c:198 test_worker_exit_lifecycle eigs_slot_num READ j +embed_smoke.c:199 test_worker_exit_lifecycle eigs_slot_num READ j +embed_smoke.c:214 test_worker_exit_lifecycle eigs_value_as_num READ j +embed_smoke.c:288 host_add eigs_value_as_num READ j +embed_smoke.c:288 host_add eigs_value_as_num READ j +embed_smoke.c:334 main SLOT_NUM_RAW WRITE j +embed_smoke.c:336 main SLOT_NUM_RAW WRITE j +embed_smoke.c:338 main SLOT_NUM_RAW RAW j +embed_smoke.c:341 main SLOT_NUM_RAW RAW j +embed_smoke.c:343 main SLOT_NUM_RAW RAW j +embed_smoke.c:345 main SLOT_NUM_RAW RAW j +embed_smoke.c:373 main eigs_value_as_num READ j +embed_smoke.c:381 main eigs_value_as_num READ j +embed_smoke.c:391 main eigs_value_as_num READ j +embed_smoke.c:416 main eigs_value_as_num READ j +embed_smoke.c:424 main eigs_value_as_num READ j +embed_smoke.c:449 main eigs_value_as_num READ j +embed_smoke.c:475 main eigs_value_as_num READ j +embed_smoke.c:486 main eigs_value_as_num READ j +embed_smoke.c:491 main eigs_value_as_num READ j +embed_smoke.c:496 main eigs_value_as_num READ j +embed_smoke.c:562 main eigs_value_as_num READ j +embed_smoke.c:580 main eigs_value_as_num READ j +embed_smoke.c:589 main eigs_value_as_num READ j +embed_smoke.c:608 main EIGS_NUM_MAX GUARD j +embed_smoke.c:616 main eigs_value_as_num READ j +embed_smoke.c:845 main eigs_value_as_num READ j +embed_smoke.c:898 main eigs_value_as_num READ j +embed_smoke.c:908 main eigs_value_as_num READ j +embed_smoke.c:918 main SLOT_NUM_RAW WRITE j +embed_smoke.c:934 main eigs_value_as_num READ j +embed_smoke.c:944 main eigs_value_as_num READ j +embed_smoke.c:953 main eigs_value_as_num READ j +embed_smoke.c:962 main eigs_value_as_num READ j +embed_smoke.c:980 main eigs_value_as_num READ j +embed_smoke.c:988 main eigs_value_as_num READ j +embed_smoke.c:992 main eigs_value_as_num READ j +embed_smoke.c:997 main eigs_value_as_num READ j +embed_smoke.c:1008 main eigs_value_as_num READ j +embed_smoke.c:1013 main eigs_value_as_num READ j +embed_smoke.c:1022 main eigs_value_as_num READ j +embed_smoke.c:1041 main eigs_value_as_num READ j +embed_smoke.c:1045 main eigs_value_as_num READ j +embed_smoke.c:1054 main eigs_value_as_num READ j +embed_smoke.c:1058 main eigs_value_as_num READ j +embed_smoke.c:1065 main eigs_value_as_num READ j +embed_smoke.c:1121 main eigs_value_as_num READ j +embed_smoke.c:1145 main eigs_value_as_num READ j +embed_smoke.c:1172 main eigs_value_as_num READ j +ext_db.c:57 db_build_query VAL_NUM TEST h +ext_db.c:58 db_build_query eigs_num_arg READ h +ext_db.c:310 builtin_db_query_value make_num PRODUCE h +ext_db.c:310 builtin_db_query_value strtod PARSE h +ext_gfx.c:407 gfx_nums VAL_NUM TEST a +ext_gfx.c:420 gfx_list_all_num VAL_NUM TEST a +ext_gfx.c:455 builtin_gfx_open VAL_NUM TEST a +ext_gfx.c:456 builtin_gfx_open VAL_NUM TEST a +ext_gfx.c:458 builtin_gfx_open eigs_list_num READ b +ext_gfx.c:459 builtin_gfx_open eigs_list_num READ b +ext_gfx.c:529 builtin_gfx_clear eigs_list_num READ b +ext_gfx.c:530 builtin_gfx_clear eigs_list_num READ b +ext_gfx.c:531 builtin_gfx_clear eigs_list_num READ b +ext_gfx.c:548 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:549 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:550 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:551 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:552 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:553 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:554 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:555 builtin_gfx_rect eigs_list_num READ b +ext_gfx.c:570 builtin_gfx_line eigs_list_num READ b +ext_gfx.c:571 builtin_gfx_line eigs_list_num READ b +ext_gfx.c:572 builtin_gfx_line eigs_list_num READ b +ext_gfx.c:573 builtin_gfx_line eigs_list_num READ b +ext_gfx.c:574 builtin_gfx_line eigs_list_num READ b +ext_gfx.c:575 builtin_gfx_line eigs_list_num READ b +ext_gfx.c:576 builtin_gfx_line eigs_list_num READ b +ext_gfx.c:590 builtin_gfx_point eigs_list_num READ b +ext_gfx.c:591 builtin_gfx_point eigs_list_num READ b +ext_gfx.c:592 builtin_gfx_point eigs_list_num READ b +ext_gfx.c:593 builtin_gfx_point eigs_list_num READ b +ext_gfx.c:594 builtin_gfx_point eigs_list_num READ b +ext_gfx.c:609 builtin_gfx_circle eigs_list_num READ b +ext_gfx.c:610 builtin_gfx_circle eigs_list_num READ b +ext_gfx.c:611 builtin_gfx_circle eigs_list_num READ b +ext_gfx.c:612 builtin_gfx_circle eigs_list_num READ b +ext_gfx.c:613 builtin_gfx_circle eigs_list_num READ b +ext_gfx.c:614 builtin_gfx_circle eigs_list_num READ b +ext_gfx.c:615 builtin_gfx_circle eigs_list_num READ b +ext_gfx.c:636 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:637 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:638 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:639 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:640 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:641 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:642 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:643 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:644 builtin_gfx_rrect eigs_list_num READ b +ext_gfx.c:690 builtin_gfx_clip eigs_list_num READ b +ext_gfx.c:691 builtin_gfx_clip eigs_list_num READ b +ext_gfx.c:692 builtin_gfx_clip eigs_list_num READ b +ext_gfx.c:693 builtin_gfx_clip eigs_list_num READ b +ext_gfx.c:722 builtin_gfx_read eigs_list_num READ b +ext_gfx.c:723 builtin_gfx_read eigs_list_num READ b +ext_gfx.c:731 builtin_gfx_read make_num PRODUCE c +ext_gfx.c:732 builtin_gfx_read make_num PRODUCE c +ext_gfx.c:733 builtin_gfx_read make_num PRODUCE c +ext_gfx.c:776 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:782 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:787 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:788 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:793 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:794 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:795 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:800 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:801 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:802 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:807 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:808 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:818 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:819 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:827 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:828 builtin_gfx_poll make_num PRODUCE c +ext_gfx.c:848 builtin_gfx_ticks make_num PRODUCE c +ext_gfx.c:853 builtin_gfx_delay VAL_NUM TEST a +ext_gfx.c:855 builtin_gfx_delay eigs_num_arg READ b +ext_gfx.c:1003 builtin_gfx_text eigs_list_num READ b +ext_gfx.c:1004 builtin_gfx_text eigs_list_num READ b +ext_gfx.c:1006 builtin_gfx_text eigs_list_num READ b +ext_gfx.c:1007 builtin_gfx_text eigs_list_num READ b +ext_gfx.c:1008 builtin_gfx_text eigs_list_num READ b +ext_gfx.c:1009 builtin_gfx_text eigs_list_num READ b +ext_gfx.c:1075 builtin_gfx_text_width VAL_NUM TEST a +ext_gfx.c:1076 builtin_gfx_text_width eigs_list_num READ b +ext_gfx.c:1084 builtin_gfx_text_width make_num PRODUCE c +ext_gfx.c:1094 builtin_gfx_text_width make_num PRODUCE c +ext_gfx.c:1096 builtin_gfx_text_width make_num PRODUCE c +ext_gfx.c:1109 builtin_gfx_text_height VAL_NUM TEST a +ext_gfx.c:1111 builtin_gfx_text_height VAL_NUM TEST a +ext_gfx.c:1113 builtin_gfx_text_height VAL_NUM TEST a +ext_gfx.c:1114 builtin_gfx_text_height eigs_num_arg READ b +ext_gfx.c:1116 builtin_gfx_text_height VAL_NUM TEST a +ext_gfx.c:1117 builtin_gfx_text_height eigs_list_num READ b +ext_gfx.c:1122 builtin_gfx_text_height make_num PRODUCE c +ext_gfx.c:1124 builtin_gfx_text_height make_num PRODUCE c +ext_gfx.c:1189 audio_convert_samples buffer_read_num READ b +ext_gfx.c:1209 audio_convert_samples VAL_NUM TEST a +ext_gfx.c:1226 audio_convert_samples eigs_slot_num READ b +ext_gfx.c:1314 builtin_audio_open VAL_NUM TEST a +ext_gfx.c:1315 builtin_audio_open VAL_NUM TEST a +ext_gfx.c:1316 builtin_audio_open make_num PRODUCE c +ext_gfx.c:1318 builtin_audio_open make_num PRODUCE c +ext_gfx.c:1321 builtin_audio_open make_num PRODUCE c +ext_gfx.c:1334 builtin_audio_open eigs_list_num READ b +ext_gfx.c:1335 builtin_audio_open eigs_list_num READ b +ext_gfx.c:1339 builtin_audio_open make_num PRODUCE c +ext_gfx.c:1343 builtin_audio_open make_num PRODUCE c +ext_gfx.c:1362 builtin_audio_pause VAL_NUM TEST a +ext_gfx.c:1365 builtin_audio_pause VAL_NUM TEST a +ext_gfx.c:1365 builtin_audio_pause eigs_num_arg READ b +ext_gfx.c:1457 builtin_audio_capture_open VAL_NUM TEST a +ext_gfx.c:1458 builtin_audio_capture_open VAL_NUM TEST a +ext_gfx.c:1459 builtin_audio_capture_open make_num PRODUCE c +ext_gfx.c:1463 builtin_audio_capture_open make_num PRODUCE c +ext_gfx.c:1467 builtin_audio_capture_open make_num PRODUCE c +ext_gfx.c:1480 builtin_audio_capture_open eigs_list_num READ b +ext_gfx.c:1481 builtin_audio_capture_open eigs_list_num READ b +ext_gfx.c:1491 builtin_audio_capture_open make_num PRODUCE c +ext_gfx.c:1494 builtin_audio_capture_open make_num PRODUCE c +ext_gfx.c:1586 builtin_audio_stream_open VAL_NUM TEST a +ext_gfx.c:1587 builtin_audio_stream_open VAL_NUM TEST a +ext_gfx.c:1588 builtin_audio_stream_open make_num PRODUCE c +ext_gfx.c:1590 builtin_audio_stream_open make_num PRODUCE c +ext_gfx.c:1593 builtin_audio_stream_open make_num PRODUCE c +ext_gfx.c:1605 builtin_audio_stream_open VAL_NUM TEST a +ext_gfx.c:1606 builtin_audio_stream_open VAL_NUM TEST a +ext_gfx.c:1607 builtin_audio_stream_open eigs_list_num READ b +ext_gfx.c:1608 builtin_audio_stream_open eigs_list_num READ b +ext_gfx.c:1616 builtin_audio_stream_open make_num PRODUCE c +ext_gfx.c:1620 builtin_audio_stream_open make_num PRODUCE c +ext_gfx.c:1664 builtin_audio_stream_queued make_num PRODUCE c +ext_gfx.c:1667 builtin_audio_stream_queued make_num PRODUCE c +ext_gfx.c:1703 builtin_audio_music_play VAL_NUM TEST a +ext_gfx.c:1706 builtin_audio_music_play VAL_NUM TEST a +ext_gfx.c:1707 builtin_audio_music_play eigs_list_num READ b +ext_gfx.c:1742 builtin_audio_music_volume VAL_NUM TEST a +ext_gfx.c:1744 builtin_audio_music_volume VAL_NUM TEST a +ext_gfx.c:1748 builtin_audio_music_volume VAL_NUM TEST a +ext_gfx.c:1748 builtin_audio_music_volume eigs_num_arg READ b +ext_gfx.c:1750 builtin_audio_music_volume VAL_NUM TEST a +ext_gfx.c:1751 builtin_audio_music_volume eigs_list_num READ b +ext_gfx.c:1774 builtin_audio_play make_num PRODUCE c +ext_gfx.c:1779 builtin_audio_play make_num PRODUCE c +ext_gfx.c:1781 builtin_audio_play make_num PRODUCE c +ext_gfx.c:1783 builtin_audio_play make_num PRODUCE c +ext_gfx.c:1797 builtin_audio_play_loop VAL_NUM TEST a +ext_gfx.c:1798 builtin_audio_play_loop make_num PRODUCE c +ext_gfx.c:1800 builtin_audio_play_loop eigs_list_num READ b +ext_gfx.c:1807 builtin_audio_play_loop make_num PRODUCE c +ext_gfx.c:1820 builtin_audio_play_loop make_num PRODUCE c +ext_gfx.c:1825 builtin_audio_play_loop make_num PRODUCE c +ext_gfx.c:1827 builtin_audio_play_loop make_num PRODUCE c +ext_gfx.c:1829 builtin_audio_play_loop make_num PRODUCE c +ext_gfx.c:1838 builtin_audio_volume VAL_NUM TEST a +ext_gfx.c:1839 builtin_audio_volume VAL_NUM TEST a +ext_gfx.c:1840 builtin_audio_volume make_num PRODUCE c +ext_gfx.c:1841 builtin_audio_volume make_num PRODUCE c +ext_gfx.c:1842 builtin_audio_volume eigs_slot_num READ b +ext_gfx.c:1843 builtin_audio_volume make_num PRODUCE c +ext_gfx.c:1844 builtin_audio_volume eigs_slot_num READ b +ext_gfx.c:1851 builtin_audio_volume make_num PRODUCE c +ext_gfx.c:1858 builtin_audio_stop VAL_NUM TEST a +ext_gfx.c:1859 builtin_audio_stop make_num PRODUCE c +ext_gfx.c:1860 builtin_audio_stop make_num PRODUCE c +ext_gfx.c:1861 builtin_audio_stop eigs_num_arg READ b +ext_gfx.c:1862 builtin_audio_stop make_num PRODUCE c +ext_gfx.c:1867 builtin_audio_stop make_num PRODUCE c +ext_gfx.c:1873 builtin_audio_queue_size make_num PRODUCE c +ext_gfx.c:1887 builtin_audio_queue_size make_num PRODUCE c +ext_gfx.c:1920 builtin_audio_sine VAL_NUM TEST a +ext_gfx.c:1921 builtin_audio_sine VAL_NUM TEST a +ext_gfx.c:1922 builtin_audio_sine VAL_NUM TEST a +ext_gfx.c:1924 builtin_audio_sine eigs_list_num READ b +ext_gfx.c:1925 builtin_audio_sine eigs_list_num READ b +ext_gfx.c:1926 builtin_audio_sine eigs_list_num READ b +ext_gfx.c:1935 builtin_audio_sine make_num PRODUCE c +ext_gfx.c:1955 builtin_audio_saw VAL_NUM TEST a +ext_gfx.c:1956 builtin_audio_saw VAL_NUM TEST a +ext_gfx.c:1957 builtin_audio_saw VAL_NUM TEST a +ext_gfx.c:1959 builtin_audio_saw eigs_list_num READ b +ext_gfx.c:1960 builtin_audio_saw eigs_list_num READ b +ext_gfx.c:1961 builtin_audio_saw eigs_list_num READ b +ext_gfx.c:1970 builtin_audio_saw make_num PRODUCE c +ext_gfx.c:1990 builtin_audio_square VAL_NUM TEST a +ext_gfx.c:1991 builtin_audio_square VAL_NUM TEST a +ext_gfx.c:1992 builtin_audio_square VAL_NUM TEST a +ext_gfx.c:1994 builtin_audio_square eigs_list_num READ b +ext_gfx.c:1995 builtin_audio_square eigs_list_num READ b +ext_gfx.c:1996 builtin_audio_square eigs_list_num READ b +ext_gfx.c:2005 builtin_audio_square make_num PRODUCE c +ext_gfx.c:2026 builtin_audio_sweep VAL_NUM TEST a +ext_gfx.c:2027 builtin_audio_sweep VAL_NUM TEST a +ext_gfx.c:2028 builtin_audio_sweep VAL_NUM TEST a +ext_gfx.c:2029 builtin_audio_sweep VAL_NUM TEST a +ext_gfx.c:2030 builtin_audio_sweep VAL_NUM TEST a +ext_gfx.c:2032 builtin_audio_sweep eigs_list_num READ b +ext_gfx.c:2033 builtin_audio_sweep eigs_list_num READ b +ext_gfx.c:2034 builtin_audio_sweep eigs_list_num READ b +ext_gfx.c:2035 builtin_audio_sweep eigs_list_num READ b +ext_gfx.c:2036 builtin_audio_sweep eigs_list_num READ b +ext_gfx.c:2053 builtin_audio_sweep make_num PRODUCE c +ext_gfx.c:2073 builtin_audio_noise VAL_NUM TEST a +ext_gfx.c:2074 builtin_audio_noise VAL_NUM TEST a +ext_gfx.c:2076 builtin_audio_noise eigs_list_num READ b +ext_gfx.c:2077 builtin_audio_noise eigs_list_num READ b +ext_gfx.c:2085 builtin_audio_noise make_num PRODUCE c +ext_gfx.c:2112 builtin_audio_mix VAL_NUM TEST a +ext_gfx.c:2112 builtin_audio_mix eigs_slot_num READ b +ext_gfx.c:2113 builtin_audio_mix VAL_NUM TEST a +ext_gfx.c:2113 builtin_audio_mix eigs_slot_num READ b +ext_gfx.c:2117 builtin_audio_mix make_num PRODUCE c +ext_gfx.c:2143 builtin_audio_gain VAL_NUM TEST a +ext_gfx.c:2145 builtin_audio_gain eigs_list_num READ b +ext_gfx.c:2150 builtin_audio_gain VAL_NUM TEST a +ext_gfx.c:2150 builtin_audio_gain eigs_slot_num READ b +ext_gfx.c:2154 builtin_audio_gain make_num PRODUCE c +ext_gfx.c:2174 builtin_audio_envelope VAL_NUM TEST a +ext_gfx.c:2175 builtin_audio_envelope VAL_NUM TEST a +ext_gfx.c:2176 builtin_audio_envelope VAL_NUM TEST a +ext_gfx.c:2177 builtin_audio_envelope VAL_NUM TEST a +ext_gfx.c:2188 builtin_audio_envelope eigs_list_num READ b +ext_gfx.c:2189 builtin_audio_envelope eigs_list_num READ b +ext_gfx.c:2190 builtin_audio_envelope eigs_list_num READ b +ext_gfx.c:2191 builtin_audio_envelope eigs_list_num READ b +ext_gfx.c:2220 builtin_audio_envelope VAL_NUM TEST a +ext_gfx.c:2220 builtin_audio_envelope eigs_slot_num READ b +ext_gfx.c:2222 builtin_audio_envelope make_num PRODUCE c +ext_gfx.c:2244 builtin_gfx_fb eigs_list_num READ b +ext_gfx.c:2245 builtin_gfx_fb eigs_list_num READ b +ext_gfx.c:2246 builtin_gfx_fb eigs_list_num READ b +ext_gfx.c:2247 builtin_gfx_fb eigs_list_num READ b +ext_gfx.c:2248 builtin_gfx_fb eigs_list_num READ b +ext_http.c:584 builtin_http_early_bind VAL_NUM TEST a +ext_http.c:594 builtin_http_early_bind eigs_opt_num READ b +ext_http.c:662 builtin_http_serve eigs_opt_num READ b +ext_http.c:948 builtin_shared_incr VAL_NUM TEST a +ext_http.c:952 builtin_shared_incr eigs_num_arg READ b +ext_http.c:964 builtin_shared_incr VAL_NUM TEST a +ext_http.c:965 builtin_shared_incr eigs_num_arg READ b +ext_http.c:975 builtin_shared_incr make_num PRODUCE c +ext_http.c:1006 builtin_shared_incr make_num PRODUCE c +ext_http.c:1035 builtin_shared_delete make_num PRODUCE c +ext_http.c:1037 builtin_shared_delete make_num PRODUCE c +ext_http.c:1053 builtin_shared_delete make_num PRODUCE c +ext_http.c:1072 builtin_shared_size make_num PRODUCE c +ext_http.c:1076 builtin_shared_size make_num PRODUCE c +ext_net.c:112 net_lookup VAL_NUM TEST a +ext_net.c:113 net_lookup eigs_num_arg READ b +ext_net.c:148 net_num_at eigs_slot_opt_num READ b +ext_net.c:158 builtin_net_listen VAL_NUM TEST a +ext_net.c:163 builtin_net_listen eigs_num_arg READ b +ext_net.c:181 builtin_net_listen make_num PRODUCE c +ext_net.c:188 builtin_net_port VAL_NUM TEST a +ext_net.c:199 builtin_net_port make_num PRODUCE c +ext_net.c:215 builtin_net_accept VAL_NUM TEST a +ext_net.c:229 builtin_net_accept make_num PRODUCE c +ext_net.c:282 builtin_net_dial make_num PRODUCE c +ext_net.c:327 net_send_bytes make_num PRODUCE c +ext_net.c:332 net_send_bytes make_num PRODUCE c +ext_net.c:335 net_send_bytes make_num PRODUCE c +ext_net.c:361 builtin_net_send buffer_read_num READ b +ext_net.c:362 builtin_net_send eigs_slot_elem_num READ b +ext_net.c:364 builtin_net_send finite_num_to_byte READ b +ext_net.c:379 builtin_net_close VAL_NUM TEST a +ext_net.c:385 builtin_net_close eigs_num_arg READ b +ext_store.c:173 store_json_encode_slot slot_is_num TEST h +ext_store.c:174 store_json_encode_slot eigs_slot_num READ h +ext_store.c:190 store_json_encode VAL_NUM CASE h +ext_store.c:191 store_json_encode eigs_num_arg READ h +ext_store.c:323 store_json_parse_number strtod PARSE h +ext_store.c:326 store_json_parse_number make_num PRODUCE h +ext_store.c:362 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:362 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:372 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:372 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:392 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:407 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:407 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:745 store_load_catalog VAL_NUM TEST h +ext_store.c:745 store_load_catalog VAL_NUM TEST h +ext_store.c:750 store_load_catalog eigs_num_arg READ h +ext_store.c:817 get_store_why VAL_NUM TEST h +ext_store.c:818 get_store_why eigs_num_arg READ h +ext_store.c:820 get_store_why VAL_NUM TEST h +ext_store.c:820 get_store_why eigs_num_arg READ h +ext_store.c:968 builtin_store_open make_num PRODUCE h +ext_store.c:969 builtin_store_open make_num PRODUCE h +ext_store.c:982 builtin_store_close VAL_NUM TEST h +ext_store.c:982 builtin_store_close eigs_num_arg READ h +ext_store.c:984 builtin_store_close VAL_NUM TEST h +ext_store.c:984 builtin_store_close eigs_num_arg READ h +ext_store.c:1030 builtin_store_put make_num PRODUCE h +ext_store.c:1031 builtin_store_put make_num PRODUCE h +ext_store.c:1045 builtin_store_put eigs_num_arg READ h +ext_store.c:1046 builtin_store_put eigs_num_arg READ h +ext_store.c:1058 builtin_store_put make_num PRODUCE h +ext_store.c:1182 builtin_store_get VAL_NUM TEST h +ext_store.c:1183 builtin_store_get eigs_num_arg READ h +ext_store.c:1192 builtin_store_get eigs_num_arg READ h +ext_store.c:1250 store_locate eigs_num_arg READ h +ext_store.c:1346 builtin_store_delete VAL_NUM TEST h +ext_store.c:1347 builtin_store_delete eigs_num_arg READ h +ext_store.c:1393 builtin_store_query eigs_num_arg READ h +ext_store.c:1428 builtin_store_count make_num PRODUCE h +ext_store.c:1436 builtin_store_count make_num PRODUCE h +ext_store.c:1437 builtin_store_count make_num PRODUCE h +ext_store.c:1440 builtin_store_count make_num PRODUCE h +ext_store.c:1446 builtin_store_count make_num PRODUCE h +ext_store.c:1450 builtin_store_count make_num PRODUCE h +ext_store.c:1451 builtin_store_count eigs_num_arg READ h +ext_store.c:1462 builtin_store_count make_num PRODUCE h +ext_store.c:1468 builtin_store_count make_num PRODUCE h +ext_store.c:1502 builtin_store_update VAL_NUM TEST h +ext_store.c:1503 builtin_store_update eigs_num_arg READ h +ext_store.c:1644 builtin_store_drop eigs_num_arg READ h +jit.c:1282 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d +jit.c:1406 emit_addsd_xmm0_xmm1 emit_addsd_xmm0_xmm1 EMIT d +jit.c:1410 emit_subsd_xmm0_xmm1 emit_subsd_xmm0_xmm1 EMIT d +jit.c:1414 emit_mulsd_xmm0_xmm1 emit_mulsd_xmm0_xmm1 EMIT d +jit.c:1418 emit_divsd_xmm0_xmm1 emit_divsd_xmm0_xmm1 EMIT d +jit.c:1424 emit_cvttsd2si_xmm0_rax emit_cvttsd2si_xmm0_rax EMIT d +jit.c:1428 emit_cvttsd2si_xmm1_rdx emit_cvttsd2si_xmm1_rdx EMIT d +jit.c:1436 emit_cvtsi2sd_rax_xmm2 emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:1440 emit_cvtsi2sd_rdx_xmm2 emit_cvtsi2sd_rdx_xmm2 EMIT d +jit.c:1444 emit_ucomisd_xmm0_xmm2 emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:1448 emit_ucomisd_xmm1_xmm2 emit_ucomisd_xmm1_xmm2 EMIT d +jit.c:1452 emit_cvtsi2sd_rdx_xmm0 emit_cvtsi2sd_rdx_xmm0 EMIT d +jit.c:1499 emit_btr_63_rax emit_btr_63_rax EMIT d +jit.c:1517 emit_cvtsi2sd_rax_xmm0 emit_cvtsi2sd_rax_xmm0 EMIT d +jit.c:1531 emit_ucomisd_xmm0_xmm1 emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:1593 emit_btr_63_rdx emit_btr_63_rdx EMIT d +jit.c:1598 emit_btr_63_rsi emit_btr_63_rsi EMIT d +jit.c:1625 emit_immediate_num_check_rax emit_immediate_num_check_rax EMIT d +jit.c:1628 emit_immediate_num_check_rax TAG-IMM 0xFFF8 EMIT d +jit.c:1631 emit_immediate_num_check_rdx emit_immediate_num_check_rdx EMIT d +jit.c:1634 emit_immediate_num_check_rdx TAG-IMM 0xFFF8 EMIT d +jit.c:1640 emit_overflow_check_rax EMIT d +jit.c:1643 emit_overflow_check_rax emit_btr_63_rdx EMIT d +jit.c:1704 emit_cvttsd2si_xmm0_r8d emit_cvttsd2si_xmm0_r8d EMIT d +jit.c:1709 emit_cvtsi2sd_r8d_xmm1 emit_cvtsi2sd_r8d_xmm1 EMIT d +jit.c:1716 emit_cvttsd2si_xmm0_edx emit_cvttsd2si_xmm0_edx EMIT d +jit.c:1721 emit_cvtsi2sd_edx_xmm0 emit_cvtsi2sd_edx_xmm0 EMIT d +jit.c:1914 emit_jump_unless_bool_rax TAG-IMM 0xFFF9 EMIT d +jit.c:2032 emit_conditional_decref_rsi_hook TAG-IMM 0xFFFB EMIT d +jit.c:2178 emit_dict_cache_probe TAG-IMM 0xFFFB EMIT d +jit.c:2343 emit_load_numeric_operand EMIT d +jit.c:2348 emit_load_numeric_operand TAG-IMM 0xFFF8 EMIT d +jit.c:2353 emit_load_numeric_operand TAG-IMM 0xFFFB EMIT d +jit.c:2356 emit_load_numeric_operand TAG-IMM 0xFFFD EMIT d +jit.c:2363 emit_load_numeric_operand VAL_NUM EMIT d +jit.c:2367 emit_load_numeric_operand VAL_NUM_OFFSET RAW d +jit.c:2368 emit_load_numeric_operand VAL_NUM_OFFSET RAW d +jit.c:2397 emit_decref_binop_operands TAG-IMM 0xFFFB EMIT d +jit.c:2425 emit_commit_binop TAG-IMM 0xFFFB EMIT d +jit.c:2633 jit_compile_to_thunk max_normal_bits EMIT d +jit.c:2634 jit_compile_to_thunk EIGS_NUM_MAX GUARD d +jit.c:2634 jit_compile_to_thunk max_normal_bits EMIT d +jit.c:2801 jit_compile_to_thunk/OP_NULL TAG-IMM 0xFFF8 EMIT d +jit.c:2822 jit_compile_to_thunk/OP_CONST VAL_NUM TEST d +jit.c:2825 jit_compile_to_thunk/OP_CONST VAL_NUM_RAW RAW d +jit.c:2828 jit_compile_to_thunk/OP_CONST TAG-IMM 0xFFFB EMIT d +jit.c:3024 jit_compile_to_thunk/OP_SET_NAME TAG-IMM 0xFFFB EMIT d +jit.c:3145 jit_compile_to_thunk/OP_LOCAL_DOT_GET emit_immediate_num_check_rax EMIT d +jit.c:3271 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rax EMIT d +jit.c:3274 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rdx EMIT d +jit.c:3452 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFF8 EMIT d +jit.c:3457 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFB EMIT d +jit.c:3459 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFD EMIT d +jit.c:3465 jit_compile_to_thunk/OP_SET_LOCAL VAL_NUM EMIT d +jit.c:3471 jit_compile_to_thunk/OP_SET_LOCAL VAL_NUM_OFFSET RAW d +jit.c:3530 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d +jit.c:3534 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d +jit.c:3544 jit_compile_to_thunk/OP_MOD emit_btr_63_rsi EMIT d +jit.c:3558 jit_compile_to_thunk/OP_MOD fmod EMIT d +jit.c:3564 jit_compile_to_thunk/OP_MOD emit_overflow_check_rax EMIT d +jit.c:3564 jit_compile_to_thunk/OP_MOD max_normal_bits EMIT d +jit.c:3612 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d +jit.c:3616 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d +jit.c:3624 jit_compile_to_thunk/OP_ADD emit_addsd_xmm0_xmm1 EMIT d +jit.c:3625 jit_compile_to_thunk/OP_ADD emit_subsd_xmm0_xmm1 EMIT d +jit.c:3626 jit_compile_to_thunk/OP_ADD emit_mulsd_xmm0_xmm1 EMIT d +jit.c:3627 jit_compile_to_thunk/OP_ADD emit_divsd_xmm0_xmm1 EMIT d +jit.c:3634 jit_compile_to_thunk/OP_ADD emit_overflow_check_rax EMIT d +jit.c:3634 jit_compile_to_thunk/OP_ADD max_normal_bits EMIT d +jit.c:3673 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d +jit.c:3677 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d +jit.c:3690 jit_compile_to_thunk/OP_EQ emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:3730 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rax EMIT d +jit.c:3732 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rdx EMIT d +jit.c:3738 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm0_rax EMIT d +jit.c:3739 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:3740 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:3743 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm1_rdx EMIT d +jit.c:3744 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm2 EMIT d +jit.c:3745 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm1_xmm2 EMIT d +jit.c:3765 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm0 EMIT d +jit.c:3795 jit_compile_to_thunk/OP_NOT emit_immediate_num_check_rax EMIT d +jit.c:3808 jit_compile_to_thunk/OP_NEG emit_btr_63_rax EMIT d +jit.c:3823 jit_compile_to_thunk/OP_NEG emit_cvttsd2si_xmm0_rax EMIT d +jit.c:3824 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:3825 jit_compile_to_thunk/OP_NEG emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:3829 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm0 EMIT d +jit.c:3948 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_immediate_num_check_rax EMIT d +jit.c:3951 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_btr_63_rax EMIT d +jit.c:4088 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rdx EMIT d +jit.c:4093 jit_compile_to_thunk/OP_INDEX_SET TAG-IMM 0xFFFB EMIT d +jit.c:4107 jit_compile_to_thunk/OP_INDEX_SET emit_cvttsd2si_xmm0_r8d EMIT d +jit.c:4108 jit_compile_to_thunk/OP_INDEX_SET emit_cvtsi2sd_r8d_xmm1 EMIT d +jit.c:4109 jit_compile_to_thunk/OP_INDEX_SET emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:4117 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rax EMIT d +jit.c:4375 jit_compile_to_thunk/OP_POP VAL_NUM TEST d +jit_smoke.c:103 jit_helper_local_idx_get slot_from_num PRODUCE d +jit_smoke.c:138 jit_helper_iter_next SLOT_NUM_RAW RAW d +jit_smoke.c:142 jit_helper_iter_next slot_from_num PRODUCE d +jit_smoke.c:149 jit_helper_index_get SLOT_NUM_RAW RAW d +jit_smoke.c:149 jit_helper_index_get SLOT_NUM_RAW RAW d +jit_smoke.c:153 jit_helper_index_get slot_from_num PRODUCE d +jit_smoke.c:172 jit_helper_set_name SLOT_NUM_RAW RAW d +jit_smoke.c:172 jit_helper_set_name SLOT_NUM_RAW RAW d +jit_smoke.c:173 jit_helper_set_name SLOT_NUM_RAW RAW d +jit_smoke.c:176 jit_helper_set_name SLOT_NUM_RAW RAW d +jit_smoke.c:329 run_store_cases slot_from_num PRODUCE d +jit_smoke.c:343 run_store_cases slot_from_num PRODUCE d +jit_smoke.c:360 run_store_cases SLOT_NUM_RAW RAW d +jit_smoke.c:360 run_store_cases SLOT_NUM_RAW RAW d +jit_smoke.c:361 run_store_cases SLOT_NUM_RAW RAW d +jit_smoke.c:368 run_store_cases SLOT_NUM_RAW RAW d +jit_smoke.c:444 run_index_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:444 run_index_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:536 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:537 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:538 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:538 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:539 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:540 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:541 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:541 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:601 run_exit_cases VAL_NUM TAGSET d +jit_smoke.c:602 run_exit_cases VAL_NUM_RAW WRITE d +jit_smoke.c:628 run_exit_cases slot_from_num PRODUCE d +jit_smoke.c:637 run_exit_cases SLOT_NUM_RAW RAW d +jit_smoke.c:642 run_exit_cases SLOT_NUM_RAW RAW d +lexer.c:42 tok_add num_val RAW b +lexer.c:647 tokenize_at_line num_val RAW b +lexer.c:750 tokenize_at_line strtod PARSE c +lint.c:247 collect_refs AST_NUM CASE a +lint.c:311 collect_assigns AST_NUM CASE a +lint.c:369 cond_has_bare_predicate AST_NUM CASE a +lint.c:431 collect_loop_assign_names AST_NUM CASE a +lint.c:531 check_empty_blocks AST_NUM CASE a +lint.c:640 check_dup_keys AST_NUM CASE a +lint.c:740 check_builtin_shadow AST_NUM CASE a +lint.c:870 check_disc_interrog AST_NUM CASE a +lint.c:947 check_func_unreachable AST_NUM CASE a +lint.c:1016 check_is_conditions AST_NUM CASE a +lint.c:1118 check_unused_params AST_NUM CASE a +lint.c:1228 w015_collect_locals AST_NUM CASE a +lint.c:1296 w015_flag AST_NUM CASE a +lint.c:1506 w023_walk AST_NUM CASE a +lint.c:1565 w023_collect_binders AST_NUM CASE a +lint.c:1726 w023_scan_sequence AST_NUM CASE a +lint.c:1890 w016_scan AST_NUM CASE a +lint.c:2049 w017_scan AST_NUM CASE a +lint.c:2076 #define LINT_FOR_EACH_CHILD AST_NUM CASE a +lint.c:2292 w022_collect_bindings AST_NUM CASE a +lint.c:2418 w020_facts AST_NUM CASE a +lint.c:2478 w020_facts AST_NUM CASE a +lint.c:2552 w020_scan AST_NUM CASE a +lint.c:2814 w018_scan AST_NUM CASE a +lint.c:3095 w024_collect AST_NUM CASE a +lint.c:3120 w024_index_varies AST_NUM CASE a +lint.c:3150 w024_elem_walks AST_NUM CASE a +lint.c:3186 w024_operand_inert AST_NUM TEST a +lint.c:3537 w024_walk AST_NUM CASE a +lint_host.c:545 w021_collect_imports AST_NUM CASE a +lint_host.c:634 w021_walk AST_NUM CASE a +lint_host.c:1093 e003_walk AST_NUM CASE a +model_infer.c:573 builtin_eigen_generate eigs_slot_opt_num READ b +model_infer.c:574 builtin_eigen_generate eigs_slot_opt_num READ b +model_infer.c:575 builtin_eigen_generate eigs_slot_opt_num READ b +model_infer.c:611 builtin_eigen_generate eigs_slot_num READ b +model_infer.c:621 builtin_eigen_generate make_num PRODUCE c +model_infer.c:652 builtin_eigen_eval_loss make_num PRODUCE c +model_infer.c:658 builtin_eigen_eval_loss make_num PRODUCE c +model_infer.c:660 builtin_eigen_eval_loss VAL_NUM TEST a +model_infer.c:662 builtin_eigen_eval_loss make_num PRODUCE c +model_infer.c:664 builtin_eigen_eval_loss eigs_list_num READ b +model_infer.c:669 builtin_eigen_eval_loss make_num PRODUCE c +model_infer.c:677 builtin_eigen_eval_loss make_num PRODUCE c +model_infer.c:685 builtin_eigen_eval_loss make_num PRODUCE c +model_infer.c:696 builtin_eigen_eval_loss eigs_slot_num READ b +model_infer.c:718 builtin_eigen_eval_loss make_num PRODUCE c +model_infer.c:719 builtin_eigen_eval_loss make_num PRODUCE c +model_io.c:69 json_parse_number strtod PARSE h +model_train.c:708 obs_drift_eps atof PARSE i +model_train.c:1457 builtin_native_train_step eigs_slot_num READ b +model_train.c:1458 builtin_native_train_step VAL_NUM TEST a +model_train.c:1458 builtin_native_train_step eigs_list_num READ b +model_train.c:1459 builtin_native_train_step strtod PARSE c +model_train.c:1474 builtin_native_train_step eigs_slot_num READ b +model_train.c:1477 builtin_native_train_step eigs_slot_num READ b +parser.c:524 free_ast AST_NUM CASE a +parser.c:793 parse_primary AST_NUM DATA a +parser.c:794 parse_primary data.num WRITE c +parser.c:794 parse_primary num_val RAW b +parser.c:821 parse_primary data.num WRITE c +tape_read.c:368 tape_parse strtod PARSE g +tape_read.c:387 tape_parse strtod PARSE g +tape_read.c:388 tape_parse strtod PARSE g +tape_read.c:389 tape_parse strtod PARSE g +tape_read.c:391 tape_parse strtod PARSE g +task.c:289 task_sched_trace_read make_num PRODUCE c +task.c:290 task_sched_trace_read make_num PRODUCE c +task.c:291 task_sched_trace_read make_num PRODUCE c +task.c:559 task_do_kill make_num PRODUCE c +trace.c:742 trace_query_at slot_from_num PRODUCE g +trace.c:757 trace_query_at slot_from_num PRODUCE g +trace.c:806 trace_query_when slot_from_num PRODUCE g +trace.c:827 trace_query_when slot_from_num PRODUCE g +trace.c:1927 #define TK_NUM_ VAL_NUM DATA g +trace.c:2018 kinds_text VAL_NUM DATA g +trace.c:2324 parse_value_p strtod PARSE g +trace.c:2407 parse_value_p strtod PARSE g +trace.c:2410 parse_value_p make_num PRODUCE g +trace.c:2820 write_value_ptr VAL_NUM CASE g +trace.c:2820 write_value_ptr VAL_NUM_RAW RAW g +trace.c:2837 write_slot SLOT_NUM_RAW RAW g +trace.c:2837 write_slot slot_is_num TEST g +trace.c:2954 write_value_ptr_full VAL_NUM CASE g +trace.c:2954 write_value_ptr_full VAL_NUM_RAW RAW g +value_slot.h:50 slot_is_num slot_is_num TEST a +value_slot.h:59 slot_is_numeric slot_is_num TEST a +value_slot.h:59 slot_is_numeric slot_is_numeric TEST a +value_slot.h:66 #define SLOT_NUM_RAW SLOT_NUM_RAW RAW b +value_slot.h:73 slot_from_num SLOT_NUM_RAW WRITE c +value_slot.h:73 slot_from_num slot_from_num PRODUCE c +value_slot.h:143 slot_truthy_immediate SLOT_NUM_RAW RAW b +value_slot.h:143 slot_truthy_immediate slot_is_num TEST a +vm.c:107 obs_dump_num eigs_num_text FORMAT i +vm.c:118 obs_dump_value SLOT_NUM_RAW RAW i +vm.c:118 obs_dump_value slot_is_num TEST i +vm.c:124 obs_dump_value VAL_NUM CASE i +vm.c:124 obs_dump_value VAL_NUM_RAW RAW i +vm.c:213 obs_dump_scope slot_is_num TEST i +vm.c:214 obs_dump_scope SLOT_NUM_RAW RAW i +vm.c:705 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c +vm.c:785 slot_bridge_unwrap slot_is_num TEST a +vm.c:787 slot_bridge_unwrap SLOT_NUM_RAW RAW b +vm.c:787 slot_bridge_unwrap make_num PRODUCE c +vm.c:830 vm_slot_lift SLOT_NUM_RAW RAW b +vm.c:830 vm_slot_lift make_num PRODUCE c +vm.c:830 vm_slot_lift slot_is_num TEST a +vm.c:863 slot_truthy SLOT_NUM_RAW RAW b +vm.c:863 slot_truthy slot_is_num TEST a +vm.c:872 slot_as_double slot_as_double READ b +vm.c:873 slot_as_double SLOT_NUM_RAW RAW b +vm.c:873 slot_as_double slot_is_num TEST a +vm.c:876 slot_as_double VAL_NUM TEST a +vm.c:876 slot_as_double VAL_NUM_RAW RAW b +vm.c:925 make_iter_state make_num PRODUCE c +vm.c:938 make_iter_state make_num PRODUCE c +vm.c:1157 vm_store_local_slot slot_is_num TEST a +vm.c:1161 vm_store_local_slot VAL_NUM TEST a +vm.c:1163 vm_store_local_slot SLOT_NUM_RAW RAW b +vm.c:1163 vm_store_local_slot VAL_NUM_RAW WRITE c +vm.c:1354 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1354 jit_helper_local_idx_get slot_from_num PRODUCE c +vm.c:1515 jit_helper_dot_set slot_is_num TEST a +vm.c:1518 jit_helper_dot_set SLOT_NUM_RAW RAW b +vm.c:1585 jit_helper_local_dot_set slot_is_num TEST a +vm.c:1586 jit_helper_local_dot_set SLOT_NUM_RAW RAW b +vm.c:1677 jit_helper_observe_assign_local SLOT_NUM_RAW RAW b +vm.c:1677 jit_helper_observe_assign_local slot_is_num TEST a +vm.c:1681 jit_helper_observe_assign_local slot_is_num TEST a +vm.c:1682 jit_helper_observe_assign_local SLOT_NUM_RAW RAW b +vm.c:1730 jit_helper_observe_name_post slot_is_num TEST a +vm.c:1737 jit_helper_observe_name_post SLOT_NUM_RAW RAW b +vm.c:1737 jit_helper_observe_name_post slot_is_num TEST a +vm.c:1742 jit_helper_observe_name_post SLOT_NUM_RAW RAW b +vm.c:1742 jit_helper_observe_name_post slot_is_num TEST a +vm.c:1774 jit_helper_iter_next VAL_NUM TEST a +vm.c:1775 jit_helper_iter_next eigs_slot_num READ b +vm.c:1785 jit_helper_iter_next VAL_NUM TEST a +vm.c:1786 jit_helper_iter_next VAL_NUM_RAW RAW b +vm.c:1793 jit_helper_iter_next buffer_read_num READ b +vm.c:1793 jit_helper_iter_next num_guard GUARD c +vm.c:1793 jit_helper_iter_next slot_from_num PRODUCE c +vm.c:1799 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1869 vm_leaf_accessor_exec VAL_NUM_RAW RAW b +vm.c:1869 vm_leaf_accessor_exec slot_from_num PRODUCE c +vm.c:1873 vm_leaf_accessor_exec slot_from_num PRODUCE c +vm.c:1876 vm_leaf_accessor_exec slot_from_num PRODUCE c +vm.c:1913 vm_leaf_accessor_exec slot_as_double READ b +vm.c:1927 vm_leaf_accessor_exec buffer_read_num READ b +vm.c:1927 vm_leaf_accessor_exec slot_from_num PRODUCE c +vm.c:1935 vm_leaf_accessor_exec slot_as_double READ b +vm.c:1936 vm_leaf_accessor_exec slot_as_double READ b +vm.c:1954 vm_leaf_accessor_exec num_guard GUARD c +vm.c:1954 vm_leaf_accessor_exec slot_from_num PRODUCE c +vm.c:2037 loop_iter_store make_num PRODUCE c +vm.c:2044 loop_iter_store slot_is_num TEST a +vm.c:2045 loop_iter_store SLOT_NUM_RAW WRITE c +vm.c:2050 loop_iter_store make_num PRODUCE c +vm.c:2172 jit_helper_index_set slot_is_num TEST a +vm.c:2174 jit_helper_index_set SLOT_NUM_RAW RAW b +vm.c:2175 jit_helper_index_set slot_is_num TEST a +vm.c:2177 jit_helper_index_set SLOT_NUM_RAW RAW b +vm.c:2179 jit_helper_index_set SLOT_NUM_RAW RAW b +vm.c:2189 jit_helper_index_set slot_is_num TEST a +vm.c:2191 jit_helper_index_set SLOT_NUM_RAW RAW b +vm.c:2192 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2194 jit_helper_index_set SLOT_NUM_RAW RAW b +vm.c:2206 jit_helper_index_set VAL_NUM TEST a +vm.c:2208 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2209 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2216 jit_helper_index_set VAL_NUM TEST a +vm.c:2218 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2219 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2222 jit_helper_index_set VAL_NUM TEST a +vm.c:2223 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2242 jit_helper_index_get slot_is_num TEST a +vm.c:2244 jit_helper_index_get SLOT_NUM_RAW RAW b +vm.c:2251 jit_helper_index_get SLOT_NUM_RAW RAW b +vm.c:2262 jit_helper_index_get buffer_read_num READ b +vm.c:2264 jit_helper_index_get slot_from_num PRODUCE c +vm.c:2266 jit_helper_index_get SLOT_NUM_RAW RAW b +vm.c:2282 jit_helper_index_get VAL_NUM TEST a +vm.c:2284 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2285 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2297 jit_helper_index_get VAL_NUM TEST a +vm.c:2299 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2300 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2309 jit_helper_index_get VAL_NUM TEST a +vm.c:2311 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2312 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2314 jit_helper_index_get buffer_read_num READ b +vm.c:2314 jit_helper_index_get make_num PRODUCE c +vm.c:2900 vm_take_error_value make_num PRODUCE c +vm.c:3243 vm_run_ex/CASE(CONST) VAL_NUM TEST a +vm.c:3244 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b +vm.c:3244 vm_run_ex/CASE(CONST) slot_from_num PRODUCE c +vm.c:3258 vm_run_ex/CASE(NUM_ZERO) slot_from_num PRODUCE c +vm.c:3263 vm_run_ex/CASE(NUM_ONE) slot_from_num PRODUCE c +vm.c:3283 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3283 #define NUM_REUSE VAL_NUM TEST a +vm.c:3294 #define ARITH_FAST slot_as_double READ b +vm.c:3294 #define ARITH_FAST slot_as_double READ b +vm.c:3295 #define ARITH_FAST num_guard GUARD c +vm.c:3300 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3301 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3309 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3310 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3318 #define ARITH_FAST slot_from_num PRODUCE c +vm.c:3328 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3328 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3329 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3329 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3329 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3330 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3330 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3331 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3331 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3332 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3381 #define NUM_BINOP VAL_NUM TEST a +vm.c:3381 #define NUM_BINOP VAL_NUM TEST a +vm.c:3382 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3382 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3382 #define NUM_BINOP num_guard GUARD c +vm.c:3383 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3383 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3385 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3385 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3386 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3386 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3387 #define NUM_BINOP make_num PRODUCE c +vm.c:3391 #define NUM_BINOP make_num PRODUCE c +vm.c:3409 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3409 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3410 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3412 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3414 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3414 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3414 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3417 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3419 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3419 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3420 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3420 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3421 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3426 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3434 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3434 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3434 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3435 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3435 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3435 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3436 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3436 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3437 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3437 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3438 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3440 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3440 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3445 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3464 #define INT_BINOP_R slot_as_double READ b +vm.c:3464 #define INT_BINOP_R slot_as_double READ b +vm.c:3466 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3467 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3470 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3471 #define INT_BINOP_R slot_from_num PRODUCE c +vm.c:3478 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3478 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3482 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3482 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3485 #define INT_BINOP_R slot_from_num PRODUCE c +vm.c:3498 #define INT_BINOP_R slot_from_num PRODUCE c +vm.c:3525 vm_run_ex/CASE(NEG) slot_as_double READ b +vm.c:3528 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3528 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c +vm.c:3531 vm_run_ex/CASE(NEG) slot_from_num PRODUCE c +vm.c:3536 vm_run_ex/CASE(NEG) slot_from_num PRODUCE c +vm.c:3551 vm_run_ex/CASE(BNOT) slot_as_double READ b +vm.c:3553 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b +vm.c:3556 vm_run_ex/CASE(BNOT) slot_from_num PRODUCE c +vm.c:3562 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a +vm.c:3562 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c +vm.c:3565 vm_run_ex/CASE(BNOT) slot_from_num PRODUCE c +vm.c:3573 vm_run_ex/CASE(BNOT) slot_from_num PRODUCE c +vm.c:3583 vm_run_ex/CASE(EQ) slot_as_double READ f +vm.c:3583 vm_run_ex/CASE(EQ) slot_as_double READ f +vm.c:3604 vm_run_ex/CASE(NE) slot_as_double READ f +vm.c:3604 vm_run_ex/CASE(NE) slot_as_double READ f +vm.c:3626 #define NUM_CMP slot_as_double READ f +vm.c:3626 #define NUM_CMP slot_as_double READ f +vm.c:4035 vm_run_ex/CASE(JUMP_BACK) SLOT_NUM_RAW RAW b +vm.c:4035 vm_run_ex/CASE(JUMP_BACK) make_num PRODUCE c +vm.c:4035 vm_run_ex/CASE(JUMP_BACK) slot_is_num TEST a +vm.c:4398 vm_run_ex/CASE(CALL) SLOT_NUM_RAW RAW b +vm.c:4398 vm_run_ex/CASE(CALL) make_num PRODUCE c +vm.c:4398 vm_run_ex/CASE(CALL) slot_is_num TEST a +vm.c:4480 vm_run_ex/CASE(RETURN) SLOT_NUM_RAW RAW b +vm.c:4480 vm_run_ex/CASE(RETURN) make_num PRODUCE c +vm.c:4480 vm_run_ex/CASE(RETURN) slot_is_num TEST a +vm.c:4564 vm_run_ex/CASE(INDEX_GET) slot_is_num TEST a +vm.c:4566 vm_run_ex/CASE(INDEX_GET) SLOT_NUM_RAW RAW b +vm.c:4573 vm_run_ex/CASE(INDEX_GET) SLOT_NUM_RAW RAW b +vm.c:4583 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4585 vm_run_ex/CASE(INDEX_GET) slot_from_num PRODUCE c +vm.c:4587 vm_run_ex/CASE(INDEX_GET) SLOT_NUM_RAW RAW b +vm.c:4602 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4604 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4605 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4615 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4617 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4618 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4625 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4627 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4628 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4630 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4630 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c +vm.c:4647 vm_run_ex/CASE(INDEX_SET) slot_is_num TEST a +vm.c:4649 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b +vm.c:4650 vm_run_ex/CASE(INDEX_SET) slot_is_num TEST a +vm.c:4652 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b +vm.c:4654 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b +vm.c:4664 vm_run_ex/CASE(INDEX_SET) slot_is_num TEST a +vm.c:4666 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b +vm.c:4666 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4668 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b +vm.c:4680 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4682 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4683 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4690 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4692 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4693 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4696 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4697 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4753 vm_run_ex/CASE(DOT_SET) slot_is_num TEST a +vm.c:4756 vm_run_ex/CASE(DOT_SET) SLOT_NUM_RAW RAW b +vm.c:4817 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_num TEST a +vm.c:4818 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_NUM_RAW RAW b +vm.c:4844 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4844 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_num PRODUCE c +vm.c:4950 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_num TEST a +vm.c:4951 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_NUM_RAW RAW b +vm.c:4996 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5002 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5010 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5011 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5024 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5028 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5028 vm_run_ex/CASE(ITER_NEXT) slot_from_num PRODUCE c +vm.c:5186 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) slot_is_num TEST i +vm.c:5187 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) SLOT_NUM_RAW RAW i +vm.c:5201 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) SLOT_NUM_RAW RAW i +vm.c:5201 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) slot_is_num TEST i +vm.c:5366 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5367 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5368 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5402 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5403 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5404 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5431 vm_run_ex/CASE(OBSERVE_NAME_POST) slot_is_num TEST i +vm.c:5439 vm_run_ex/CASE(OBSERVE_NAME_POST) SLOT_NUM_RAW RAW i +vm.c:5439 vm_run_ex/CASE(OBSERVE_NAME_POST) slot_is_num TEST i +vm.c:5442 vm_run_ex/CASE(OBSERVE_NAME_POST) SLOT_NUM_RAW RAW i +vm.c:5442 vm_run_ex/CASE(OBSERVE_NAME_POST) slot_is_num TEST i +vm.c:5466 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5466 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i +vm.c:5466 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5470 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5471 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5472 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5473 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5477 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5491 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5492 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5493 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5494 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5514 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5540 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5543 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5544 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5547 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5563 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i +vm.c:5570 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i +vm.c:5590 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i +vm.c:5591 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i +vm.c:5721 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a +vm.c:5738 #define READ_SLICE_BOUND slot_is_num TEST a +vm.c:5739 #define READ_SLICE_BOUND SLOT_NUM_RAW RAW b +vm.c:5741 #define READ_SLICE_BOUND SLOT_NUM_RAW RAW b +vm.c:5748 #define READ_SLICE_BOUND VAL_NUM TEST a +vm.c:5749 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5752 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:6348 vm_run_ex/CASE(DISPATCH) slot_is_num TEST a +vm.c:6349 vm_run_ex/CASE(DISPATCH) SLOT_NUM_RAW RAW b +vm.c:6351 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a +vm.c:6352 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b +vm.c:6496 vm_run_ex/CASE(DISPATCH) SLOT_NUM_RAW RAW b +vm.c:6496 vm_run_ex/CASE(DISPATCH) make_num PRODUCE c +vm.c:6496 vm_run_ex/CASE(DISPATCH) slot_is_num TEST a diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md new file mode 100644 index 000000000..e29767d91 --- /dev/null +++ b/docs/design/phase2-numbers.md @@ -0,0 +1,1272 @@ +# Phase 2 numbers (#1758): round 0 design + +Status: design for blind review, before round 1 builds. Nothing here changes +`src/`. Spec: issue #1758 (Revision 1) and its owner decisions (A), (B), (C). +Evidence base: issue #1746 and the `exp-ieee-p1` branch (canonical NaN, the +single slot writer, the JIT bailing on NaN, refusal inside writers). + +Tree measured: `phase2-numbers` at `0740af03` (main, v0.46.0-8). The tag the +Done-when means is `v0.46.0` = `4a3a5c19`. + +Companion artifacts: +- `tools/phase2_inventory.py`: the site inventory and the builtin-table check. + It writes `docs/design/phase2-inventory.txt`. +- `tests/phase2/MAP.md`: every N, O and T item mapped to planned rows. + +Contents: +1. The inventory +2. Representation +3. Measured prototype +4. The JIT +5. N12 and SMI share the NaN space +6. Builtin classification +7. Semantics-to-sites map +8. Round plan +9. Test plan +10. Lua differential tool +11. Open questions this design does not decide + +--- + +## 1. The inventory + +`python3 tools/phase2_inventory.py` prints `examined=1773 classified=1773 +unclassified=0` on this tree and writes every site to +`docs/design/phase2-inventory.txt` (file:line, enclosing function, token, +syntactic kind, category). + +**Population.** A site is one occurrence, outside comments and string +literals, of a token of the value model's numeric vocabulary in `src/*.c` and +`src/*.h`. The vocabulary is: +- the type tag `VAL_NUM` and the slot predicates; +- the raw and checked payload accessors and the constructors; +- the clamp (`num_guard`) and the number formatter; +- the double parsers (`strtod`, `atof`); +- the AST literal fields (`AST_NUM`, `data.num`, `num_val`); +- in the JIT files only, the tag-range immediates (`0xFFF8`..`0xFFFF`) and the + emitters that assume a double (`emit_load_numeric_operand`, the `*sd` + arithmetic, `cvt*`, `fmod`, ...). The JIT's guards compare raw tag bits and + name no vocabulary token, so without these the JIT category would hold 40 + sites instead of 127. + +**The key and its blind spot.** The key is the token, so code that handles a +number without naming one is invisible. Two derived checks bound that, and +both can make `unclassified` nonzero: +1. Every function that returns or writes out a `double` and whose body + performs a payload read is a numeric accessor. It must be in the + vocabulary (its call sites then count as sites) or in a reviewed + `WRAPPERS` list with a reason. 17 such functions exist. 11 are in the + vocabulary and 6 are wrappers, for example `tensor_to_flat`, whose + per-element read is the site. +2. Every `VAL_NUM`/`AST_NUM` must sit in a recognized syntactic position: + test, case, tag store, type yield, data, or emitter immediate. An + unrecognized position (for example `1u << VAL_NUM`) is unclassified. + +Also outside the population: +- `src/freestanding/` (`mini_strtod.c`, `mini_fmt.c`), which N1, N6 and N10 + must also reach for the EigenOS profile; the round plan names it; +- code that computes on a double after a counted read extracted it. + +**Categories** (one per site; the first matching rule wins). Role rules, +keyed by file or function, come first; otherwise the token's own kind +decides (a)/(b)/(c)/(e). + +| | category | sites | kinds | +|---|---|---:|---| +| a | type tests | 384 | TEST 327, CASE 52, DATA 3, YIELD 2 | +| b | payload reads | 505 | READ 392, RAW 113 | +| c | producers | 472 | PRODUCE 373, GUARD 71, WRITE 22, PARSE 3, TAGSET 3 | +| d | JIT emitters and guards | 127 | EMIT 89, RAW 27, PRODUCE 6, TEST 2, GUARD 1, TAGSET 1, WRITE 1 | +| e | number formatting | 14 | | +| f | equality, ordering and hashing | 27 | | +| g | tape encode and decode | 20 | | +| h | JSON, store and db encoders | 70 | | +| i | observer numeric paths | 90 | | +| j | embed API | 64 | | +| | **total** | **1773** | | + +`WRITE` is `VAL_NUM_RAW(v) = x`, the NUM_REUSE in-place writes the brief +names as producers. + +Largest files: builtins.c 319, vm.c 304, ext_gfx.c 229, builtins_tensor.c +184, builtins_buf.c 97, jit.c 96. The per-file and per-token tables are in +the inventory file. + +**The brief's headline figures, re-measured.** The brief says ~420 `VAL_NUM`, +366 `make_num` and 274 argument reads. Outside comments and literals this +tree has: +- `VAL_NUM` 329, plus `VAL_NUM_RAW` 92; +- `make_num` 368; +- argument and element reads 357 (`eigs_num_arg` 145, `eigs_list_num` 130, + `eigs_slot_num` 52, the optional and element forms 30). + +**Builtins.** The registration table is derived from the +`env_set_local_owned(env, "name", make_builtin(fn))` lines plus the +`ext_names.h` X-lists. It holds 311 names, and it was calibrated once against +the runtime's own `eigenscript --api --json` (223 core + 88 extension = 311; +equal in both directions). A builtin is numeric when a site is contained in +its function, in a same-file function it calls or names as a value (a +comparator, an op-table entry; closure depth 4), or in the shared formatter +or equality it calls. That gives 229 numeric builtins, and §6 +classifies every one. The script fails if a numeric builtin has no row, a row +names no numeric builtin, a class or loss mark is not one of the allowed +tokens, or a `LOSS` row has no double path in its closure. + +--- + +## 2. Representation + +### 2.1 What every alternative shares: the slot + +`EigsSlot` stays a NaN-boxed 64-bit word (`src/value_slot.h`). + +| bits (high 16) | meaning | +|---|---| +| `< 0xFFF8` | a double (`slot_is_num` today) | +| `0xFFF8` | null | +| `0xFFF9` | bool | +| `0xFFFA` | **SMI: an int in [-2^47, 2^47), 48-bit two's complement payload** (reserved today, unused) | +| `0xFFFB` | heap pointer; **an int outside the SMI range is a heap-boxed int64 here** | +| `0xFFFC`-`0xFFFE` | reserved | +| `0xFFFF` | sentinel | + +- SMI encode: `s.u = 0xFFFA000000000000 | ((uint64_t)i & 0x0000FFFFFFFFFFFF)`. +- SMI decode, sign-extending bit 47 portably: + `(int64_t)((s.u & PAYLOAD) ^ 0x800000000000) - 0x800000000000`. + The `(int64_t)(u << 16) >> 16` form relies on implementation-defined right + shifts. +- Adding or subtracting two SMIs cannot overflow int64 (|a ± b| < 2^48), so + round 1 computes those in int64 and range-checks the result into SMI or + boxed. Multiplication can overflow int64 (|a·b| < 2^94), so it always uses + `__builtin_mul_overflow`, as do boxed operands for every operator. An int64 + overflow raises `value` ((A)). + +**Canonical-form invariant (all alternatives):** an int in [-2^47, 2^47) is +always an SMI in a slot, never boxed; a boxed int is always outside that +range. Equality fast paths, hashing and the tape depend on it (#1758). + +It is enforced inside the two writers that can put an int into a slot, not +beside their callers (the #1746 lesson): +- `slot_from_int(int64_t)`, the only int-to-slot constructor; +- `slot_from_heap(Value *)`, which already normalizes the null and bool + singletons (value_slot.h:86) and gains the same rule for a small boxed + int. + +Every other route into a slot goes through one of them: `slot_from_value`, +`eigs_container_slot`, `vm_push`/`slot_bridge_wrap`, the tape decoder (it +returns Values), and the JIT `OP_CONST` emitter, which must compute its bits +with the same function (§4). + +### 2.2 The four alternatives + +**Alt 1: `VAL_INT` beside `VAL_NUM`.** +- Value: a new `ValType VAL_INT` with an `int64_t` payload, appended after + `VAL_BOOL`. `VAL_NUM` keeps meaning a double. +- Slot: SMI plus boxed `VAL_INT`. +- `type of` still answers `"num"` for both ((B)): `val_type_name(VAL_INT)` + returns `"num"`. `num_type of x` reads the tag. + +**Alt 1R (chosen): Alt 1, and the double vocabulary renamed, the ambiguous +accessors deleted.** +- `VAL_NUM` becomes `VAL_FLOAT`, `num_` becomes `f64_`, `VAL_NUM_RAW` and + `SLOT_NUM_RAW` become `*_F64_RAW`, `slot_is_num` becomes `slot_is_f64`, + `make_num` becomes `make_float`, `slot_from_num` becomes `slot_from_f64`. +- `eigs_num_arg`, `eigs_list_num`, `eigs_opt_num` and the slot forms are + deleted. Replacements state intent: + - `eigs_float_arg` converts an int to a double. It is legal only for + float-producing builtins. + - `eigs_int_arg` applies N5's exact rule and raises otherwise. + - `eigs_number_arg` returns `EigsNum { kind, i, f }` for int-preserving + builtins. + - `make_int`. +- This is the repo's own precedent: #1637 round 4 renamed the union member to + `num_` "so no unchecked read compiles" (eigenscript.h:281). + +**Alt 2: one `VAL_NUM` with an int/float subtype (Lua 5.4's `TValue` +model).** +- Value: `VAL_NUM` plus a `numkind` field. The payload union holds `num_` + (double) or `i64_`. +- Slot: SMI plus boxed `VAL_NUM`/INT. +- (B) falls out of the type layer for free: `type of`, `who is` and every + `== VAL_NUM` test already say "number". + +**Alt 3: double-plus-int shadow.** +- As Alt 2, but an int Value also keeps `num_ = (double)i64_`, so every + existing double read keeps working. +- Slots still need the SMI tag, because a slot has no room for a shadow, so + the slot work equals Alt 1's. + +### 2.3 How many sites change, and what a missed site does + +The counts come from the inventory (§1); the token-by-token split was +computed from the site list. + +| | sites that must be revisited | how the revisit is forced | what a MISSED site does | +|---|---|---|---| +| **Alt 1** | the 382 TEST and 63 CASE sites (all categories) that should admit ints; reads after them; every producer that should yield an int; JIT producers | CASE only: 62 of the 63 `case VAL_NUM:`/`case AST_NUM:` switches have no `default:`, so `-Werror=switch` names them. TEST sites are not forced. | The int fails `== VAL_NUM` and takes the non-number branch. That raises a type error where the branch raises (loud, acceptable), but returns a **soft default** where the branch is soft. Examples: `what is 5` answers 0 and `who is 5` answers "unknown" (vm.c:5465-5484); `json_encode of 5` writes `null` (builtins.c:998, the one switch with a `default:`). Silently wrong, but never a lossy double. | +| **Alt 1R** | the same sites | **1,449 non-JIT sites and 39 JIT-file sites name a renamed or deleted token and stop compiling** until visited. 197 sites keep their token (the clamp 73, the formatter 7, buffer float reads 38, parsers 17, conversions 14, the embed accessor 48); each is pinned by a MAP row or a round-2 item. 88 JIT emitter tokens are reviewed per opcode (§4). | **A compile error.** It cannot exist in code that names the vocabulary. Two residual routes remain: (1) a switch with a `default:` absorbs the new `VAL_INT` (only builtins.c:915-998, removed first in round 1), and (2) code that tests raw slot bits: 74 sites, 59 of them value_slot.h's own definitions, 13 in the JIT files, 2 in eigenscript.c (a bit-identity shortcut that stays correct). | +| **Alt 2** | payload reads and producers (enforced only if `num_` is renamed); the type tests keep compiling and now admit ints | none for the 382+63 type tests and the 484 checked reads | **A silent wrong number.** After `== VAL_NUM`, a `VAL_NUM_RAW` read of an int reads its int64 bits as a double (5 reads as 2.5e-323). An accessor that converts loses precision above 2^53 silently. In the JIT, three emitters misread with no compiler to catch them: `emit_load_numeric_operand`'s heap arm (jit.c:2343) loads `data.num_` of a boxed int; the `OP_SET_LOCAL` in-place branch (jit.c:3410) writes double bits into an int Value; the `OP_CONST` emitter (jit.c:2816) pushes `VAL_NUM_RAW` bits of an int constant. Constant dedup `const_equal` (chunk.c:212) merges `3` and `3.0`. | +| **Alt 3** | only the sites that need exactness (N2, N3, N6, N8, N14, tape) | none: every existing read compiles and works below 2^53 | **A silently lossy double**, exact below 2^53, so ordinary tests cannot see it. This is precisely the class the brief says to design out. | + +### 2.4 The choice: Alt 1R + +1. **It is the only alternative whose missed site is loud by construction.** + 1,488 of 1,773 sites stop compiling until a person decides, site by site, + whether the site admits ints and with what semantics. Alt 2 and Alt 3 + leave 445 type tests and cases plus 484 checked reads compiling with a + widened or lossy meaning. +2. **The JIT argues for it independently.** All three of Alt 2's emitted + misreads exist because the emitter checks `type == VAL_NUM` and then loads + at a fixed offset (`VAL_NUM_OFFSET`). Under Alt 1R a boxed int has another + type, so the same unchanged code bails (§4). +3. **(B) does not require Alt 2.** (B) is a language-surface decision. + `val_type_name(VAL_INT)` returns `"num"`, and the `who` interrogative + answers "number". Lua itself keeps two variant tags under one basic type + (`LUA_VNUMINT` / `LUA_VNUMFLT` of `LUA_TNUMBER`) and tests the variant + wherever arithmetic cares, which is Alt 1's shape at the C level. +4. **No measurement favours another alternative** (§3). The slot cost is + identical for all four; the Value-level type test is one compare (Alt 1) + against two (Alt 2). + +The cost of Alt 1R is the size of the round-1 diff. §8 stages it with +deprecation warnings, so the compiler's warning count is the progress meter +and the final commit deletes the old names. A mechanical `sed` from old name +to new would reintroduce the silent class (`len` returning +`make_float(count)`), so the migration is per site, with the builtin table +(§6) deciding each builtin's accessor and the int-fuzz gate (§9) checking it. + +### 2.5 The slot layer already mishandles an unknown tag, today + +Nothing produces `0xFFFA` yet, so these paths are dead today. They show what +the **first** SMI producer would do anywhere it is missed, and they are why +round 1 starts by making every slot classifier exhaustive: + +| function | what an SMI slot does today | +|---|---| +| `slot_type` (container.h:92), `eigs_slot_ref` (container.h:98), `slot_bridge_unwrap` (vm.c:784), `slot_truthy` (vm.c:862) | **pointer misread**: "not num/null/bool" is taken to mean heap, so the payload is dereferenced as a `Value *` | +| `vm_slot_lift` (vm.c:826), `slot_to_value` (eigenscript.c:1885) | **silent null**: the int becomes null | +| `obs_slot_observable` (vm.c:1630) and the observe sites | **silently unobserved**: the binding answers from no data | +| `write_slot` (trace.c:2836) | writes ``, an unreplayable marker, so replay falls back to live source | +| `slot_as_double` (vm.c:872) | returns 0, taking the slow path into `slot_bridge_unwrap`, which misreads | +| `slot_type_name` (vm.c:3000) | answers `"num"` (right by accident) | + +Round 1's first commit makes each of these test the SMI tag explicitly and +`abort()` on an unknown tag, instead of guessing heap or null. + +### 2.6 The accessor API after round 1 (Alt 1R) + +``` +/* slots */ +int slot_is_f64(EigsSlot); /* high16 < 0xFFF8 */ +int slot_is_smi(EigsSlot); /* high16 == 0xFFFA */ +int slot_is_int(EigsSlot); /* SMI or heap VAL_INT */ +int slot_is_number(EigsSlot); /* f64 or int */ +EigsSlot slot_from_f64(double); /* the ONE double writer; round 2: canonical NaN */ +EigsSlot slot_from_int(int64_t); /* the ONE int writer; SMI or boxed (canonical) */ + +/* Values */ +Value *make_float(double); +Value *make_int(int64_t); +EigsNum eigs_number_arg(const Value *, const char *who); /* int-preserving */ +double eigs_float_arg(const Value *, const char *who); /* float-producing: int converts */ +int64_t eigs_int_arg(const Value *, const char *who); /* int-requiring: N5 exact rule */ +``` + +Each `_arg` reader also has the list, slot and optional forms of today's +checked accessors. + +--- + +## 3. Measured prototype + +**Question.** What does an SMI arm cost in the VM's ADD fast path, in which +order, and does inline SMI beat boxing every int? + +**Probe.** A 155-line standalone C file +(`/tmp/claude-1000/.../p2r0/bench/p2bench.c`, not committed). It mirrors +`ARITH_FAST` (vm.c:3290) on a two-slot stack. Each variant is one `noinline` +handler; the accumulator round-trips through memory as on the VM stack. It +is built with the runtime's flags: `-O2 -fstack-protector-strong +-D_FORTIFY_SOURCE=2 -fPIE`, gcc 13.3. All nine runs agree on the checksum +(2984375 at 1e6 iterations). + +**Instrument.** `perf` is unavailable (perf_event_paranoid=4). Instruction +counts come from callgrind at 1e6 and 2e6 iterations. The difference divided +by 1e6 cancels startup cost, and both runs scale exactly, so the counts are +deterministic. Wall time is the interleaved median of 7 runs at 2e7 +iterations. The box (Celeron N3350) carried load 1.2-3.8 from another job, +so read wall time as secondary. + +| variant | data | Ir/op | wall median ns/op | +|---|---|---:|---:| +| A: today, double-only + `num_guard` | float | **38** | 8.38 | +| B: float first, then SMI (range check) | float | 40 (+2) | 8.88 | +| C: SMI first, then float | float | 44 (+6) | 10.17 | +| D: float first, SMI via shifted add + overflow flag | float | 40 (+2) | 9.04 | +| E: no SMI, every int a boxed int64 (freelist hit) | float | 49 (+11: harness prologue, see below) | 8.76 | +| B | int | 50 | 10.97 | +| C | int | **42** | 10.46 | +| D | int | **44** | 10.45 | +| E | int | **77** | 17.24 | + +**Reading the disassembly.** +- B's +2 on floats is two register copies the compiler keeps live for the + SMI arm (`movq %xmm0,%rdx; mov %rdx,%rcx`). That is a real cost of sharing + the operand bits. +- E's +11 on floats is four callee-saved push/pop pairs in the per-variant + function prologue. That is an artifact of the harness: in the VM the + handler is inside `vm_run_ex`, which saves those registers once per call. + +**What it decides.** +1. **Check order: float first.** It costs the float path +2 Ir (5% of the + isolated op). SMI-first costs floats +6. Float-first keeps every existing + float program within 2 Ir per arithmetic op. +2. **Overflow check: the shifted add (D)** is 6 Ir cheaper on the int path + than a range check on the sum (B). Put both payloads in the top 48 bits + and let the hardware overflow flag fire exactly when the sum leaves 48 + bits. This is a round-5 fast-path choice, recorded here because it + decides the int arm's shape. +3. **Inline SMI against boxing every int: +33 Ir (+75%) and +65% wall per + add for boxing, even when every allocation hits a freelist.** This + confirms #1758's SMI tag decision with a number. + +**Scale.** The real interpreter spends 685 Ir per iteration of `loop while i +< N: i is i + 1` (callgrind on the existing main binary, `EIGS_JIT_OFF=1`, +1e5 against 2e5 iterations: 69,804,271 and 138,304,271). The SMI arm's +2 +on the float path is 0.3% of that. + +**What it does not decide.** Alt 1R against Alt 2. Their slot cost is +identical, and at the Value level the difference is one compare against two. +The choice rests on §2.3, not on speed. + +**A measured risk it exposes.** The same loop under the default JIT costs 402 +Ir per iteration (42,924,355 against 83,124,355; `[jit] compiled=1`). After +N1, `i` is an int, so the JIT's LT and ADD bail on the SMI every iteration +(§4). Expect at least the interpreter's 685 (+70%) on int loops until round +5's fast paths. + +The CodSpeed lane's two-sided Ir gate (#1220) will fire on its JIT-tier +targets with int loops: `scalar_loop`, `bench_perf`, `bench_dmg_shape`, +`bench_idxset` and the real DMG `cpu_instrs` row (codspeed.yml). The lane's +own measurement bounds the size: "JIT removes 48% of the instructions on +bench_dmg_shape, 11.8% on DMG itself" (codspeed.yml:65-67). Losing the JIT +on int code costs up to about 1.9x Ir there, and about 1.13x on DMG. That +must be accepted up front, not discovered. + +--- + +## 4. The JIT + +Round 1 needs correctness by bailing; fast paths are round 5. Every +consuming guard was read for how it treats a slot whose high 16 bits are +`0xFFFA` (SMI), and how it treats a heap slot whose `Value` is a boxed int. +Line numbers are jit.c at `0740af03`. + +### 4.1 Consuming guards: all bail on SMI + +| guard | the tag-range test | SMI (`0xFFFA`) | boxed int, Alt 1R (`VAL_INT`) | +|---|---|---|---| +| `emit_immediate_num_check_rax/rdx` (1625-1636) | `shr $48; cmp $0xFFF8; jae bail` | 0xFFFA >= 0xFFF8: **bail** | 0xFFFB >= 0xFFF8: **bail** | +| `emit_load_numeric_operand` (2343-2378) | `< 0xFFF8` is a double; `< 0xFFFB` bails (the comment reads "Tag 0xFFF8-0xFFFA (null/bool/SMI-reserved): not numeric"); `>= 0xFFFD` bails; else a heap Value must have `type == VAL_NUM && refcount >= 2` | **bail** | type is `VAL_INT`, not `VAL_NUM`: **bail** | +| `emit_jump_unless_bool_rax` (1911-1916) | `cmp $0xFFF9; jnz` | not a bool, falls to the num check: **bail** | not a bool: **bail** | +| `emit_dict_cache_probe` (2172-2185) | `cmp $0xFFFB; jne slow` | **slow path** (helper) | heap, then type `!= VAL_DICT`: **slow** | +| `OP_SET_LOCAL` in-place branch (3410-3475) | TOS `>= 0xFFF8` goes to the generic swap; the old slot must be a heap `VAL_NUM` with rc 1 | TOS SMI: **generic swap** (correct) | old slot `VAL_INT`: **generic swap** | +| `OP_INDEX_SET` inline (4067-4130) | index and value use `emit_immediate_num_check_*`; target `== 0xFFFB && type == VAL_BUFFER` | **helper** (C, the interpreter's semantics) | **helper** | +| `OP_LOCAL_DOT_GET` inline (3108-3170) | the field uses `emit_immediate_num_check_rax` | **helper** | **helper** | + +The refcount paths treat an SMI as an immediate, which is correct (it has no +refcount): +- `emit_conditional_incref_rax` (1279) and `emit_conditional_decref_rsi_hook` + (2028) test `cmp $0xFFFB; jb skip`, and 0xFFFA < 0xFFFB. +- The binop commit's OR-of-tags exit (2391, 2421) already lists "bool|smi + tags OR-ing up to 0xFFFB" as taking the per-slot path, which handles every + tag. + +The opcodes that consume through these guards are: +- ADD, SUB, MUL, DIV, MOD, EQ, NE, LT, GT, LE and GE through + `emit_load_numeric_operand`; +- BAND, BOR, BXOR, SHL, SHR, NEG, NOT, BNOT and JUMP_IF_* through + `emit_immediate_num_check_*`. + +ITER_NEXT, INDEX_GET and LOCAL_IDX_GET are C helper calls (`jit_helper_*` in +vm.c). They are migrated with the C code, and the inventory counts their +sites (for example `jit_helper_index_get` 17). + +**Finding: no consuming guard reads SMI tag bits as a double.** Under Alt 2 +three would misread a boxed int (§2.3). Under Alt 1R none does. + +### 4.2 Producer emitters: these do not bail, they must change + +The emitter writes bits directly, so a guard cannot protect these. A missed +one silently produces a float where the interpreter produces an int: + +| emitter | today | round 1 | +|---|---|---| +| `OP_NUM_ZERO`/`OP_NUM_ONE` (2797-2814) | pushes the double bits of 0.0 and 1.0 | The compiler (compiler.c:2071-2077) emits these for any literal `== 0.0` or `== 1.0`, so `0` and `0.0` share an opcode. Round 1 makes them mean int 0 and 1: the interpreter (vm.c:3257) and the emitter push SMI bits; `0.0` and `1.0` go through `OP_CONST`. | +| `OP_CONST` (2816-2838) | `VAL_NUM`: the bits of `num_`; else pushes a `TAG_HEAP` pointer plus an incref | An int constant would be pushed boxed, breaking the canonical form. Compute the bits with `slot_from_int` at compile time: SMI immediate, or `TAG_HEAP` for an int64 outside the SMI range. `last_imm` (4375) must then be 1 exactly when the pushed bits are immediate, never for a boxed int: the jit skill's lockstep rule. | +| BAND/BOR/BXOR/SHL/SHR (3716-3768), BNOT (3819-3830) | double operands, cvttsd2si, op, cvtsi2sd: a **double** result | N8 makes bitwise results ints. Round 1: **the scanner refuses these opcodes** (the op interprets) until round 5 emits SMI results. | +| MOD (3511-3585) | `call fmod`, which truncates toward zero | N4 makes `%` floor modulo (sign of the divisor), so fmod is wrong for mixed-sign floats (`-7.5 % 2` gives -1.5; Lua gives 0.5). Round 1: the scanner refuses MOD, or the emitter adds the floor correction. | + +### 4.3 For round 2 (N11/N12) + +The experiment already did each of these and the branch carries the code: +- `max_normal_bits` (2634) becomes inf's bits, so a NaN result bails; +- NEG gains a NaN bail, because a flipped canonical NaN spells + `SLOT_NULL_BITS`; +- comparisons gain a `jp` bail; +- CONST canonicalizes a NaN constant. + +### 4.4 For round 5 (recorded so it is not rediscovered) + +An int fast path must bail when its result leaves the SMI range. A boxed +result is a heap push, and `last_imm = 1` on ADD (4366) would then skip its +decref at the following POP: one leak per iteration (the #231 shape). +`jit_smoke` needs SMI rows for every guard above, each with a value that +differs only in the tag bits, so a guard that compared the wrong bits would +fail. The jit skill's wide-bit rule applies. + +--- + +## 5. N12 and SMI share the NaN space + +- **The canonical quiet NaN is `0x7FF8000000000000`**, with the sign bit + clear, as in #1746 and the `exp-ieee-p1` `SLOT_CANON_NAN`. +- **Every tag has the sign bit set** (high 16 bits `0xFFF8`-`0xFFFF`). The + SMI tag is `0xFFFA`. +- So canonical NaN (high 16 = `0x7FF8`) and every tag, SMI included, differ + in bit 63. **They cannot collide.** +- The patterns that *can* collide are NaNs with the sign set and the quiet + bit set (high 16 `0xFFF8`-`0xFFFF`). This includes x86's default NaN + `0xFFF8000000000000`, which **is** `SLOT_NULL_BITS`, and any NaN built + from bytes (`f64_from_bits of 0xFFFA000000000005` spells SMI 5). +- `slot_from_f64` is the single double-to-slot writer, and the JIT bails + before storing a NaN result, so no such pattern reaches a slot. Every NaN + is rewritten to `0x7FF8000000000000`. The other negative NaNs (high 16 + `0xFFF0`-`0xFFF7` with a nonzero mantissa: the signalling ones) do not + collide but are canonicalized too: one NaN. +- `-0.0` (`0x8000...`) and `-inf` (`0xFFF0000000000000`) are below `0xFFF8`, + so they are ordinary doubles. + +**`f64_bits of x`** returns the IEEE bits as an int, exact (int64 +reinterpretation, two's complement). Cases: +- for a float held in a slot, the stored bits; for NaN that is always + `0x7FF8000000000000` = 9221120237041090560, which is outside the SMI + range, so a boxed int; +- `f64_bits of -0.0` = INT64_MIN (boxed); +- `f64_bits of 1.0` = 4607182418800017408 (boxed). + +**`f64_from_bits of i`** builds the double from `i`'s 64 bits. If they spell +a NaN, the result enters a slot as the canonical NaN. Its payload is gone +from the float but still held by the int `i`. So `f64_bits of (f64_from_bits +of i) == i` for every `i` that is not a non-canonical NaN pattern, and +payload fidelity goes through ints (N12: "Ints are never NaN-canonicalized"). + +**Buffers** hold raw doubles and are not slots, so a buffer element may hold +any payload. Reading it as a float (`buf_get`) puts it in a slot, so it is +canonicalized. Reading it through the new bits accessor (N12: "Buffer +elements are also readable and writable as bits") returns the stored bits +exactly as an int. That is the path the bar critic found missing: payload +`0x7FF0...01` came back canonical through every route on the prototype. + +--- + +## 6. Builtin classification + +**Classes.** The reference for counterparts is Lua 5.4 (manual §6.7, +`math`; §3.4.1-3.4.3, operators and coercions; §6.4, `string`; §6.6, +`table`). + +- **int-preserving:** returns an exact int. + - Where the inputs are ints: `abs`, `min`, `max`, `sum`, `floor`, `ceil`, + `round`. These follow §6.7's "integer/float" annotation: "integer + results for integer arguments". `math.min`/`math.max` return the winning + argument. + - Where the result is a count, code or index by definition: `len`, + `range`, `ord`, `index_of`, handles. These follow Lua's `#` and + `string.byte`. + - Rounding (§6.7): "math.ceil, math.floor, and math.modf return an integer + when the result fits in the range of an integer, or a float otherwise". + `round` has no Lua counterpart and follows floor and ceil (§11, Q4). +- **float-producing:** ints convert to float and the result is a float. + Examples: Lua's `math.sin`, `sqrt`, `log`, `exp`; `/` and `^`, which + "always convert integer operands to floats" (§3.4.1); and the float-tensor + and audio-sample builtins (buffer storage is float). +- **int-requiring:** an argument is an index, count, size, code or bit + pattern, so it converts by N5's exact rule. Examples: Lua's string + positions, `table.insert`/`table.remove` positions, bitwise operands + (§3.4.2), `math.random(m, n)` bounds, and `math.randomseed`. +- **other:** everything else that takes or returns numbers: + - formatting (N6); + - JSON, store and db codecs (N13, N14); + - parsing (`num`, N10); + - `type` ((B)); + - byte consumers (truncate and wrap modulo 256, documented + eigenscript.h:1901); + - C-API arguments that truncate today: gfx coordinates, audio rates, + `usleep`. Their N5 scope is open: §11, Q1. + +**The `loss` column.** `LOSS` marks a builtin whose *current* body reads its +argument through a double accessor, or builds its result from a computed +double, on a path where its class needs an exact int. An int beyond 2^53 +would then come out silently wrong if the body were kept and its accessor +re-pointed to int-to-float conversion. Under Alt 1R the old accessors no +longer compile, so every row is revisited anyway; `LOSS` rows are where the +mechanical re-point would be wrong. Builtins that only call the shared +formatter or equality (`print`, `str`, `join`, `list_contains`) are `-`, +because their exactness change happens once, in `eigs_num_text` or +`values_equal_impl`. + +**Counts** (from the table below, checked by `tools/phase2_inventory.py`, +which prints them): 229 numeric builtins. By class: 37 int-preserving, 58 +float-producing, 67 int-requiring, 67 other. 39 are LOSS: +- arithmetic: `abs`, `add`, `subtract`, `multiply`, `negative`, `sum`, + `num_copy`; +- min/max and rounding: `min`, `max`, `floor`, `ceil`, `round`; +- bitwise: the six `bit_*`, `sign_extend`, `hex`; +- clock, RNG and seeds: `monotonic_ns`, `random_int`, `seed_random`, + `task_sched_seed`; +- shared counters: `shared_incr`; +- integer scanners: `scan_ints`, `scan_int_tokens`; +- ordering: `sort`, `sort_by`; +- store keys: `store_get`, `store_delete`, `store_update`, plus + `store_query` and `db_query_value`, which decode integer text with + `strtod`; +- JSON and parsing: `json_decode`, `json_path`, `num`, `json_encode`, + `json_build`. + +Probes on the main binary (0.46.0, built 2026-10-13; not the tag) show the +current state behind several rows: +- `str of 3.0` prints `3`. +- `json_encode of [3.0, 0.1]` gives `[3,0.1]`. +- `9007199254740993 == 9007199254740992` is `true`: the lexer rounds. +- `store_get of [s, "c", 1.9]` finds record `"1"` (a silent truncating key). +- `store_get of [s, "c", 4294967297]` returns `null`, because the `(int)` + cast is out of range (a pre-existing defect, reported for filing; out of + scope here). + + +| builtin | class | loss | note | +|---|---|---|---| +| `abs` | int-preserving | LOSS | Lua math.abs (integer/float); abs of INT64_MIN raises (N4b) | +| `acos` | float-producing | - | Lua math.acos | +| `add` | int-preserving | LOSS | scalar arm mirrors `+` (overflow raises, (A)); buffer arms stay float | +| `append` | other | - | appends any value; VAL_NUM appears only as a diagnostic default | +| `asin` | float-producing | - | Lua math.asin | +| `assert` | other | - | message via value_to_string (N6) | +| `atan` | float-producing | - | Lua math.atan | +| `atan2` | float-producing | - | Lua math.atan(y, x) | +| `audio_capture_open` | other | - | freq/channels truncated to C int (Q1); returns a device id | +| `audio_envelope` | float-producing | - | float samples; times in seconds | +| `audio_gain` | float-producing | - | float samples | +| `audio_mix` | float-producing | - | float samples | +| `audio_music_play` | other | - | loop count truncated to C int (Q1) | +| `audio_music_volume` | other | - | volume truncated to C int (Q1) | +| `audio_noise` | float-producing | - | float samples | +| `audio_open` | other | - | freq/channels truncated to C int (Q1); returns a device id | +| `audio_pause` | other | - | flag truncated to C int | +| `audio_play` | other | - | float samples in; returns a channel number | +| `audio_play_loop` | other | - | loop count truncated to C int (Q1); returns a channel | +| `audio_queue_size` | int-preserving | - | byte count (computed in a double, below 2^53) | +| `audio_saw` | float-producing | - | float samples | +| `audio_sine` | float-producing | - | float samples | +| `audio_square` | float-producing | - | float samples | +| `audio_stop` | int-requiring | - | channel number | +| `audio_stream_open` | other | - | freq/channels truncated to C int (Q1); returns a device id | +| `audio_stream_push` | other | - | float samples quantized to int16 | +| `audio_stream_queued` | int-preserving | - | sample count | +| `audio_sweep` | float-producing | - | float samples; wave selector truncated | +| `audio_volume` | other | - | channel index plus a float volume | +| `bit_and` | int-requiring | LOSS | Lua `&` (§3.4.2): N5 operands, int64-pattern result (N8); today a double result | +| `bit_not` | int-requiring | LOSS | Lua unary `~` | +| `bit_or` | int-requiring | LOSS | Lua `\|` | +| `bit_shl` | int-requiring | LOSS | Lua `<<`; today masks the count mod 64, N8 needs >=64 gives 0 and negative shifts right | +| `bit_shr` | int-requiring | LOSS | Lua `>>` is logical (N8); today an arithmetic shift with `& 63` | +| `bit_xor` | int-requiring | LOSS | Lua binary `~` | +| `buf_copy` | int-requiring | - | offsets and counts | +| `buf_deinterleave` | int-requiring | - | channel count and index | +| `buf_dot` | float-producing | - | buffer dot product | +| `buf_fill` | float-producing | - | fills float storage; offsets by N5 | +| `buf_from_list` | float-producing | - | buffer storage is float: an int element converts (Q2) | +| `buf_from_pcm16le` | float-producing | - | decodes bytes to floats | +| `buf_get` | int-requiring | - | index; returns the float element | +| `buf_len` | int-preserving | - | element count | +| `buf_mix` | float-producing | - | float storage | +| `buf_peak` | float-producing | - | float max abs | +| `buf_resample_linear` | float-producing | - | float storage | +| `buf_scale_range` | float-producing | - | float storage | +| `buf_set` | int-requiring | - | index; the value converts to float storage (Q2) | +| `buf_to_pcm16le` | other | - | quantizes floats to byte values | +| `buffer` | int-requiring | - | size or [rows, cols] | +| `build_corpus` | int-requiring | - | counts; returns counts | +| `ceil` | int-preserving | LOSS | Lua math.ceil: an int when the result fits int64, else a float | +| `channel` | int-preserving | - | handle dict with int id/gen fields | +| `channel_closed` | int-requiring | - | channel handle ids | +| `char_at` | int-requiring | - | string position (Lua string.sub) | +| `chr` | int-requiring | - | byte 1..255, already exactness-checked (Lua string.char) | +| `clock_unix` | float-producing | - | fractional seconds | +| `close_channel` | int-requiring | - | channel handle ids | +| `copy_into` | int-requiring | - | offset; values convert to float storage | +| `cos` | float-producing | - | Lua math.cos | +| `db_execute` | other | - | parameter encoding (ext_db) | +| `db_query_json` | other | - | row encoding (ext_db, N14) | +| `db_query_value` | other | LOSS | decodes a numeric column with strtod: integer text beyond 2^53 rounds | +| `dispatch` | int-requiring | - | integer table key, already exactness-checked | +| `divide` | float-producing | - | mirrors `/` (Lua §3.4.1: always float) | +| `dot` | float-producing | - | buffer dot product | +| `eigen_eval_loss` | float-producing | - | token ids are indices; the loss is a float | +| `eigen_generate` | other | - | token ids in and out are ints; temperature and top_p floats | +| `eigen_model_load` | other | - | parses model JSON numbers with strtod | +| `exec_capture` | other | - | float timeout in seconds; returns exit status ints | +| `exit` | int-requiring | - | exit code (today truncates) | +| `exp` | float-producing | - | Lua math.exp | +| `f64_from_bytes` | other | - | byte consumer (truncate and wrap) into a float; NaN canonical (N12) | +| `f64_to_bytes` | other | - | float to 8 byte ints; f64_bits (N12) is the int-valued sibling | +| `fill` | int-requiring | - | count | +| `floor` | int-preserving | LOSS | Lua math.floor: an int when the result fits int64, else a float | +| `gather` | int-requiring | - | index or index vector; returns elements unchanged | +| `get_at` | int-requiring | - | index, row and col; returns the element | +| `get_observer_thresholds` | float-producing | - | observer thresholds (O3 drops h_low) | +| `gfx_circle` | other | - | coordinates and colours truncated to C int (Q1) | +| `gfx_clear` | other | - | colours truncated to C int (Q1) | +| `gfx_clip` | other | - | rect truncated to C int (Q1) | +| `gfx_delay` | other | - | milliseconds truncated to Uint32 (Q1) | +| `gfx_fb` | other | - | dims and scale truncated to C int (Q1) | +| `gfx_line` | other | - | coordinates and colours truncated to C int (Q1) | +| `gfx_open` | other | - | width and height truncated to C int (Q1) | +| `gfx_point` | other | - | coordinates and colours truncated to C int (Q1) | +| `gfx_poll` | int-preserving | - | event fields x, y, scancode, button are ints | +| `gfx_read` | other | - | rect origin truncated; returns channel ints | +| `gfx_rect` | other | - | rect and colours truncated to C int (Q1) | +| `gfx_rrect` | other | - | truncated to C int (Q1) | +| `gfx_text` | other | - | position, colours and scale truncated to C int (Q1) | +| `gfx_text_height` | int-preserving | - | pixel height | +| `gfx_text_width` | int-preserving | - | pixel width | +| `gfx_ticks` | int-preserving | - | SDL ticks (Uint32 ms) | +| `hex` | int-requiring | LOSS | refuses above 2^53 by a double compare, so int 2^53+1 reads as 2^53 and passes silently | +| `http_early_bind` | int-requiring | - | port | +| `http_post` | other | - | header values via value_to_string (N6) | +| `http_route` | other | - | formats via value_to_string | +| `http_route_authed` | other | - | formats via value_to_string | +| `http_serve` | int-requiring | - | port | +| `http_static` | other | - | formats via value_to_string | +| `index_of` | int-preserving | - | byte index or -1 | +| `inflate` | other | - | byte consumer (truncate and wrap) | +| `join` | other | - | elements via value_to_string (N6) | +| `json_build` | other | LOSS | N14 encoder; reads values through eigs_num_arg (a double) | +| `json_decode` | other | LOSS | N14 decoder; integer text decodes through strtod (a double) | +| `json_encode` | other | LOSS | N13/N14 encoder; reads values through eigs_num_arg; its `default:` writes null (builtins.c:998) | +| `json_path` | other | LOSS | decodes with strtod, then formats (N14, N6) | +| `leaky_relu` | float-producing | - | ML activation (float tensors; no Lua counterpart) | +| `len` | int-preserving | - | count (Lua `#` is an integer) | +| `list_contains` | other | - | equality via values_equal (N2) | +| `list_index_of` | int-preserving | - | returns an index; equality via values_equal (N2) | +| `list_insert_at` | int-requiring | - | position (Lua table.insert) | +| `list_remove_at` | int-requiring | - | position (Lua table.remove) | +| `list_slice` | int-requiring | - | start and end indices | +| `list_truncate` | int-requiring | - | new length | +| `log` | float-producing | - | Lua math.log; log of 0 is -inf (N11) | +| `log_softmax` | float-producing | - | ML (float) | +| `matmul` | float-producing | - | float tensors | +| `matmul_at` | float-producing | - | float tensors | +| `matmul_bt` | float-producing | - | float tensors | +| `max` | int-preserving | LOSS | Lua math.max returns the winning argument with its own subtype | +| `mean` | float-producing | - | arithmetic mean | +| `min` | int-preserving | LOSS | Lua math.min | +| `model_load_weights` | other | - | alias of eigen_model_load | +| `monotonic_ms` | float-producing | - | fractional milliseconds | +| `monotonic_ns` | int-preserving | LOSS | exact below 2^53 ns (104 days of uptime), a rounded double after; an exact int under N1 | +| `multiply` | int-preserving | LOSS | scalar arm mirrors `*` (overflow raises, (A)); buffer arms float | +| `native_train_step_builtin` | other | - | token ids are ints; lr float (a numeric string is accepted through strtod) | +| `nearest_in_range` | float-producing | - | geometry floats; the `index` field is an int | +| `nearest_in_range_all` | float-producing | - | geometry floats; the `index` field is an int | +| `negative` | int-preserving | LOSS | mirrors unary `-`; negating INT64_MIN raises (N4b) | +| `net_accept` | int-requiring | - | socket handle | +| `net_close` | int-requiring | - | socket handle | +| `net_dial` | int-requiring | - | port; returns a handle | +| `net_listen` | int-requiring | - | port; returns a handle | +| `net_port` | int-requiring | - | socket handle; returns a port | +| `net_recv` | int-requiring | - | handle and max bytes | +| `net_send` | other | - | byte consumer (truncate and wrap) | +| `norm` | float-producing | - | L2 norm | +| `num` | other | LOSS | N10 parser: integer text decodes through strtod today (a double) | +| `num_copy` | int-preserving | LOSS | copies a number and must keep its subtype; today re-boxes through a double | +| `numerical_grad` | float-producing | - | finite differences | +| `numerical_grad_cols` | float-producing | - | finite differences; column indices int | +| `numerical_grad_rows` | float-producing | - | finite differences; row indices int | +| `observe` | other | - | observer readouts (O4) | +| `ord` | int-preserving | - | byte code (Lua string.byte) | +| `pi` | float-producing | - | Lua math.pi | +| `pow` | float-producing | - | mirrors `^` (Lua §3.4.1: exponentiation is always float) | +| `print` | other | - | N6 printing via value_to_string | +| `proc_read_buf` | int-requiring | - | fd and max bytes; bytes stored as floats | +| `random` | float-producing | - | Lua math.random() in [0,1) | +| `random_hex` | int-requiring | - | digit count | +| `random_int` | int-requiring | LOSS | Lua math.random(m, n) is an integer; bounds read as doubles today | +| `random_normal` | float-producing | - | dims int; samples float | +| `range` | int-preserving | - | bounds by N5; the elements are ints (floats today, inside int range) | +| `read_bytes` | int-preserving | - | byte values 0..255 | +| `read_bytes_buf` | int-requiring | - | cap and length; bytes stored as floats | +| `record_history` | other | - | truthiness flag in; previous flag out | +| `recv` | int-requiring | - | channel handle ids | +| `recv_timeout` | other | - | channel handle ids; float milliseconds | +| `relu` | float-producing | - | ML activation (float tensors; no Lua counterpart) | +| `reshape` | int-requiring | - | rows and cols | +| `round` | int-preserving | LOSS | no Lua counterpart; follows floor and ceil (Q4) | +| `sandbox_run` | int-requiring | - | iteration, byte and work limits; returns line ints | +| `scan_int_tokens` | int-preserving | LOSS | integers accumulate in a double | +| `scan_ints` | int-preserving | LOSS | integers accumulate in a double | +| `scatter_add` | float-producing | - | indices exactness-checked; float accumulation | +| `seed_random` | int-requiring | LOSS | `(long)` of a double; Lua randomseed takes integers | +| `send` | int-requiring | - | channel handle ids | +| `set_at` | int-requiring | - | index, row and col; a buffer value converts to float | +| `sgd_update` | float-producing | - | float update | +| `sgd_update_cols` | float-producing | - | column indices int | +| `sgd_update_rows` | float-producing | - | row indices int | +| `shape` | int-preserving | - | dimension counts | +| `shared_delete` | int-preserving | - | removed count | +| `shared_incr` | int-preserving | LOSS | shared counter: delta and stored value in doubles | +| `shared_size` | int-preserving | - | entry count | +| `sign_extend` | int-requiring | LOSS | `(int64_t)` of a double | +| `sin` | float-producing | - | Lua math.sin | +| `softmax` | float-producing | - | ML (float) | +| `sort` | other | LOSS | sort_cmp_num compares doubles: ints beyond 2^53 tie (N2 needs exact) | +| `sort_by` | other | LOSS | key results compared as doubles | +| `spawn` | int-preserving | - | handle dict with int id/gen fields | +| `sqrt` | float-producing | - | Lua math.sqrt; sqrt of -1 is NaN (N11) | +| `state_at` | int-requiring | - | step index | +| `store_close` | int-requiring | - | handle id/gen | +| `store_collections` | int-requiring | - | handle id | +| `store_count` | int-requiring | - | handle and page ids; returns a count | +| `store_delete` | int-requiring | LOSS | key formatted `%d` of an `(int)` cast: 1.9 finds "1"; keys above INT_MAX are UB (probed) | +| `store_drop` | int-requiring | - | handle and page ids | +| `store_get` | int-requiring | LOSS | same key cast as store_delete; decodes records (N14) | +| `store_open` | int-preserving | - | handle dict with int id/gen fields | +| `store_put` | other | - | N13/N14 encoder; refusal belongs inside the encoder | +| `store_query` | other | LOSS | decodes records; integer text through strtod (N14) | +| `store_update` | other | LOSS | same key cast as store_delete; N13/N14 encoder | +| `str` | other | - | N6 printing via value_to_string | +| `str_from_bytes` | other | - | byte consumer (truncate and wrap) | +| `stream_open` | int-requiring | - | element count, already floor-checked | +| `stream_write` | float-producing | - | writes a raw f64 | +| `substr` | int-requiring | - | start and length (Lua string.sub) | +| `subtract` | int-preserving | LOSS | scalar arm mirrors `-` (overflow raises, (A)) | +| `sum` | int-preserving | LOSS | an all-int input sums exactly, and overflow raises (A); today a guarded double sum | +| `tan` | float-producing | - | Lua math.tan | +| `task_alive` | int-requiring | - | task handle (packed below 2^53, exactness-checked) | +| `task_detach` | int-requiring | - | task handle | +| `task_join` | int-requiring | - | task handle | +| `task_kill` | int-requiring | - | task handle | +| `task_sched_seed` | int-requiring | LOSS | `(int64_t)` of a double | +| `task_self` | int-preserving | - | task handle | +| `task_send` | int-requiring | - | task handle | +| `task_sleep` | other | - | float milliseconds | +| `task_spawn` | int-preserving | - | returns a task handle | +| `tensor_load` | float-producing | - | float tensor; shape ints | +| `tensor_save` | float-producing | - | writes float cells | +| `text_builder_append` | other | - | formats via value_to_string (N6) | +| `text_builder_append_line` | other | - | formats via value_to_string (N6) | +| `thread_join` | int-requiring | - | thread handle id/gen | +| `throw` | other | - | message via value_to_string | +| `token_name` | int-requiring | - | token id | +| `try_recv` | int-requiring | - | channel handle ids | +| `type` | other | - | `type of` an int or a float is "num" ((B)) | +| `usleep` | other | - | microseconds truncated to C int (Q1) | +| `vm_run_bytecode` | int-requiring | - | opcode bytes and ABI numbers | +| `write` | other | - | N6 printing | +| `write_bytes` | other | - | byte consumer (truncate and wrap); returns bytes written | +| `zeros` | int-requiring | - | size or [rows, cols]; elements are float 0.0 | +| `zeros_like` | float-producing | - | float zeros | + + +**Builtins to add**, outside the checked table until they exist: +- `num_type` (N7); +- `f64_bits` and `f64_from_bits`, plus buffer bits get/set (N12); +- the N9 width family: wrapping, checked and saturating i8..i64 and u8..u64; + unsigned compare, div, rem and to-string; `fround`. + +--- + +## 7. Semantics-to-sites map + +Each item lists the files and functions that implement it. The site lists +inside each function are in `docs/design/phase2-inventory.txt`. All line +numbers are at `0740af03`. + +- **N1 (int literals; decimal outside int64 is a float; hex wraps):** + - lexer.c:717-753 (number lexing, hex accumulates in a double today); + the token's `num_val` (eigenscript.h:188); + - parser.c:791 (`TOK_NUM` to `AST_NUM`, `data.num`); + - compiler.c:2071-2077 (`AST_NUM` emission, `NUM_ZERO`/`NUM_ONE`, + `add_num_constant`) and compiler.c:2929/2985/3030 (index fast paths read + `data.num`); + - chunk.c:193-260 (constant pool dedup: `const_hash_value`, `const_equal`, + `chunk_add_constant_ex`, which must key on kind and bits); + - vm.c:3238 `CASE(CONST)` and 3257 `CASE(NUM_ZERO)`/`NUM_ONE`; + - jit.c:2797/2816 (producer emitters, §4.2); + - lint.c, lint_host.c and eigenlsp.c (the `AST_NUM` type knowledge, 34 + sites); + - `src/freestanding/mini_strtod.c`; + - ouroboros `src/frontend.eigs` (the AOT's lexer). +- **N2 (subtype visible; exact comparison across kinds):** + - vm.c:3579 `CASE(EQ)`, 3600 `CASE(NE)` and 3621 `NUM_CMP`; + - eigenscript.c:2849 `values_equal_impl`; + - builtins.c:5868 `sort_cmp_num`, and `sort_by`, `list_contains`, + `list_index_of`; + - JIT comparisons bail on SMI (§4.1). + - The exact int/float compare: + - if the float is NaN, the result is unordered (every comparison + false except `!=`); + - if `f >= 2^63`, the float is greater than every int; if `f < -2^63`, + it is smaller; + - otherwise compare `i` with `fl = (int64_t)floor(f)`: `i < fl` or + `i > fl` decides, and when `i == fl` the float is greater exactly when + `f != floor(f)`. + - Lua's `LTintfloat`/`EQintfloat` (lvm.c) reach the same answers by + converting whichever side converts exactly. +- **N3 (`+ - *` on ints give an int; overflow raises):** + - vm.c:3290 `ARITH_FAST`, 3324 `CASE(ADD)` and 3377 `NUM_BINOP` + (SUB, MUL); + - builtins_tensor.c `op_add`, `op_sub`, `op_mul` and + `tensor_elementwise` (the scalar arms of `add`, `subtract`, + `multiply`), plus `sum` and `shared_incr`; + - JIT bails (§4.1). +- **N4 (`/` float; `//` new; `%` floor; division by zero):** + - vm.c:3407 `CASE(DIV)` (int/int gives a float) and 3432 `CASE(MOD)` + (fmod becomes floor-mod; int by zero raises); + - **new `OP_IDIV`**, appended at the end of `OpCode` (vm.h). The + extend-vm checklist applies: dispatch table, handler, `op_name` + (chunk.c), `op_stack_effect` (compiler.c), an `/*obs:NONE*/` marker + (`tools/obs_marker_check.sh`) and `tests/test_opcode_abi.c`. Appending + needs no `EIGS_BYTECODE_ABI` bump. + - Lexer: `//` lexes as two `TOK_SLASH` today, so a new `TOK_SLASH_SLASH` + is appended to the token enum, the X2 table (lexer.c:241) and the token + text (lexer.c:357). + - parser.c (multiplicative level), fmt.c, lint, the LSP and ouroboros + `frontend.eigs`; + - JIT MOD (§4.2). + - Float `x % 0` (NaN) and `x / 0` (inf) wait for N11 in round 2. +- **N4b (INT64_MIN edges):** + - vm.c:3522 `CASE(NEG)` (int arm raises on INT64_MIN); + - builtins.c `builtin_abs` (2056); + - the new `OP_IDIV` (`x // -1`); + - `CASE(MOD)`: `INT64_MIN % -1` is 0, computed without `idiv`, which + faults on x86. +- **N5 (float-to-int by the exact rule wherever an int is needed):** + - eigenscript.h:1910 `num_to_i64_exact` (#1740); + - every int-requiring row of §6, through `eigs_int_arg`; + - vm.c index paths (`jit_helper_index_get`/`set`, `CASE(INDEX_*)`) and + `range_bound` (builtins.c:3877); + - the JIT `OP_INDEX_SET` integrality guard (jit.c:4100-4112) stays + correct, because a non-exact index goes to the helper. +- **N6 (printing):** + - eigenscript.c:2938 `eigs_num_text` (today integral doubles below 2^53 + print without `.0`) and 2957 `value_to_string`; + - the f-string conversion (`EIGS_FSTR_CONV_NAME`, builtins.c:6207); + - vm.c `obs_dump_num` (106); + - chunk.c `chunk_disassemble`; + - the JSON encoders (h); + - trace.c's `%.17g` writers (2817, 2836, 2950), whose tape text is §7 T1; + - `src/freestanding/mini_fmt.c`. + - Also chunk.c:196, the constant dedup folding `-0.0` into `+0.0`. Under + N6, `-0.0` prints `-0.0`, so the dedup must compare bits. +- **N7 (B: `type of` is `"num"`; `num_type`):** + - builtins.c:864 `builtin_type`, unchanged; + - `val_type_name(VAL_INT)` returns `"num"`; + - vm.c:5476 `who`, which answers "number"; + - new `num_type` (builtins.c, registration at 6184). +- **N8 (bitwise on ints, Lua shift rules):** + - vm.c:3459 `INT_BINOP_R` (`& 63` becomes Lua's rule; `>>` becomes + logical) and 3548 `CASE(BNOT)`; + - builtins.c:349-414 `bit_*`; + - JIT bitwise is refused (§4.2). +- **N9 (width builtins):** new code (builtins.c or a new `builtins_int.c`); + `fround` (`(double)(float)x`). +- **N10 (`num of`):** builtins.c:494 `builtin_num` (partial input #1638, + radix prefixes, int or float result). +- **N11 (IEEE doubles; strict becomes opt-in):** + - eigenscript.h:1876 `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` and + `STRICT_DOMAIN`: the 73 GUARD and clamp sites of (c); + - builtins_tensor.c `op_sqrt` (711) and `op_log_safe` (729); + - builtins.c `asin`/`acos` domain; + - state.c:62 `st->strict` defaults to 1 and must become opt-in; + - jit.c:2634 `max_normal_bits`. +- **N12 (canonical NaN; payload fidelity through ints):** + - value_slot.h:73 `slot_from_num`, becoming `slot_from_f64`: the single + writer; + - the JIT NaN bails (§4.3); + - new `f64_bits`/`f64_from_bits` and buffer bits accessors; + - builtins_buf.c `f64_from_bytes` and `f64_to_bytes`; + - eigs_embed.c:339 (the host boundary; #1746 round 3, item 4). +- **N13 (refusal inside writers):** + - builtins.c:907 `eigs_json_encode_value`; + - ext_store.c's encoder: the #1746 residue is `store_nonfinite_scalar` + (ext_store.c:278 on the experiment), which must be deleted in favour of + refusal inside the encoder; + - the byte encoders (`finite_num_to_byte`, eigenscript.h:1901) and the + `buf_to_pcm16le` quantizer; + - every int conversion (`eigs_int_arg`, `num_to_i64_exact` callers); + - the tape writers record, not refuse. +- **N14 (JSON):** + - builtins.c:907 encode and 1406 `builtin_json_decode`, plus + `eigs_json_parse_value`, `json_path` and `json_build`; + - the ext_store.c record codec; + - ext_http.c request/response JSON; + - model_io.c `json_*` (model files). +- **(A) (overflow raises, no wraparound):** the N3 and N4b sites; `sum`, + `shared_incr`, the `add`/`subtract`/`multiply` scalar arms; the N9 + builtins provide explicit wrapping. +- **(B):** as N7; `type of` and the 54 consumer `type of ... == "num"` lines + keep working. +- **T1 (tape v7):** + - trace.h:32 `TRACE_FORMAT_VERSION`, 6 becoming 7; + - trace.c:2817 `write_value_ptr`, 2836 `write_slot` and 2950 + `write_value_ptr_full`: ints as digits, floats in a form that always + shows the kind (N6 repr), `inf`/`-inf`/`nan` in round 2; + - trace.c:2284 `parse_value_p`: digits only give an int, anything else + goes through strtod as a float; + - trace.c:2194 and tape_read.c:155 (version refusal); + - tape_read.c:368 (the step reader's `strtod`); + - eigsdap.c; + - docs/TRACE.md (bump plus the compat decision, #411); + - the `O cfg` record (trace.c:1577-1584 writes `h_low`; tape_read.c:389 + reads it). O3 drops it in round 3. +- **O1-O4 (observer, round 3):** + - eigenscript.c:698 `observer_slot_record_value`, 804 + `observer_slot_update_num`, the `obs_num_*` predicates (935-1193) and + `compute_entropy_impl` (435), from which entropy is removed for numerics; + - vm.c `obs_slot_observable` (1630); + - the observe helpers `jit_helper_observe_assign_local` (1661) and + `jit_sample_num_gated`, which must route an SMI into the numeric channel + in round 1 already, converting to double for the distance (§2.5); + - vm.c:5460 `CASE(INTERROGATE)` (`where`/`why`/`how`); + - `builtin_observe`; + - the `O cfg` record; + - tools/observer_oracle/score.py (the IEEE mode and `--floor` from the + oracle PR). + +--- + +## 8. Round plan + +Every commit builds, passes the full suite, and carries its own MAP rows. +"Unchanged" means a differential against the baseline binary captured +before the commit (the verify-and-fix rule), not "the suite passed". + +### Round 1: the core model (Alt 1R) + +1. **R1.1, the slot layer becomes exhaustive (no producer yet).** + - Add `TAG_SMI`, `slot_is_smi`, `slot_from_int` and `slot_smi_val` in + value_slot.h. + - Every slot classifier in §2.5 gets an explicit SMI arm and aborts on an + unknown tag. + - `slot_as_ptr` asserts the heap tag in ASan and debug builds. + - Test: a C unit test (`tests/phase2/slot_layer.c`) builds SMI slots by + hand and drives every classifier. Before the commit it crashes or + misreads; after, it answers. Language behaviour is unchanged + (differential over the suite's `.eigs` corpus). + - Risk: a classifier the test does not enumerate. Its list is derived + from the inventory: every function holding both `slot_is_num` and + `slot_as_ptr`. +2. **R1.2, the Value layer and the renames (deprecate, then delete).** + - R1.2a: `VAL_INT` (appended), `make_int`, the §2.6 accessors and + `val_type_name(VAL_INT) = "num"`. **Delete the `default:` arm of + `eigs_json_encode_value` (builtins.c:998)**, enumerating the types, so + `-Werror=switch` reaches the last switch that could absorb `VAL_INT` + silently. The old names stay, marked + `__attribute__((deprecated))`; macros are routed through a deprecated + inline. + - R1.2b-n: one commit per file group (vm.c; builtins.c; tensor; buf; + host; gfx; net/http/db/model; store; trace; observer; embed; lint and + LSP). Each migrates its sites by the §6 table and lowers the + deprecation-warning count. `VAL_INT` exists and is handled, but nothing + produces it, so behaviour is unchanged (differential). + - R1.2z: delete the old names. A straggler fails to compile. + - Risk: the size (1,488 compile-forced sites); and a mis-migration that + picks `eigs_float_arg` for an int-preserving builtin, caught by the + int-fuzz gate (§9.4). +3. **R1.3, the flip: int literals and exact int arithmetic.** + - N1 (lexer, parser, AST kind, constant pool keyed by kind and bits, + `NUM_ZERO`/`NUM_ONE` mean int, the JIT `CONST`/`NUM_ZERO`/`NUM_ONE` + emit SMI bits). + - N3 with (A) overflow raise, N2 exact cross-kind comparison, N4b `-x`, + N7 `num_type`. + - The EQ/NE int fast path relies on canonical form, as #1758 says + equality does. Two SMIs compare by bits; an SMI against a boxed int is + unequal without loading the box (a boxed int is outside the SMI range). + This is what makes plant 1 visible from a program (§9.3). + - The JIT scanner refuses `BAND`/`BOR`/`BXOR`/`SHL`/`SHR`/`BNOT`/`MOD`. + - **The tape goes to v7 in this commit.** The moment ints exist, a v6 + writer would print `3` for both kinds and replay would turn ints into + floats. The float token marks its kind now (`3.0`); N6's full repr + replaces it in R1.7, still inside v7. + - The observer routes an SMI into the numeric channel (converted to + double). + - The visible change is small: ints print as today. The rest waits for + N4/N6. + - Risks: + - JIT int loops bail every iteration (§3: +70% Ir on a counter loop). + Declare the CodSpeed baseline move first. + - Consumer hashes that relied on double rounding now raise ((A)); they + move to the N9 wrapping builtins. +4. **R1.4, N4.** `//` (token, parser, `OP_IDIV` appended, + `op_name`/`op_stack_effect`/obs marker/ABI test), `%` floor modulo for + ints and floats, int division by zero raises, `INT64_MIN % -1` is 0. +5. **R1.5, N8.** Bitwise ops on ints with Lua's shift rules; `bit_*` + returns ints. +6. **R1.6, N5, N9, N10 and the §6 builtins.** Every int-preserving and + int-requiring row, the 39 LOSS rows first; `num of` (#1638); the N9 + width family. +7. **R1.7, N6 and N14's int half.** + - Python-repr floats; ints as exact digits. + - The constant dedup compares bits, so `-0.0` survives. + - JSON writes ints as digits and floats with `.0`; integer text within + int64 decodes as an int; `1e400` raises. + - `src/freestanding/mini_fmt.c` and `mini_strtod.c` follow, gated by + `make freestanding-libc-diff`. + - This is the largest visible change: every golden that prints an + integral float. +8. **R1.8, the embed API, lint/LSP type knowledge and docs** (SPEC, + COMPARISON, README, llms.txt executed fences). The CLAUDE.md same-PR + docs rule applies to the integration PR as a whole. + +### Round 2: IEEE (N11-N14 remainder), on the experiment's evidence + +1. **R2.1, canonical NaN at the single double writer** (`slot_from_f64`) + **and the JIT NaN bails** (§4.3), while `num_guard` still keeps NaN out: + memory safety first. + - Test: the C slot test writes every tag-spelling NaN payload. The + #1746 plant (a raw store) segfaults in `slot_incref`. +2. **R2.2, retire `num_guard`** (73 sites), `EIGS_NUM_MAX` and the 1e308 + clamp. `EIGS_STRICT` becomes an opt-in trap (state.c:62). + `sqrt of -1` is NaN, `log of 0` is -inf, `x/0` is ±inf, `0/0` and + float `x%0` are NaN. +3. **R2.3, N13 refusal inside the writers:** the JSON encoder, the store + encoder (delete the pre-walk `store_nonfinite_scalar`), the byte + encoders and the int conversion. This removes the class #1746 chased for + three rounds, rather than its instances. +4. **R2.4, N12.** `f64_bits`/`f64_from_bits`, buffer bits get/set, and a + canonical NaN at the embed boundary. +5. **R2.5, tape v7 `inf`/`-inf`/`nan` tokens; N6 non-finite printing; + N14 `1e400` raises.** +6. **R2.6, the #1746 residue:** + - the gfx/net/model `fix_trunc` sites; + - `net_send` continuing after a raise (ext_net.c:364); + - `buf_to_pcm16le` NaN; + - the `numerical_grad` waiver. + +### Risks across both rounds + +- The AOT is a round of its own (ouroboros, pinned to the integration SHA). + Its numeric model is C `double` throughout: 294 `double` in aot_rt.h and + 228 in compile.eigs, with `make_num` 40+27 and `num_guard` 61+27. Under + Alt 1R its generated C fails to compile against the renamed runtime, + which is loud. + - The AOT's existing int census (a `long` storage regime for counters) + must follow literal kinds, not inference. + - `fuzzdiff` must never apply `ULP_BOUND` to an int result (the + aot-differential skill: "Integer data compare exactly even inside a + reduction arm"). +- Consumers. N6 printing moves goldens in all 16; N4 changes `%` on + negatives; (A) raises where doubles lost precision silently. +- Observer. Until round 3, ints are observed as their double value (the + distance channel works on doubles), so `where`/`why`/`how` keep today's + meaning. + +--- + +## 9. Test plan + +### 9.1 `tests/phase2/MAP.md` + +The skeleton is committed with this round. Every item (N1-N14, N4b, (A), +(B), T1, O1-O4) has planned rows, each recording: +- an id; +- the program; +- the expected branch output; +- the round that lands it; +- why the row **fails on the v0.46.0 tag**. + +Behaviour the branch must *preserve* (`1 == 1.0` is true on both binaries) +cannot fail on the tag, so it is pinned two ways: +- inside a mapped row that also checks the kind (the row fails on the tag + because the kind is invisible there); +- as a separate **control** row, counted on its own line and never in + `tag_fail` (§121: each population pinned separately). + +### 9.2 `tools/phase2_check.sh ` (round 1 builds it) + +- **Rows** live in `tests/phase2/rows/.eigs`. Each has a header + `# ROW: `, `# ITEMS: N1 N2`, `# EXPECT-RC: `, `# TIER-WITNESS: + loop|none`, plus `.out` (the exact branch stdout). Controls live in + `tests/phase2/controls/`. +- **Population:** + - the row set is the directory listing (it cannot drift from a list); + - every row id appears in MAP.md and every MAP id has a file (both + directions); + - every item in the fixed list (N1-N14, N4b, A, B, T1, O1-O4, transcribed + from #1758 Revision 1) has at least one row; + - zero rows is a FAIL. +- **Tiers:** + - `off` = `EIGS_JIT_OFF=1`; + - `default`; + - `osr` = `EIGS_JIT_OSR_THRESHOLD=1`. + - Every run is bounded at 30 s, with `= 1 (`lar_jit_witness`'s rule): a JIT row that + compiled nothing measured the interpreter. +- **Verdicts per row and tier:** + - branch PASS = rc equals EXPECT-RC and stdout byte-equals `.out`; + - tag FAIL = not that; + - rc 124 is the named verdict `TIMEOUT` and rc >= 128 is `SIGNAL`. Both + are a FAIL on the branch; on the tag they count as `tag_fail` and are + also shown in their own counters. +- **Output, one line per tier:** `tier= examined=N rows tag_fail=N + branch_pass=N tag_timeout=K tag_signal=K`, then `controls=M both_pass=M` + and an environment banner (both binaries' `--version` and sha256). +- **Exit 0** iff in every tier examined == tag_fail == branch_pass > 0, the + controls all pass on both, and the population checks pass. +- **Calibration** (one-time, in the commit that adds it): + - tag passed as both binaries: `branch_pass=0`, exit 1; + - one `.out` corrupted: exit 1, naming the row; + - an empty rows directory: exit 1; + - a MAP id with no file, and a file with no MAP id: exit 1 each. + +### 9.3 `tools/phase2_plants.sh` (round 1 builds it; detached, about 7 release builds) + +Each plant: +1. `git archive HEAD` into a scratch dir (no `.git`); +2. applies one `sed`, asserting the original text occurs exactly once before + and the planted text after (a plant that did not apply is `BROKEN`); +3. builds the release with plain `make`, once at a time, `timeout 1500`; +4. runs **its named check** and requires the check's own FAIL line naming + the row (keyed on the gate's message, not on a nonzero exit, §179). + +Verdicts: `KILLED`, `SURVIVED`, or `BROKEN` (patch, build or timeout). +Output: `plants=7 killed=7 survived=0 broken=0`; exit 0 only for exactly +that. + +| # | plant | where | named check that must turn RED | +|---|---|---|---| +| 1 | an int that fits inline stored boxed | `slot_from_heap` skips the small-`VAL_INT` normalization | row `N1.canon-eq` (`abs of -5` round-trips through a Value; then `== 5` in the bit fast path) and `tests/phase2/slot_layer.c` (every int writer, every value in ±2^47, must carry tag 0xFFFA) | +| 2 | a NaN stored raw in a slot | `slot_from_f64` without the canonical branch | row `N12.nan-payload-tags` (`f64_from_bits` of every tag-spelling payload into a variable, list, dict and buffer; `type of` each is "num", under ASan in the plant build) | +| 3 | a writer accepting a non-finite value | the refusal inside `eigs_json_encode_value` deleted; separately inside the store encoder | rows `N13.json-refuses-inf` and `N13.store-refuses-nan` (raise `value`, and nothing written: the store row re-reads the record count) | +| 4 | `+` wrapping on overflow | the SMI+boxed add path uses wrapping `uint64` add | row `A.add-overflow-raises` (`9223372036854775807 + 1` raises `value` naming `+`) | +| 5 | `-INT64_MIN` wrapping | `CASE(NEG)`'s int arm without the INT64_MIN check | row `N4b.neg-min-raises` | +| 6 | `num_type of 3.0` returning "int" | `num_type` answers "int" for an integral float | row `N7.num-type-float` | +| 7 | a v6 tape accepted | the version check accepts 6 | row `T1.v6-refused` (the committed v6 fixture must exit nonzero naming version 6) | + +Each plant is transverse (§100): deleting its named check's assertion must +let the plant through. That is shown once per plant during calibration by +running the plant against a copy of the check with its assertion removed. + +### 9.4 The int-fuzz gate (round 1; the §6 table's enforcement) + +It follows `tests/test_bool_fuzz.sh` (which feeds bools to every builtin +`--api --json` lists): +- every numeric builtin of §6 is called with ints in each numeric slot; +- **int-preserving:** the result's `num_type` is "int" for int inputs; +- **int-requiring:** a float with a fraction raises `value` (N5), and an + integral float converts; +- **float-producing:** the result is a float; +- the population is derived from `--api --json` intersected with the table, + and the gate prints `examined=N` equal to the table's row count. + +It catches a mis-migrated accessor (R1.2) that compiles. + +--- + +## 10. The Lua differential tool (`tools/phase2_lua_diff.py`, round 1) + +**Oracle.** +`/home/jon/src/InauguralSystems/EigenScriptEcosystem/EigenLua/.ref/bin/lua` +(PUC-Rio 5.4.9, pristine). +- Checked at start with `EigenLua/tools/build_ref.sh --check-not-compat + `. The binary argument is required; the bare form fails with + `$2: unbound variable`. It exited 0 on this box. +- A failed check stops the run as an instrument failure (exit 2), never as + a verdict. + +**Cases.** Expressions over operands drawn from the edge set {0, ±1, ±2^31, +±(2^47 - 1), ±2^47 (the SMI boundary), ±2^53, ±(2^53 + 1), ±2^62, +INT64_MIN, INT64_MAX, 0.5, -0.0, 1e308, 2^63 as a float}. Operators: +- arithmetic `+ - * / // %`; +- unary `-`; +- bitwise `& | ~ << >>`; +- comparisons `== < <=`; +- `math.abs`, `math.floor`, `math.ceil`, `math.max`, `math.min` against + `abs`/`floor`/`ceil`/`max`/`min`; +- `math.type` against `num_type`. + +Translation: Lua binary `~` is EigenScript `^`, Lua `^` is `pow of`, and +Lua unary `~` is `~`. + +String operands are excluded: Lua coerces `"10" + 1` and EigenScript does +not. That divergence is documented and not exercised. + +**Comparison by value, never by text.** +- Each side prints its result in a canonical machine form. Lua uses + `math.type(x)` plus `string.format("%d" | "%a", x)`. EigenScript uses + `num_type` plus `str` for ints, and `f64_bits` once round 2 lands it; + until then, float text parsed to a double by Python, whose float parsing + is correctly rounded. +- Kind and value must match. +- A raise on both sides compares as `RAISE` (for example Lua `n//0` "attempt + to perform 'n//0'" against EigenScript `value`). + +**Deliberate divergences**, each a rule with its own counter, never a skip: + +| rule | Lua 5.4.9 (probed) | EigenScript | how the tool checks it | +|---|---|---|---| +| (A) | `math.maxinteger + 1` gives `-9223372036854775808` (wraps) | raises `value` naming the operator | the tool computes the exact result in Python (arbitrary precision); when Lua's int result differs from it, EigenScript must raise | +| N6 | prints `%.14g` (`0.3`, `1e+15`, `-nan`) | Python `repr` (`0.30000000000000004`, `1000000000000000.0`, `nan`) | values compared by bits; EigenScript's text is checked against Python `repr` separately (Python is the N6 oracle, not Lua) | +| (B) | `type(3)` is "number", `math.type(3)` is "integer", `math.type("3")` is nil | `type of 3` is "num", `num_type of 3` is "int", `num_type of "3"` is null | name mapping number to num, integer to int, nil to null | +| N4b | `-mininteger`, `math.abs(mininteger)` and `mininteger//-1` all give mininteger | each raises `value` | expected RAISE; `mininteger % -1` is 0 on both (no divergence) | + +**Output:** `examined=N agree=N rule_A=N rule_N6=N rule_B=N rule_N4b=N +disagree=0`. It exits 1 on any unexplained disagreement or on examined=0. + +**Calibration plants:** +- flip rule (A) to expect wrapping: red on the overflow cases; +- compare by text instead of value: red on the N6 cases; +- a fake `lua` that prints `float` for an int: red. + +--- + +## 11. Open questions this design does not decide + +These need an owner decision or the standard answer cited. Round 1 must not +pick them silently. + +- **Q1. N5's scope beyond index, count and bitwise.** gfx coordinates and + colours, audio rates, `usleep`/`gfx_delay` durations and C-API ints + truncate a float today. N5 lists "index, count, bitwise". Raising on + `gfx_rect of [10.5, ...]` would break every app that computes float + positions. Options: + - (a) keep truncation for C-API arguments, documented; + - (b) apply N5 everywhere. +- **Q2. An int stored into float storage** (`buf_set`, `buf_from_list`, + `copy_into`, `set_at` on a buffer, `stream_write`). Converting rounds + above 2^53. Options: + - (a) convert, as numpy float64 does; + - (b) refuse an inexact int, as N13 refuses non-finite values. +- **Q3. The embed accessors for an int.** Options for `eigs_value_as_num` + given an int: + - (a) convert, as Lua's `lua_tonumber` does, lossy above 2^53; + - (b) convert only when exact and leave an error pending otherwise. + - Either way: `eigs_value_new_int`, `eigs_value_as_int` and a kind query + are added; and `EIGS_TYPE_NUM` covers both kinds, or a new type value is + appended? +- **Q4. `round`.** It has no Lua counterpart. Proposed: follow floor and + ceil (an int when it fits), keeping C `round`'s half-away-from-zero. + Python's `round` uses banker's rounding and returns an int; JavaScript + rounds half up. +- **Q5. `why is x` for an int binding.** Δv is exact in int64 except at the + INT64_MIN↔INT64_MAX swing the oracle rows include (it overflows). Options: + - (a) always a float; + - (b) an int when it fits, else a float. + - (A) does not apply: a readout is not an operator. +- **Q6. `//=`** beside `/=` (the lexer's X2 table). N4 adds `//` and is + silent on the compound form. diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md new file mode 100644 index 000000000..e5377c9c2 --- /dev/null +++ b/tests/phase2/MAP.md @@ -0,0 +1,348 @@ +# tests/phase2/MAP.md: #1758 items to the test rows that pin them + +This is the skeleton, committed in round 0 with `docs/design/phase2-numbers.md`. +Round 1 writes each row as `tests/phase2/rows/.eigs` (or `.sh` for a +row that needs a shell: tape, env, files), with its exact expected stdout in +`.out`. + +`tools/phase2_check.sh ` (design: §9.2 of the +design doc) runs every row: +- against the **v0.46.0 tag** (`4a3a5c19`, built from the tag commit, not + main) and the branch; +- in three tiers: `EIGS_JIT_OFF=1`, the default JIT, and + `EIGS_JIT_OSR_THRESHOLD=1`. + +Every mapped row must FAIL on the tag and PASS on the branch in every tier. + +## Format (machine-read by `phase2_check.sh`) + +- `### ` opens an item. The items are fixed by #1758 Revision 1: `N1` + to `N14`, `N4b`, `A`, `B`, `T1`, `O1` to `O4`. Every item must have at + least one row. +- ``- `` [Rn] `` is one row. Below it, two more + lines: `-> `, and `tag: `. + A row whose program pins several items lists them in its file header + (`# ITEMS: O3 T1`); it appears here once, under its first item. + - The row id is the file stem. Every id must have a file, and every file + must be listed here. + - `[Rn]` is the commit of the round plan that makes the row pass on the + branch. +- In program sketches, ` / ` separates source lines and `{try X catch}` means: + ``` + try: + X + catch e: + print of [e.kind, ...] + ``` + The row file holds the exact program. +- `tag:` says why the row fails on v0.46.0: + - `(probed main)` is output observed on the main-checkout binary (0.46.0, + built 2026-10-13). Main differs from the tag only by #1740/#1741 + (bitwise and range conversion) and #1735. + - `(read)` is derived from the tag's source. +- **Controls** (`ctl.*`) must PASS on both binaries. They guard behaviour + the branch must preserve, and are counted separately: never in + `tag_fail`. +- **Gates** (`gate.*`) name a check the Done-when runs on its own (the + observer oracle with `--floor`). `phase2_check.sh` lists them and verifies + their command exists, but does not run or count them as rows. + +--- + +### N1 +- `N1.literal-kind` [R1.3] `print of [num_type of 3, num_type of 3.0, num_type of 1e3, num_type of 0x10]` + -> `["int", "float", "float", "int"]` + tag: `num_type` is undefined, an error (read) +- `N1.exact-past-2p53` [R1.3] `print of [9007199254740993, 9223372036854775807]` + -> `[9007199254740993, 9223372036854775807]` + tag: `[9007199254740992, 9.223372036854776e+18]` (probed main) +- `N1.decimal-past-int64-is-float` [R1.3] `x is 9223372036854775808 / print of [num_type of x, x]` + -> `["float", 9.223372036854776e+18]` + tag: `num_type` undefined (read) +- `N1.hex-wraps` [R1.3] `print of [0x1FFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF]` + -> `[-1, -1, 9223372036854775807]` + tag: `[3.6893488147419103e+19, 1.8446744073709552e+19, 9.223372036854776e+18]` (probed main) +- `N1.canon-eq` [R1.3] `a is abs of -5 / b is 0 - 5 / print of [a == 5, -b == 5, num_type of a]` + -> `[true, true, "int"]` + tag: `num_type` undefined. **Plant 1's named check**: with small ints boxed, the SMI/boxed-int equality fast path, which relies on canonical form, answers false. The direct witness is `tests/phase2/slot_layer.c`. + +### N2 +- `N2.int-eq-float-kinds` [R1.3] `print of [1 == 1.0, 1 != 1.0, num_type of 1, num_type of 1.0]` + -> `[true, false, "int", "float"]` + tag: `num_type` undefined (read) +- `N2.exact-eq-past-2p53` [R1.3] `print of [9007199254740993 == 9007199254740992.0, 9007199254740993 != 9007199254740992.0]` + -> `[false, true]` + tag: `[true, false]` (probed main: the lexer rounds) +- `N2.exact-order` [R1.3] `print of [9007199254740993 > 9007199254740992.0, 9223372036854775807 < 9223372036854775808.0]` + -> `[true, true]` + tag: `[false, false]` (probed main for the second) +- `N2.membership-exact` [R1.3] `print of [list_contains of [[9007199254740993], 9007199254740992.0], list_index_of of [[1, 9007199254740993], 9007199254740992.0]]` + -> `[false, -1]` + tag: `[true, 1]` (read: everything is a double) +- `N2.sort-exact` [R1.6] `print of (sort of [9007199254740993, 9007199254740992, -1])` + -> `[-1, 9007199254740992, 9007199254740993]` + tag: the literal rounds, so `[-1, 9007199254740992, 9007199254740992]` (probed main, same shape) +- `ctl.N2.float-eq` (control) `print of [0.5 + 0.25 == 0.75, 1 == 1.0, 3 < 3.5]` + -> `[true, true, true]`, both binaries + +### N3 +- `N3.int-ops-kind` [R1.3] `print of [num_type of (2 + 3), num_type of (7 - 9), num_type of (6 * 7), num_type of (2 + 0.5)]` + -> `["int", "int", "int", "float"]` + tag: `num_type` undefined +- `N3.exact-product` [R1.3] `print of [3037000499 * 3037000499, 4503599627370496 * 2 + 1]` + -> `[9223372030926249001, 9007199254740993]` + tag: `[9.223372030926249e+18, 9007199254740992]` (probed main) +- `ctl.N3.small-ints` (control) `print of [1 + 2, 10 - 3, 6 * 7, -4]` + -> `[3, 7, 42, -4]`, both binaries + +### A +- `A.add-overflow-raises` [R1.3] `{try print of (9223372036854775807 + 1) catch}`, printing `[e.kind, (index_of of [e.message, "+"]) >= 0]` + -> `["value", true]` + tag: prints a rounded double, no raise (read). **Plant 4's named check.** +- `A.sub-overflow-raises` [R1.3] `{try print of (-9223372036854775807 - 2) catch}`, the same print with `"-"` + -> `["value", true]` + tag: a double, no raise +- `A.mul-overflow-raises` [R1.3] `{try print of (4611686018427387904 * 2) catch}`, the same print with `"*"` + -> `["value", true]` + tag: `9.223372036854776e+18`, no raise +- `A.sum-overflow-raises` [R1.6] `{try print of (sum of [9223372036854775807, 1]) catch}` + -> `["value", true]`, the message naming `sum` + tag: a double sum, no raise +- `A.tensor-scalar-overflow-raises` [R1.6] `{try print of (multiply of [4611686018427387904, 2]) catch}` + -> `["value", true]` + tag: a double + +### B +- `B.type-of-both-num` [R1.3] `print of [type of 3, type of 3.0, (type of 3) == (type of 3.0), num_type of 3]` + -> `["num", "num", true, "int"]` + tag: `num_type` undefined +- `ctl.B.type-of` (control) `print of [type of 3, type of 3.0, type of -2]` + -> `["num", "num", "num"]`, both binaries + +### N4 +- `N4.div-always-float` [R1.7] `print of [7 / 2, 6 / 2, num_type of (6 / 2)]` + -> `[3.5, 3.0, "float"]` + tag: `[3.5, 3, ...]` then `num_type` undefined (probed main for `[3.5, 3]`) +- `N4.floordiv` [R1.4] `print of [7 // 2, -7 // 2, 7.5 // 2, num_type of (7 // 2), num_type of (7.5 // 2)]` + -> `[3, -4, 3.0, "int", "float"]` + tag: parse error, `unexpected '/'` (probed main) +- `N4.floor-mod` [R1.4] `print of [-7 % 3, 7 % -3, -7.5 % 2, 7 % 3]` + -> `[2, -2, 0.5, 1]` + tag: `[-1, 1, -1.5, 1]`, i.e. fmod (probed main) +- `N4.int-floordiv-zero-raises` [R1.4] `{try print of (7 // 0) catch}`, printing `e.kind` + -> `value` + tag: parse error +- `N4.float-div-zero-inf` [R2.2] `print of [1.0 / 0, -1.0 / 0, 1 / 0]` + -> `[inf, -inf, inf]` + tag: raises `division by zero` (read) +- `N4.float-zero-div-zero-nan` [R2.2] `x is 0.0 / 0 / print of [x == x, num_type of x]` + -> `[false, "float"]` + tag: raises +- `N4.float-mod-zero-nan` [R2.2] `x is 5.5 % 0 / print of (x == x)` + -> `false` + tag: raises `modulo by zero` +- `ctl.N4.int-mod-zero-raises` (control) `{try x is 7 % 0 catch}`, printing `e.kind` + -> `value`, both binaries (probed main) + +### N4b +- `N4b.neg-min-raises` [R1.3] `m is -9223372036854775807 - 1 / {try print of (-m) catch}` + -> `["value", true]`, the message naming the unary minus + tag: a double, no raise. **Plant 5's named check.** +- `N4b.abs-min-raises` [R1.6] `m is -9223372036854775807 - 1 / {try print of (abs of m) catch}` + -> `["value", true]` + tag: `9.223372036854776e+18`, no raise +- `N4b.floordiv-min-by-neg1-raises` [R1.4] `m is ... / {try print of (m // -1) catch}` + -> `["value", true]` + tag: parse error +- `N4b.min-mod-neg1-zero` [R1.4] `m is ... / print of [m % -1, num_type of (m % -1)]` + -> `[0, "int"]`, with no hardware fault (x86 `idiv` faults on `INT64_MIN % -1`) + tag: `num_type` undefined + +### N5 +- `N5.substr-fraction-raises` [R1.6] `{try print of (substr of ["hello", 1.5, 2]) catch}`, printing `e.kind` + -> `value` + tag: `el` (probed main: truncation) +- `N5.store-key-fraction-raises` [R1.6] `s is store_open of "/db" / k is store_put of [s, "c", {"v": 1}] / {try print of (store_get of [s, "c", 1.9]) catch}` + -> `value` + tag: returns record "1" (probed main) +- `N5.bitwise-fraction-raises` [R1.5] `{try print of (1.5 | 0) catch}`, printing `e.kind` + -> `value` + tag: `1` (the bar critic's probe of the tag; main already raises: #1740) +- `N5.integral-float-converts` [R1.5] `print of [6.0 | 1, num_type of (6.0 | 1), (list_slice of [[1, 2, 3], 1.0, 2.0])]` + -> `[7, "int", [2]]` + tag: `num_type` undefined +- `N5.range-fraction-raises` [R1.6] `{try print of (range of 2.5) catch}`, printing `e.kind` + -> `value` + tag: no raise (read: `range_bound` accepts any double inside the int range) + +### N6 +- `N6.float-repr` [R1.7] `print of [3.0, 1e3, -0.0, 0.1 + 0.2, 1e15, 1e16, 1e-05, 0.0001]` + -> `[3.0, 1000.0, -0.0, 0.30000000000000004, 1000000000000000.0, 1e+16, 1e-05, 0.0001]` + tag: `[3, 1000, 0, 0.30000000000000004, 1000000000000000, 1e+16, 1e-05, 0.0001]` (probed main for the first seven) +- `N6.int-exact-digits` [R1.7] `print of [9007199254740993, -9223372036854775807 - 1]` + -> `[9007199254740993, -9223372036854775808]` + tag: rounded doubles +- `N6.str-fstring` [R1.7] `x is 2.0 / print of [str of x, f"{x}", str of 2]` + -> `["2.0", "2.0", "2"]` + tag: `["2", "2", ...]` (probed main) +- `N6.neg-zero-literal-dedup` [R1.7] `a is 0.0 / b is -0.0 / print of [a, b]` + -> `[0.0, -0.0]` + tag: `[0, 0]`. (The constant pool dedup folds `-0.0` into `+0.0`, chunk.c:196; the row pins that a literal `-0.0` survives a chunk that also holds `0.0`.) +- `N6.nonfinite` [R2.5] `print of [1.0 / 0, -1.0 / 0, 0.0 / 0, -(0.0 / 0)]` + -> `[inf, -inf, nan, nan]` (never `-nan`) + tag: raises +- `ctl.N6.small-ints` (control) `print of [1, 2, 3, -4, 100000]` + -> `[1, 2, 3, -4, 100000]`, both binaries + +### N7 +- `N7.num-type-float` [R1.3] `print of [num_type of 3.0, num_type of -0.0, num_type of 1e300, num_type of 2.5]` + -> `["float", "float", "float", "float"]` + tag: `num_type` undefined. **Plant 6's named check.** +- `N7.num-type-int` [R1.3] `print of [num_type of 0, num_type of -1, num_type of 9223372036854775807, num_type of (2 * 3)]` + -> `["int", "int", "int", "int"]` + tag: undefined +- `N7.num-type-non-number` [R1.3] `print of [num_type of "3", num_type of null, num_type of true, num_type of [1]]` + -> `[null, null, null, null]` (Lua `math.type` returns fail) + tag: undefined + +### N8 +- `N8.bitwise-results-int` [R1.5] `print of [6 & 3, 6 | 3, 6 ^ 3, ~0, num_type of (6 & 3)]` + -> `[2, 7, 5, -1, "int"]` + tag: `num_type` undefined +- `N8.lua-shifts` [R1.5] `print of [1 << 64, 1 << 63, 1 << -1, -1 >> 1, 8 >> -1]` + -> `[0, -9223372036854775808, 0, 9223372036854775807, 16]` + tag: not this (probed main: `1 << 64` is `1`, `1 << 63` a negative double, `-1 >> 1` is `-1`) +- `N8.bit-builtins-int64` [R1.5] `print of [bit_or of [4611686018427387904, 1], bit_shl of [1, 64]]` + -> `[4611686018427387905, 0]` + tag: `4.611686018427388e+18`, ... + +### N9 +The builtin names are decided in round 1 (`` etc. below are placeholders the row files replace). +- `N9.wrapping` [R1.6] `print of [ of [9223372036854775807, 1], of [255, 1]]` + -> `[-9223372036854775808, 0]` + tag: undefined +- `N9.checked-raises` [R1.6] `{try print of ( of [200, 100]) catch}` + -> `["value", ...]` + tag: undefined +- `N9.saturating` [R1.6] `print of [ of [-100, 100], of [-1, 1]]` + -> `[-128, -1]`. A u64 is carried in an int64 bit pattern, so u64 max is `-1`. + tag: undefined +- `N9.unsigned-ops` [R1.6] `print of [ of [-1, 1], of [-1], of [-1, 2]]` + -> `[1, "18446744073709551615", 9223372036854775807]` + tag: undefined +- `N9.fround` [R1.6] `print of (fround of 0.1)` + -> `0.10000000149011612` + tag: undefined + +### N10 +- `N10.partial-refused` [R1.6] `{try print of (num of "12abc") catch}`, printing `e.kind` + -> `value` + tag: `12` (probed main) +- `N10.radix` [R1.6] `print of [num of "0x1F", num of "0b101", num of "0o17"]` + -> `[31, 5, 15]` (the prefix set is decided in round 1; `0x` is certain) + tag: `[31, 0, ...]` (probed main for the first two) +- `N10.int-or-float` [R1.6] `print of [num_type of (num of "3"), num_type of (num of "3.0"), num_type of (num of "9223372036854775808"), num of "9007199254740993"]` + -> `["int", "float", "float", 9007199254740993]` + tag: `num_type` undefined + +### N11 +- `N11.sqrt-neg-nan` [R2.2] `x is sqrt of -1 / print of [x == x, num_type of x]` + -> `[false, "float"]` + tag: raises `sqrt: argument out of domain` (probed main) +- `N11.log-zero` [R2.2] `print of (log of 0)` + -> `-inf` + tag: raises `log: argument out of domain` (probed main) +- `N11.no-clamp` [R2.2] `print of [1e308 * 10, 1e308 * 10 == 1e308]` + -> `[inf, false]` + tag: `1e+308` then `true` (probed main for the first) +- `N11.strict-opt-in` [R2.2] (sh row, `EIGS_STRICT=1`) `{try print of (1e308 * 10) catch}` + -> `value`. Default strict off: the same program prints `inf`. + tag: `1e+308` under either setting (read: the clamp, not a raise) +- `N11.constant-1e308-converges` [R2.2] the #1746 row: a binding assigned the literal `1e308` 12 times; `print of (converged of x)` + -> `true` + tag: `false`, because saturation reads as diverging (#861; probed on the #1746 baseline) + +### N12 +- `N12.f64-bits` [R2.4] `print of [f64_bits of 1.0, f64_bits of -0.0, f64_from_bits of 4607182418800017408]` + -> `[4607182418800017408, -9223372036854775808, 1.0]` + tag: undefined +- `N12.nan-canonical-bits` [R2.4] `print of (f64_bits of (0.0 / 0))` + -> `9221120237041090560` (`0x7FF8000000000000`) + tag: raises +- `N12.nan-payload-tags` [R2.1/R2.4] for every tag-spelling payload `p` in `0xFFF8000000000000, 0xFFF9000000000001, 0xFFFA000000000005, 0xFFFB000000001000, 0xFFFF000000000000`, `x is f64_from_bits of p`, stored in a variable, a list, a dict and a buffer; print `[type of x, x == x, f64_bits of x]` for each + -> `["num", false, 9221120237041090560]` five times + tag: undefined. **Plant 2's named check**, run under the plant build with ASan. +- `N12.payload-through-ints` [R2.4] `i is 9218868437227405313 / print of [f64_bits of (f64_from_bits of i), of ( of [buffer of 1, 0, i])]` + -> `[9221120237041090560, 9218868437227405313]`. Ints and buffer bits keep the payload; a float does not. + tag: undefined + +### N13 +- `N13.json-refuses-inf` [R2.3] `x is 1e308 * 10 / {try print of (json_encode of [x]) catch}`, printing `e.kind` + -> `value` + tag: `1e+308`, the clamp (read; a one-element literal list passes its element, #405). **Plant 3's named check.** +- `N13.store-refuses-nan` [R2.3] `x is (1e308 * 10) - (1e308 * 10) / s is store_open of "/db" / {try k is store_put of [s, "c", {"v": x}] catch} / print of (store_count of [s, "c"])` + -> `value` then `0` (refused, and nothing written) + tag: no raise, so the count is `1` (read: `1e308 - 1e308` is `0`). **Plant 3's second named check.** +- `N13.int-conversion-refuses` [R2.3] `x is 1e308 * 10 / {try print of (substr of ["abc", x, 1]) catch}` + -> `value` + tag: no raise (read: `(int)` of a clamped 1e308) + +### N14 +- `N14.encode-kinds` [R1.7] `print of (json_encode of [3, 3.0, 0.1, -0.0])` + -> `[3,3.0,0.1,-0.0]` + tag: `[3,3,0.1,0]` (probed main for the first three) +- `N14.decode-kinds` [R1.7] `v is json_decode of "[3, 3.0, 9223372036854775807, 18446744073709551615]" / print of [num_type of v[0], num_type of v[1], v[2], num_type of v[3]]` + -> `["int", "float", 9223372036854775807, "float"]` + tag: `num_type` undefined +- `N14.decode-overflow-raises` [R2.5] `{try print of (json_decode of "1e400") catch}` + -> `value` + tag: `1e+308` (read: strtod gives inf, then the clamp) + +### T1 +- `T1.v7-header` [R1.3] (sh row) `EIGS_TRACE=t.tape eigenscript p.eigs; head -1 t.tape | cut -d' ' -f1-2` + -> `V 7` + tag: `V 6` +- `T1.int-float-on-tape` [R1.3] (sh row) record `x is 3 / y is 3.0 / print of [x, y]`; grep the tape's A records for `x=3` and `y=3.0`; replay with `EIGS_REPLAY_STRICT=1`; the output is byte-identical + -> `A x=3`, `A y=3.0`, `replay identical` + tag: `A y=3` (read: `%.17g`) +- `T1.int-replay-kind` [R1.3] (sh row) record `r is random_int of [1, 6] / print of [r, num_type of r]`, then replay + -> the same line twice, kind `"int"` on replay + tag: `num_type` undefined +- `T1.v6-refused` [R1.3] (sh row) `EIGS_REPLAY=tests/phase2/fixtures/v6.tape eigenscript p.eigs`; print the rc and whether stderr names version 6 + -> `rc!=0 names-6` + tag: rc 0 (the fixture is its own version). **Plant 7's named check.** +- `T1.nonfinite-on-tape` [R2.5] (sh row) record inf, -inf and nan values; the tape holds the tokens `inf`, `-inf`, `nan`; strict replay is byte-identical + -> as stated + tag: the program raises + +The `O cfg` record's v7 shape is pinned by `O3.ocfg-no-hlow` (its file lists +`# ITEMS: O3 T1`). + +### O1 +- `gate.O1.oracle-floor` [R3] for each oracle int row (a counter, doubling to 2^62, an INT64_MIN to INT64_MAX swing), in all three tiers: `make observer-oracle` with `--floor floor.json` exits 0 + -> exit 0 + tag: n/a. This is the oracle gate of #1758 Done-when "Observer", so it is a gate, not a row. +- `O1.where-is-value` [R3] `x is 2.5 / print of (where is x)` + -> `2.5` + tag: `0.7219...`, an entropy (probed main: `where is x` after 1 and 4 gives `0.7219280948873623`) + +### O2 +- `gate.O2.predicate-floors` [R3] the post-#1754 corpus with per-predicate TP/TN floors (`floor.json`, the corpus sha256 recorded) + -> at or above every floor + tag: n/a (the floors are measured on the tag), so it is a gate +- `O2.noise-not-oscillating` [R3] a seeded iid noise sequence (±1 around 100, 60 steps, an LCG in the program); `print of (oscillating of x)` + -> `false`, per #1754's definition (Hardy §62; iid noise is the in-control baseline, not an oscillation) + tag: `true` (#1746 prior-art report, probe P3: 99.3% of steps read `oscillating`) + +### O3 +- `O3.ocfg-no-hlow` [R3] (sh row) record any observed program; print the field count of the `O cfg` record + -> one fewer field than v6: no `h_low` + tag: has `h_low` (trace.c:1580-1584 writes it) + +### O4 +- `O4.why-is-displacement` [R3] `x is 1 / x is 4 / print of (why is x)` + -> `3`, or `3.0` (the int-or-float question is design §11 Q5) + tag: `-0.2780719051126377`, a dH (probed main) +- `O4.how-is-settledness` [R3] a binding held constant for one window; `print of (how is x)` + -> the R3 settledness value at full rest (to be fixed by the R3 design) + tag: an entropy-derived value diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py new file mode 100755 index 000000000..17087a655 --- /dev/null +++ b/tools/phase2_inventory.py @@ -0,0 +1,687 @@ +#!/usr/bin/env python3 +"""phase2_inventory.py -- #1758 round 0: every numeric site in src/*.c and +src/*.h, classified into exactly one category. + +POPULATION. A site is one occurrence, outside comments and string/char +literals, of a token in VOCAB: the value model's numeric vocabulary (the +number type tag, the slot predicates, the raw and checked payload accessors, +the constructors, the clamp, the formatter, the double parsers, and the AST +literal fields). The key is the TOKEN, so the blind spot is code that handles +a number without naming one of them. Two derived checks bound that blind spot: + - every function in src/ that returns or writes out a `double` AND reads a + payload (a raw or checked read appears in its body) is a numeric accessor; + it must be in VOCAB (its call sites are then sites) or in WRAPPERS with a + reason. A new accessor nobody reviewed is UNCLASSIFIED. + - every VAL_NUM must sit in a syntactic position the classifier recognizes + (test, case, tag store, type yield, emitter immediate); any other position + is UNCLASSIFIED. +Not in the population: src/freestanding/ (outside the src/*.c glob), and code +that computes on a double already extracted by a counted read. + +CATEGORIES (first matching rule wins; ROLE rules by file/function come first, +then the token's own kind): + a type tests b payload reads c producers + d JIT emitters/guards e number formatting + f equality, ordering and hashing g tape encode/decode + h JSON, store and db encoders i observer numeric paths + j embed API + +BUILTINS. The registration table (env_set_local_owned(env, "name", +make_builtin(fn)) lines and the ext_names.h X-lists) is the builtin +population (calibrated once against `eigenscript --api --json`: 311 = 311). +A builtin is numeric if its function, or a same-file function it calls or +names as a value (a comparator, an op table entry; closure depth 4), contains +a site, or if it calls the shared formatter or equality (SEMANTIC_LEAVES). +Every numeric builtin must have exactly one row in the classification table +of docs/design/phase2-numbers.md (class and loss columns from closed token +sets), every row must name a numeric builtin, and a LOSS row must have a +double path in its closure. + +Usage: tools/phase2_inventory.py [--src DIR] [--doc FILE] [--out FILE] + [--no-write] [--sites] +Prints `examined=N classified=N unclassified=0` and the builtin line; exits 1 +if any site or builtin is unclassified, a table row is stale, a rule or +token never fires, or nothing was examined. +""" +import argparse +import glob +import os +import re +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# ---- vocabulary: token -> kind ------------------------------------------- +# Kinds decide the default category (a/b/c/e) when no role rule matches. +VOCAB = { + # (a) type tests and type derivations + 'VAL_NUM': 'TAG', # position decides: TEST/CASE/TAGSET/YIELD/EMIT + 'slot_is_num': 'TEST', + 'slot_is_numeric': 'TEST', + 'NUM_REUSE': 'TEST', + 'AST_NUM': 'TAG', + # (b) payload reads + 'VAL_NUM_RAW': 'RAW', # an lvalue: `VAL_NUM_RAW(v) = x` is a WRITE + 'SLOT_NUM_RAW': 'RAW', + 'VAL_NUM_OFFSET': 'RAW', + 'slot_as_double': 'READ', + 'eigs_num_arg': 'READ', + 'eigs_num_arg_slow': 'READ', + 'eigs_list_num': 'READ', + 'eigs_opt_num': 'READ', + 'eigs_elem_num': 'READ', + 'eigs_slot_num': 'READ', + 'eigs_slot_elem_num': 'READ', + 'eigs_slot_opt_num': 'READ', + 'list_get_num': 'READ', + 'dict_value_get_num': 'READ', + 'buffer_read_num': 'READ', + 'num_to_i64_exact': 'READ', + 'finite_num_to_byte': 'READ', + 'buf_num_arg': 'READ', # builtins_buf.c wrapper of eigs_list_num + 'eigs_value_as_num': 'READ', # embed API accessor + 'num_val': 'RAW', # lexer token payload (double) + # (c) producers + 'make_num': 'PRODUCE', + 'make_num_permanent': 'PRODUCE', + 'slot_from_num': 'PRODUCE', + 'list_set_num': 'PRODUCE', + 'list_append_num': 'PRODUCE', + 'dict_value_set_num': 'PRODUCE', + 'list_rewrite_num': 'PRODUCE', + 'dict_value_rewrite_num': 'PRODUCE', + 'num_guard': 'GUARD', + 'num_guard_named': 'GUARD', + 'EIGS_NUM_MAX': 'GUARD', + 'strtod': 'PARSE', + 'atof': 'PARSE', + # (e) formatting + 'eigs_num_text': 'FORMAT', +} +# JIT-only vocabulary (jit.c, jit.h, jit_smoke.c): the emitted guards test +# raw tag bits and never name a VOCAB token, so a token scan alone sees almost +# none of them. These are the tag-range immediates and the emitters that +# assume an operand or result is a double. Category (d). +JIT_FILES = re.compile(r'^(jit\.c|jit\.h|jit_smoke\.c)$') +JIT_TOKEN_RE = re.compile( + r'\b(0x[Ff]{3}[89A-Fa-f](?:0{12})?(?:ULL|ull)?|max_normal_bits|' + r'emit_immediate_num_check_r[a-z]{2}|emit_load_numeric_operand|emit_overflow_check_rax|' + r'emit_(?:add|sub|mul|div)sd_xmm0_xmm1|emit_ucomisd_\w+|emit_cvttsd2si_\w+|' + r'emit_cvtsi2sd_\w+|emit_btr_63_\w+|fmod)\b') + +# `data.num` is the AST literal's double (`data.num_` is the Value member, +# reached only through VAL_NUM_RAW); matched as a member access, below. +AST_NUM_FIELD = re.compile(r'(?:->|\.)data\.num\b(?!_)') + +KIND_CATEGORY = { + 'TEST': 'a', 'CASE': 'a', 'YIELD': 'a', 'DATA': 'a', + 'READ': 'b', 'RAW': 'b', + 'TAGSET': 'c', 'WRITE': 'c', 'PRODUCE': 'c', 'GUARD': 'c', 'PARSE': 'c', + 'EMIT': 'd', + 'FORMAT': 'e', +} + +CATEGORY_NAMES = { + 'a': 'type tests', + 'b': 'payload reads', + 'c': 'producers', + 'd': 'JIT emitters and guards', + 'e': 'number formatting', + 'f': 'equality, ordering and hashing', + 'g': 'tape encode and decode', + 'h': 'JSON, store and db encoders', + 'i': 'observer numeric paths', + 'j': 'embed API', +} + +# Functions that return/write a double from a payload read, reviewed: their +# call sites are NOT sites, because the read inside them already is one and +# changes with them. (Derived check: a new such function must be added to +# VOCAB or here, with a reason.) +WRAPPERS = { + 'compute_entropy_impl': 'observer: returns an entropy, not the number; its payload read is the site', + 'ent_child_slot': 'observer: returns a child entropy, not the number; its payload read is the site', + 'observer_entropy_now': 'observer: writes an entropy, not the number; its payload read is the site', + 'numerical_loss': 'tensor: reads the loss callback result once; that read is the site', + 'tensor_flatten_recursive': 'tensor: bulk element flattener into a double array; the per-element read is the site', + 'tensor_to_flat': 'tensor: bulk element flattener into a double array; the per-element read is the site', +} + +# ---- role rules: (category, file regex, scope regex), first match wins ---- +# A scope is the enclosing function, `#define NAME`, ``, or for +# the two dispatchers `vm_run_ex/CASE(X)` and `jit_compile_to_thunk/OP_X`. +ROLE_RULES = [ + ('d', r'^(jit\.c|jit\.h|jit_smoke\.c)$', r'.*'), + ('j', r'^(eigs_embed\.[ch]|embed_smoke\.c|embed_concurrent\.c|embed_roads\.c)$', r'.*'), + ('g', r'^(trace\.[ch]|tape_read\.[ch]|eigsdap\.c|step\.c)$', r'.*'), + ('h', r'^(ext_store\.c|ext_store_internal\.h|ext_db\.c|ext_db_internal\.h)$', r'.*'), + ('h', r'.*', r'(^|_)json(_|$)|^eigs_json|^builtin_json'), + ('i', r'.*', r'observer|^obs_|_obs_|^ent_|entropy|^jit_sample_num|' + r'^builtin_(observe|classify|report|get_observer_thresholds|record_history|state_at)$|' + r'CASE\((OBSERVE|PREDICATE|REPORT|INTERROGATE|LOOP_STALL)'), + ('f', r'.*', r'^(values_equal_impl|values_equal|values_equal_op|const_equal|const_hash_value|' + r'cmp_[a-z_]*|[a-z_]*_cmp|builtin_(list_contains|list_index_of|sort|sort_by|secure_equals))$|' + r'CASE\((EQ|NE)\)|^#define NUM_CMP$'), + ('e', r'.*', r'^(eigs_num_text|value_to_string|chunk_disassemble|slot_type_name|' + r'builtin_(str|print|write|hex))$'), +] + +TOKEN_RE = re.compile(r'\b(' + '|'.join(sorted(VOCAB, key=len, reverse=True)) + r')\b') +C_KEYWORDS = {'if', 'while', 'for', 'switch', 'return', 'sizeof', 'do', 'else', + 'case', 'defined', '__attribute__', '__typeof__', '_Generic'} + + +def strip_c(text, keep_strings=False): + """Blank comments and (unless keep_strings) string/char literals, keeping + every newline (so line numbers survive) and every other column.""" + out = [] + i, n = 0, len(text) + state = 'code' + while i < n: + c = text[i] + nxt = text[i + 1] if i + 1 < n else '' + if state == 'code': + if c == '/' and nxt == '/': + state = 'line'; out.append(' '); i += 2; continue + if c == '/' and nxt == '*': + state = 'block'; out.append(' '); i += 2; continue + if c == '"': + state = 'str'; out.append('"'); i += 1; continue + if c == "'": + state = 'chr'; out.append("'"); i += 1; continue + out.append(c); i += 1; continue + if state == 'line': + if c == '\n': + state = 'code'; out.append('\n') + else: + out.append('\\' if c == '\\' and nxt == '\n' else ' ') + i += 1; continue + if state == 'block': + if c == '*' and nxt == '/': + state = 'code'; out.append(' '); i += 2; continue + # keep a line-continuation backslash: a comment inside a + # multi-line #define must not end the macro early + out.append(c if c in '\n\\' and (c == '\n' or nxt == '\n') else ' '); i += 1; continue + # string or char literal + quote = '"' if state == 'str' else "'" + if c == '\\' and i + 1 < n: + if keep_strings or text[i + 1] == '\n': + out.append(text[i:i + 2]) + else: + out.append(' ') + i += 2; continue + if c == quote: + state = 'code'; out.append(quote); i += 1; continue + out.append(c if keep_strings or c == '\n' else ' '); i += 1 + return ''.join(out) + + +def scopes_for(stripped, fname, sigs=None): + """Return a list: scope name per line (1-based index; [0] unused). + `sigs`, if given, collects each function's signature text.""" + lines = stripped.split('\n') + scope = [''] * (len(lines) + 1) + depth = 0 + sig = '' # text since the last top-level ; or } (signature) + cur = '' + sub = None # dispatcher sub-scope (CASE(X) / OP_X) + in_macro = None + for ln, line in enumerate(lines, 1): + # #define bodies (with continuations) are their own scope + if in_macro is not None: + scope[ln] = in_macro + if not line.rstrip().endswith('\\'): + in_macro = None + continue + m = re.match(r'\s*#\s*define\s+([A-Za-z_]\w*)', line) + if m: + scope[ln] = '#define ' + m.group(1) + if line.rstrip().endswith('\\'): + in_macro = '#define ' + m.group(1) + continue + if re.match(r'\s*#', line): + scope[ln] = cur if depth > 0 else '' + continue + if depth > 0 and cur == 'vm_run_ex': + mc = re.match(r'\s*CASE\((\w+)\)', line) + if mc: + sub = 'CASE(%s)' % mc.group(1) + if depth > 0 and cur == 'jit_compile_to_thunk': + mo = re.search(r'\b(?:if|else if)\s*\(\s*op\s*==\s*(OP_\w+)', line) + if mo and depth <= 3: + sub = mo.group(1) + line_scope = cur if depth > 0 else '' + if depth > 0 and sub and cur in ('vm_run_ex', 'jit_compile_to_thunk'): + line_scope = cur + '/' + sub + for ch in line: + if ch == '{': + if depth == 0: + cur = function_name(sig) + if sigs is not None and not cur.startswith('<'): + sigs.setdefault(cur, sig) + sub = None + line_scope = cur + depth += 1 + elif ch == '}': + depth -= 1 + if depth == 0: + sig = '' + cur = '' + sub = None + elif ch == ';' and depth == 0: + sig = '' + elif depth == 0: + sig += ch + if depth == 0 and line.strip() and not line.strip().startswith('}'): + sig += '\n' + scope[ln] = line_scope + return scope + + +def function_name(sig): + """The identifier before the last top-level parenthesized group of a + definition's signature; '' for struct/enum/array bodies.""" + s = re.sub(r'__attribute__\s*\(\(.*?\)\)', ' ', sig, flags=re.S) + if '(' not in s or '=' in s.split('(')[0]: + return '' + # find the last balanced (...) group at nesting level 0 + depth, last_open = 0, -1 + for idx, ch in enumerate(s): + if ch == '(': + if depth == 0: + last_open = idx + depth += 1 + elif ch == ')': + depth -= 1 + if last_open < 0: + return '' + head = s[:last_open] + ids = re.findall(r'[A-Za-z_]\w*', head) + ids = [i for i in ids if i not in C_KEYWORDS] + return ids[-1] if ids else '' + + +def val_num_kind(line, start, end, token): + """Syntactic role of a VAL_NUM / AST_NUM occurrence.""" + before = line[:start].rstrip() + after = line[end:].lstrip() + if re.search(r'(==|!=)\s*$', before) or re.match(r'(==|!=)', after): + return 'TEST' + if re.search(r'\bcase\s*$', before): + return 'CASE' + if re.search(r'(?])=\s*$', before): + return 'TAGSET' + if re.search(r'\breturn\s*$', before) or re.search(r'[?:]\s*$', before): + return 'YIELD' + if re.search(r'\(\s*uint32_t\s*\)\s*$', before): + return 'EMIT' # JIT immediate operand of a type compare + if (re.search(r'[({,]\s*$', before) or not before) and re.match(r'[)},]', after): + return 'DATA' # the tag as data: enumerator, kind table, argument + return 'UNKNOWN' + + +def raw_kind(line, end): + """VAL_NUM_RAW(...)/SLOT_NUM_RAW(...) followed by a plain `=` is a write.""" + depth, i = 0, end + while i < len(line): + ch = line[i] + if ch == '(': + depth += 1 + elif ch == ')': + depth -= 1 + if depth == 0: + rest = line[i + 1:].lstrip() + if re.match(r'=(?!=)', rest): + return 'WRITE' + return 'RAW' + elif depth == 0 and not ch.isspace(): + return 'RAW' + i += 1 + return 'RAW' + + +def scan_file(path, rel): + with open(path, encoding='utf-8', errors='replace') as f: + text = f.read() + stripped = strip_c(text) + sigs = {} + scope = scopes_for(stripped, rel, sigs) + sites = [] + for ln, line in enumerate(stripped.split('\n'), 1): + for m in TOKEN_RE.finditer(line): + tok = m.group(1) + kind = VOCAB[tok] + if kind == 'TAG': + kind = val_num_kind(line, m.start(), m.end(), tok) + elif tok in ('VAL_NUM_RAW', 'SLOT_NUM_RAW'): + kind = raw_kind(line, m.end()) + sites.append((rel, ln, scope[ln], tok, kind)) + if JIT_FILES.match(rel): + for m in JIT_TOKEN_RE.finditer(line): + tok = m.group(1) + tok = 'TAG-IMM ' + tok[:6] if tok.lower().startswith('0xfff') else tok + sites.append((rel, ln, scope[ln], tok, 'EMIT')) + for m in AST_NUM_FIELD.finditer(line): + rest = line[m.end():].lstrip() + kind = 'WRITE' if re.match(r'=(?!=)', rest) else 'RAW' + sites.append((rel, ln, scope[ln], 'data.num', kind)) + return sites, stripped, scope, sigs + + +def classify(site): + rel, ln, scope, tok, kind = site + if kind == 'UNKNOWN': + return None, None + base = scope.split('/')[-1] if '/' in scope else scope + for idx, (cat, frx, srx) in enumerate(ROLE_RULES): + if re.search(frx, rel) and (re.search(srx, scope) or re.search(srx, base)): + return cat, idx + return KIND_CATEGORY[kind], None + + +# ---- derived accessor check ---------------------------------------------- +READ_IN_BODY = re.compile(r'\b(VAL_NUM_RAW|SLOT_NUM_RAW|eigs_num_arg|eigs_list_num|' + r'eigs_slot_num|list_get_num|dict_value_get_num|slot_as_double)\b') + + +def derived_accessors(stripped_by_file, scope_by_file, sigs_by_file): + """Functions whose signature returns `double` (or has a `double *` out + parameter) and whose body performs a payload read.""" + found = {} + for rel, stripped in stripped_by_file.items(): + sigs = sigs_by_file[rel] + lines = stripped.split('\n') + scope = scope_by_file[rel] + bodies = {} + for ln, line in enumerate(lines, 1): + s = scope[ln] + if s.startswith('<') or s.startswith('#define') or '/' in s: + continue + bodies.setdefault(s, []).append(line) + for fn, blines in bodies.items(): + body = '\n'.join(blines) + if not READ_IN_BODY.search(body): + continue + sigtext = sigs.get(fn) + if not sigtext or fn not in sigtext: + continue + cut = sigtext.rindex(fn) + ret, params = sigtext[:cut], sigtext[cut + len(fn):] + if re.search(r'\bdouble\b', ret) or re.search(r'\bdouble\s*\*', params): + found.setdefault(fn, rel) + return found + + +# ---- builtins ------------------------------------------------------------ +REG_DIRECT = re.compile(r'env_set_local_owned\(\s*\w+\s*,\s*"([A-Za-z_]\w*)"\s*,\s*' + r'make_builtin\(\s*(\w+)\s*\)\s*\)') +REG_XLIST = re.compile(r'\bX\(\s*([A-Za-z_]\w*)\s*,\s*(\w+)\s*\)') + + +def registered_builtins(src): + regs = {} + for path in sorted(glob.glob(os.path.join(src, '*.c'))): + with open(path, encoding='utf-8', errors='replace') as f: + text = strip_c(f.read(), keep_strings=True) + for m in REG_DIRECT.finditer(text): + regs.setdefault(m.group(1), m.group(2)) + names_h = os.path.join(src, 'ext_names.h') + if os.path.exists(names_h): + with open(names_h, encoding='utf-8', errors='replace') as f: + text = strip_c(f.read()) + for m in REG_XLIST.finditer(text): + if m.group(1) != 'name': + regs.setdefault(m.group(1), m.group(2)) + return regs + + +def function_bodies(stripped_by_file, scope_by_file): + """fn -> (file, body text), for every top-level function definition.""" + out = {} + for rel, stripped in stripped_by_file.items(): + lines = stripped.split('\n') + scope = scope_by_file[rel] + for ln, line in enumerate(lines, 1): + s = scope[ln].split('/')[0] + if s.startswith('<') or s.startswith('#define'): + continue + f_rel, buf = out.setdefault(s, (rel, [])) + if f_rel == rel: + buf.append(line) + return {k: (v[0], '\n'.join(v[1])) for k, v in out.items()} + + +# Cross-file functions whose numeric semantics a builtin inherits by calling +# them: number text (N6) and equality (N2). Followed from any file. +SEMANTIC_LEAVES = {'value_to_string': 'eigs_num_text', 'eigs_num_text': 'eigs_num_text', + 'values_equal': 'values_equal', 'values_equal_op': 'values_equal'} + + +def numeric_builtins(regs, sites, bodies): + sites_by_fn = {} + for (rel, ln, scope, tok, kind) in sites: + fn = scope.split('/')[0] + sites_by_fn.setdefault(fn, []).append(tok) + # a callee is any same-file function the body names: a call, or a + # reference passed as a value (a comparator or an op table entry) + ident = re.compile(r'\b([A-Za-z_]\w*)\b') + result = {} + for name, fn in regs.items(): + seen, frontier, toks = {fn}, [fn], [] + depth = 0 + while frontier and depth <= 4: + nxt = [] + for f in frontier: + toks.extend(sites_by_fn.get(f, [])) + if f not in bodies: + continue + f_rel, body = bodies[f] + for callee in ident.findall(body): + if callee in SEMANTIC_LEAVES: + toks.append(SEMANTIC_LEAVES[callee]) + if callee in seen or callee not in bodies: + continue + if bodies[callee][0] != f_rel and not callee.startswith('builtin_'): + continue # same-file helpers only (closure) + seen.add(callee) + nxt.append(callee) + frontier = nxt + depth += 1 + if toks: + result[name] = (fn, sorted(set(toks))) + return result + + +TABLE_ROW = re.compile(r'^\|\s*`([A-Za-z_]\w*)`\s*\|\s*([a-z-]+)\s*\|\s*(\S+)\s*\|') +CLASSES = {'int-preserving', 'float-producing', 'int-requiring', 'other'} +LOSS_MARKS = {'LOSS', '-'} +# A LOSS row claims the body computes through a double; it must have one. +DOUBLE_PATH = {'eigs_num_arg', 'eigs_list_num', 'eigs_slot_num', 'eigs_opt_num', 'eigs_slot_opt_num', + 'eigs_slot_elem_num', 'eigs_elem_num', 'buffer_read_num', 'make_num', 'slot_as_double', + 'VAL_NUM_RAW', 'SLOT_NUM_RAW', 'strtod', 'atof', 'num_guard', 'list_set_num'} + + +def read_table(doc): + rows, bad = {}, [] + if not os.path.exists(doc): + return None, ['classification table %s missing' % doc] + with open(doc, encoding='utf-8') as f: + in_table = False + for ln, line in enumerate(f, 1): + if line.startswith(''): + in_table = True; continue + if line.startswith(''): + in_table = False; continue + if not in_table: + continue + m = TABLE_ROW.match(line) + if not m: + # inside the markers only the header and separator may fail + # to parse; anything else is refused, never skipped + if line.strip() and not re.match(r'^\|\s*(builtin|-+)\s*\|', line.strip()): + bad.append('%s:%d: unparsed table line: %s' % (doc, ln, line.strip()[:60])) + continue + name, cls, loss = m.group(1), m.group(2), m.group(3) + if cls not in CLASSES: + bad.append('%s:%d: `%s` has unknown class %r' % (doc, ln, name, cls)) + if loss not in LOSS_MARKS: + bad.append('%s:%d: `%s` has unknown loss mark %r' % (doc, ln, name, loss)) + if name in rows: + bad.append('%s:%d: `%s` has two rows' % (doc, ln, name)) + rows[name] = (cls, loss) + return rows, bad + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument('--src', default=os.path.join(ROOT, 'src')) + ap.add_argument('--doc', default=os.path.join(ROOT, 'docs/design/phase2-numbers.md')) + ap.add_argument('--out', default=os.path.join(ROOT, 'docs/design/phase2-inventory.txt')) + ap.add_argument('--no-write', action='store_true') + ap.add_argument('--sites', action='store_true', help='print every site') + args = ap.parse_args() + + files = sorted(glob.glob(os.path.join(args.src, '*.c')) + glob.glob(os.path.join(args.src, '*.h'))) + sites, stripped_by_file, scope_by_file, sigs_by_file = [], {}, {}, {} + for path in files: + rel = os.path.basename(path) + s, stripped, scope, sigs = scan_file(path, rel) + sites.extend(s) + stripped_by_file[rel] = stripped + scope_by_file[rel] = scope + sigs_by_file[rel] = sigs + + examined = len(sites) + classified, unclassified = [], [] + rule_hits = [0] * len(ROLE_RULES) + token_hits = {t: 0 for t in VOCAB} + for site in sites: + cat, rule = classify(site) + if site[3] in token_hits: + token_hits[site[3]] += 1 + if cat is None: + unclassified.append((site, 'VAL_NUM/AST_NUM in an unrecognized position')) + continue + if rule is not None: + rule_hits[rule] += 1 + classified.append((site, cat)) + + # derived: numeric accessors must be reviewed + acc = derived_accessors(stripped_by_file, scope_by_file, sigs_by_file) + unreviewed = sorted(fn for fn in acc if fn not in VOCAB and fn not in WRAPPERS) + for fn in unreviewed: + unclassified.append(((acc[fn], 0, fn, fn, 'ACCESSOR'), + 'reads a payload and returns/writes a double; not in VOCAB or WRAPPERS')) + stale_wrappers = sorted(w for w in WRAPPERS if w not in acc) + dead_tokens = sorted(t for t, c in token_hits.items() if c == 0) + dead_rules = [i for i, c in enumerate(rule_hits) if c == 0] + + # builtins + regs = registered_builtins(args.src) + bodies = function_bodies(stripped_by_file, scope_by_file) + nb = numeric_builtins(regs, sites, bodies) + table, table_bad = read_table(args.doc) + b_unclassified = sorted(n for n in nb if table is None or n not in table) + b_stale = sorted(n for n in (table or {}) if n not in nb) + loss_rows = sorted(n for n, (c, l) in (table or {}).items() if l == 'LOSS') + for n in loss_rows: + if n in nb and not (set(nb[n][1]) & DOUBLE_PATH): + table_bad.append('`%s` is marked LOSS but its closure has no double-path token' % n) + class_count = {} + for n, (c, l) in (table or {}).items(): + class_count[c] = class_count.get(c, 0) + 1 + + # ---- report ---- + cats = 'abcdefghij' + per_cat = {c: 0 for c in cats} + per_file = {} + per_cat_file = {} + per_kind = {} + for (rel, ln, scope, tok, kind), cat in classified: + per_cat[cat] += 1 + per_file[rel] = per_file.get(rel, 0) + 1 + per_cat_file.setdefault(cat, {}).setdefault(rel, 0) + per_cat_file[cat][rel] += 1 + per_kind.setdefault(cat, {}).setdefault(kind, 0) + per_kind[cat][kind] += 1 + + out = [] + out.append('# docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit.') + out.append('# Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped.') + out.append('examined=%d classified=%d unclassified=%d' % (examined + len(unreviewed), + len(classified), len(unclassified))) + out.append('files=%d tokens=%d role_rules=%d derived_accessors=%d wrappers=%d' % ( + len(files), len(VOCAB), len(ROLE_RULES), len(acc), len(WRAPPERS))) + out.append('') + out.append('## Per category') + for c in cats: + kinds = ' '.join('%s=%d' % (k, v) for k, v in sorted(per_kind.get(c, {}).items())) + out.append('(%s) %-34s %5d %s' % (c, CATEGORY_NAMES[c], per_cat[c], kinds)) + out.append('') + out.append('## Per token') + for t in sorted(token_hits, key=lambda t: (-token_hits[t], t)): + out.append('%-24s %5d' % (t, token_hits[t])) + out.append('%-24s %5d' % ('data.num (AST)', sum(1 for s in sites if s[3] == 'data.num'))) + out.append('') + out.append('## Per file (category counts)') + for rel in sorted(per_file, key=lambda r: (-per_file[r], r)): + parts = ' '.join('%s=%d' % (c, per_cat_file.get(c, {}).get(rel, 0)) for c in cats + if per_cat_file.get(c, {}).get(rel, 0)) + out.append('%-24s %5d %s' % (rel, per_file[rel], parts)) + out.append('') + out.append('## Builtins') + out.append('registered=%d numeric=%d classified=%d unclassified=%d stale=%d' % ( + len(regs), len(nb), len(nb) - len(b_unclassified), len(b_unclassified), len(b_stale))) + out.append('classes: ' + ' '.join('%s=%d' % (c, class_count.get(c, 0)) for c in sorted(CLASSES))) + out.append('LOSS (%d): %s' % (len(loss_rows), ' '.join(loss_rows))) + for name in sorted(nb): + fn, toks = nb[name] + cls, loss = (table or {}).get(name, ('-', '-')) + out.append('%-28s %-34s %-16s %-5s %s' % (name, fn, cls, loss, ','.join(toks))) + out.append('') + out.append('## Sites (file:line scope token kind category)') + for (rel, ln, scope, tok, kind), cat in sorted(classified, key=lambda x: (x[0][0], x[0][1], x[0][3])): + out.append('%s:%d %s %s %s %s' % (rel, ln, scope, tok, kind, cat)) + text = '\n'.join(out) + '\n' + + if not args.no_write: + os.makedirs(os.path.dirname(args.out), exist_ok=True) + with open(args.out, 'w', encoding='utf-8') as f: + f.write(text) + + # stdout: the summary (not the site list unless --sites) + summary_end = text.index('## Builtins') + sys.stdout.write(text[:summary_end]) + if args.sites: + sys.stdout.write(text[summary_end:]) + fail = [] + for (site, why) in unclassified: + rel, ln, scope, tok, kind = site + print('UNCLASSIFIED: %s:%d %s %s (%s)' % (rel, ln, scope, tok, why)) + for w in stale_wrappers: + fail.append('stale WRAPPERS row: %s is no longer a payload-reading double accessor' % w) + for t in dead_tokens: + fail.append('VOCAB token never occurs: %s' % t) + for i in dead_rules: + fail.append('role rule %d (%s %s) matched no site' % (i, ROLE_RULES[i][0], ROLE_RULES[i][2][:40])) + for b in table_bad: + fail.append(b) + for n in b_unclassified: + fail.append('numeric builtin `%s` (%s) has no classification row' % (n, nb[n][0])) + for n in b_stale: + fail.append('classification row `%s` names no numeric registered builtin' % n) + for f_ in fail: + print('FAIL: ' + f_) + print('builtins: registered=%d numeric=%d classified=%d unclassified=%d stale=%d' % ( + len(regs), len(nb), len(nb) - len(b_unclassified), len(b_unclassified), len(b_stale))) + print('examined=%d classified=%d unclassified=%d' % (examined + len(unreviewed), + len(classified), len(unclassified))) + if examined <= 0 or not regs or unclassified or fail: + print('phase2-inventory: FAIL') + return 1 + print('phase2-inventory: PASS') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) From 102e66341be5d6e4420fb8ecd862341d743a5db4 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 12:23:42 -0500 Subject: [PATCH 002/188] phase2 design r2: leaf evaluator, token-forced meaning changes, measured compile count (#1758) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design round 2 of #1758, after the blind critic's FAIL on round 0. Still no src/ change. - The third numeric evaluator, vm_leaf_accessor_exec (vm.c:1856; scanner chunk.c:1072, #366), is in the inventory (dispatcher arms, an executor matrix that requires the leaf scanner and evaluator to admit the same opcodes), in design §4.5 and §7 with every arm, and gets a gate: a `trace` tier in phase2_check.sh (EIGS_TRACE switches the leaf off) that is the leaf-on/leaf-off differential over every row. - Every meaning change coincides with a token change (§2.7): int literals get new appended opcodes (OP_INT_ZERO/ONE/CONST); OP_NUM_ZERO/ONE keep their float meaning in all three executors; slot_as_double is deleted in R1.1; buffer_read_byte and finite_num_to_byte are deleted with Q1. - The compile count is re-measured with clang's `unavailable` attribute in a scratch copy under server-db, release and freestanding: 1,416 of 1,798 sites stop compiling, 44 sit inside deleted definitions, and each of the 338 others is classified with its reason. - Slot classifiers are derived (D1 forced; 43 D2/D3 entries each carry a reviewed disposition the inventory checks both ways), and raw union-member reads are vocabulary, so the critic's e_blind_member plant now fails the run. Inventory plants A-R all turn red. - The canonical form is corrected: the lifts box on purpose, so equality compares by value whenever a box is involved; plant 1's check is the C slot test. - The builtin table follows the decided Q1 (16 rows move to int-requiring, ppu_render_frame added) and gains the #1762 LOSS rows (store_put, db_execute, db_query_json); §11 records Q1-Q6 as decided, and parks Q7 (out-of-range continuous parameters) and Q8 (NaN order). - tests/phase2/MAP.md gains 35 shaped rows (leaf, function JIT, OSR) with tier witnesses read from EIGS_JIT_HOT/STATS/STOPS, covering all 20 numeric JIT and leaf arms, and the record-twice tape rows. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 298 +++++++- docs/design/phase2-numbers.md | 1192 ++++++++++++++++++++++++------ tests/phase2/MAP.md | 212 +++++- tools/phase2_inventory.py | 244 +++++- 4 files changed, 1644 insertions(+), 302 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 1526cda9e..962e42147 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,11 +1,11 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1773 classified=1773 unclassified=0 -files=64 tokens=39 role_rules=8 derived_accessors=17 wrappers=6 +examined=1798 classified=1798 unclassified=0 +files=64 tokens=40 role_rules=8 derived_accessors=17 wrappers=6 ## Per category (a) type tests 384 CASE=52 DATA=3 TEST=327 YIELD=2 -(b) payload reads 505 RAW=113 READ=392 +(b) payload reads 530 RAW=116 READ=414 (c) producers 472 GUARD=71 PARSE=3 PRODUCE=373 TAGSET=3 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 14 CASE=1 FORMAT=3 PARSE=1 RAW=2 READ=3 TEST=4 @@ -29,6 +29,7 @@ eigs_slot_num 52 eigs_value_as_num 48 slot_from_num 41 buffer_read_num 38 +buffer_read_byte 22 list_set_num 22 slot_as_double 16 strtod 16 @@ -50,7 +51,9 @@ list_rewrite_num 3 eigs_elem_num 2 list_append_num 2 make_num_permanent 2 +num_ 2 atof 1 +d_ 1 dict_value_get_num 1 dict_value_set_num 1 list_get_num 1 @@ -60,7 +63,7 @@ data.num (AST) 7 ## Per file (category counts) builtins.c 319 a=74 b=94 c=111 e=6 f=8 h=15 i=11 vm.c 304 a=78 b=105 c=72 f=6 i=43 -ext_gfx.c 229 a=56 b=103 c=70 +ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 184 a=39 b=59 c=86 builtins_buf.c 97 a=21 b=37 c=39 jit.c 96 d=96 @@ -69,8 +72,8 @@ container.h 72 a=23 b=24 c=25 embed_smoke.c 50 j=50 ext_store.c 50 h=50 builtins_host.c 47 a=11 b=24 c=12 +eigenscript.h 33 a=3 b=18 c=11 e=1 jit_smoke.c 31 d=31 -eigenscript.h 30 a=3 b=15 c=11 e=1 lint.c 29 a=29 compiler.c 21 a=13 b=5 c=1 i=2 ext_net.c 19 a=5 b=7 c=7 @@ -78,7 +81,7 @@ model_infer.c 16 a=1 b=6 c=9 trace.c 15 g=15 ext_http.c 14 a=3 b=4 c=7 chunk.c 11 a=3 e=2 f=6 -value_slot.h 8 a=4 b=2 c=2 +value_slot.h 9 a=4 b=3 c=2 eigs_embed.c 7 j=7 model_train.c 7 a=1 b=4 c=1 i=1 embed_concurrent.c 6 j=6 @@ -92,10 +95,199 @@ eigenlsp.c 2 a=2 eigs_embed.h 1 j=1 model_io.c 1 h=1 +## Executors (arms per opcode; roles: interp jit_scan jit_emit leaf_scan leaf_exec) +OP_ADD interp jit_scan jit_emit leaf_scan leaf_exec +OP_BAND interp jit_scan jit_emit - - +OP_BNOT interp jit_scan jit_emit - - +OP_BOR interp jit_scan jit_emit - - +OP_BXOR interp jit_scan jit_emit - - +OP_CALL interp jit_scan jit_emit - - +OP_CONST interp jit_scan jit_emit leaf_scan leaf_exec +OP_DIV interp jit_scan jit_emit - - +OP_DOT_GET interp jit_scan jit_emit - - +OP_DOT_SET interp jit_scan jit_emit - - +OP_DUP interp jit_scan jit_emit - - +OP_DUP2 interp jit_scan jit_emit - - +OP_EQ interp jit_scan jit_emit - - +OP_FALSE interp jit_scan jit_emit - - +OP_GE interp jit_scan jit_emit - - +OP_GET_LOCAL interp jit_scan jit_emit leaf_scan leaf_exec +OP_GET_NAME interp jit_scan jit_emit - - +OP_GT interp jit_scan jit_emit - - +OP_INDEX_GET interp jit_scan jit_emit leaf_scan leaf_exec +OP_INDEX_SET interp jit_scan jit_emit - - +OP_ITER_NEXT interp jit_scan jit_emit - - +OP_JUMP interp jit_scan jit_emit - - +OP_JUMP_BACK interp jit_scan jit_emit - - +OP_JUMP_IF_FALSE interp jit_scan jit_emit - - +OP_JUMP_IF_FALSE_PEEK interp jit_scan jit_emit - - +OP_JUMP_IF_TRUE interp jit_scan jit_emit - - +OP_JUMP_IF_TRUE_PEEK interp jit_scan jit_emit - - +OP_LE interp jit_scan jit_emit - - +OP_LINE interp jit_scan - leaf_scan leaf_exec +OP_LOCAL_DOT_GET interp jit_scan jit_emit leaf_scan leaf_exec +OP_LOCAL_DOT_SET interp jit_scan jit_emit - - +OP_LOCAL_IDX_DOT_GET interp jit_scan jit_emit - - +OP_LOCAL_IDX_GET interp jit_scan jit_emit - - +OP_LOOP_CAP_CHECK interp jit_scan jit_emit - - +OP_LOOP_STALL_CHECK interp jit_scan jit_emit - - +OP_LT interp jit_scan jit_emit - - +OP_MOD interp jit_scan jit_emit - - +OP_MUL interp jit_scan jit_emit leaf_scan leaf_exec +OP_NE interp jit_scan jit_emit - - +OP_NEG interp jit_scan jit_emit - - +OP_NOT interp jit_scan jit_emit - - +OP_NULL interp jit_scan jit_emit - - +OP_NUM_ONE interp jit_scan jit_emit leaf_scan leaf_exec +OP_NUM_ZERO interp jit_scan jit_emit leaf_scan leaf_exec +OP_OBSERVE_ASSIGN interp jit_scan jit_emit - - +OP_OBSERVE_ASSIGN_LOCAL interp jit_scan jit_emit - - +OP_OBSERVE_NAME_POST interp jit_scan jit_emit - - +OP_POP interp jit_scan jit_emit - - +OP_REPORT_SLOT interp jit_scan jit_emit - - +OP_RETURN interp jit_scan jit_emit leaf_scan leaf_exec +OP_RETURN_NULL interp jit_scan jit_emit - - +OP_SET_FN_NAME_LOCAL interp jit_scan jit_emit - - +OP_SET_LOCAL interp jit_scan jit_emit - - +OP_SET_NAME interp jit_scan jit_emit - - +OP_SET_NAME_LOCAL interp jit_scan jit_emit - - +OP_SHL interp jit_scan jit_emit - - +OP_SHR interp jit_scan jit_emit - - +OP_SUB interp jit_scan jit_emit leaf_scan leaf_exec +OP_TRUE interp jit_scan jit_emit - - +OP_UNOBSERVED_BEGIN interp jit_scan jit_emit - - +OP_UNOBSERVED_END interp jit_scan jit_emit - - + +## Numeric arms (JIT emitter and leaf evaluator arms holding a numeric site) +jit_emit OP_ADD OP_ADD OP_DIV OP_MUL OP_SUB +jit_emit OP_BAND OP_BAND OP_BOR OP_BXOR OP_SHL OP_SHR +jit_emit OP_CONST OP_CONST +jit_emit OP_EQ OP_EQ OP_GE OP_GT OP_LE OP_LT OP_NE +jit_emit OP_INDEX_SET OP_INDEX_SET +jit_emit OP_JUMP_IF_FALSE OP_JUMP_IF_FALSE OP_JUMP_IF_FALSE_PEEK OP_JUMP_IF_TRUE OP_JUMP_IF_TRUE_PEEK +jit_emit OP_LOCAL_DOT_GET OP_LOCAL_DOT_GET +jit_emit OP_LOCAL_DOT_SET OP_LOCAL_DOT_SET +jit_emit OP_MOD OP_MOD +jit_emit OP_NEG OP_BNOT OP_NEG OP_NOT +jit_emit OP_NOT OP_NOT +jit_emit OP_NULL OP_FALSE OP_NULL OP_NUM_ONE OP_NUM_ZERO OP_TRUE +jit_emit OP_POP OP_POP +jit_emit OP_SET_LOCAL OP_SET_LOCAL +jit_emit OP_SET_NAME OP_SET_FN_NAME_LOCAL OP_SET_NAME OP_SET_NAME_LOCAL +leaf_exec OP_ADD|OP_SUB|OP_MUL OP_ADD OP_MUL OP_SUB +leaf_exec OP_CONST OP_CONST +leaf_exec OP_INDEX_GET OP_INDEX_GET +leaf_exec OP_NUM_ONE OP_NUM_ONE +leaf_exec OP_NUM_ZERO OP_NUM_ZERO + +## Slot classifiers (R1.1 worklist) +D1=58 D2=20 D3=23 T=67 dispositions=43 missing=0 stale=0 +D1 container.h:dict_value_get_num forced slot_is_num=1 +D1 container.h:dict_value_get_ref forced eigs_slot_ref=1 slot_is_num=1 +D1 container.h:dict_value_get_return forced eigs_slot_ref=1 slot_is_num=1 +D1 container.h:eigs_slot_box forced eigs_slot_ref=1 slot_is_num=1 +D1 container.h:eigs_slot_elem_num forced eigs_slot_ref=1 slot_is_num=1 +D1 container.h:eigs_slot_num forced eigs_slot_ref=1 slot_as_ptr=2 slot_is_heap=1 slot_is_num=1 +D1 container.h:eigs_slot_opt_num forced eigs_slot_ref=1 slot_as_ptr=3 slot_is_heap=2 slot_is_null=1 slot_is_num=1 +D1 container.h:eigs_slot_store_borrow forced slot_as_ptr=1 slot_is_heap=1 slot_is_num=1 +D1 container.h:eigs_slot_store_owned forced slot_as_ptr=1 slot_is_heap=1 slot_is_num=1 +D1 container.h:list_get_num forced slot_is_num=1 +D1 container.h:list_get_ref forced eigs_slot_ref=1 slot_is_num=1 +D1 container.h:list_get_return forced eigs_slot_ref=1 slot_is_num=1 +D1 container.h:slot_type forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 slot_type=1 +D1 container.h:slot_view forced eigs_slot_ref=1 slot_as_ptr=1 slot_is_num=2 slot_type=1 +D1 eigenscript.c:ent_child_slot forced eigs_slot_ref=1 slot_is_num=1 +D1 eigenscript.c:module_ns_project forced slot_is_num=2 +D1 eigenscript.c:observer_entropy_now forced slot_as_ptr=1 slot_is_bool=1 slot_is_num=1 slot_is_ptr=1 +D1 eigenscript.c:slot_to_value forced slot_as_ptr=1 slot_is_bool=1 slot_is_heap=1 slot_is_null=1 slot_is_num=1 +D1 ext_store.c:store_json_encode_slot forced eigs_slot_ref=1 slot_is_num=1 +D1 trace.c:write_slot forced slot_as_ptr=1 slot_is_bool=1 slot_is_heap=1 slot_is_null=1 slot_is_num=1 +D1 value_slot.h:slot_is_num forced SLOT_QNAN_MASK=2 slot_is_num=1 +D1 value_slot.h:slot_is_numeric forced slot_is_num=1 slot_is_numeric=1 +D1 value_slot.h:slot_truthy_immediate forced SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 slot_is_null=1 slot_is_num=1 +D1 vm.c:#define ARITH_FAST forced slot_as_double=2 slot_as_ptr=2 slot_is_ptr=2 +D1 vm.c:#define INT_BINOP_R forced slot_as_double=2 slot_as_ptr=2 slot_is_ptr=2 +D1 vm.c:#define NUM_CMP forced slot_as_double=2 slot_as_ptr=2 slot_is_ptr=2 +D1 vm.c:#define READ_SLICE_BOUND forced slot_as_ptr=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:jit_helper_dot_set forced slot_as_ptr=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:jit_helper_index_get forced slot_as_ptr=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:jit_helper_index_set forced slot_as_ptr=1 slot_is_num=3 slot_is_ptr=1 +D1 vm.c:jit_helper_local_dot_set forced slot_is_num=1 +D1 vm.c:jit_helper_observe_assign_local forced slot_is_num=2 +D1 vm.c:jit_helper_observe_name_post forced slot_is_num=3 +D1 vm.c:loop_iter_store forced slot_is_num=1 +D1 vm.c:obs_dump_scope forced slot_as_ptr=3 slot_is_bool=1 slot_is_num=1 slot_is_ptr=3 +D1 vm.c:obs_dump_value forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:slot_as_double forced slot_as_double=1 slot_as_ptr=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:slot_bridge_unwrap forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 +D1 vm.c:slot_truthy forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 +D1 vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL forced slot_as_double=2 +D1 vm.c:vm_leaf_accessor_exec/OP_INDEX_GET forced slot_as_double=1 slot_as_ptr=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(BNOT) forced slot_as_double=1 slot_as_ptr=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(CALL) forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 +D1 vm.c:vm_run_ex/CASE(DISPATCH) forced slot_as_ptr=5 slot_is_bool=1 slot_is_null=1 slot_is_num=2 slot_is_ptr=2 +D1 vm.c:vm_run_ex/CASE(DOT_SET) forced slot_as_ptr=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(EQ) forced slot_as_double=2 +D1 vm.c:vm_run_ex/CASE(INDEX_GET) forced slot_as_ptr=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(INDEX_SET) forced slot_as_ptr=1 slot_is_num=3 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(JUMP_BACK) forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 +D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) forced slot_is_num=1 +D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) forced slot_is_num=1 +D1 vm.c:vm_run_ex/CASE(NE) forced slot_as_double=2 +D1 vm.c:vm_run_ex/CASE(NEG) forced slot_as_double=1 slot_as_ptr=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) forced slot_is_num=2 +D1 vm.c:vm_run_ex/CASE(OBSERVE_NAME_POST) forced slot_is_num=3 +D1 vm.c:vm_run_ex/CASE(RETURN) forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 +D1 vm.c:vm_slot_lift forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 +D1 vm.c:vm_store_local_slot forced slot_as_ptr=1 slot_is_heap=1 slot_is_num=1 +D2 builtins.c:bool_gate_name guarded slot_as_ptr=1 slot_is_ptr=1 +D2 builtins.c:sort_cmp_str guarded slot_as_ptr=2 +D2 builtins_host.c:ls_entry_cmp guarded slot_as_ptr=2 +D2 container.h:eigs_slot_ref refuse eigs_slot_ref=1 slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 +D2 eigenscript.c:#define GC_EDGE_TABLE guarded slot_as_ptr=6 slot_is_ptr=3 +D2 eigenscript.c:env_get_hashed guarded slot_as_ptr=1 slot_is_ptr=1 +D2 eigenscript.c:env_get_local_hashed guarded slot_as_ptr=1 slot_is_ptr=1 +D2 eigenscript.c:gc_collect_at_exit guarded slot_as_ptr=1 slot_is_ptr=1 +D2 value_slot.h:#define slot_as_heap refuse slot_as_heap=1 slot_as_ptr=1 +D2 value_slot.h:slot_as_ptr refuse SLOT_PAYLOAD_MASK=1 slot_as_ptr=1 +D2 vm.c:jit_helper_iter_next guarded list_elem_type=1 slot_as_ptr=1 slot_is_ptr=1 +D2 vm.c:obs_slot_value guarded slot_as_ptr=1 slot_is_bool=1 +D2 vm.c:slot_type_name smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_ptr=1 +D2 vm.c:vm_borrow_scan guarded slot_as_ptr=2 slot_is_heap=2 +D2 vm.c:vm_builtin_name_for guarded slot_as_ptr=1 slot_is_heap=1 +D2 vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET guarded slot_as_ptr=1 slot_is_null=1 slot_is_ptr=1 +D2 vm.c:vm_local_lift guarded slot_as_ptr=1 slot_is_null=1 slot_is_ptr=1 +D2 vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK) guarded slot_as_ptr=2 slot_is_ptr=1 +D2 vm.c:vm_run_ex/CASE(SLICE_GET) guarded slot_as_ptr=1 slot_is_ptr=1 +D2 vm.c:vm_slot_value_opaque guarded slot_as_ptr=1 slot_is_ptr=1 +D3 container.h:eigs_slot_adopt guarded slot_is_heap=1 +D3 jit.c:jit_compile_to_thunk/OP_EQ not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 +D3 jit.c:jit_compile_to_thunk/OP_NEG not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 +D3 jit.c:jit_compile_to_thunk/OP_NULL not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 +D3 jit_smoke.c:run_bool_cases not-a-classifier SLOT_FALSE_BITS=2 SLOT_TRUE_BITS=3 +D3 jit_smoke.c:run_index_bail_cases guarded slot_is_null=1 +D3 value_slot.h:slot_decref guarded SLOT_PAYLOAD_MASK=1 SLOT_QNAN_MASK=2 SLOT_TAG_MASK=1 TAG_HEAP=1 +D3 value_slot.h:slot_false not-a-classifier SLOT_FALSE_BITS=1 +D3 value_slot.h:slot_from_bool not-a-classifier TAG_BOOL=1 +D3 value_slot.h:slot_from_heap guarded SLOT_NULL_BITS=1 SLOT_PAYLOAD_MASK=1 TAG_HEAP=1 +D3 value_slot.h:slot_incref guarded SLOT_PAYLOAD_MASK=1 SLOT_QNAN_MASK=2 SLOT_TAG_MASK=1 TAG_HEAP=1 +D3 value_slot.h:slot_is_bool guarded SLOT_TAG_MASK=1 TAG_BOOL=1 slot_is_bool=1 +D3 value_slot.h:slot_is_heap guarded SLOT_TAG_MASK=1 TAG_HEAP=1 slot_is_heap=1 +D3 value_slot.h:slot_is_null guarded SLOT_NULL_BITS=1 slot_is_null=1 +D3 value_slot.h:slot_is_ptr guarded SLOT_TAG_MASK=1 TAG_HEAP=1 slot_is_ptr=1 +D3 value_slot.h:slot_null not-a-classifier SLOT_NULL_BITS=1 +D3 value_slot.h:slot_true not-a-classifier SLOT_TRUE_BITS=1 +D3 vm.c:jit_helper_dot_get guarded slot_is_null=1 +D3 vm.c:jit_helper_local_idx_dot_get guarded slot_is_null=1 +D3 vm.c:obs_slot_observable refuse slot_is_bool=1 slot_is_ptr=1 +D3 vm.c:vm_local_is_null guarded slot_is_null=1 +D3 vm.c:vm_run_ex/CASE(DOT_GET) guarded slot_is_null=1 +D3 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET) guarded slot_is_null=1 + ## Builtins -registered=311 numeric=229 classified=229 unclassified=0 stale=0 -classes: float-producing=58 int-preserving=37 int-requiring=67 other=67 -LOSS (39): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_query store_update subtract sum task_sched_seed +registered=311 numeric=230 classified=230 unclassified=0 stale=0 +classes: float-producing=58 int-preserving=37 int-requiring=84 other=51 +LOSS (42): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_execute db_query_json db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed abs builtin_abs int-preserving LOSS VAL_NUM,eigs_num_arg,make_num acos builtin_acos float-producing - VAL_NUM,eigs_num_arg,make_num add builtin_tensor_add int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard @@ -104,27 +296,27 @@ asin builtin_asin float-producing assert builtin_assert other - eigs_num_text atan builtin_atan float-producing - VAL_NUM,eigs_num_arg,make_num atan2 builtin_atan2 float-producing - VAL_NUM,eigs_num_arg,make_num -audio_capture_open builtin_audio_capture_open other - VAL_NUM,eigs_list_num,make_num +audio_capture_open builtin_audio_capture_open int-requiring - VAL_NUM,eigs_list_num,make_num audio_envelope builtin_audio_envelope float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num audio_gain builtin_audio_gain float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num audio_mix builtin_audio_mix float-producing - VAL_NUM,eigs_slot_num,make_num -audio_music_play builtin_audio_music_play other - VAL_NUM,eigs_list_num +audio_music_play builtin_audio_music_play int-requiring - VAL_NUM,eigs_list_num audio_music_volume builtin_audio_music_volume other - VAL_NUM,eigs_list_num,eigs_num_arg audio_noise builtin_audio_noise float-producing - VAL_NUM,eigs_list_num,make_num -audio_open builtin_audio_open other - VAL_NUM,eigs_list_num,make_num -audio_pause builtin_audio_pause other - VAL_NUM,eigs_num_arg +audio_open builtin_audio_open int-requiring - VAL_NUM,eigs_list_num,make_num +audio_pause builtin_audio_pause int-requiring - VAL_NUM,eigs_num_arg audio_play builtin_audio_play other - VAL_NUM,buffer_read_num,eigs_slot_num,make_num -audio_play_loop builtin_audio_play_loop other - VAL_NUM,buffer_read_num,eigs_list_num,eigs_slot_num,make_num +audio_play_loop builtin_audio_play_loop int-requiring - VAL_NUM,buffer_read_num,eigs_list_num,eigs_slot_num,make_num audio_queue_size builtin_audio_queue_size int-preserving - make_num audio_saw builtin_audio_saw float-producing - VAL_NUM,eigs_list_num,make_num audio_sine builtin_audio_sine float-producing - VAL_NUM,eigs_list_num,make_num audio_square builtin_audio_square float-producing - VAL_NUM,eigs_list_num,make_num audio_stop builtin_audio_stop int-requiring - VAL_NUM,eigs_num_arg,make_num -audio_stream_open builtin_audio_stream_open other - VAL_NUM,eigs_list_num,make_num +audio_stream_open builtin_audio_stream_open int-requiring - VAL_NUM,eigs_list_num,make_num audio_stream_push builtin_audio_stream_push other - VAL_NUM,buffer_read_num,eigs_slot_num audio_stream_queued builtin_audio_stream_queued int-preserving - make_num audio_sweep builtin_audio_sweep float-producing - VAL_NUM,eigs_list_num,make_num -audio_volume builtin_audio_volume other - VAL_NUM,eigs_slot_num,make_num +audio_volume builtin_audio_volume int-requiring - VAL_NUM,eigs_slot_num,make_num bit_and builtin_bit_and int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact bit_not builtin_bit_not int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact bit_or builtin_bit_or int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact @@ -156,19 +348,19 @@ clock_unix builtin_clock_unix float-producing close_channel builtin_close_channel int-requiring - VAL_NUM,eigs_num_arg copy_into builtin_copy_into int-requiring - VAL_NUM,eigs_num_arg cos builtin_cos float-producing - VAL_NUM,eigs_num_arg,make_num -db_execute builtin_db_execute other - VAL_NUM,eigs_num_arg -db_query_json builtin_db_query_json other - VAL_NUM,eigs_num_arg +db_execute builtin_db_execute other LOSS VAL_NUM,eigs_num_arg +db_query_json builtin_db_query_json other LOSS VAL_NUM,eigs_num_arg db_query_value builtin_db_query_value other LOSS VAL_NUM,eigs_num_arg,make_num,strtod dispatch builtin_dispatch int-requiring - VAL_NUM,eigs_num_arg,make_num divide builtin_tensor_divide float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard dot builtin_dot float-producing - buffer_read_num,make_num,num_guard eigen_eval_loss builtin_eigen_eval_loss float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num -eigen_generate builtin_eigen_generate other - eigs_slot_num,eigs_slot_opt_num,make_num +eigen_generate builtin_eigen_generate int-requiring - eigs_slot_num,eigs_slot_opt_num,make_num eigen_model_load builtin_eigen_model_load other - strtod exec_capture builtin_exec_capture other - VAL_NUM,eigs_list_num,list_append_num exit builtin_exit int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg exp builtin_tensor_exp float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard -f64_from_bytes builtin_f64_from_bytes other - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named +f64_from_bytes builtin_f64_from_bytes int-requiring - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named f64_to_bytes builtin_f64_to_bytes other - VAL_NUM,eigs_num_arg,make_num fill builtin_fill int-requiring - eigs_list_num floor builtin_floor int-preserving LOSS VAL_NUM,eigs_num_arg,make_num @@ -179,7 +371,7 @@ gfx_circle builtin_gfx_circle other gfx_clear builtin_gfx_clear other - VAL_NUM,eigs_list_num gfx_clip builtin_gfx_clip other - VAL_NUM,eigs_list_num gfx_delay builtin_gfx_delay other - VAL_NUM,eigs_num_arg -gfx_fb builtin_gfx_fb other - VAL_NUM,eigs_list_num +gfx_fb builtin_gfx_fb int-requiring - VAL_NUM,buffer_read_byte,eigs_list_num gfx_line builtin_gfx_line other - VAL_NUM,eigs_list_num gfx_open builtin_gfx_open other - VAL_NUM,eigs_list_num gfx_point builtin_gfx_point other - VAL_NUM,eigs_list_num @@ -199,7 +391,7 @@ http_route_authed builtin_http_route_authed other http_serve builtin_http_serve int-requiring - eigs_num_text,eigs_opt_num http_static builtin_http_static other - eigs_num_text index_of builtin_index_of int-preserving - make_num -inflate builtin_inflate other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num +inflate builtin_inflate int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num join builtin_join other - eigs_num_text json_build builtin_json_build other LOSS VAL_NUM,eigs_num_arg,eigs_num_text json_decode builtin_json_decode other LOSS make_num,strtod @@ -225,7 +417,7 @@ model_load_weights builtin_eigen_model_load other monotonic_ms builtin_monotonic_ms float-producing - make_num monotonic_ns builtin_monotonic_ns int-preserving LOSS make_num multiply builtin_tensor_multiply int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard -native_train_step_builtin builtin_native_train_step other - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod +native_train_step_builtin builtin_native_train_step int-requiring - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod nearest_in_range builtin_nearest_in_range float-producing - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num nearest_in_range_all builtin_nearest_in_range_all float-producing - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num negative builtin_tensor_negative int-preserving LOSS VAL_NUM,eigs_num_arg,make_num @@ -235,7 +427,7 @@ net_dial builtin_net_dial int-requiring net_listen builtin_net_listen int-requiring - VAL_NUM,eigs_num_arg,make_num net_port builtin_net_port int-requiring - VAL_NUM,eigs_num_arg,make_num net_recv builtin_net_recv int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_opt_num -net_send builtin_net_send other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +net_send builtin_net_send int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num norm builtin_tensor_norm float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard num builtin_num other LOSS VAL_NUM,make_num,num_guard_named,strtod num_copy builtin_num_copy int-preserving LOSS VAL_NUM,eigs_num_arg,make_num @@ -246,6 +438,7 @@ observe builtin_observe other ord builtin_ord int-preserving - make_num pi builtin_pi float-producing - make_num pow builtin_tensor_pow float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard_named +ppu_render_frame builtin_ppu_render_frame int-requiring - buffer_read_byte print builtin_print other - eigs_num_text proc_read_buf builtin_proc_read_buf int-requiring - VAL_NUM,eigs_num_arg random builtin_random float-producing - make_num @@ -257,7 +450,7 @@ read_bytes builtin_read_bytes int-preserving read_bytes_buf builtin_read_bytes_buf int-requiring - VAL_NUM,eigs_num_arg,make_num record_history builtin_record_history other - VAL_NUM,eigs_num_arg,make_num recv builtin_recv int-requiring - VAL_NUM,eigs_num_arg -recv_timeout builtin_recv_timeout other - VAL_NUM,eigs_num_arg +recv_timeout builtin_recv_timeout int-requiring - VAL_NUM,eigs_num_arg relu builtin_tensor_relu float-producing - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num reshape builtin_reshape int-requiring - VAL_NUM,eigs_list_num round builtin_round int-preserving LOSS VAL_NUM,eigs_num_arg,make_num @@ -290,11 +483,11 @@ store_delete builtin_store_delete int-requiring store_drop builtin_store_drop int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num store_get builtin_store_get int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,strtod store_open builtin_store_open int-preserving - VAL_NUM,eigs_num_arg,make_num,strtod -store_put builtin_store_put other - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num +store_put builtin_store_put other LOSS VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num store_query builtin_store_query other LOSS VAL_NUM,eigs_num_arg,make_num,strtod store_update builtin_store_update other LOSS VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num str builtin_str other - eigs_num_text -str_from_bytes builtin_str_from_bytes other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte +str_from_bytes builtin_str_from_bytes int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte stream_open builtin_stream_open int-requiring - VAL_NUM,eigs_num_arg stream_write builtin_stream_write float-producing - VAL_NUM,eigs_num_arg substr builtin_substr int-requiring - VAL_NUM,eigs_num_arg @@ -322,7 +515,7 @@ type builtin_type other usleep builtin_usleep other - VAL_NUM,eigs_num_arg vm_run_bytecode builtin_vm_run_bytecode int-requiring - VAL_NUM,eigs_num_arg write builtin_write other - eigs_num_text -write_bytes builtin_write_bytes other - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +write_bytes builtin_write_bytes int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num zeros builtin_tensor_zeros int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg,make_num zeros_like builtin_tensor_zeros_like float-producing - VAL_NUM,make_num @@ -984,7 +1177,7 @@ chunk.c:234 const_dedup_grow VAL_NUM TEST a chunk.c:243 chunk_add_constant_ex VAL_NUM TEST a chunk.c:421 chunk_disassemble VAL_NUM TEST e chunk.c:422 chunk_disassemble VAL_NUM_RAW RAW e -chunk.c:1090 chunk_scan_leaf_accessor VAL_NUM TEST a +chunk.c:1090 chunk_scan_leaf_accessor/OP_CONST VAL_NUM TEST a compiler.c:582 add_num_constant make_num PRODUCE c compiler.c:791 collect_referenced_names_skip AST_NUM CASE a compiler.c:935 collect_referenced_names AST_NUM CASE a @@ -1167,7 +1360,9 @@ eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a eigenscript.h:270 VAL_NUM DATA a eigenscript.h:285 #define VAL_NUM_RAW VAL_NUM_RAW RAW b +eigenscript.h:285 #define VAL_NUM_RAW num_ RAW b eigenscript.h:286 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b +eigenscript.h:286 #define VAL_NUM_OFFSET num_ RAW b eigenscript.h:1390 eigs_num_arg_slow READ b eigenscript.h:1391 eigs_num_arg eigs_num_arg READ b eigenscript.h:1392 eigs_num_arg VAL_NUM TEST a @@ -1188,6 +1383,7 @@ eigenscript.h:1894 buffer_read_num buffer_read_num READ b eigenscript.h:1895 buffer_read_num num_guard GUARD c eigenscript.h:1901 finite_num_to_byte finite_num_to_byte READ b eigenscript.h:1910 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1919 buffer_read_byte buffer_read_byte READ b eigenscript.h:1920 buffer_read_byte buffer_read_num READ b eigenscript.h:1922 buffer_read_byte finite_num_to_byte READ b eigenscript.h:1933 num_guard_named num_guard_named GUARD c @@ -1490,6 +1686,27 @@ ext_gfx.c:2245 builtin_gfx_fb eigs_list_num READ b ext_gfx.c:2246 builtin_gfx_fb eigs_list_num READ b ext_gfx.c:2247 builtin_gfx_fb eigs_list_num READ b ext_gfx.c:2248 builtin_gfx_fb eigs_list_num READ b +ext_gfx.c:2284 builtin_gfx_fb buffer_read_byte READ b +ext_gfx.c:2324 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2332 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2334 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2336 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2338 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2340 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2342 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2344 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2388 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2397 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2399 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2430 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2439 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2441 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2460 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2462 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2467 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2469 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2506 builtin_ppu_render_frame buffer_read_byte READ b +ext_gfx.c:2508 builtin_ppu_render_frame buffer_read_byte READ b ext_http.c:584 builtin_http_early_bind VAL_NUM TEST a ext_http.c:594 builtin_http_early_bind eigs_opt_num READ b ext_http.c:662 builtin_http_serve eigs_opt_num READ b @@ -1792,6 +2009,7 @@ value_slot.h:50 slot_is_num slot_is_num TEST a value_slot.h:59 slot_is_numeric slot_is_num TEST a value_slot.h:59 slot_is_numeric slot_is_numeric TEST a value_slot.h:66 #define SLOT_NUM_RAW SLOT_NUM_RAW RAW b +value_slot.h:66 #define SLOT_NUM_RAW d_ RAW b value_slot.h:73 slot_from_num SLOT_NUM_RAW WRITE c value_slot.h:73 slot_from_num slot_from_num PRODUCE c value_slot.h:143 slot_truthy_immediate SLOT_NUM_RAW RAW b @@ -1846,17 +2064,17 @@ vm.c:1793 jit_helper_iter_next buffer_read_num READ b vm.c:1793 jit_helper_iter_next num_guard GUARD c vm.c:1793 jit_helper_iter_next slot_from_num PRODUCE c vm.c:1799 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1869 vm_leaf_accessor_exec VAL_NUM_RAW RAW b -vm.c:1869 vm_leaf_accessor_exec slot_from_num PRODUCE c -vm.c:1873 vm_leaf_accessor_exec slot_from_num PRODUCE c -vm.c:1876 vm_leaf_accessor_exec slot_from_num PRODUCE c -vm.c:1913 vm_leaf_accessor_exec slot_as_double READ b -vm.c:1927 vm_leaf_accessor_exec buffer_read_num READ b -vm.c:1927 vm_leaf_accessor_exec slot_from_num PRODUCE c -vm.c:1935 vm_leaf_accessor_exec slot_as_double READ b -vm.c:1936 vm_leaf_accessor_exec slot_as_double READ b -vm.c:1954 vm_leaf_accessor_exec num_guard GUARD c -vm.c:1954 vm_leaf_accessor_exec slot_from_num PRODUCE c +vm.c:1869 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b +vm.c:1869 vm_leaf_accessor_exec/OP_CONST slot_from_num PRODUCE c +vm.c:1873 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_num PRODUCE c +vm.c:1876 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_num PRODUCE c +vm.c:1913 vm_leaf_accessor_exec/OP_INDEX_GET slot_as_double READ b +vm.c:1927 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1927 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_num PRODUCE c +vm.c:1935 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_as_double READ b +vm.c:1936 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_as_double READ b +vm.c:1954 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:1954 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_num PRODUCE c vm.c:2037 loop_iter_store make_num PRODUCE c vm.c:2044 loop_iter_store slot_is_num TEST a vm.c:2045 loop_iter_store SLOT_NUM_RAW WRITE c diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index e29767d91..8806d944e 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1,7 +1,9 @@ -# Phase 2 numbers (#1758): round 0 design +# Phase 2 numbers (#1758): design (round 0, revised in design round 2) Status: design for blind review, before round 1 builds. Nothing here changes -`src/`. Spec: issue #1758 (Revision 1) and its owner decisions (A), (B), (C). +`src/`. Spec: issue #1758 (Revision 1), its owner decisions (A), (B), (C), and +the Q1-Q6 decisions +([comment](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6171744498)). Evidence base: issue #1746 and the `exp-ieee-p1` branch (canonical NaN, the single slot writer, the JIT bailing on NaN, refusal inside writers). @@ -9,28 +11,47 @@ Tree measured: `phase2-numbers` at `0740af03` (main, v0.46.0-8). The tag the Done-when means is `v0.46.0` = `4a3a5c19`. Companion artifacts: -- `tools/phase2_inventory.py`: the site inventory and the builtin-table check. - It writes `docs/design/phase2-inventory.txt`. -- `tests/phase2/MAP.md`: every N, O and T item mapped to planned rows. +- `tools/phase2_inventory.py`: the site inventory, the executor matrix, the + slot-classifier derivation, and the builtin-table check. It writes + `docs/design/phase2-inventory.txt`. +- `tests/phase2/MAP.md`: every N, O and T item mapped to planned rows, with + row shapes and tier witnesses. + +**What design round 2 changed** (after the blind critic's FAIL on round 0): +- The third numeric evaluator, `vm_leaf_accessor_exec` (vm.c:1856, scanner + chunk.c:1072, #366), is in the inventory (§1), the JIT/leaf section (§4.5) + and the map (§7), with every arm, and it gets its own gate (§9.2). +- Every meaning change now coincides with a token change (§2.7). Int + literals get new opcodes; `OP_NUM_ZERO`/`OP_NUM_ONE` keep their float + meaning; `slot_as_double` is deleted in R1.1. +- The compile-forced count is re-measured with clang's `unavailable` + attribute under three configurations (§2.3a), and every site that does + not stop compiling is classified. +- The slot classifiers are derived, not listed (§2.5), and raw union-member + reads are in the vocabulary. +- The canonical-form invariant is corrected (§2.1): the lifts box on purpose. +- The builtin table follows the decided Q1 (§6), with the LOSS rows #1762 + found; §11 records Q1-Q6 as decided. +- The test plan has row shapes and tier witnesses (§9). Contents: 1. The inventory 2. Representation 3. Measured prototype -4. The JIT +4. The JIT and the leaf evaluator 5. N12 and SMI share the NaN space 6. Builtin classification 7. Semantics-to-sites map 8. Round plan 9. Test plan 10. Lua differential tool -11. Open questions this design does not decide +11. Decided questions (Q1-Q6) and what stays open --- ## 1. The inventory -`python3 tools/phase2_inventory.py` prints `examined=1773 classified=1773 +`python3 tools/phase2_inventory.py` prints `examined=1798 classified=1798 unclassified=0` on this tree and writes every site to `docs/design/phase2-inventory.txt` (file:line, enclosing function, token, syntactic kind, category). @@ -40,6 +61,15 @@ literals, of a token of the value model's numeric vocabulary in `src/*.c` and `src/*.h`. The vocabulary is: - the type tag `VAL_NUM` and the slot predicates; - the raw and checked payload accessors and the constructors; +- the raw union members themselves: `.d_` / `->d_` (the slot's double) and + `.num_` / `->num_` (the Value's double). Inside their three accessor + macros (`SLOT_NUM_RAW`, `VAL_NUM_RAW`, `VAL_NUM_OFFSET`) they are RAW + sites; anywhere else they are a `BYPASS`, which the script leaves + unclassified, so the run fails. This closes the blind spot the critic's + plant `e_blind_member` (`static double p2_plant_blind(EigsSlot s) { + return s.d_; }` appended to vm.c) showed: the round-0 oracle stayed green + on it. The repo's own `tools/num_read_check.sh` (#1637) already refuses + such a bypass in CI; the inventory now sees it too; - the clamp (`num_guard`) and the number formatter; - the double parsers (`strtod`, `atof`); - the AST literal fields (`AST_NUM`, `data.num`, `num_val`); @@ -49,9 +79,21 @@ literals, of a token of the value model's numeric vocabulary in `src/*.c` and name no vocabulary token, so without these the JIT category would hold 40 sites instead of 127. +**Attribution.** Each site carries its enclosing function. Inside the five +opcode dispatchers it also carries its arm: +- `vm_run_ex` (the interpreter): `CASE(X)`. A macro whose body spells + `CASE()` generates an arm at each invocation, closed + over chains (`INT_BINOP` -> `INT_BINOP_R` -> `CASE(NAME)`), so + `NUM_BINOP(SUB, ...)` and `NUM_CMP(LT, ...)` are interpreter arms too; +- `jit_supported_prefix` and `jit_compile_to_thunk` (the JIT scanner and + emitter): the `if (op == OP_X || ...)` chain, named by its first opcode; +- `chunk_scan_leaf_accessor` and `vm_leaf_accessor_exec` (the leaf scanner + and evaluator): the `case` labels at the dispatch switch's own depth, + grouped labels joined (`OP_ADD|OP_SUB|OP_MUL`). + **The key and its blind spot.** The key is the token, so code that handles a -number without naming one is invisible. Two derived checks bound that, and -both can make `unclassified` nonzero: +number without naming one is invisible. Four derived checks bound that, and +each can fail the run: 1. Every function that returns or writes out a `double` and whose body performs a payload read is a numeric accessor. It must be in the vocabulary (its call sites then count as sites) or in a reviewed @@ -61,6 +103,35 @@ both can make `unclassified` nonzero: 2. Every `VAL_NUM`/`AST_NUM` must sit in a recognized syntactic position: test, case, tag store, type yield, data, or emitter immediate. An unrecognized position (for example `1u << VAL_NUM`) is unclassified. +3. **The executor matrix** (`## Executors` in the inventory file). For every + opcode, the roles that implement it: `interp`, `jit_scan`, `jit_emit`, + `leaf_scan`, `leaf_exec`. The leaf scanner and the leaf evaluator must + admit exactly the same opcodes, in both directions (a scanner arm with no + evaluator arm, or the reverse, fails the run). Today both hold the same + 11: `LINE`, `CONST`, `NUM_ZERO`, `NUM_ONE`, `GET_LOCAL`, `LOCAL_DOT_GET`, + `INDEX_GET`, `ADD`, `SUB`, `MUL`, `RETURN`. So `OP_NUM_ZERO` and + `OP_NUM_ONE` have three executors (interpreter vm.c:3257, JIT emitter + jit.c:2797, leaf evaluator vm.c:1872) and two scanners; the round-0 draft + named two executors. +4. **The slot classifiers** (`## Slot classifiers`). Every function, or + dispatcher arm, that tests, dereferences or types an `EigsSlot`, by the + tokens it names: + - D1: it names a number test (`slot_is_num`, `slot_is_numeric`, + `slot_as_double`). All three are renamed or deleted, so the compiler + forces every D1 entry (58 today); + - D2: it dereferences (`slot_as_ptr`, `slot_as_heap`, `eigs_slot_ref`) + without a number test (20); + - D3: it tests other tags or raw tag bits (23); + - T: it only reads a slot's `ValType` (`slot_type`, `list_elem_type`, + `dict_value_type`), 67. A comparison with `VAL_NUM` is compile-forced; + a comparison with another enumerator is unaffected by ints; a switch is + forced by `-Werror=switch`. + + Every D2 and D3 entry needs a reviewed row in §2.5's table, with a + disposition from a fixed set. A missing row and a stale row each fail the + run. The three classifiers the critic found outside round 0's rule + (`eigs_slot_ref`, `obs_slot_observable`, `slot_type_name`) are D2/D3 + entries of this derivation. Also outside the population: - `src/freestanding/` (`mini_strtod.c`, `mini_fmt.c`), which N1, N6 and N10 @@ -74,7 +145,7 @@ decides (a)/(b)/(c)/(e). | | category | sites | kinds | |---|---|---:|---| | a | type tests | 384 | TEST 327, CASE 52, DATA 3, YIELD 2 | -| b | payload reads | 505 | READ 392, RAW 113 | +| b | payload reads | 530 | READ 414, RAW 116 | | c | producers | 472 | PRODUCE 373, GUARD 71, WRITE 22, PARSE 3, TAGSET 3 | | d | JIT emitters and guards | 127 | EMIT 89, RAW 27, PRODUCE 6, TEST 2, GUARD 1, TAGSET 1, WRITE 1 | | e | number formatting | 14 | | @@ -83,12 +154,14 @@ decides (a)/(b)/(c)/(e). | h | JSON, store and db encoders | 70 | | | i | observer numeric paths | 90 | | | j | embed API | 64 | | -| | **total** | **1773** | | +| | **total** | **1798** | | `WRITE` is `VAL_NUM_RAW(v) = x`, the NUM_REUSE in-place writes the brief -names as producers. +names as producers. Design round 2 added 25 sites: the raw members inside +their three accessor macros (`RAW`, 3) and `buffer_read_byte`, the byte +reader Q1 changes (`READ`, 22). -Largest files: builtins.c 319, vm.c 304, ext_gfx.c 229, builtins_tensor.c +Largest files: builtins.c 319, vm.c 304, ext_gfx.c 250, builtins_tensor.c 184, builtins_buf.c 97, jit.c 96. The per-file and per-token tables are in the inventory file. @@ -107,10 +180,46 @@ the runtime's own `eigenscript --api --json` (223 core + 88 extension = 311; equal in both directions). A builtin is numeric when a site is contained in its function, in a same-file function it calls or names as a value (a comparator, an op-table entry; closure depth 4), or in the shared formatter -or equality it calls. That gives 229 numeric builtins, and §6 -classifies every one. The script fails if a numeric builtin has no row, a row -names no numeric builtin, a class or loss mark is not one of the allowed -tokens, or a `LOSS` row has no double path in its closure. +or equality it calls. That gives 230 numeric builtins, and §6 +classifies every one. (The closure does not follow a call into another +file, so a header helper that reads a number must itself be in the +vocabulary for its callers to count: `buffer_read_byte` entered the +vocabulary this round, which made `ppu_render_frame` numeric. A one-off scan +of every header inline and every exported function that reads a number and +returns something other than a double found no other such reader: the rest +return a status (`jit_helper_*`, the observer), a slot (`slot_from_value`, +the container writers) or a truth value (`is_truthy`, +`slot_truthy_immediate`).) The script fails if a numeric builtin has no +row, a row names no numeric builtin, a class or loss mark is not one of the +allowed tokens, or a `LOSS` row has no double path in its closure. + +**Calibration: every check turns red on its plant.** Each plant runs +against a scratch copy of `src/` and of this document (`--src`, `--doc`, +`--no-write`), never the worktree; the unplanted copy passes first. All 18 +were KILLED on this tree, each by its own FAIL line: + +| plant | mutation | the red line | +|---|---|---| +| A | `1u << VAL_NUM` appended to vm.c | `UNCLASSIFIED: ... VAL_NUM (VAL_NUM/AST_NUM in an unrecognized position)` | +| B | a new function returning `VAL_NUM_RAW(v)` | `UNCLASSIFIED: ... p2_plant_read (reads a payload and returns/writes a double; not in VOCAB or WRAPPERS)` | +| C | a registered numeric builtin with no row | ``numeric builtin `p2plant` ... has no classification row`` | +| D | class `integer` | `` `abs` has unknown class 'integer' `` | +| E | loss mark `maybe` | `` `type` has unknown loss mark 'maybe' `` | +| F | a row for a non-numeric builtin | ``classification row `keys` names no numeric registered builtin`` | +| G | `LOSS` on a builtin with no double path | `` `type` is marked LOSS but its closure has no double-path token `` | +| H | a row without backticks | `unparsed table line: \| type \| other ...` | +| I | the JIT files removed | `role rule 0 (d ...) matched no site` | +| J | an empty source tree | `examined=0 classified=0` (fails) | +| K | a VOCAB token that never occurs | `VOCAB token never occurs: p2_never_token` | +| L | the `abs` row deleted | ``numeric builtin `abs` ... has no classification row`` | +| M | the critic's `e_blind_member`: `static double p2_plant_blind(EigsSlot s) { return s.d_; }` | `UNCLASSIFIED: vm.c:6733 p2_plant_blind d_ (raw union member outside its accessor macro)` | +| N | the leaf scanner admits `OP_DIV` | `leaf scanner admits OP_DIV but the leaf evaluator has no arm` | +| O | a new function returning `slot_as_ptr(s)` | ``slot classifier `vm.c:p2_plant_deref` has no disposition row`` | +| P | a disposition row for a function that does not exist | ``disposition row `vm.c:p2_gone` names no D2/D3 slot classifier`` | +| Q | disposition `fine` | `` `vm.c:slot_type_name` has unknown disposition 'fine' `` | +| R | `vm_leaf_accessor_exec` renamed | `dispatcher vm_leaf_accessor_exec (leaf_exec) attributed no opcode arm` | + +M is the critic's plant verbatim; on the round-0 oracle it stayed green. --- @@ -141,21 +250,51 @@ tokens, or a `LOSS` row has no double path in its closure. `__builtin_mul_overflow`, as do boxed operands for every operator. An int64 overflow raises `value` ((A)). -**Canonical-form invariant (all alternatives):** an int in [-2^47, 2^47) is -always an SMI in a slot, never boxed; a boxed int is always outside that -range. Equality fast paths, hashing and the tape depend on it (#1758). - -It is enforced inside the two writers that can put an int into a slot, not -beside their callers (the #1746 lesson): -- `slot_from_int(int64_t)`, the only int-to-slot constructor; -- `slot_from_heap(Value *)`, which already normalizes the null and bool - singletons (value_slot.h:86) and gains the same rule for a small boxed - int. - -Every other route into a slot goes through one of them: `slot_from_value`, -`eigs_container_slot`, `vm_push`/`slot_bridge_wrap`, the tape decoder (it -returns Values), and the JIT `OP_CONST` emitter, which must compute its bits -with the same function (§4). +**Canonical form (all alternatives), corrected in design round 2.** The +round-0 draft said an int in [-2^47, 2^47) is never boxed in any slot, with +`slot_from_heap` normalizing a small box. That cannot hold: the VM boxes +numbers on purpose today, and must keep doing it for ints. +- `vm_slot_lift` (vm.c:826, the store at 834) and `vm_local_lift` (vm.c:717, + store at 723) materialize an immediate into a heap Value and **overwrite + the slot with it**, because the caller keeps using that pointer. + `env_get_hashed` and `env_get_local_hashed` (eigenscript.c:4986-5026) do + the same through `slot_to_value` plus `slot_from_heap`. +- `vm_push` goes through `slot_bridge_wrap` (vm.c:768), which by contract + "NEVER emits an immediate": a builtin's boxed result stays a heap slot. +- So a boxed number on the stack or in an env slot is a legal state today + (the JIT's operand loader already accepts a heap `VAL_NUM` with refcount + >= 2, jit.c:2343). A boxed small int is the same state. + +The invariant that does hold, and that round 1 keeps: +- **Container storage is canonical.** A list item or dict value is an + immediate number, null, bool, or a heap pointer to a Value that is not a + number (container.h:4-16). After round 1: a small int is stored as an + SMI, and a `VAL_INT` box only for an int outside [-2^47, 2^47). It is + enforced inside the four container writers that already unbox a + `VAL_NUM` (`eigs_container_slot`, `eigs_slot_adopt`, + `eigs_slot_store_owned`, `eigs_slot_store_borrow`), not beside their + callers (the #1746 lesson). +- **The int writers produce the SMI.** `slot_from_int(int64_t)` (new, the + only int constructor) and `slot_from_value` (an owned Value*, which + already releases a `VAL_NUM` box into an immediate, eigenscript.c:1862) + produce an SMI for a small int and a box outside the range. +- **Everything that compares compares by value whenever a box is + involved.** The only bit-level fast path is "both operands SMI" (equal + bits iff equal ints). An SMI against a box, or two boxes, compares the + int64 values; an int against a float uses N2's exact rule. + `values_equal_impl`, the EQ/NE/compare arms, the sort comparators and + every hash of a number follow this. + +Consequences: +- A writer that skips the small-int rule produces a box where an SMI was + due. No program can see that: equality, ordering, printing and the tape + all go by value. The only witness is the C slot test + (`tests/phase2/slot_layer.c`, §8 R1.1), which drives each writer above + with every boundary value (±2^47, ±(2^47 - 1), 0, INT64_MIN, INT64_MAX) + and asserts the resulting tag. That is plant 1's named check (§9.3); the + round-0 claim that a program row (`N1.canon-eq`) would see it was wrong. +- The JIT `OP_CONST` emitter never meets an int: int literals use new + opcodes (§2.7, §4.2). ### 2.2 The four alternatives @@ -179,6 +318,10 @@ accessors deleted.** - `eigs_number_arg` returns `EigsNum { kind, i, f }` for int-preserving builtins. - `make_int`. +- Design round 2 extends the list (measured in §2.3a): the AST and token + literal payloads, `slot_as_double` (deleted), the container f64 helpers, + `make_num_permanent`, `buf_num_arg`, `finite_num_to_byte` and + `buffer_read_byte`. - This is the repo's own precedent: #1637 round 4 renamed the union member to `num_` "so no unchecked read compiles" (eigenscript.h:281). @@ -204,17 +347,102 @@ computed from the site list. | | sites that must be revisited | how the revisit is forced | what a MISSED site does | |---|---|---|---| | **Alt 1** | the 382 TEST and 63 CASE sites (all categories) that should admit ints; reads after them; every producer that should yield an int; JIT producers | CASE only: 62 of the 63 `case VAL_NUM:`/`case AST_NUM:` switches have no `default:`, so `-Werror=switch` names them. TEST sites are not forced. | The int fails `== VAL_NUM` and takes the non-number branch. That raises a type error where the branch raises (loud, acceptable), but returns a **soft default** where the branch is soft. Examples: `what is 5` answers 0 and `who is 5` answers "unknown" (vm.c:5465-5484); `json_encode of 5` writes `null` (builtins.c:998, the one switch with a `default:`). Silently wrong, but never a lossy double. | -| **Alt 1R** | the same sites | **1,449 non-JIT sites and 39 JIT-file sites name a renamed or deleted token and stop compiling** until visited. 197 sites keep their token (the clamp 73, the formatter 7, buffer float reads 38, parsers 17, conversions 14, the embed accessor 48); each is pinned by a MAP row or a round-2 item. 88 JIT emitter tokens are reviewed per opcode (§4). | **A compile error.** It cannot exist in code that names the vocabulary. Two residual routes remain: (1) a switch with a `default:` absorbs the new `VAL_INT` (only builtins.c:915-998, removed first in round 1), and (2) code that tests raw slot bits: 74 sites, 59 of them value_slot.h's own definitions, 13 in the JIT files, 2 in eigenscript.c (a bit-identity shortcut that stays correct). | +| **Alt 1R** | the same sites | **Measured (§2.3a): 1,416 of the 1,798 sites stop compiling (1,380 non-JIT, 36 in the JIT files)**, plus 44 inside a deleted definition. The other 338 keep a token on purpose, each class with its reason in §2.3a: the AST kind (52), the clamp R2.2 deletes (60), the decided embed accessor (48), f64 buffer reads (26), the libc parsers (15), the exact-conversion and formatter helpers (9), definitions (38), 87 JIT emitter immediates and helpers reviewed per guard (§4), and 3 `offsetof` uses that a real member rename does reach (measured). | **A compile error.** It cannot exist in code that names the vocabulary. The meaning changes that carry no token are listed with the token event that forces them (§2.7); the last `default:` that could absorb `VAL_INT` (builtins.c:998) is removed first in round 1. | | **Alt 2** | payload reads and producers (enforced only if `num_` is renamed); the type tests keep compiling and now admit ints | none for the 382+63 type tests and the 484 checked reads | **A silent wrong number.** After `== VAL_NUM`, a `VAL_NUM_RAW` read of an int reads its int64 bits as a double (5 reads as 2.5e-323). An accessor that converts loses precision above 2^53 silently. In the JIT, three emitters misread with no compiler to catch them: `emit_load_numeric_operand`'s heap arm (jit.c:2343) loads `data.num_` of a boxed int; the `OP_SET_LOCAL` in-place branch (jit.c:3410) writes double bits into an int Value; the `OP_CONST` emitter (jit.c:2816) pushes `VAL_NUM_RAW` bits of an int constant. Constant dedup `const_equal` (chunk.c:212) merges `3` and `3.0`. | | **Alt 3** | only the sites that need exactness (N2, N3, N6, N8, N14, tape) | none: every existing read compiles and works below 2^53 | **A silently lossy double**, exact below 2^53, so ordinary tests cannot see it. This is precisely the class the brief says to design out. | +### 2.3a The compile measurement (design round 2) + +Round 0 claimed 1,449 non-JIT sites stop compiling. That was a token count, +not a compile. The critic compiled it and found 1,331, with 118 sites +carrying tokens round 0 never renamed (`AST_NUM` 52, `list_set_num` 21, +`slot_as_double` 16, `data.num` 7, `num_val` 5, and 17 more). This round +extends the rename list and measures again, the critic's way. + +**Method.** +- A scratch copy of `src/` (never the worktree). Each token Alt 1R renames + or deletes gets a declaration with clang's + `__attribute__((unavailable("P2 ...")))`, so every USE is a compile error + and the definition stays legal. `SLOT_NUM_RAW`, a macro, is routed + through an unavailable `extern` so each expansion errors; `VAL_NUM_RAW` + expands to the unavailable member `num_` and errors with a macro note. +- The list: the enumerator `VAL_NUM`; the members `num_` (Value), `num` + (AST literal payload) and `num_val` (token); `eigs_num_arg`, + `eigs_num_arg_slow`, `eigs_list_num`, `eigs_elem_num`, `eigs_opt_num`, + `eigs_slot_num`, `eigs_slot_elem_num`, `eigs_slot_opt_num` and + `buf_num_arg` (deleted); `make_num` and `make_num_permanent`; + `finite_num_to_byte` and `buffer_read_byte` (deleted: Q1 byte values + follow N5); `SLOT_NUM_RAW`, + `slot_is_num`, `slot_from_num` and `slot_is_numeric` (deleted); + `slot_as_double` (deleted in R1.1, §2.7); and the container f64 helpers + `list_set_num`, `list_append_num`, `list_rewrite_num`, + `dict_value_set_num`, `dict_value_rewrite_num`, `list_get_num`, + `dict_value_get_num` (renamed `_f64`). +- clang 18.1.3, `-fsyntax-only -ferror-limit=0 + -Werror=implicit-function-declaration` plus `tools/werror_flags.txt`, one + translation unit at a time. The three configurations take their TU sets + from the Makefile at run time (`make print-`): + - `server-db`: every `src/*.c` (41 TUs), all extensions on; + - `release`: `HOSTED_SOURCES` (29 TUs), gfx on, http/model/db off; + - `freestanding`: `SOURCES` minus `CLI_ONLY` (23 TUs), `-ffreestanding + -DEIGENSCRIPT_FREESTANDING=1`, every extension off. +- The generated `lsp_stdlib_index.h` is produced into the scratch copy + (`tools/gen_lsp_stdlib_index.sh /lsp_stdlib_index.h`), so + `eigenlsp.c` compiles. +- An error line, and each macro-expansion note under it, is mapped back to + the unmutated copy's line (difflib). A site is **flagged** when its + file:line carries an error. + +**Results** (the unmutated copy first, as the control): + +``` +base: cfg=server-db tus=41 errors=0 unparsed_failures=0 + cfg=release tus=29 errors=0 unparsed_failures=0 + cfg=freestanding tus=23 errors=0 unparsed_failures=0 +R: cfg=server-db tus=41 errors=2756 unparsed_failures=0 + cfg=release tus=29 errors=2293 unparsed_failures=0 + cfg=freestanding tus=23 errors=1740 unparsed_failures=0 +inventory sites=1798 (non-JIT 1671, JIT-file 127) +cfg=server-db distinct_flagged_lines=1245 sites_flagged=1416 (non-JIT 1380, JIT-file 36) +cfg=release distinct_flagged_lines=1151 sites_flagged=1315 (non-JIT 1310, JIT-file 5) +cfg=freestanding distinct_flagged_lines=812 sites_flagged=960 (non-JIT 960, JIT-file 0) +UNION: flagged=1416 (non-JIT 1380, JIT-file 36) inside-deleted-definitions=44 not-flagged=338 (non-JIT 247, JIT-file 91) +``` + +The error totals count a header's error once per TU that includes it; +the distinct lines and the sites are what matter. The union equals +`server-db`, because every TU is in it. `release` and +`freestanding` matter for what a build of that configuration forces (a +freestanding build cannot see the JIT, for instance), not for the union. + +**The 338 sites that do not stop compiling, every one classified:** + +| class | sites | why it keeps compiling, and what forces it instead | +|---|---:|---| +| `AST_NUM` | 52 | Under (B) the node kind still means "number literal". Its payload `num` is renamed, so all 7 reads of the literal's value are flagged; a site that only tests the kind is right for both kinds. The critic made the same call. | +| the clamp: `num_guard` 48, `num_guard_named` 4, `EIGS_NUM_MAX` 8 | 60 | A float clamp whose meaning does not change in round 1. R2.2 deletes all three, so every one of these sites stops compiling in that round: a token event of its own. | +| `eigs_value_as_num` | 48 | The embed accessor, used by the embed test harnesses (`embed_smoke.c` 42, `embed_concurrent.c` 6). Q3 decided it converts an int as `lua_tonumber` does, so "this value as a double" is unchanged. Exact ints get `eigs_value_as_int`/`eigs_value_is_int`. | +| `buffer_read_num` | 26 | Buffers are f64 storage (Q2): the read is a float by contract. Of its other 12 sites, 11 share a line with a renamed token and one is inside the deleted `buffer_read_byte`. | +| `strtod` 14, `atof` 1 | 15 | The libc parsers. The lexer's result reaches the renamed `num_val` through `tok_add`, whose store is flagged; the literal's kind changes `tok_add`'s parameter, which forces the call. The JSON, store and trace scalar parsers return `make_num(d)` a few lines on (flagged); trace.c:2324 fills a buffer's f64 storage (Q2). The rest parse model hyperparameters (float), the tape's observer config, and `tape_read.c:368`, which feeds the observer replay a double (`tape_read.c:635`); round 1 observes ints as doubles live and on replay alike (§8 risks), and round 3's change to `observer_slot_record_value`'s parameter forces this line. | +| `num_to_i64_exact` 6, `eigs_num_text` 3 | 9 | Pure helpers over a double, unchanged in meaning; every input reaches them through a renamed reader. N6 changes the formatter's output on purpose (pinned by the N6 rows), not silently. | +| definitions | 38 | Declarations and bodies of the renamed and deleted names themselves. | +| `VAL_NUM_OFFSET` in jit.c | 3 | `offsetof` uses, which the attribute does not reach. A real rename does: renaming `num_` to `f64_` (and the macro) in a further scratch copy gives exactly 3 errors, jit.c:2367, 2368 and 3471. | +| JIT emitter immediates and helpers | 87 | Tag compares (`0xFFF8`/`0xFFF9`/`0xFFFB`/`0xFFFD`) and the `emit_*` helpers. Reviewed per guard in §4.1: an SMI or a `VAL_INT` box fails every consuming guard and bails; the producer emitters keep their float meaning (§4.2). | +| **total** | **338** | | + +So the round-0 headline becomes: **1,416 of 1,798 sites stop compiling** +(1,380 non-JIT, 36 JIT-file), 44 more are inside deleted definitions, and +338 keep a token for the reasons above. None of the 338 changes meaning +without a token event: the ones that change meaning later change it in +R2.2 (the clamp) or round 3 (the observer), each forced then. + ### 2.4 The choice: Alt 1R 1. **It is the only alternative whose missed site is loud by construction.** - 1,488 of 1,773 sites stop compiling until a person decides, site by site, - whether the site admits ints and with what semantics. Alt 2 and Alt 3 - leave 445 type tests and cases plus 484 checked reads compiling with a - widened or lossy meaning. + Measured: 1,416 of 1,798 sites stop compiling until a person decides, + site by site, whether the site admits ints and with what semantics + (§2.3a). Alt 2 and Alt 3 leave 445 type tests and cases plus 484 checked + reads compiling with a widened or lossy meaning. 2. **The JIT argues for it independently.** All three of Alt 2's emitted misreads exist because the emitter checks `type == VAL_NUM` and then loads at a fixed offset (`VAL_NUM_OFFSET`). Under Alt 1R a boxed int has another @@ -235,46 +463,205 @@ to new would reintroduce the silent class (`len` returning `make_float(count)`), so the migration is per site, with the builtin table (§6) deciding each builtin's accessor and the int-fuzz gate (§9) checking it. -### 2.5 The slot layer already mishandles an unknown tag, today - -Nothing produces `0xFFFA` yet, so these paths are dead today. They show what -the **first** SMI producer would do anywhere it is missed, and they are why -round 1 starts by making every slot classifier exhaustive: - -| function | what an SMI slot does today | -|---|---| -| `slot_type` (container.h:92), `eigs_slot_ref` (container.h:98), `slot_bridge_unwrap` (vm.c:784), `slot_truthy` (vm.c:862) | **pointer misread**: "not num/null/bool" is taken to mean heap, so the payload is dereferenced as a `Value *` | -| `vm_slot_lift` (vm.c:826), `slot_to_value` (eigenscript.c:1885) | **silent null**: the int becomes null | -| `obs_slot_observable` (vm.c:1630) and the observe sites | **silently unobserved**: the binding answers from no data | -| `write_slot` (trace.c:2836) | writes ``, an unreplayable marker, so replay falls back to live source | -| `slot_as_double` (vm.c:872) | returns 0, taking the slow path into `slot_bridge_unwrap`, which misreads | -| `slot_type_name` (vm.c:3000) | answers `"num"` (right by accident) | - -Round 1's first commit makes each of these test the SMI tag explicitly and -`abort()` on an unknown tag, instead of guessing heap or null. +### 2.5 The slot classifiers, derived + +Nothing produces `0xFFFA` yet. The first SMI producer meets every function +that classifies a slot, and today those guess: "not a number, null or bool" +is taken to mean heap. What an SMI would do, once one exists: +- **pointer misread**: `slot_type` (container.h:92), `eigs_slot_ref` + (container.h:98), `slot_bridge_unwrap` (vm.c:784), `slot_truthy` + (vm.c:862) dereference the payload as a `Value *`; +- **silent null**: `vm_slot_lift` (vm.c:826) and `slot_to_value` + (eigenscript.c:1885) turn the int into null; +- **silently unobserved**: `obs_slot_observable` (vm.c:1630) answers + "pointer or bool", so the binding answers from no data; +- **unreplayable**: `write_slot` (trace.c:2836) writes ``; +- **slow path into a misread**: `slot_as_double` (vm.c:872) returns 0; +- **right by accident**: `slot_type_name` (vm.c:3000) answers `"num"`. + +Round 0 listed these by hand and gave R1.1 a rule ("every function holding +both `slot_is_num` and `slot_as_ptr`") that the critic showed misses three of +them: `eigs_slot_ref`, `obs_slot_observable` and `slot_type_name`. Round 2 +derives the population instead (§1, check 4, `## Slot classifiers` in the +inventory file): +- **D1 (58)** names `slot_is_num`, `slot_is_numeric` or `slot_as_double`. + All three are renamed or deleted in R1.1, so the compiler stops at every + D1 entry. `slot_type`, `slot_bridge_unwrap`, `slot_truthy`, + `vm_slot_lift`, `slot_to_value`, `write_slot` and every arithmetic and + compare arm are D1. +- **D2 (20) and D3 (23)** name no number test, so nothing forces them. Each + has the reviewed row below. The inventory fails on a D2/D3 entry with no + row and on a row with no entry, and accepts only these dispositions: + - `guarded`: an SMI can reach it and is handled correctly as written (it + skips non-pointers, or tests one exact tag); + - `smi-arm`: R1.1 adds an explicit SMI arm; + - `refuse`: R1.1 makes it abort on an SMI, and on any tag it does not + handle, so a caller missed later fails loudly instead of misreading; + - `not-a-classifier`: it writes bits (a constructor, a bool result) and + classifies nothing. +- **T (67)** only reads a slot's `ValType` (§1). + +The three the critic named are now derived entries: `eigs_slot_ref` (D2, +refuse), `obs_slot_observable` (D3, refuse) and `slot_type_name` (D2, +smi-arm). + +**R1.1's C slot test** (`tests/phase2/slot_layer.c`) reaches the static +classifiers by including the single-file amalgamation (`make amalgamation`, +#397, which already leaves out the CLI's `main`). Its population is the +inventory file's D1/D2/D3 function entries (the file lists them; the test's +generator reads each signature from the source and keeps those whose first +parameter is an `EigsSlot`); it asserts `examined` equals that count and is +above zero. Each +entry is called under ASan with hand-built SMI slots at the boundary values +(0, ±1, ±(2^47 - 1), -2^47): a `refuse` entry must abort (in a forked +child), and every other entry must return without a sanitizer report, with +the int's Value, type name or truthiness where it returns one. This runs in +R1.1, before any program can produce an SMI. + + +| name | disposition | why an SMI is safe there, or what R1.1 does | +|---|---|---| +| `builtins.c:bool_gate_name` | guarded | skips every non-pointer slot (`!slot_is_ptr`); an SMI is never a builtin (D2) | +| `builtins.c:sort_cmp_str` | guarded | reached only after `builtin_sort` proved every element a string (its homogeneity test names `VAL_NUM`, compile-forced) (D2) | +| `builtins_host.c:ls_entry_cmp` | guarded | sorts the string entries `ls` built itself (D2) | +| `container.h:eigs_slot_ref` | refuse | today an immediate double or an SMI is dereferenced as a pointer; every caller tests `slot_is_num` first (compile-forced). R1.1 aborts on any slot that is not a pointer, null or bool, so a caller missed later fails loudly (D2) | +| `eigenscript.c:#define GC_EDGE_TABLE` | guarded | a GC edge exists only for `slot_is_ptr`; an SMI has no edge (D2) | +| `eigenscript.c:env_get_hashed` | guarded | a non-pointer slot goes through `slot_to_value` (compile-forced) and comes back boxed: the lift boxes on purpose (§2.1) (D2) | +| `eigenscript.c:env_get_local_hashed` | guarded | as `env_get_hashed` (D2) | +| `eigenscript.c:gc_collect_at_exit` | guarded | skips every non-pointer slot (D2) | +| `value_slot.h:#define slot_as_heap` | refuse | alias of `slot_as_ptr` (D2) | +| `value_slot.h:slot_as_ptr` | refuse | the raw dereference: R1.1 asserts the heap tag in ASan and debug builds (D2) | +| `vm.c:jit_helper_iter_next` | guarded | a non-pointer state slot returns 1 (bail); its index-kind test `!= VAL_NUM` is compile-forced (D2) | +| `vm.c:obs_slot_value` | guarded | called only after `obs_slot_observable` answered true (pointer or bool) (D2) | +| `vm.c:slot_type_name` | smi-arm | today an SMI reaches the final `return "num"` by accident. R1.1 adds an explicit SMI arm ("num") and aborts on an unknown tag (D2) | +| `vm.c:vm_borrow_scan` | guarded | compares heap slots with the result pointer; an SMI is not heap (D2) | +| `vm.c:vm_builtin_name_for` | guarded | skips every non-heap slot (D2) | +| `vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET` | guarded | a non-pointer target bails (`return 0`); a non-null field is borrowed as its bits, an SMI included (D2) | +| `vm.c:vm_local_lift` | guarded | a non-pointer, non-null slot goes through `slot_to_value` (compile-forced) and is boxed on purpose (D2) | +| `vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK)` | guarded | a non-pointer source takes the error path, which names the type through `slot_type_name` (D2) | +| `vm.c:vm_run_ex/CASE(SLICE_GET)` | guarded | as DESTRUCTURE_UNPACK (D2) | +| `vm.c:vm_slot_value_opaque` | guarded | only a pointer can be a fn or builtin; an SMI answers "not opaque", which is right (D2) | +| `container.h:eigs_slot_adopt` | guarded | decides ownership from what `eigs_container_slot` returned (compile-forced); a small int comes back as an SMI and its box is released (D3) | +| `jit.c:jit_compile_to_thunk/OP_EQ` | not-a-classifier | writes the bool result bits (D3) | +| `jit.c:jit_compile_to_thunk/OP_NEG` | not-a-classifier | the NOT arm writes bool result bits (D3) | +| `jit.c:jit_compile_to_thunk/OP_NULL` | not-a-classifier | the constant arm writes null and bool bits (D3) | +| `jit_smoke.c:run_bool_cases` | not-a-classifier | test harness: expected bool bits (D3) | +| `jit_smoke.c:run_index_bail_cases` | guarded | test harness: an exact null test of a result (D3) | +| `value_slot.h:slot_decref` | guarded | acts only on tag `0xFFFB`; an SMI has no refcount (D3) | +| `value_slot.h:slot_false` | not-a-classifier | constructor (D3) | +| `value_slot.h:slot_from_bool` | not-a-classifier | constructor (D3) | +| `value_slot.h:slot_from_heap` | guarded | maps null and bool Values to their immediates and every other Value to a heap slot, so a `VAL_INT` box stays a box: the lifts depend on that (§2.1) (D3) | +| `value_slot.h:slot_incref` | guarded | as `slot_decref` (D3) | +| `value_slot.h:slot_is_bool` | guarded | exact tag test (D3) | +| `value_slot.h:slot_is_heap` | guarded | exact tag test (D3) | +| `value_slot.h:slot_is_null` | guarded | exact bit test (D3) | +| `value_slot.h:slot_is_ptr` | guarded | exact tag test (D3) | +| `value_slot.h:slot_null` | not-a-classifier | constructor (D3) | +| `value_slot.h:slot_true` | not-a-classifier | constructor (D3) | +| `vm.c:jit_helper_dot_get` | guarded | a non-null field is pushed as its bits; an SMI is a valid stack slot (D3) | +| `vm.c:jit_helper_local_idx_dot_get` | guarded | as `jit_helper_dot_get` (D3) | +| `vm.c:obs_slot_observable` | refuse | answers "pointer or bool", so an SMI is silently unobserved. Its callers test `slot_is_num` first (compile-forced) and must route an SMI into the numeric channel; R1.1 aborts here on an SMI, so a missed caller fails loudly (D3) | +| `vm.c:vm_local_is_null` | guarded | exact null test (D3) | +| `vm.c:vm_run_ex/CASE(DOT_GET)` | guarded | exact null test of a field (D3) | +| `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET)` | guarded | exact null test of a field (D3) | + ### 2.6 The accessor API after round 1 (Alt 1R) ``` -/* slots */ +/* slots (R1.1) */ int slot_is_f64(EigsSlot); /* high16 < 0xFFF8 */ int slot_is_smi(EigsSlot); /* high16 == 0xFFFA */ int slot_is_int(EigsSlot); /* SMI or heap VAL_INT */ int slot_is_number(EigsSlot); /* f64 or int */ EigsSlot slot_from_f64(double); /* the ONE double writer; round 2: canonical NaN */ -EigsSlot slot_from_int(int64_t); /* the ONE int writer; SMI or boxed (canonical) */ - -/* Values */ -Value *make_float(double); +EigsSlot slot_from_int(int64_t); /* the ONE int writer: SMI in range, else a box */ +int slot_f64_value(EigsSlot, double *); /* an immediate double or a VAL_FLOAT + box; 0 for anything else, ints + included. Replaces slot_as_double. */ +int slot_int_value(EigsSlot, int64_t *); /* an SMI or a VAL_INT box */ +#define SLOT_F64_RAW(s) /* was SLOT_NUM_RAW */ +/* container f64 storage helpers (R1.1): list_set_f64, list_append_f64, + list_rewrite_f64, dict_value_set_f64, dict_value_rewrite_f64, + list_get_f64, dict_value_get_f64 (were *_num) */ + +/* Values (R1.2) */ +Value *make_float(double); Value *make_float_permanent(double); Value *make_int(int64_t); +#define VAL_F64_RAW(v) /* member f64_; were VAL_NUM_RAW and num_ */ +#define VAL_F64_OFFSET /* was VAL_NUM_OFFSET (the JIT's fixed-offset load) */ EigsNum eigs_number_arg(const Value *, const char *who); /* int-preserving */ double eigs_float_arg(const Value *, const char *who); /* float-producing: int converts */ int64_t eigs_int_arg(const Value *, const char *who); /* int-requiring: N5 exact rule */ +int eigs_int_arg_range(const Value *, int64_t lo, int64_t hi, + int64_t *out, const char *who); /* N5, then the C range */ +uint8_t eigs_byte_arg(const Value *, const char *who); /* Q1: N5, then 0..255 */ +int eigs_round_arg(const Value *, int *out, const char *who); + /* Q1 continuous: round to nearest, half away + from zero (as Q4's round); non-finite is + refused (N13); finite but outside the C int + range is open: §11 Q7 */ + +/* literals (R1.3) */ +OP_INT_ZERO, OP_INT_ONE, OP_INT_CONST /* appended to OpCode; §2.7 */ +/* AST literal payload `num` and the token's `num_val` become an EigsNum */ ``` Each `_arg` reader also has the list, slot and optional forms of today's checked accessors. +### 2.7 Every meaning change coincides with a token change + +Round 0's order changed meanings with no token change: R1.1 widened +`slot_as_double` with an SMI arm, and R1.3 re-meant `OP_NUM_ZERO`/`OP_NUM_ONE` +as ints. Neither produces a compile error, so a missed caller or a missed +executor (the critic found the leaf evaluator's `OP_NUM_ZERO`/`OP_NUM_ONE` +arms, vm.c:1872-1877) would keep compiling with the old meaning. The rule +now: **a meaning change lands in the same commit as the token change that +stops every affected site**, or it is listed below with the reason no token +exists and the gate that catches a miss instead. + +| meaning change | commit | token change in that commit | a missed site | +|---|---|---|---| +| a slot may hold an int (SMI tag 0xFFFA) | R1.1 | `slot_is_num` -> `slot_is_f64`, `SLOT_NUM_RAW` -> `SLOT_F64_RAW`, `slot_from_num` -> `slot_from_f64`; `slot_is_numeric` deleted; the container helpers `*_num` -> `*_f64` | compile error (D1, 58 entries) | +| "a number from an immediate or a box" (`slot_as_double`) | R1.1 | **deleted**. Its 15 calls (leaf `INDEX_GET` and `ADD/SUB/MUL`, `ARITH_FAST`, `INT_BINOP_R`, `NEG`, `BNOT`, `EQ`, `NE`, `NUM_CMP`) are rewritten with an explicit int decision: the float fast path reads `slot_f64_value` (float only), an int takes the slow path that R1.2/R1.3 give int semantics, and the leaf bails | compile error at all 15 | +| a slot classifier without a number test meets an SMI | R1.1 | none can exist (they name no number token) | the derived D2/D3 table (§2.5): `refuse` entries abort, `smi-arm` entries answer; the inventory fails on an unreviewed entry | +| raw access to a slot's or Value's double | R1.1/R1.2 | the members and macros renamed (`SLOT_F64_RAW`, `VAL_F64_RAW`, `f64_`) | a spelled-out `.d_`/`.num_` is refused by `tools/num_read_check.sh` and by the inventory (BYPASS) | +| a Value number may be an int (`VAL_INT`) | R1.2a | `VAL_NUM` -> `VAL_FLOAT`; `VAL_INT` appended, so `-Werror=switch` stops every default-less ValType switch; the one `default:` (builtins.c:998) is removed in the same commit | compile error | +| the checked readers' contract (number in, double out) | R1.2 | `eigs_num_arg` family, `eigs_slot_num` family and `buf_num_arg` deleted; the replacements name the intent (§2.6) | compile error | +| the number constructors | R1.2 | `make_num` -> `make_float`, `make_num_permanent` -> `make_float_permanent`; `make_int` added | compile error | +| equality, ordering and hashing across kinds | R1.2 | their `VAL_NUM` arms and cross-type test renamed (`values_equal_impl`'s type-mismatch block names `VAL_NUM`; `sort_cmp_num`; `const_hash_value`/`const_equal`) | compile error | +| `VAL_NUM_OFFSET` (the JIT's fixed-offset load) | R1.2 | renamed `VAL_F64_OFFSET` with the member | compile error (jit.c:2367, 2368, 3471; measured) | +| an int literal | R1.3 | **new opcodes `OP_INT_ZERO`, `OP_INT_ONE`, `OP_INT_CONST`, appended** (the opcode-ABI rule, no `EIGS_BYTECODE_ABI` bump); the AST payload `num` and the token's `num_val` renamed to an `EigsNum` in the same commit | the four exhaustive OpCode switches stop compiling (`op_name` chunk.c:337, `op_verify_operands` chunk.c:466, `op_verify_stack_effect` chunk.c:615, `op_stack_effect` compiler.c:305), and `tools/obs_marker_check.sh` requires each new enumerator's `/*obs:NONE*/` marker (`opcode_is_observer_reader`, chunk.c:1302, has a `default:` that correctly answers "not a reader"); the JIT scanner and the leaf scanner refuse an opcode they do not know (their `default:`), so the literal runs interpreted; the interpreter's computed-goto table is the one executor the compiler cannot check, and a missing entry is a NULL jump that crashes the first int-literal row (loud) | +| `OP_NUM_ZERO`, `OP_NUM_ONE` | none | **no meaning change**: they keep pushing float 0.0 and 1.0, so their three executors (interpreter vm.c:3257, JIT emitter jit.c:2797, leaf evaluator vm.c:1872) and two scanners stay correct untouched. The compiler emits them only for a float literal (compiler.c:2073, which reads the renamed payload) | n/a | +| `OP_CONST` | none | **no meaning change**: an int is never an `OP_CONST` operand (`OP_INT_CONST` carries it). Its three executors already push any non-number constant as a box, and the leaf scanner refuses a non-`VAL_FLOAT` constant (renamed test, chunk.c:1090) | a stray int constant is a box: correct, merely slow | +| the byte conversion (wrap modulo 256 -> N5, Q1) | R1.6 | `finite_num_to_byte` deleted (7 calls), and with it `buffer_read_byte` (21 calls in `gfx_fb` and `ppu_render_frame`), replaced by a reader that raises on a non-byte | compile error | +| the observer's numeric channel receives an int | R1.1 (refusal), R1.3 (routing) | `obs_slot_observable` refuses an SMI (D3 `refuse`); its callers are D1 (forced in R1.1) and route an SMI into the numeric channel as a double once ints exist | abort | +| `tape_read.c:368`'s double (the observer replay's input) | round 3 | none in round 1: live and replayed observers both see an int as its double. Round 3 changes `observer_slot_record_value`'s parameter to the numeric kind, which forces this line | n/a in round 1 | +| the embed accessor `eigs_value_as_num` given an int | R1.8 | none, **by decision** (Q3): it converts, like `lua_tonumber`; `eigs_value_as_int`, `eigs_value_is_int` and `eigs_value_new_int` are added | n/a | +| the clamp's removal: NaN and inf become reachable | R2.2 | `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` deleted (74 sites forced: 60, 6 and 8) | compile error | + +**The meaning changes that cannot carry a token**, each with the gate that +catches a miss: +- **The leaf evaluator vs the generic path.** The leaf has no frame and no + `OP_LINE`, so nothing marks it when the generic path's semantics change. + The gate is the leaf differential (§9.2, the `trace` tier): every row runs + with the leaf on and off, and the outputs must be byte-identical. +- **Consumers that assumed a finite double (R2.2).** No token marks code that + merely receives a NaN or an inf after the clamp is gone: + - `values_equal_impl`'s identity shortcut (`if (a == b && ...) return + 1;`) would call a NaN box equal to itself. No program path reaches it + with one float box on both sides today (EQ compares two floats in its + fast path, and container comparisons pass fresh element views; read, + not probed, since no NaN exists yet), so R2.2 excludes floats from the + shortcut as #1417 excluded buffers, and the C slot test calls it with + one NaN box on both sides; + - C casts of a double to an integer type (undefined on NaN/inf): every + builtin argument goes through a §2.6 reader, which refuses a non-finite + value (N13); the internal casts left are the #1746 residue (R2.6); + - the sort comparators: NaN has no order, and the order a sort should + give it is not decided (§11 Q8). + --- ## 3. Measured prototype @@ -341,9 +728,15 @@ The choice rests on §2.3, not on speed. **A measured risk it exposes.** The same loop under the default JIT costs 402 Ir per iteration (42,924,355 against 83,124,355; `[jit] compiled=1`). After -N1, `i` is an int, so the JIT's LT and ADD bail on the SMI every iteration -(§4). Expect at least the interpreter's 685 (+70%) on int loops until round -5's fast paths. +N1, `i` is an int: the JIT scanner stops at the new `OP_INT_ONE` (§2.7), and +the LT and ADD guards bail on the SMI (§4). Expect at least the +interpreter's 685 (+70%) on int loops until round 5's fast paths. + +The leaf evaluator (#366, §4.5) loses int helpers the same way: an int +literal makes its scanner refuse the chunk, and an int argument bails at the +first arithmetic or index op. `define inc(x) as: return x + 1` then takes the +generic call, the round trip #366 measured at about 200 ns per call +(vm.c:1836-1842), until round 5 gives the leaf int arms. The CodSpeed lane's two-sided Ir gate (#1220) will fire on its JIT-tier targets with int loops: `scalar_loop`, `bench_perf`, `bench_dmg_shape`, @@ -355,7 +748,13 @@ must be accepted up front, not discovered. --- -## 4. The JIT +## 4. The JIT and the leaf evaluator + +Three evaluators compute numbers: the interpreter (`vm_run_ex`), the JIT +(`jit_compile_to_thunk`, admitted by `jit_supported_prefix`) and the leaf +evaluator (`vm_leaf_accessor_exec`, admitted by `chunk_scan_leaf_accessor`; +§4.5). The inventory's executor matrix (§1, check 3) lists which of them +implements each opcode. Round 1 needs correctness by bailing; fast paths are round 5. Every consuming guard was read for how it treats a slot whose high 16 bits are @@ -395,17 +794,19 @@ sites (for example `jit_helper_index_get` 17). **Finding: no consuming guard reads SMI tag bits as a double.** Under Alt 2 three would misread a boxed int (§2.3). Under Alt 1R none does. -### 4.2 Producer emitters: these do not bail, they must change +### 4.2 Producer emitters: these do not bail -The emitter writes bits directly, so a guard cannot protect these. A missed -one silently produces a float where the interpreter produces an int: +The emitter writes bits directly, so a guard cannot protect these. Round 0 +re-meant two of them; round 2 changes none of their meanings, so none can be +missed (§2.7): | emitter | today | round 1 | |---|---|---| -| `OP_NUM_ZERO`/`OP_NUM_ONE` (2797-2814) | pushes the double bits of 0.0 and 1.0 | The compiler (compiler.c:2071-2077) emits these for any literal `== 0.0` or `== 1.0`, so `0` and `0.0` share an opcode. Round 1 makes them mean int 0 and 1: the interpreter (vm.c:3257) and the emitter push SMI bits; `0.0` and `1.0` go through `OP_CONST`. | -| `OP_CONST` (2816-2838) | `VAL_NUM`: the bits of `num_`; else pushes a `TAG_HEAP` pointer plus an incref | An int constant would be pushed boxed, breaking the canonical form. Compute the bits with `slot_from_int` at compile time: SMI immediate, or `TAG_HEAP` for an int64 outside the SMI range. `last_imm` (4375) must then be 1 exactly when the pushed bits are immediate, never for a boxed int: the jit skill's lockstep rule. | +| `OP_NUM_ZERO`/`OP_NUM_ONE` (2797-2814) | pushes the double bits of 0.0 and 1.0 | **Unchanged: they keep meaning float 0.0 and 1.0** in all three executors (this emitter, the interpreter vm.c:3257, the leaf vm.c:1872-1877). Today the compiler (compiler.c:2073-2074) emits them for any literal `== 0.0` or `== 1.0`, so `0` and `0.0` share an opcode; from R1.3 the compiler emits them only for a float literal, and `0`/`1` become the new `OP_INT_ZERO`/`OP_INT_ONE`. | +| `OP_CONST` (2816-2838) | `VAL_NUM`: the bits of `num_`; else pushes a `TAG_HEAP` pointer plus an incref | **Unchanged**: an int is never an `OP_CONST` operand. Its `VAL_NUM` test is renamed `VAL_FLOAT` (forced), and `last_imm` (4375) stays 1 exactly for a float constant. | +| `OP_INT_ZERO`/`OP_INT_ONE`/`OP_INT_CONST` (new, R1.3) | none | **Refused by the scanner** (its `default:`), so an int literal ends the compiled prefix and runs interpreted. Round 5 emits them: SMI bits computed by `slot_from_int` at compile time, or a `TAG_HEAP` box for an int64 outside the SMI range; `last_imm` is then 1 exactly when the bits are immediate (the jit skill's lockstep rule). | | BAND/BOR/BXOR/SHL/SHR (3716-3768), BNOT (3819-3830) | double operands, cvttsd2si, op, cvtsi2sd: a **double** result | N8 makes bitwise results ints. Round 1: **the scanner refuses these opcodes** (the op interprets) until round 5 emits SMI results. | -| MOD (3511-3585) | `call fmod`, which truncates toward zero | N4 makes `%` floor modulo (sign of the divisor), so fmod is wrong for mixed-sign floats (`-7.5 % 2` gives -1.5; Lua gives 0.5). Round 1: the scanner refuses MOD, or the emitter adds the floor correction. | +| MOD (3511-3585) | `call fmod`, which truncates toward zero | N4 makes `%` floor modulo (sign of the divisor), so fmod is wrong for mixed-sign floats (`-7.5 % 2` gives -1.5; Lua gives 0.5). Round 1: **the scanner refuses MOD** (§8 R1.3; the MAP's `N4.fn-floor-mod` witness expects it); round 5 may emit the floor correction. | ### 4.3 For round 2 (N11/N12) @@ -425,6 +826,63 @@ decref at the following POP: one leak per iteration (the #231 shape). differs only in the tag bits, so a guard that compared the wrong bits would fail. The jit skill's wide-bit rule applies. +### 4.5 The leaf evaluator (`vm_leaf_accessor_exec`, #366) + +**What it is.** `chunk_scan_leaf_accessor` (chunk.c:1072-1134) runs once per +compiled function (compiler.c:2703 and 2767). It flags a chunk `leaf_accessor` when the body is one +side-effect-free expression over the parameters ending in `RETURN`: at most +128 bytes of code, at most 8 parameters, stack depth at most 8, no +defaulted parameters, and only +the 11 opcodes `LINE`, `CONST` (a `VAL_NUM` constant only), `NUM_ZERO`, +`NUM_ONE`, `GET_LOCAL` (a parameter), `LOCAL_DOT_GET`, `INDEX_GET`, `ADD`, +`SUB`, `MUL`, `RETURN`; its `default:` refuses everything else. An +exactly-fed call to such a chunk is then computed by +`vm_leaf_accessor_exec` (vm.c:1856-1971) against the caller's stack, with no +frame, no env, no `OP_LINE` and no dispatch. Its contract: return 1 with the +generic call's stack effect, or return 0 having touched nothing, and the +generic path re-executes. + +**Where it runs.** Both call paths try it before the generic call: +`CASE(CALL)` (vm.c:4253) and `jit_helper_call` (vm.c:2503, the JIT's calls). +The gate is `!g_sandbox_active && leaf_accessor && argc == param_count && +!g_trace_hist`. So it computes `define sq(x) as: return x * x` and +`one of 7` in **every** tier, `EIGS_JIT_OFF=1` included. Probed on the main +binary: 200 calls of a leaf `sq` leave its chunk with no entries at all in +`EIGS_JIT_HOT` under all three tiers (the leaf path never counts an entry; +both generic paths do, vm.c:2617 and vm.c:4353). + +**It is off under `EIGS_TRACE`.** `g_trace_hist` is set while recording, so a +recorded run computes every leaf call on the generic path and a live run +computes it in the leaf. Probed: the same program records `sq` with 200 +generic entries (`jit yes`, `adv RET`). A recorded run and a live run +therefore execute different evaluators. That is correct only while the two +agree on every value, so it gets a gate: the `trace` tier of §9.2 runs every +row with the leaf off and requires byte-identical output. Round 1 keeps the +leaf off under trace (the tape records every line, and the leaf skips +`OP_LINE`). + +**Every arm** (vm.c line, today, round 1): + +| arm | today | round 1 | +|---|---|---| +| `LINE` (1863) | skips the operand | unchanged | +| `CONST` (1866) | `slot_from_num(VAL_NUM_RAW(constant))`; the scanner admitted only a `VAL_NUM` constant (chunk.c:1090) | renamed `slot_from_f64(VAL_F64_RAW(...))`; the scanner's test becomes `!= VAL_FLOAT`, so an int constant is refused (it is an `OP_INT_CONST` anyway) | +| `NUM_ZERO` (1872), `NUM_ONE` (1875) | `slot_from_num(0.0)` / `(1.0)` | renamed `slot_from_f64`; **meaning unchanged** (float 0.0/1.0) | +| `OP_INT_ZERO/ONE/CONST` | do not exist | **not admitted**: the scanner's `default:` refuses the chunk, so an int literal sends every call down the generic path. Round 5 adds scanner and evaluator arms together (the inventory requires both directions) | +| `GET_LOCAL` (1878) | borrows the argument slot | unchanged (an SMI argument is a valid slot) | +| `LOCAL_DOT_GET` (1883) | the target must be a pointer to a dict, else bail; a missing field is null; a field is borrowed as its bits | unchanged: an SMI field is borrowed as an SMI (§2.5 row `guarded`) | +| `INDEX_GET` (1907) | the index through `slot_as_double` (an immediate or a boxed `VAL_NUM`) then `vm_index_is_int`; a list element is borrowed; a buffer element is `slot_from_num(buffer_read_num(...))` | `slot_as_double` is deleted (R1.1), so this arm stops compiling. It reads the index with `slot_f64_value` and **bails on an int index**; the buffer element is `slot_from_f64` (Q2: f64 storage). Round 5 adds the SMI index | +| `ADD`/`SUB`/`MUL` (1933) | both operands through `slot_as_double`; `r = a op b`; the underflow flag for MUL (#1079); `slot_from_num(num_guard(r))` | stops compiling (R1.1). Reads with `slot_f64_value` and **bails unless both operands are floats**, so an int or mixed operation runs on the generic path with N2/N3/(A) semantics. Round 5 adds int arms whose overflow bails (never raises inside the leaf: the generic path raises with the caller's line). R2.2 deletes `num_guard` here with the others | +| `RETURN` (1957) | increfs the result, pops args and fn, pushes the result | unchanged (`slot_incref` ignores an SMI) | +| `default` (1966) | unreachable; returns 0 | unchanged | + +**Its witness.** No counter exists for the leaf. The design uses the hot-chunk +table instead of adding one (§9.2): both generic call paths count an entry +and the leaf never does, so "the callee has no entries in the normal run, and +K entries in the leaf-off (`trace`) run" proves that all K calls were +computed by the leaf. Probed on main: `sq` absent with the leaf on, `sq +200` with it off. + --- ## 5. N12 and SMI share the NaN space @@ -486,24 +944,31 @@ exactly as an int. That is the path the bar critic found missing: payload `string.byte`. - Rounding (§6.7): "math.ceil, math.floor, and math.modf return an integer when the result fits in the range of an integer, or a float otherwise". - `round` has no Lua counterpart and follows floor and ceil (§11, Q4). + `round` has no Lua counterpart and follows floor and ceil (Q4, + decided: half away from zero, an int when it fits int64). - **float-producing:** ints convert to float and the result is a float. Examples: Lua's `math.sin`, `sqrt`, `log`, `exp`; `/` and `^`, which "always convert integer operands to floats" (§3.4.1); and the float-tensor and audio-sample builtins (buffer storage is float). -- **int-requiring:** an argument is an index, count, size, code or bit - pattern, so it converts by N5's exact rule. Examples: Lua's string - positions, `table.insert`/`table.remove` positions, bitwise operands - (§3.4.2), `math.random(m, n)` bounds, and `math.randomseed`. +- **int-requiring:** an argument is integer-valued, so it converts by N5's + exact rule, then the C type's range: an index, count, size, code, bit + pattern, byte value, handle, port or seed (Q1, decided: the parameter's + meaning decides, not the C type). Examples: Lua's string positions, + `table.insert`/`table.remove` positions, bitwise operands (§3.4.2), + `math.random(m, n)` bounds, `math.randomseed`, and `string.char`, which + raises on `65.5` and on `256` (probed, 5.4.9). - **other:** everything else that takes or returns numbers: - formatting (N6); - JSON, store and db codecs (N13, N14); - parsing (`num`, N10); - `type` ((B)); - - byte consumers (truncate and wrap modulo 256, documented - eigenscript.h:1901); - - C-API arguments that truncate today: gfx coordinates, audio rates, - `usleep`. Their N5 scope is open: §11, Q1. + - continuous parameters (Q1, decided): gfx coordinates and sizes, colour + channels, durations and audio gain accept an int or a float. Where the + C API needs an int, `eigs_round_arg` rounds to nearest (half away from + zero, as `round`), replacing today's truncation toward zero, which gets + negative coordinates wrong; a finite value outside the C range is §11 + Q7, still open. (Byte consumers, which truncated and + wrapped modulo 256 here in round 0, are int-requiring under Q1.) **The `loss` column.** `LOSS` marks a builtin whose *current* body reads its argument through a double accessor, or builds its result from a computed @@ -516,9 +981,35 @@ formatter or equality (`print`, `str`, `join`, `list_contains`) are `-`, because their exactness change happens once, in `eigs_num_text` or `values_equal_impl`. +Two consequences of the definition, made explicit in design round 2: +- **The Q1 rows are not LOSS.** A byte, a count, a handle, a port or a C + `int` is range-checked after the exact rule, and every int beyond 2^53 is + outside every such range, so the double path cannot return a wrong + in-range value: it raises either way. What WAS lossy beyond 2^53 is the + modulo-256 wrap the byte consumers did, and Q1 deletes it. Seeds are the + exception (a seed's range is all of int64), so `seed_random` and + `task_sched_seed` stay LOSS. +- **A writer that loses digits of a double is LOSS even without ints.** + `store_put`/`store_update` (the record encoder's `%.15g`) and + `db_execute`/`db_query_json`/`db_query_value` (the parameter binder's + `%g`) lose digits on main and on the tag today, filed as + [#1762](https://github.com/InauguralSystems/EigenScript/issues/1762). + Round 0 missed them; the critic found them. R1.7, N14's int half, fixes + both writers by routing them through the one N6 number writer: + `store_json_encode` (ext_store.c:184-202) writes an int as exact digits + and a float as its shortest round-trip repr, replacing the int32 `%d` arm + and `%.15g`; `db_build_query` (ext_db.c:57-58) binds the same text + instead of `"%g"`. N13's refusal of a non-finite value stays inside the + encoder (R2.3). If #1762 lands on main first (it does not depend on ints), + R1.7 inherits the fix and only adds the int arm. Its MAP entries are the + row `N14.store-exact-digits` and the gate `gate.N14.db-param-exact`. + **Counts** (from the table below, checked by `tools/phase2_inventory.py`, -which prints them): 229 numeric builtins. By class: 37 int-preserving, 58 -float-producing, 67 int-requiring, 67 other. 39 are LOSS: +which prints them): 230 numeric builtins (`ppu_render_frame` joined when +`buffer_read_byte` entered the vocabulary). By class: 37 int-preserving, 58 +float-producing, 84 int-requiring, 51 other. The decided Q1 moved 16 rows +from other to int-requiring (counts, byte values, handles, flags and +selectors), and `ppu_render_frame` is a new int-requiring row. 42 are LOSS: - arithmetic: `abs`, `add`, `subtract`, `multiply`, `negative`, `sum`, `num_copy`; - min/max and rounding: `min`, `max`, `floor`, `ceil`, `round`; @@ -531,6 +1022,9 @@ float-producing, 67 int-requiring, 67 other. 39 are LOSS: - store keys: `store_get`, `store_delete`, `store_update`, plus `store_query` and `db_query_value`, which decode integer text with `strtod`; +- writers that drop digits today (#1762): `store_put` (and `store_update`) + through `%.15g`, `db_execute` and `db_query_json` (and `db_query_value`) + through `%g`; - JSON and parsing: `json_decode`, `json_path`, `num`, `json_encode`, `json_build`. @@ -541,8 +1035,9 @@ current state behind several rows: - `9007199254740993 == 9007199254740992` is `true`: the lexer rounds. - `store_get of [s, "c", 1.9]` finds record `"1"` (a silent truncating key). - `store_get of [s, "c", 4294967297]` returns `null`, because the `(int)` - cast is out of range (a pre-existing defect, reported for filing; out of - scope here). + cast is out of range (a pre-existing defect, filed as + [#1760](https://github.com/InauguralSystems/EigenScript/issues/1760); R1.6's + `eigs_int_arg` for the key closes it if it is still open then). | builtin | class | loss | note | @@ -555,27 +1050,27 @@ current state behind several rows: | `assert` | other | - | message via value_to_string (N6) | | `atan` | float-producing | - | Lua math.atan | | `atan2` | float-producing | - | Lua math.atan(y, x) | -| `audio_capture_open` | other | - | freq/channels truncated to C int (Q1); returns a device id | +| `audio_capture_open` | int-requiring | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | | `audio_envelope` | float-producing | - | float samples; times in seconds | | `audio_gain` | float-producing | - | float samples | | `audio_mix` | float-producing | - | float samples | -| `audio_music_play` | other | - | loop count truncated to C int (Q1) | -| `audio_music_volume` | other | - | volume truncated to C int (Q1) | +| `audio_music_play` | int-requiring | - | loop count: N5, then the C int range (Q1) | +| `audio_music_volume` | other | - | volume is a gain: continuous, rounds to nearest for the C int API (Q1) | | `audio_noise` | float-producing | - | float samples | -| `audio_open` | other | - | freq/channels truncated to C int (Q1); returns a device id | -| `audio_pause` | other | - | flag truncated to C int | +| `audio_open` | int-requiring | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | +| `audio_pause` | int-requiring | - | the pause flag is discrete, not continuous: N5 (Q1; today `(int)0.5` silently un-pauses) | | `audio_play` | other | - | float samples in; returns a channel number | -| `audio_play_loop` | other | - | loop count truncated to C int (Q1); returns a channel | +| `audio_play_loop` | int-requiring | - | loop count: N5, then the C int range (Q1); returns a channel | | `audio_queue_size` | int-preserving | - | byte count (computed in a double, below 2^53) | | `audio_saw` | float-producing | - | float samples | | `audio_sine` | float-producing | - | float samples | | `audio_square` | float-producing | - | float samples | | `audio_stop` | int-requiring | - | channel number | -| `audio_stream_open` | other | - | freq/channels truncated to C int (Q1); returns a device id | +| `audio_stream_open` | int-requiring | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | | `audio_stream_push` | other | - | float samples quantized to int16 | | `audio_stream_queued` | int-preserving | - | sample count | -| `audio_sweep` | float-producing | - | float samples; wave selector truncated | -| `audio_volume` | other | - | channel index plus a float volume | +| `audio_sweep` | float-producing | - | float samples; frequencies, duration and amplitude are continuous; the wave selector is integer-valued: N5 (Q1) | +| `audio_volume` | int-requiring | - | channel index: N5 (Q1); the volume is a float gain | | `bit_and` | int-requiring | LOSS | Lua `&` (§3.4.2): N5 operands, int64-pattern result (N8); today a double result | | `bit_not` | int-requiring | LOSS | Lua unary `~` | | `bit_or` | int-requiring | LOSS | Lua `\|` | @@ -607,40 +1102,40 @@ current state behind several rows: | `close_channel` | int-requiring | - | channel handle ids | | `copy_into` | int-requiring | - | offset; values convert to float storage | | `cos` | float-producing | - | Lua math.cos | -| `db_execute` | other | - | parameter encoding (ext_db) | -| `db_query_json` | other | - | row encoding (ext_db, N14) | -| `db_query_value` | other | LOSS | decodes a numeric column with strtod: integer text beyond 2^53 rounds | +| `db_execute` | other | LOSS | binds every numeric parameter with `%g`, 6 significant digits (ext_db.c:57-58, #1762). R1.7: the N6/N14 writer | +| `db_query_json` | other | LOSS | binds parameters with `%g` (#1762); encodes rows (N14) | +| `db_query_value` | other | LOSS | binds parameters with `%g` (#1762); decodes a numeric column with strtod, so integer text beyond 2^53 rounds | | `dispatch` | int-requiring | - | integer table key, already exactness-checked | | `divide` | float-producing | - | mirrors `/` (Lua §3.4.1: always float) | | `dot` | float-producing | - | buffer dot product | | `eigen_eval_loss` | float-producing | - | token ids are indices; the loss is a float | -| `eigen_generate` | other | - | token ids in and out are ints; temperature and top_p floats | +| `eigen_generate` | int-requiring | - | token ids and max_tokens are integer-valued (N5, Q1); temperature and top_p are floats | | `eigen_model_load` | other | - | parses model JSON numbers with strtod | -| `exec_capture` | other | - | float timeout in seconds; returns exit status ints | -| `exit` | int-requiring | - | exit code (today truncates) | +| `exec_capture` | other | - | the timeout is a duration in seconds (continuous, a float; Q1); returns exit status ints | +| `exit` | int-requiring | - | exit code: N5, then the C int range (Q1) | | `exp` | float-producing | - | Lua math.exp | -| `f64_from_bytes` | other | - | byte consumer (truncate and wrap) into a float; NaN canonical (N12) | +| `f64_from_bytes` | int-requiring | - | 8 byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone); the float result's NaN is canonical (N12) | | `f64_to_bytes` | other | - | float to 8 byte ints; f64_bits (N12) is the int-valued sibling | | `fill` | int-requiring | - | count | | `floor` | int-preserving | LOSS | Lua math.floor: an int when the result fits int64, else a float | | `gather` | int-requiring | - | index or index vector; returns elements unchanged | | `get_at` | int-requiring | - | index, row and col; returns the element | | `get_observer_thresholds` | float-producing | - | observer thresholds (O3 drops h_low) | -| `gfx_circle` | other | - | coordinates and colours truncated to C int (Q1) | -| `gfx_clear` | other | - | colours truncated to C int (Q1) | -| `gfx_clip` | other | - | rect truncated to C int (Q1) | -| `gfx_delay` | other | - | milliseconds truncated to Uint32 (Q1) | -| `gfx_fb` | other | - | dims and scale truncated to C int (Q1) | -| `gfx_line` | other | - | coordinates and colours truncated to C int (Q1) | -| `gfx_open` | other | - | width and height truncated to C int (Q1) | -| `gfx_point` | other | - | coordinates and colours truncated to C int (Q1) | +| `gfx_circle` | other | - | centre, radius and colour are continuous: round to nearest (Q1), replacing truncation | +| `gfx_clear` | other | - | colour channels are continuous: round to nearest (Q1) | +| `gfx_clip` | other | - | the clip rect is continuous: round to nearest (Q1) | +| `gfx_delay` | other | - | milliseconds are a duration: continuous, round to nearest into Uint32 (Q1) | +| `gfx_fb` | int-requiring | - | w and h lay out the pixel buffer (integer-valued: N5, Q1); its elements are palette bytes read through `buffer_read_byte` (N5, then 0..255); dx, dy and scale are drawing coordinates and size (continuous: round to nearest, Q1) | +| `gfx_line` | other | - | endpoints and colour are continuous: round to nearest (Q1) | +| `gfx_open` | other | - | window width and height are gfx sizes: continuous, round to nearest (Q1) | +| `gfx_point` | other | - | position and colour are continuous: round to nearest (Q1) | | `gfx_poll` | int-preserving | - | event fields x, y, scancode, button are ints | -| `gfx_read` | other | - | rect origin truncated; returns channel ints | -| `gfx_rect` | other | - | rect and colours truncated to C int (Q1) | -| `gfx_rrect` | other | - | truncated to C int (Q1) | -| `gfx_text` | other | - | position, colours and scale truncated to C int (Q1) | -| `gfx_text_height` | int-preserving | - | pixel height | -| `gfx_text_width` | int-preserving | - | pixel width | +| `gfx_read` | other | - | the origin is continuous: round to nearest (Q1); returns the channel values as ints | +| `gfx_rect` | other | - | rect and colour are continuous: round to nearest (Q1) | +| `gfx_rrect` | other | - | rect, radius and colour are continuous: round to nearest (Q1) | +| `gfx_text` | other | - | position, colour and scale are continuous: round to nearest (Q1) | +| `gfx_text_height` | int-preserving | - | pixel height, an int; the scale is continuous: round to nearest (Q1) | +| `gfx_text_width` | int-preserving | - | pixel width, an int; the scale is continuous: round to nearest (Q1) | | `gfx_ticks` | int-preserving | - | SDL ticks (Uint32 ms) | | `hex` | int-requiring | LOSS | refuses above 2^53 by a double compare, so int 2^53+1 reads as 2^53 and passes silently | | `http_early_bind` | int-requiring | - | port | @@ -650,7 +1145,7 @@ current state behind several rows: | `http_serve` | int-requiring | - | port | | `http_static` | other | - | formats via value_to_string | | `index_of` | int-preserving | - | byte index or -1 | -| `inflate` | other | - | byte consumer (truncate and wrap) | +| `inflate` | int-requiring | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone) | | `join` | other | - | elements via value_to_string (N6) | | `json_build` | other | LOSS | N14 encoder; reads values through eigs_num_arg (a double) | | `json_decode` | other | LOSS | N14 decoder; integer text decodes through strtod (a double) | @@ -676,7 +1171,7 @@ current state behind several rows: | `monotonic_ms` | float-producing | - | fractional milliseconds | | `monotonic_ns` | int-preserving | LOSS | exact below 2^53 ns (104 days of uptime), a rounded double after; an exact int under N1 | | `multiply` | int-preserving | LOSS | scalar arm mirrors `*` (overflow raises, (A)); buffer arms float | -| `native_train_step_builtin` | other | - | token ids are ints; lr float (a numeric string is accepted through strtod) | +| `native_train_step_builtin` | int-requiring | - | token ids are integer-valued (N5, Q1); lr is a float (a numeric string is accepted through strtod) | | `nearest_in_range` | float-producing | - | geometry floats; the `index` field is an int | | `nearest_in_range_all` | float-producing | - | geometry floats; the `index` field is an int | | `negative` | int-preserving | LOSS | mirrors unary `-`; negating INT64_MIN raises (N4b) | @@ -686,7 +1181,7 @@ current state behind several rows: | `net_listen` | int-requiring | - | port; returns a handle | | `net_port` | int-requiring | - | socket handle; returns a port | | `net_recv` | int-requiring | - | handle and max bytes | -| `net_send` | other | - | byte consumer (truncate and wrap) | +| `net_send` | int-requiring | - | the handle and the byte values: N5, bytes then 0..255 (Q1; the modulo-256 wrap is gone) | | `norm` | float-producing | - | L2 norm | | `num` | other | LOSS | N10 parser: integer text decodes through strtod today (a double) | | `num_copy` | int-preserving | LOSS | copies a number and must keep its subtype; today re-boxes through a double | @@ -697,6 +1192,7 @@ current state behind several rows: | `ord` | int-preserving | - | byte code (Lua string.byte) | | `pi` | float-producing | - | Lua math.pi | | `pow` | float-producing | - | mirrors `^` (Lua §3.4.1: exponentiation is always float) | +| `ppu_render_frame` | int-requiring | - | reads the emulated memory buffer through `buffer_read_byte`: byte values by N5, then 0..255 (Q1; the modulo-256 wrap is gone) | | `print` | other | - | N6 printing via value_to_string | | `proc_read_buf` | int-requiring | - | fd and max bytes; bytes stored as floats | | `random` | float-producing | - | Lua math.random() in [0,1) | @@ -708,7 +1204,7 @@ current state behind several rows: | `read_bytes_buf` | int-requiring | - | cap and length; bytes stored as floats | | `record_history` | other | - | truthiness flag in; previous flag out | | `recv` | int-requiring | - | channel handle ids | -| `recv_timeout` | other | - | channel handle ids; float milliseconds | +| `recv_timeout` | int-requiring | - | the channel handle: N5 (Q1); milliseconds are a duration (continuous, a float) | | `relu` | float-producing | - | ML activation (float tensors; no Lua counterpart) | | `reshape` | int-requiring | - | rows and cols | | `round` | int-preserving | LOSS | no Lua counterpart; follows floor and ceil (Q4) | @@ -741,11 +1237,11 @@ current state behind several rows: | `store_drop` | int-requiring | - | handle and page ids | | `store_get` | int-requiring | LOSS | same key cast as store_delete; decodes records (N14) | | `store_open` | int-preserving | - | handle dict with int id/gen fields | -| `store_put` | other | - | N13/N14 encoder; refusal belongs inside the encoder | +| `store_put` | other | LOSS | the record encoder writes a non-int32 number with `%.15g`: 1234567890123456 is stored as 1234567890123460 and 0.1 + 0.2 as 0.3, on main and the tag (#1762). R1.7: the N6/N14 writer; R2.3: refusal inside the encoder | | `store_query` | other | LOSS | decodes records; integer text through strtod (N14) | -| `store_update` | other | LOSS | same key cast as store_delete; N13/N14 encoder | +| `store_update` | other | LOSS | same key cast as store_delete; re-puts through the `%.15g` encoder (#1762); N13/N14 | | `str` | other | - | N6 printing via value_to_string | -| `str_from_bytes` | other | - | byte consumer (truncate and wrap) | +| `str_from_bytes` | int-requiring | - | byte values: N5, then 0..255 (Q1; Lua string.char raises on 65.5 and on 256) | | `stream_open` | int-requiring | - | element count, already floor-checked | | `stream_write` | float-producing | - | writes a raw f64 | | `substr` | int-requiring | - | start and length (Lua string.sub) | @@ -759,7 +1255,7 @@ current state behind several rows: | `task_sched_seed` | int-requiring | LOSS | `(int64_t)` of a double | | `task_self` | int-preserving | - | task handle | | `task_send` | int-requiring | - | task handle | -| `task_sleep` | other | - | float milliseconds | +| `task_sleep` | other | - | milliseconds are a duration: continuous, a float (Q1) | | `task_spawn` | int-preserving | - | returns a task handle | | `tensor_load` | float-producing | - | float tensor; shape ints | | `tensor_save` | float-producing | - | writes float cells | @@ -770,10 +1266,10 @@ current state behind several rows: | `token_name` | int-requiring | - | token id | | `try_recv` | int-requiring | - | channel handle ids | | `type` | other | - | `type of` an int or a float is "num" ((B)) | -| `usleep` | other | - | microseconds truncated to C int (Q1) | +| `usleep` | other | - | microseconds are a duration: continuous, round to nearest (Q1) | | `vm_run_bytecode` | int-requiring | - | opcode bytes and ABI numbers | | `write` | other | - | N6 printing | -| `write_bytes` | other | - | byte consumer (truncate and wrap); returns bytes written | +| `write_bytes` | int-requiring | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone); returns bytes written | | `zeros` | int-requiring | - | size or [rows, cols]; elements are float 0.0 | | `zeros_like` | float-producing | - | float zeros | @@ -796,13 +1292,26 @@ numbers are at `0740af03`. - lexer.c:717-753 (number lexing, hex accumulates in a double today); the token's `num_val` (eigenscript.h:188); - parser.c:791 (`TOK_NUM` to `AST_NUM`, `data.num`); - - compiler.c:2071-2077 (`AST_NUM` emission, `NUM_ZERO`/`NUM_ONE`, - `add_num_constant`) and compiler.c:2929/2985/3030 (index fast paths read + - compiler.c:2071-2077 (`AST_NUM` emission, reading the renamed payload): + from R1.3 an int literal emits the new `OP_INT_ZERO`/`OP_INT_ONE`/ + `OP_INT_CONST`, and a float literal keeps `OP_NUM_ZERO`/`OP_NUM_ONE`/ + `OP_CONST` (§2.7); compiler.c:2929/2985/3030 (index fast paths read `data.num`); + - vm.h `OpCode` (the three opcodes appended, each `/*obs:NONE*/`), and the + exhaustive switches that must name them: `op_name` (chunk.c:337), + `op_verify_operands` (chunk.c:466), `op_verify_stack_effect` + (chunk.c:615), `op_stack_effect` (compiler.c:305); the interpreter's + dispatch table (vm.c:3091) and three new CASEs; `tests/test_opcode_abi.c`; - chunk.c:193-260 (constant pool dedup: `const_hash_value`, `const_equal`, `chunk_add_constant_ex`, which must key on kind and bits); - - vm.c:3238 `CASE(CONST)` and 3257 `CASE(NUM_ZERO)`/`NUM_ONE`; - - jit.c:2797/2816 (producer emitters, §4.2); + - vm.c:3238 `CASE(CONST)` and 3257 `CASE(NUM_ZERO)`/`NUM_ONE`: renamed, + float meaning unchanged; + - the JIT: the scanner refuses the new opcodes in round 1 (round 5 emits + them); its `NUM_ZERO`/`NUM_ONE`/`CONST` emitters (jit.c:2797/2816) keep + their float meaning (§4.2); + - the leaf evaluator: its scanner refuses the new opcodes (chunk.c:1129, + the `default:`); its `CONST`, `NUM_ZERO` and `NUM_ONE` arms + (vm.c:1866-1877) keep their float meaning (§4.5); - lint.c, lint_host.c and eigenlsp.c (the `AST_NUM` type knowledge, 34 sites); - `src/freestanding/mini_strtod.c`; @@ -829,7 +1338,10 @@ numbers are at `0740af03`. - builtins_tensor.c `op_add`, `op_sub`, `op_mul` and `tensor_elementwise` (the scalar arms of `add`, `subtract`, `multiply`), plus `sum` and `shared_incr`; - - JIT bails (§4.1). + - JIT bails (§4.1); + - the leaf's `ADD`/`SUB`/`MUL` arm (vm.c:1933-1956): bails unless both + operands are floats in round 1, so int, mixed and overflowing operations + take the generic path (§4.5). - **N4 (`/` float; `//` new; `%` floor; division by zero):** - vm.c:3407 `CASE(DIV)` (int/int gives a float) and 3432 `CASE(MOD)` (fmod becomes floor-mod; int by zero raises); @@ -853,11 +1365,18 @@ numbers are at `0740af03`. faults on x86. - **N5 (float-to-int by the exact rule wherever an int is needed):** - eigenscript.h:1910 `num_to_i64_exact` (#1740); - - every int-requiring row of §6, through `eigs_int_arg`; + - every int-requiring row of §6, through `eigs_int_arg` (with + `eigs_int_arg_range`, `eigs_byte_arg` for Q1's integer-valued + parameters; `eigs_round_arg` for its continuous ones); - vm.c index paths (`jit_helper_index_get`/`set`, `CASE(INDEX_*)`) and `range_bound` (builtins.c:3877); - the JIT `OP_INDEX_SET` integrality guard (jit.c:4100-4112) stays - correct, because a non-exact index goes to the helper. + correct, because a non-exact index goes to the helper; + - the leaf's `INDEX_GET` arm (vm.c:1907-1931): in round 1 it bails on an + int index (the generic path applies N5), and a float index still goes + through `vm_index_is_int`; + - `buffer_read_byte` and `finite_num_to_byte` (Q1 byte values), deleted + in R1.6 (§2.7). - **N6 (printing):** - eigenscript.c:2938 `eigs_num_text` (today integral doubles below 2^53 print without `.0`) and 2957 `value_to_string`; @@ -885,14 +1404,20 @@ numbers are at `0740af03`. radix prefixes, int or float result). - **N11 (IEEE doubles; strict becomes opt-in):** - eigenscript.h:1876 `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` and - `STRICT_DOMAIN`: the 73 GUARD and clamp sites of (c); + `STRICT_DOMAIN`: the 74 clamp sites (`num_guard` 60, `num_guard_named` + 6, `EIGS_NUM_MAX` 8); - builtins_tensor.c `op_sqrt` (711) and `op_log_safe` (729); - builtins.c `asin`/`acos` domain; - state.c:62 `st->strict` defaults to 1 and must become opt-in; - - jit.c:2634 `max_normal_bits`. + - jit.c:2634 `max_normal_bits`; + - the leaf's `num_guard(r)` (vm.c:1954), deleted with the others; + - the consumers no token marks (§2.7): `values_equal_impl`'s identity + shortcut (eigenscript.c, first line of the function) must not call a + NaN box equal to itself; the sort comparators (NaN order: §11 Q8). - **N12 (canonical NaN; payload fidelity through ints):** - value_slot.h:73 `slot_from_num`, becoming `slot_from_f64`: the single - writer; + writer, including the leaf's five calls (vm.c:1869, 1873, 1876, 1927, + 1954), so a NaN the leaf computes is canonical too; - the JIT NaN bails (§4.3); - new `f64_bits`/`f64_from_bits` and buffer bits accessors; - builtins_buf.c `f64_from_bytes` and `f64_to_bytes`; @@ -902,8 +1427,8 @@ numbers are at `0740af03`. - ext_store.c's encoder: the #1746 residue is `store_nonfinite_scalar` (ext_store.c:278 on the experiment), which must be deleted in favour of refusal inside the encoder; - - the byte encoders (`finite_num_to_byte`, eigenscript.h:1901) and the - `buf_to_pcm16le` quantizer; + - the byte encoders (`eigs_byte_arg`, which replaces `finite_num_to_byte` + and `buffer_read_byte` in R1.6) and the `buf_to_pcm16le` quantizer; - every int conversion (`eigs_int_arg`, `num_to_i64_exact` callers); - the tape writers record, not refuse. - **N14 (JSON):** @@ -929,7 +1454,16 @@ numbers are at `0740af03`. - eigsdap.c; - docs/TRACE.md (bump plus the compat decision, #411); - the `O cfg` record (trace.c:1577-1584 writes `h_low`; tape_read.c:389 - reads it). O3 drops it in round 3. + reads it). O3 drops it in round 3; + - the leaf evaluator is off while recording (`g_trace_hist`, vm.c:2505 + and vm.c:4255), so a tape always holds the generic path's values; the + `trace` tier (§9.2) gates that the live leaf agrees; + - the Done-when's "record twice and replay strict byte-identically" for + int, float, inf and NaN programs: rows `T1.twice-int` (R1.3), + `T1.twice-float` (R1.7, N6's text), `T1.twice-inf` and `T1.twice-nan` + (R2.5). Each records one deterministic program twice, requires + byte-identical tapes, and replays strict against the live (leaf-on) + output. - **O1-O4 (observer, round 3):** - eigenscript.c:698 `observer_slot_record_value`, 804 `observer_slot_update_num`, the `obs_num_*` predicates (935-1193) and @@ -943,6 +1477,21 @@ numbers are at `0740af03`. - the `O cfg` record; - tools/observer_oracle/score.py (the IEEE mode and `--floor` from the oracle PR). +- **The leaf evaluator, arm by arm** (vm.c:1856-1971, scanner + chunk.c:1072-1134; every arm is in §4.5): + - `CONST` (1866), `NUM_ZERO` (1872), `NUM_ONE` (1875): N1, float + literals only; the renamed writer `slot_from_f64` (N12); int literals + are refused by the scanner (§2.7); + - `GET_LOCAL` (1878), `LOCAL_DOT_GET` (1883): borrow any slot, an SMI + included (§2.5, `guarded`); + - `INDEX_GET` (1907): N5 (index exactness), Q2 (a buffer element is an + f64); bails on an int index in round 1; + - `ADD`/`SUB`/`MUL` (1933): N3, (A), N2's float half, #1079's underflow + flag, N11 (`num_guard` goes in R2.2), N12 (canonical NaN through + `slot_from_f64`); bails unless both operands are floats in round 1; + - `RETURN` (1957): unchanged; + - the gate `!g_trace_hist` (vm.c:2505, vm.c:4255): T1, and the `trace` + tier of §9.2. --- @@ -950,84 +1499,115 @@ numbers are at `0740af03`. Every commit builds, passes the full suite, and carries its own MAP rows. "Unchanged" means a differential against the baseline binary captured -before the commit (the verify-and-fix rule), not "the suite passed". +before the commit (the verify-and-fix rule), not "the suite passed". Every +meaning change lands in the commit that carries its token change (§2.7). ### Round 1: the core model (Alt 1R) -1. **R1.1, the slot layer becomes exhaustive (no producer yet).** - - Add `TAG_SMI`, `slot_is_smi`, `slot_from_int` and `slot_smi_val` in - value_slot.h. - - Every slot classifier in §2.5 gets an explicit SMI arm and aborts on an - unknown tag. - - `slot_as_ptr` asserts the heap tag in ASan and debug builds. - - Test: a C unit test (`tests/phase2/slot_layer.c`) builds SMI slots by - hand and drives every classifier. Before the commit it crashes or - misreads; after, it answers. Language behaviour is unchanged - (differential over the suite's `.eigs` corpus). - - Risk: a classifier the test does not enumerate. Its list is derived - from the inventory: every function holding both `slot_is_num` and - `slot_as_ptr`. +1. **R1.1, the slot layer: the SMI exists, every slot reader is forced (no + producer yet).** + - Add `TAG_SMI`, `slot_is_smi`, `slot_from_int`, `slot_smi_val`, + `slot_f64_value` and `slot_int_value` (§2.6). + - The token changes of this commit: `slot_is_num` -> `slot_is_f64`, + `SLOT_NUM_RAW` -> `SLOT_F64_RAW`, `slot_from_num` -> `slot_from_f64`, + the container helpers `*_num` -> `*_f64`; `slot_is_numeric` deleted; + **`slot_as_double` deleted**. Its 15 calls are rewritten with an + explicit int decision: the arithmetic and compare arms take their float + fast path through `slot_f64_value` and send anything else to the slow + path; the leaf evaluator's `INDEX_GET` and `ADD`/`SUB`/`MUL` arms bail + on anything that is not a float. + - The D2/D3 dispositions (§2.5): `eigs_slot_ref`, `obs_slot_observable`, + `slot_as_ptr` and `slot_as_heap` refuse an SMI (abort; `slot_as_ptr` + in ASan and debug builds); `slot_type_name` gains its SMI arm. Every D1 + function gets its SMI arm as the compiler stops at it. + - `tools/phase2_check.sh` (§9.2) lands here with its calibration, and + runs the rows whose round has landed. + - Test: the C slot test (§2.5), through the amalgamation, built from the + inventory's D1-D3 list and run under ASan; plant 1 (§9.3). Language + behaviour is unchanged (differential over the suite's `.eigs` corpus), + because nothing produces an SMI yet. 2. **R1.2, the Value layer and the renames (deprecate, then delete).** - - R1.2a: `VAL_INT` (appended), `make_int`, the §2.6 accessors and + - R1.2a: `VAL_INT` (appended), `make_int`, the §2.6 readers and `val_type_name(VAL_INT) = "num"`. **Delete the `default:` arm of `eigs_json_encode_value` (builtins.c:998)**, enumerating the types, so `-Werror=switch` reaches the last switch that could absorb `VAL_INT` - silently. The old names stay, marked - `__attribute__((deprecated))`; macros are routed through a deprecated - inline. + silently. The old names stay, marked `__attribute__((deprecated))`; + macros are routed through a deprecated inline. - R1.2b-n: one commit per file group (vm.c; builtins.c; tensor; buf; host; gfx; net/http/db/model; store; trace; observer; embed; lint and LSP). Each migrates its sites by the §6 table and lowers the - deprecation-warning count. `VAL_INT` exists and is handled, but nothing - produces it, so behaviour is unchanged (differential). - - R1.2z: delete the old names. A straggler fails to compile. - - Risk: the size (1,488 compile-forced sites); and a mis-migration that - picks `eigs_float_arg` for an int-preserving builtin, caught by the - int-fuzz gate (§9.4). + deprecation-warning count. `VAL_INT` exists and is handled (the int + arms are written against the final semantics), but nothing produces + it, so behaviour is unchanged (differential). + - R1.2z: delete the old names (`VAL_NUM`, `num_`, `VAL_NUM_RAW`, + `VAL_NUM_OFFSET`, `make_num`, `make_num_permanent`, the `eigs_num_arg` + and `eigs_slot_num` families, `buf_num_arg`). A straggler fails to + compile (§2.3a measured which sites). + - Risk: the size (1,416 compile-forced sites across R1.1-R1.2); and a + mis-migration that picks `eigs_float_arg` for an int-preserving + builtin, caught by the int-fuzz gate (§9.4). 3. **R1.3, the flip: int literals and exact int arithmetic.** - - N1 (lexer, parser, AST kind, constant pool keyed by kind and bits, - `NUM_ZERO`/`NUM_ONE` mean int, the JIT `CONST`/`NUM_ZERO`/`NUM_ONE` - emit SMI bits). + - N1, with its token changes in this same commit: the lexer produces an + int literal; the AST payload `num` and the token's `num_val` become an + `EigsNum` (renamed, so the parser, compiler, lint and LSP sites stop + compiling here); **`OP_INT_ZERO`, `OP_INT_ONE` and `OP_INT_CONST` are + appended** to `OpCode` (the four exhaustive OpCode switches stop + compiling until they name them; three new interpreter CASEs; the JIT + scanner and the leaf scanner refuse them by their `default:`); + `OP_NUM_ZERO`/`OP_NUM_ONE`/`OP_CONST` keep their float meaning in all + three executors. The constant pool keys on kind and bits. - N3 with (A) overflow raise, N2 exact cross-kind comparison, N4b `-x`, N7 `num_type`. - - The EQ/NE int fast path relies on canonical form, as #1758 says - equality does. Two SMIs compare by bits; an SMI against a boxed int is - unequal without loading the box (a boxed int is outside the SMI range). - This is what makes plant 1 visible from a program (§9.3). + - EQ/NE: the only bit fast path is "both SMI"; anything boxed compares by + value (§2.1). - The JIT scanner refuses `BAND`/`BOR`/`BXOR`/`SHL`/`SHR`/`BNOT`/`MOD`. - **The tape goes to v7 in this commit.** The moment ints exist, a v6 writer would print `3` for both kinds and replay would turn ints into floats. The float token marks its kind now (`3.0`); N6's full repr replaces it in R1.7, still inside v7. - The observer routes an SMI into the numeric channel (converted to - double). + double); `obs_slot_observable`'s refusal (R1.1) catches a missed caller. + - The `trace` tier (§9.2, the leaf differential) and the tier witnesses + start gating here, because ints now reach all three evaluators. - The visible change is small: ints print as today. The rest waits for N4/N6. - Risks: - - JIT int loops bail every iteration (§3: +70% Ir on a counter loop). - Declare the CodSpeed baseline move first. + - JIT int loops leave the JIT (§3: +70% Ir on a counter loop), and the + leaf evaluator stops computing int helpers. Declare the CodSpeed + baseline move first. - Consumer hashes that relied on double rounding now raise ((A)); they move to the N9 wrapping builtins. 4. **R1.4, N4.** `//` (token, parser, `OP_IDIV` appended, - `op_name`/`op_stack_effect`/obs marker/ABI test), `%` floor modulo for - ints and floats, int division by zero raises, `INT64_MIN % -1` is 0. + `op_name`/`op_stack_effect`/obs marker/ABI test), `//=` beside `/=` + (Q6, decided), `%` floor modulo for ints and floats, int division by + zero raises, `INT64_MIN % -1` is 0. 5. **R1.5, N8.** Bitwise ops on ints with Lua's shift rules; `bit_*` returns ints. 6. **R1.6, N5, N9, N10 and the §6 builtins.** Every int-preserving and - int-requiring row, the 39 LOSS rows first; `num of` (#1638); the N9 - width family. + int-requiring row, the 42 LOSS rows first; Q1 (decided): integer-valued + parameters through `eigs_int_arg_range`/`eigs_byte_arg` + (`finite_num_to_byte` and `buffer_read_byte` deleted in this commit), + continuous ones through `eigs_round_arg` once §11 Q7 is decided (until + then they keep R1.2's behaviour-preserving truncation); Q4 `round`; + `num of` (#1638); the N9 width family. 7. **R1.7, N6 and N14's int half.** - Python-repr floats; ints as exact digits. - The constant dedup compares bits, so `-0.0` survives. - JSON writes ints as digits and floats with `.0`; integer text within int64 decodes as an int; `1e400` raises. + - #1762's writers: `store_json_encode` and `db_build_query` go through + the same N6 writer (§6), unless #1762 landed on main first. - `src/freestanding/mini_fmt.c` and `mini_strtod.c` follow, gated by `make freestanding-libc-diff`. - This is the largest visible change: every golden that prints an integral float. -8. **R1.8, the embed API, lint/LSP type knowledge and docs** (SPEC, - COMPARISON, README, llms.txt executed fences). The CLAUDE.md same-PR - docs rule applies to the integration PR as a whole. +8. **R1.8, the embed API (Q3, decided), lint/LSP type knowledge and docs.** + `eigs_value_as_num` converts an int (like `lua_tonumber`); + `eigs_value_new_int`, `eigs_value_as_int` (with a success flag, like + `lua_tointegerx`) and `eigs_value_is_int` are added; `EIGS_TYPE_NUM` + covers both kinds. Docs: SPEC, COMPARISON, README, llms.txt executed + fences. The CLAUDE.md same-PR docs rule applies to the integration PR as + a whole. ### Round 2: IEEE (N11-N14 remainder), on the experiment's evidence @@ -1036,10 +1616,13 @@ before the commit (the verify-and-fix rule), not "the suite passed". memory safety first. - Test: the C slot test writes every tag-spelling NaN payload. The #1746 plant (a raw store) segfaults in `slot_incref`. -2. **R2.2, retire `num_guard`** (73 sites), `EIGS_NUM_MAX` and the 1e308 - clamp. `EIGS_STRICT` becomes an opt-in trap (state.c:62). - `sqrt of -1` is NaN, `log of 0` is -inf, `x/0` is ±inf, `0/0` and - float `x%0` are NaN. +2. **R2.2, retire `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` and the + 1e308 clamp** (74 sites, the leaf's included). `EIGS_STRICT` becomes an + opt-in trap + (state.c:62). `sqrt of -1` is NaN, `log of 0` is -inf, `x/0` is ±inf, + `0/0` and float `x%0` are NaN. The consumers no token marks (§2.7): + `values_equal_impl`'s identity shortcut excludes floats; NaN order in + sort follows §11 Q8 once decided. 3. **R2.3, N13 refusal inside the writers:** the JSON encoder, the store encoder (delete the pre-walk `store_nonfinite_scalar`), the byte encoders and the int conversion. This removes the class #1746 chased for @@ -1067,10 +1650,17 @@ before the commit (the verify-and-fix rule), not "the suite passed". aot-differential skill: "Integer data compare exactly even inside a reduction arm"). - Consumers. N6 printing moves goldens in all 16; N4 changes `%` on - negatives; (A) raises where doubles lost precision silently. + negatives; (A) raises where doubles lost precision silently; Q1 raises on + a non-integral count, handle or byte, and on a byte outside 0..255 that + used to wrap. The DMG emulator feeds `ppu_render_frame` its memory buffer + through `buffer_read_byte`; the consumer acceptance run (Done-when) shows + whether any program stored a non-byte there. - Observer. Until round 3, ints are observed as their double value (the distance channel works on doubles), so `where`/`why`/`how` keep today's meaning. +- The leaf evaluator. It is off while recording, so every recorded run and + every live run compute leaf helpers on different evaluators. The `trace` + tier is the only thing that keeps them equal; it runs on every row. --- @@ -1078,13 +1668,14 @@ before the commit (the verify-and-fix rule), not "the suite passed". ### 9.1 `tests/phase2/MAP.md` -The skeleton is committed with this round. Every item (N1-N14, N4b, (A), +The skeleton is committed with this design. Every item (N1-N14, N4b, (A), (B), T1, O1-O4) has planned rows, each recording: - an id; - the program; - the expected branch output; - the round that lands it; -- why the row **fails on the v0.46.0 tag**. +- why the row **fails on the v0.46.0 tag**; +- its **shape** and its **tier witness** (below). Behaviour the branch must *preserve* (`1 == 1.0` is true on both binaries) cannot fail on the tag, so it is pinned two ways: @@ -1093,46 +1684,147 @@ cannot fail on the tag, so it is pinned two ways: - as a separate **control** row, counted on its own line and never in `tag_fail` (§121: each population pinned separately). -### 9.2 `tools/phase2_check.sh ` (round 1 builds it) +**Shapes.** The round-0 rows were all module-level straight-line code. The +critic ran them: both JIT tiers printed `[jit] scanned=0 compiled=0`, so +`phase2_check.sh`'s three tiers would have run the interpreter three times, +and no row reached a JIT producer emitter or the leaf evaluator. Every row +now has one of four shapes: +- `S`: straight-line module code. It runs interpreted in every tier and + claims nothing about tiers (witness `none`). These rows pin semantics. +- `L`: a one-line helper, `define h(x) as: return `, called K >= 1 + times: the leaf evaluator's shape (§4.5). +- `F`: a multi-statement function called at least 60 times, above the + default entry threshold of 50 (jit.c:2478): the function JIT's shape. +- `O`: a loop, in a function or at module level, run in the `osr` tier + (`EIGS_JIT_OSR_THRESHOLD=1`): the OSR shape. + +The `L`, `F` and `O` rows (35 in the MAP) cover every JIT-emitter and leaf +arm that holds a numeric site (the inventory's `## Numeric arms`, 20 today; +§9.2 checks the coverage): the literals (`NUM_ZERO`, `NUM_ONE`, `CONST` and +the new `INT_*`), the arithmetic, `DIV`/`MOD`, `NEG`/`NOT`/`BNOT`, the +comparisons, the bitwise ops, the conditional jumps, the field, local, name +and index stores, and the leaf's `INDEX_GET`, over ints and floats, with +overflow rows for the leaf, the function JIT and OSR. + +**Tier witnesses.** A row that claims a tier must prove the tier ran its +operation; otherwise it is **VACUOUS**, a FAIL with its own counter. The +witness line is `witness: ... []` (a `leaf` or `leaf-gen` +witness may name several helpers, each of which must hold), followed by +`ops: ...`, the opcodes whose JIT or leaf arm the row exercises: + +| kind | holds when (read from the branch run) | +|---|---| +| `none` | no claim (shape `S`) | +| `leaf ` | in every tier, the normal run's `EIGS_JIT_HOT` table has no entries for ``, and the `trace` run (leaf off) has K >= 1: the leaf computed every call | +| `leaf-gen ` | the normal run and the `trace` run both show the same K >= 1 entries: every call took the generic path (the scanner refused the chunk, or the leaf bailed) | +| `fn ` | in the default and `osr` tiers, ``'s row has `jit yes` and `adv RET`: its last call ran natively to its return | +| `fn-stop ` | `jit yes`, and the opcode at offset `adv` of ``'s bytecode (`EIGS_DUMP_BC=1`) is ``: the thunk handed back at ``, by a compile stop or a guard bail | +| `osr ` | in the `osr` tier, ``'s row has `osr yes`, and `oent + oadv` lies past the loop's `JUMP_BACK`: the thunk ran the loop to its exit | +| `osr-stop ` | `osr yes`, and the opcode at `oent + oadv` is `` | + +Why `EIGS_JIT_HOT` and not only `EIGS_JIT_STATS`/`EIGS_JIT_STOPS`: +`STATS` counts are process-wide (`scanned`, `compiled`), and `STOPS` records +where each compile's prefix ended. Neither says whether a run executed the +operation natively. `HOT` records, per chunk, the last run's native advance +(`adv` for the function thunk, `oadv` from `oent` for the OSR thunk, jit.c: +237-245), which is exactly that. `phase2_check.sh` reads all three: `STATS` +must show `compiled >= 1` for an `fn`/`osr` claim, and for a `-stop` claim +whose stop is a compile stop, `STOPS` must name ``. The leaf has no +counter; its witness is the entry count, because both generic call paths +count an entry (vm.c:2617, vm.c:4353) and the leaf path never does. The +witness uses only existing diagnostics: nothing in production changes so a +test can observe it. + +**Calibrated on the main binary this round** (each predicate holds where it +should and fails where it should not): +- `leaf sq`: `sq` called 200 times has no `HOT` row in the `off`, default and + `osr` tiers; with `EIGS_TRACE` set it shows `sq 200 yes ... RET`. The same + predicate is false for the leaf-off run. +- `fn g`: `g` called 60 times shows `g 60 yes ... RET ... RETURN`. +- `fn-stop h ADD`: `h` called 55 times with numbers and then once with a + string operand (the program raises there) shows `h 56 yes ... 30`; offset + 30 of `h` is `ADD`: the thunk's guard bailed there and the interpreter + raised. +- `osr f`: `f`'s loop under `EIGS_JIT_OSR_THRESHOLD=1` shows `osr yes`, + `oent 31`, `oadv 57`: 31 + 57 = 88, past `JUMP_BACK` at 85. + +**What the witnesses expect in round 1.** The JIT and the leaf bail on an +int that meets an arithmetic, comparison, bitwise or index op, and refuse an +int literal, until round 5 (§4), so such a row's honest witness is +`fn-stop`, `osr-stop` or `leaf-gen`: it proves the guard fired (or the +scanner refused) and the interpreter produced the row's output. An int that +only moves, into a local, a field, a list element or a module binding, +passes through the JIT's C helpers and the leaf's borrows, so those rows +(`N1.fn-int-local`, `N1.fn-dot-fields`, `N1.osr-module-int-store`, +`N5.osr-index-set`, `N1.leaf-dot-get`) have native witnesses already in +round 1. A float row's witness is native too: it proves the float meaning of +`NUM_ZERO`/`NUM_ONE`/`CONST` survived in the JIT and the leaf. Round 5 flips +the int witnesses to native, one row at a time, and each flip is a +deliberate edit of the row. + +### 9.2 `tools/phase2_check.sh ` (R1.1 builds it) - **Rows** live in `tests/phase2/rows/.eigs`. Each has a header - `# ROW: `, `# ITEMS: N1 N2`, `# EXPECT-RC: `, `# TIER-WITNESS: - loop|none`, plus `.out` (the exact branch stdout). Controls live in - `tests/phase2/controls/`. + `# ROW: `, `# ITEMS: N1 N2`, `# EXPECT-RC: `, `# SHAPE: S|L|F|O`, + `# WITNESS: ... []`, `# OPS: ...`, plus `.out` + (the exact branch stdout). Controls live in `tests/phase2/controls/`. - **Population:** - the row set is the directory listing (it cannot drift from a list); - every row id appears in MAP.md and every MAP id has a file (both - directions); + directions), with the same shape and witness; - every item in the fixed list (N1-N14, N4b, A, B, T1, O1-O4, transcribed from #1758 Revision 1) has at least one row; + - the `ops:` of the `L`, `F` and `O` rows together cover every + JIT-emitter arm and leaf-evaluator arm that holds a numeric site, read + from the inventory file's `## Numeric arms` (15 emitter arms and 5 leaf + arms today, each with its opcode chain; an arm is covered when some + row's `ops:` names an opcode of its chain that the row runs natively or + stops exactly at; the MAP's shaped rows cover all 20); - zero rows is a FAIL. - **Tiers:** - `off` = `EIGS_JIT_OFF=1`; - `default`; - - `osr` = `EIGS_JIT_OSR_THRESHOLD=1`. + - `osr` = `EIGS_JIT_OSR_THRESHOLD=1`; + - `trace` = `EIGS_TRACE=/t.tape` with the default JIT. The leaf + evaluator is off under trace (§4.5), so this tier is the **leaf + differential**: every `.eigs` row must print exactly what it prints in + the other tiers, so an `L` row compares the leaf with the generic path + on its int, float or overflow program. (`sh` rows that set `EIGS_TRACE` + themselves skip this tier.) - Every run is bounded at 30 s, with `= 1 (`lar_jit_witness`'s rule): a JIT row that - compiled nothing measured the interpreter. + `timeout`: macOS runners lack coreutils (`.claude/rules/test-suite.md`). + These knobs are the ones jit.c reads (jit.c:2501-2509, 4524). + - Each `L`/`F`/`O` row runs once more per claimed tier on the branch with + `EIGS_JIT_STATS=1 EIGS_JIT_STOPS=1 EIGS_JIT_HOT=1` (and `EIGS_DUMP_BC=1` + for a `-stop` or `osr` claim) to read its witness. - **Verdicts per row and tier:** - branch PASS = rc equals EXPECT-RC and stdout byte-equals `.out`; - tag FAIL = not that; + - VACUOUS = the branch passed but the witness does not hold; - rc 124 is the named verdict `TIMEOUT` and rc >= 128 is `SIGNAL`. Both are a FAIL on the branch; on the tag they count as `tag_fail` and are also shown in their own counters. - **Output, one line per tier:** `tier= examined=N rows tag_fail=N - branch_pass=N tag_timeout=K tag_signal=K`, then `controls=M both_pass=M` - and an environment banner (both binaries' `--version` and sha256). -- **Exit 0** iff in every tier examined == tag_fail == branch_pass > 0, the - controls all pass on both, and the population checks pass. + branch_pass=N vacuous=0 tag_timeout=K tag_signal=K`, then `controls=M + both_pass=M`, `witnessed=W` (the rows whose witness held), and an + environment banner (both binaries' `--version` and sha256). +- **Exit 0** iff in every tier examined == tag_fail == branch_pass > 0, + vacuous == 0, the controls all pass on both, and the population checks + pass. - **Calibration** (one-time, in the commit that adds it): - tag passed as both binaries: `branch_pass=0`, exit 1; - one `.out` corrupted: exit 1, naming the row; - an empty rows directory: exit 1; - - a MAP id with no file, and a file with no MAP id: exit 1 each. + - a MAP id with no file, and a file with no MAP id: exit 1 each; + - a `leaf` row run against a scratch build whose leaf scanner returns + early (`chunk_scan_leaf_accessor` never sets the flag): `vacuous=1`, + exit 1; + - an `fn` row whose function is called 10 times instead of 60: `vacuous=1` + (the JIT never compiled it); + - an `L` row run against a scratch build whose leaf `MUL` arm computes + `a * b + 1`: the `trace` tier differs from the others, exit 1, naming + the row. ### 9.3 `tools/phase2_plants.sh` (round 1 builds it; detached, about 7 release builds) @@ -1150,7 +1842,7 @@ that. | # | plant | where | named check that must turn RED | |---|---|---|---| -| 1 | an int that fits inline stored boxed | `slot_from_heap` skips the small-`VAL_INT` normalization | row `N1.canon-eq` (`abs of -5` round-trips through a Value; then `== 5` in the bit fast path) and `tests/phase2/slot_layer.c` (every int writer, every value in ±2^47, must carry tag 0xFFFA) | +| 1 | an int that fits inline stored boxed | `eigs_container_slot` (or `slot_from_int`) skips the small-int rule and stores a `VAL_INT` box | `tests/phase2/slot_layer.c`: every canonicalizing writer of §2.1, driven with every boundary value, must give tag 0xFFFA inside ±2^47 and a box outside. No program row can see this plant (§2.1: everything compares by value), so the round-0 claim that `N1.canon-eq` would turn red is withdrawn; that row now pins only semantics | | 2 | a NaN stored raw in a slot | `slot_from_f64` without the canonical branch | row `N12.nan-payload-tags` (`f64_from_bits` of every tag-spelling payload into a variable, list, dict and buffer; `type of` each is "num", under ASan in the plant build) | | 3 | a writer accepting a non-finite value | the refusal inside `eigs_json_encode_value` deleted; separately inside the store encoder | rows `N13.json-refuses-inf` and `N13.store-refuses-nan` (raise `value`, and nothing written: the store row re-reads the record count) | | 4 | `+` wrapping on overflow | the SMI+boxed add path uses wrapping `uint64` add | row `A.add-overflow-raises` (`9223372036854775807 + 1` raises `value` naming `+`) | @@ -1162,6 +1854,10 @@ Each plant is transverse (§100): deleting its named check's assertion must let the plant through. That is shown once per plant during calibration by running the plant against a copy of the check with its assertion removed. +The tier-witness and leaf-differential plants (§9.2's calibration) belong to +`phase2_check.sh`'s own calibration, not to this list: they test the +instrument, not the semantics. + ### 9.4 The int-fuzz gate (round 1; the §6 table's enforcement) It follows `tests/test_bool_fuzz.sh` (which feeds bools to every builtin @@ -1235,38 +1931,62 @@ disagree=0`. It exits 1 on any unexplained disagreement or on examined=0. --- -## 11. Open questions this design does not decide - -These need an owner decision or the standard answer cited. Round 1 must not -pick them silently. - -- **Q1. N5's scope beyond index, count and bitwise.** gfx coordinates and - colours, audio rates, `usleep`/`gfx_delay` durations and C-API ints - truncate a float today. N5 lists "index, count, bitwise". Raising on - `gfx_rect of [10.5, ...]` would break every app that computes float - positions. Options: - - (a) keep truncation for C-API arguments, documented; - - (b) apply N5 everywhere. -- **Q2. An int stored into float storage** (`buf_set`, `buf_from_list`, - `copy_into`, `set_at` on a buffer, `stream_write`). Converting rounds - above 2^53. Options: - - (a) convert, as numpy float64 does; - - (b) refuse an inexact int, as N13 refuses non-finite values. -- **Q3. The embed accessors for an int.** Options for `eigs_value_as_num` - given an int: - - (a) convert, as Lua's `lua_tonumber` does, lossy above 2^53; - - (b) convert only when exact and leave an error pending otherwise. - - Either way: `eigs_value_new_int`, `eigs_value_as_int` and a kind query - are added; and `EIGS_TYPE_NUM` covers both kinds, or a new type value is - appended? -- **Q4. `round`.** It has no Lua counterpart. Proposed: follow floor and - ceil (an int when it fits), keeping C `round`'s half-away-from-zero. - Python's `round` uses banker's rounding and returns an int; JavaScript - rounds half up. -- **Q5. `why is x` for an int binding.** Δv is exact in int64 except at the - INT64_MIN↔INT64_MAX swing the oracle rows include (it overflows). Options: - - (a) always a float; - - (b) an int when it fits, else a float. - - (A) does not apply: a readout is not an operator. -- **Q6. `//=`** beside `/=` (the lexer's X2 table). N4 adds `//` and is - silent on the compound form. +## 11. Decided questions (Q1-Q6) and what stays open + +Q1-Q6 were open in round 0. They were decided on 2026-10-14 by the +standard answer, each verified by probe, in +[#1758 (comment)](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6171744498). +The owner may overrule any of them; until then this design follows them. + +- **Q1, N5's scope: DECIDED.** The parameter's meaning decides, not the C + type. + - Integer-valued parameters (indices, counts, sizes, byte values, + handles, ports, seeds) follow N5: `1.5` raises `value`. Lua: + `string.sub("abc", 1.5)` raises "number has no integer representation". + - Continuous parameters (gfx coordinates and sizes, colour channels, + durations, audio gain) accept floats; where the C API needs an int, the + conversion rounds to nearest, replacing truncation toward zero (SDL3's + float coordinates, LÖVE's numeric drawing API). + - Applied: §6's rows (16 moved from other to int-requiring; byte + consumers no longer wrap), `eigs_byte_arg`, `eigs_int_arg_range` and + `eigs_round_arg` (§2.6), R1.6 (§8). +- **Q2, an int stored into float storage: DECIDED.** Convert with IEEE + round-to-nearest, documented as the container's contract (Python + `float(2**53+1)`, numpy, JS `Float64Array`). Applied: `buf_set`, + `buf_from_list`, `copy_into`, `set_at` on a buffer, `stream_write`; the + inventory's `buffer_read_num` sites keep their token (§2.3a). +- **Q3, the embed API: DECIDED, Lua's C API.** `eigs_value_as_num(int)` + converts (lossy above 2^53, like `lua_tonumber`); add + `eigs_value_new_int`, `eigs_value_as_int` (succeeds only for an exact + int64, with a success flag, like `lua_tointegerx`) and `eigs_value_is_int` + (like `lua_isinteger`); `EIGS_TYPE_NUM` covers both kinds (like + `LUA_TNUMBER`). Applied: R1.8; the 48 `eigs_value_as_num` sites keep + their token (§2.3a). +- **Q4, `round`: DECIDED.** Keep half away from zero (C and Rust `round`); + the result is an int when it fits int64 and a float otherwise, like Lua's + `math.floor`/`math.ceil` (`math.floor(1e300)` stays `1e+300`). Applied: + §6 (`round` int-preserving, LOSS), R1.6; `eigs_round_arg` uses the same + tie rule. +- **Q5, `why is x` for an int binding: DECIDED.** An int when Δv fits in + int64, otherwise a float. A readout never raises; (A) applies to + operators, not to observer readouts. Applied: round 3 (O4). +- **Q6, `//=`: DECIDED.** Add it beside `/=`. Applied: R1.4. + +**Open, new in design round 2.** Round 1 must not pick these silently; each +needs the standard answer cited or an owner decision. +- **Q7. A finite continuous parameter outside the C type's range** + (`gfx_rect of [3e9, 0, 10, 10, ...]`). Q1 decides rounding to nearest, + and N13 already decides that a non-finite one is refused (it is an int + conversion). The finite out-of-range case is open; today the C cast is + undefined behaviour. Options: saturate to the C range (it draws + off-screen, as a huge float coordinate does in SDL3), or raise `value`. + This design does not pick: R1.2's gfx group re-points the reads to + `eigs_float_arg` with today's truncation (behaviour unchanged, like every + R1.2 commit), and the part of R1.6 that installs `eigs_round_arg` waits + for the decision. Nothing else in round 1 depends on it. +- **Q8. NaN in an ordering.** From R2.2 a NaN can reach `sort`, `sort_by`, + `min` and `max`. NaN has no order: C's `qsort` with an inconsistent + comparator gives an unspecified order, Python's `sorted` too, and Lua's + `table.sort` may raise "invalid order function". Options: raise `value` + when a NaN is compared for order, or define a total order (NaN last, as + IEEE `totalOrder` and numpy's `sort` do). diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index e5377c9c2..c1e9fc523 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -1,6 +1,8 @@ # tests/phase2/MAP.md: #1758 items to the test rows that pin them -This is the skeleton, committed in round 0 with `docs/design/phase2-numbers.md`. +This is the skeleton, committed in round 0 with `docs/design/phase2-numbers.md` +and revised in design round 2 (row shapes, tier witnesses, the leaf +differential, the record-twice tape rows). Round 1 writes each row as `tests/phase2/rows/.eigs` (or `.sh` for a row that needs a shell: tape, env, files), with its exact expected stdout in `.out`. @@ -9,10 +11,13 @@ row that needs a shell: tape, env, files), with its exact expected stdout in design doc) runs every row: - against the **v0.46.0 tag** (`4a3a5c19`, built from the tag commit, not main) and the branch; -- in three tiers: `EIGS_JIT_OFF=1`, the default JIT, and - `EIGS_JIT_OSR_THRESHOLD=1`. +- in four tiers: `EIGS_JIT_OFF=1`, the default JIT, + `EIGS_JIT_OSR_THRESHOLD=1`, and `trace` (`EIGS_TRACE=/t.tape`, + default JIT). The leaf evaluator is off under trace, so the `trace` tier is + the leaf differential: a row must print the same in it as in the others. -Every mapped row must FAIL on the tag and PASS on the branch in every tier. +Every mapped row must FAIL on the tag and PASS on the branch in every tier, +and its witness must hold on the branch (design §9.1), or it is VACUOUS. ## Format (machine-read by `phase2_check.sh`) @@ -44,8 +49,41 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. the branch must preserve, and are counted separately: never in `tag_fail`. - **Gates** (`gate.*`) name a check the Done-when runs on its own (the - observer oracle with `--floor`). `phase2_check.sh` lists them and verifies - their command exists, but does not run or count them as rows. + observer oracle with `--floor`, the db parameter test). `phase2_check.sh` + lists them and verifies their command exists, but does not run or count + them as rows. +- **Shape and witness.** A row without a `shape:` line is shape `S` + (straight-line module code, interpreted in every tier, witness `none`). + The other shapes carry a fourth line, `shape: witness: + ... [] ops: ...`: + - `L`: a one-line helper (the leaf evaluator); `F`: a multi-statement + function called at least 60 times (the function JIT); `O`: a loop, in a + function or at module level, witnessed in the `osr` tier (OSR). + - witness kinds (design §9.1): `leaf ` (no `EIGS_JIT_HOT` entries for + `` in the normal run, K >= 1 in the `trace` run), `leaf-gen ` + (the same K >= 1 entries in both: every call took the generic path), + `fn ` (`jit yes`, `adv RET`), `fn-stop ` (`jit yes`, the + op at `adv` is ``), `osr ` (`osr yes`, `oent + oadv` past the + loop's `JUMP_BACK`), `osr-stop ` (the op at `oent + oadv` is + ``). + - `leaf` and `leaf-gen` may name several helpers; each must hold. + - `ops:` lists the opcodes whose JIT or leaf arm the row exercises: run + natively, or stopped at exactly (a `-stop` witness's ``, which proves + the guard or the scanner's refusal of that op). Ops after a stop are not + listed. `phase2_check.sh` requires the union over all `L`/`F`/`O` rows to + cover every JIT-emitter and leaf-evaluator arm that holds a numeric site (the + inventory file's `## Numeric arms` lists them: 15 emitter arms and 5 leaf + arms today). + - The witnesses state round 1's expectation. The JIT and the leaf bail on + an int that meets an arithmetic, comparison, bitwise or index op, or on + an int literal, until round 5, so such a row's witness is a `-stop` or + `leaf-gen`: the guard fired and the interpreter produced the output. An + int that only moves (into a local, a field, a list element or a module + binding) passes through the JIT's C helpers and the leaf's borrows, so + those rows' witnesses are native, as are the float rows'. + `(witness probed main)` marks a witness observed on the main binary + (with a double where the row passes an int); the others are read from + design §2.7, §4.1 and §4.5. --- @@ -64,7 +102,49 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. tag: `[3.6893488147419103e+19, 1.8446744073709552e+19, 9.223372036854776e+18]` (probed main) - `N1.canon-eq` [R1.3] `a is abs of -5 / b is 0 - 5 / print of [a == 5, -b == 5, num_type of a]` -> `[true, true, "int"]` - tag: `num_type` undefined. **Plant 1's named check**: with small ints boxed, the SMI/boxed-int equality fast path, which relies on canonical form, answers false. The direct witness is `tests/phase2/slot_layer.c`. + tag: `num_type` undefined. (Round 0 named this row as plant 1's check; it cannot see that plant, because everything compares by value (design §2.1). Plant 1's check is `tests/phase2/slot_layer.c`.) +- `N1.leaf-int-literal` [R1.3] `define big(x) as: return 9007199254740993 / define one(x) as: return 1 / print of [big of 0, one of 0]` + -> `[9007199254740993, 1]` + tag: `[9007199254740992, 1]` (probed main, all three tiers) + shape: L witness: leaf-gen big one (the leaf scanner refuses `OP_INT_CONST` and `OP_INT_ONE`) ops: INT_CONST INT_ONE +- `N1.leaf-float-literal` [R1.7] `define onef(x) as: return 1.0 / define zerof(x) as: return 0.0 / define halff(x) as: return 0.5 / print of [onef of 7, zerof of 7, halff of 7]` + -> `[1.0, 0.0, 0.5]` (the leaf's `NUM_ONE`, `NUM_ZERO` and `CONST` keep their float meaning) + tag: `[1, 0, 0.5]` (probed main) + shape: L witness: leaf onef zerof halff (witness probed main: no entries normally, 1 each under trace) ops: NUM_ONE NUM_ZERO CONST +- `N1.leaf-dot-get` [R1.3] `define px(p) as: return p.x / d is {"x": 9007199254740993} / print of (px of d)` + -> `9007199254740993` (an int field is borrowed through the leaf with no arithmetic, so the leaf computes it even in round 1) + tag: `9007199254740992` (probed main) + shape: L witness: leaf px (witness probed main: no entries normally, 1 under trace) ops: LOCAL_DOT_GET +- `N1.fn-float-literals` [R1.7] `define f(a) as: t is a * 1.0 / u is t + 0.0 / return u`, called 60 times with `2.0`; print the last result + -> `2.0` (the JIT's `NUM_ONE`/`NUM_ZERO` emitters keep their float meaning) + tag: `2` (probed main) + shape: F witness: fn f (witness probed main: `f 60 yes ... RET`) ops: NUM_ONE NUM_ZERO MUL ADD +- `N1.fn-int-literal` [R1.3] `define g(a) as: t is a + 1 / return t * 2`, called 60 times with `9007199254740992`; print the last result + -> `18014398509481986` + tag: `18014398509481984` (probed main) + shape: F witness: fn-stop g INT_ONE (the JIT scanner refuses the new opcode) ops: INT_ONE +- `N1.fn-dot-fields` [R1.3] `define setx(p, q) as: p.x is q / return p.x`, called 60 times with `[{"x": 1}, 9007199254740993]` (a fresh dict each time); print the last result + -> `9007199254740993` (the field store and load take their C helpers for a non-double and the thunk runs on) + tag: `9007199254740992` (probed main) + shape: F witness: fn setx (witness probed main, with a double: `setx 60 yes ... RET`) ops: LOCAL_DOT_SET LOCAL_DOT_GET +- `ctl.N1.fn-int-truthiness` (control) `define truth(a) as: if a: return 1 / return 2`, called 60 times with `0`; `print of [truth of 0, truth of 5, truth of 0.0]` + -> `[2, 1, 2]` on both (0 and 0.0 are falsy) + shape: F witness: fn-stop truth JUMP_IF_FALSE (an SMI condition fails the bool and number checks; on main a double 0.0 instead leaves at the jump target, 21) ops: JUMP_IF_FALSE +- `ctl.N1.fn-int-not` (control) `define neg(a) as: r is not a / return r`, called 60 times with `0`; `print of [neg of 0, neg of 5, neg of 0.0]` + -> `[true, false, true]` on both + shape: F witness: fn-stop neg NOT (an SMI fails NOT's number check) ops: NOT +- `N1.fn-int-local` [R1.3] `define keep(q) as: t is q / return t`, called 60 times with `9007199254740993`; print the last result + -> `9007199254740993` (an int stored into a local takes `SET_LOCAL`'s generic swap and the thunk runs on) + tag: `9007199254740992` (probed main) + shape: F witness: fn keep (witness probed main, with a double: `keep 60 yes ... RET`) ops: SET_LOCAL POP +- `N1.osr-module-int-store` [R1.3] module-level `big is 9007199254740993 / x is 0 / i is 0.0 / loop while i < 100.0: (x is big / i is i + 1.0) / print of x` + -> `9007199254740993` + tag: `9007199254740992` (probed main) + shape: O witness: osr (witness probed main: `osr yes`, `oent 55`, `oadv 59`, 114 past `JUMP_BACK` at 111) ops: SET_NAME LT ADD +- `N1.osr-int-counter` [R1.3] `define count(n) as: i is 9007199254740990 / k is 0 / loop while k < n: (i is i + 1 / k is k + 1) / return i`; `print of (count of 10)` + -> `9007199254741000` + tag: `9007199254740992`: the double counter stalls at 2^53 (probed main) + shape: O witness: osr-stop count LT (the SMI `k` fails LT's operand guard) ops: LT ### N2 - `N2.int-eq-float-kinds` [R1.3] `print of [1 == 1.0, 1 != 1.0, num_type of 1, num_type of 1.0]` @@ -82,6 +162,17 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. - `N2.sort-exact` [R1.6] `print of (sort of [9007199254740993, 9007199254740992, -1])` -> `[-1, 9007199254740992, 9007199254740993]` tag: the literal rounds, so `[-1, 9007199254740992, 9007199254740992]` (probed main, same shape) +- `N2.fn-exact-compare` [R1.3] `define lt(a, b) as: t is a < b / return t`, called 60 times with `[9007199254740992, 9007199254740993]`; print the last result + -> `true` + tag: `false` (probed main) + shape: F witness: fn-stop lt LT (a boxed int fails the operand guard) ops: LT +- `N2.fn-compare-all` [R1.3] `define cmp(a, b) as: e is a == b / n is a != b / g is a > b / l is a <= b / q is a >= b / return [e, n, g, l, q]`, called 60 times with `[9007199254740993, 9007199254740992.0]`; print the last result + -> `[false, true, true, false, true]` (N2's exact cross-kind compare) + tag: `[true, false, false, true, true]` (probed main) + shape: F witness: fn-stop cmp EQ (a boxed int fails the first comparison's guard) ops: EQ +- `ctl.N2.fn-float-compare` (control) `define ltf(a, b) as: t is a < b / return t`, called 60 times with `[0.5, 0.75]` + -> `true` on both + shape: F witness: fn ltf (witness probed main: `ltf 60 yes ... RET`) ops: LT - `ctl.N2.float-eq` (control) `print of [0.5 + 0.25 == 0.75, 1 == 1.0, 3 < 3.5]` -> `[true, true, true]`, both binaries @@ -94,6 +185,32 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. tag: `[9.223372030926249e+18, 9007199254740992]` (probed main) - `ctl.N3.small-ints` (control) `print of [1 + 2, 10 - 3, 6 * 7, -4]` -> `[3, 7, 42, -4]`, both binaries +- `N3.leaf-mul-exact` [R1.3] `define sq(x) as: return x * x / print of (sq of 94906267)` + -> `9007199515875289` + tag: `9007199515875288` (probed main; the critic's gdb probe shows the leaf computed it there) + shape: L witness: leaf-gen sq (an SMI operand makes the leaf's MUL bail) ops: MUL +- `N3.leaf-add-exact` [R1.3] `define add2(a, b) as: return a + b / print of (add2 of [9007199254740992, 1])` + -> `9007199254740993` + tag: `9007199254740992` (probed main) + shape: L witness: leaf-gen add2 ops: ADD +- `ctl.N3.leaf-float` (control) `define sqf(x) as: return x * x / print of (sqf of 1.5)` + -> `2.25` on both + shape: L witness: leaf sqf (witness probed main: no entries normally, 1 under trace) ops: MUL +- `N3.fn-arith-exact` [R1.3] `define f(a, b) as: t is a * b / u is t + a / return u - b`, called 60 times with `[94906267, 94906267]`; print the last result + -> `9007199515875289` + tag: `9007199515875288` (probed main) + shape: F witness: fn-stop f MUL ops: MUL +- `N3.osr-sum-exact` [R1.3] `define total(n) as: acc is 9007199254740000 / i is 0 / loop while i < n: (acc is acc + 1 / i is i + 1) / return acc`; `print of (total of 1000)` + -> `9007199254741000` + tag: `9007199254740992`: the double sum stalls at 2^53 (probed main) + shape: O witness: osr-stop total LT ops: LT +- `N3.osr-module-sum` [R1.3] module-level `acc is 9007199254740000 / i is 0 / loop while i < 1000: (acc is acc + 1 / i is i + 1) / print of acc` + -> `9007199254741000` + tag: `9007199254740992` (probed main) + shape: O witness: osr-stop INT_CONST (the OSR scanner stops at the literal `1000`) ops: INT_CONST +- `ctl.N3.osr-float` (control) `define totalf(n) as: acc is 0.5 / i is 0.0 / loop while i < n: (acc is acc + 1.5 / i is i + 1.0) / return acc`; `print of (totalf of 100.0)` + -> `150.5` on both + shape: O witness: osr totalf (witness probed main: `osr yes`, `oent 33`, `oadv 57`; 90 is past `JUMP_BACK` at 87) ops: LT ADD NUM_ONE CONST JUMP_IF_FALSE SET_LOCAL POP ### A - `A.add-overflow-raises` [R1.3] `{try print of (9223372036854775807 + 1) catch}`, printing `[e.kind, (index_of of [e.message, "+"]) >= 0]` @@ -111,6 +228,18 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. - `A.tensor-scalar-overflow-raises` [R1.6] `{try print of (multiply of [4611686018427387904, 2]) catch}` -> `["value", true]` tag: a double +- `A.leaf-mul-overflow` [R1.3] `define sq(x) as: return x * x / {try print of (sq of 3037000500) catch}`, printing `e.kind` + -> `value` (the leaf bails; the generic path raises with the caller's line) + tag: `9.22337203700025e+18`, no raise (probed main) + shape: L witness: leaf-gen sq ops: MUL +- `A.fn-add-overflow` [R1.3] `define inc(a) as: t is a + 1 / return t`, called 60 times with small ints, then `{try print of (inc of 9223372036854775807) catch}`, printing `e.kind` + -> `value` + tag: `9.223372036854776e+18`, no raise (probed main) + shape: F witness: fn-stop inc INT_ONE ops: INT_ONE +- `A.osr-double-overflow` [R1.3] `define dbl(n) as: x is 1 / i is 0 / loop while i < n: (x is x * 2 / i is i + 1) / return x`; `{try print of (dbl of 63) catch}`, printing `e.kind` + -> `value` (2^63 overflows on the 63rd doubling) + tag: `9.223372036854776e+18`, no raise (probed main) + shape: O witness: osr-stop dbl LT ops: LT ### B - `B.type-of-both-num` [R1.3] `print of [type of 3, type of 3.0, (type of 3) == (type of 3.0), num_type of 3]` @@ -143,6 +272,14 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. tag: raises `modulo by zero` - `ctl.N4.int-mod-zero-raises` (control) `{try x is 7 % 0 catch}`, printing `e.kind` -> `value`, both binaries (probed main) +- `N4.fn-floor-mod` [R1.4] `define m(a, b) as: t is a % b / return t`, called 60 times with `[-7, 3]`; `print of [r, m of [-7.5, 2]]` + -> `[2, 0.5]` (floor modulo for an int and a float) + tag: `[-1, -1.5]` (probed main) + shape: F witness: fn-stop m MOD (the JIT scanner refuses MOD in round 1) ops: MOD +- `N4.fn-div-float` [R1.7] `define d(a, b) as: t is a / b / return t`, called 60 times with `[6, 2]`; print the last result + -> `3.0` + tag: `3` (probed main) + shape: F witness: fn-stop d DIV (SMI operands fail DIV's operand guard) ops: DIV ### N4b - `N4b.neg-min-raises` [R1.3] `m is -9223372036854775807 - 1 / {try print of (-m) catch}` @@ -157,6 +294,10 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. - `N4b.min-mod-neg1-zero` [R1.4] `m is ... / print of [m % -1, num_type of (m % -1)]` -> `[0, "int"]`, with no hardware fault (x86 `idiv` faults on `INT64_MIN % -1`) tag: `num_type` undefined +- `N4b.fn-neg-min` [R1.3] `define n(a) as: t is -a / return t`, called 60 times with small ints, then `m is -9223372036854775807 - 1 / {try print of (n of m) catch}`, printing `e.kind` + -> `value` + tag: `9.223372036854776e+18`, no raise (probed main) + shape: F witness: fn-stop n NEG ops: NEG ### N5 - `N5.substr-fraction-raises` [R1.6] `{try print of (substr of ["hello", 1.5, 2]) catch}`, printing `e.kind` @@ -174,6 +315,17 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. - `N5.range-fraction-raises` [R1.6] `{try print of (range of 2.5) catch}`, printing `e.kind` -> `value` tag: no raise (read: `range_bound` accepts any double inside the int range) +- `N5.leaf-buffer-index` [R1.7] `define bat(b, i) as: return b[i] / b is buffer of 3 / print of (bat of [b, 1])` + -> `0.0` (a buffer element is an f64, Q2) + tag: `0` (probed main) + shape: L witness: leaf-gen bat (an SMI index makes the leaf's INDEX_GET bail in round 1) ops: INDEX_GET +- `ctl.N5.leaf-float-index` (control) `define nth(xs, i) as: return xs[i] / print of (nth of [[10, 20, 30], 1.0])` + -> `20` on both (an integral float index converts, N5) + shape: L witness: leaf nth (witness probed main: no entries normally, 1 under trace) ops: INDEX_GET +- `N5.osr-index-set` [R1.3] `define fill(big, n) as: xs is [0, 0, 0, 0] / i is 0.0 / loop while i < n: (xs[i] is big / i is i + 1.0) / return xs`; `print of (fill of [9007199254740993, 4.0])` + -> `[9007199254740993, 9007199254740993, 9007199254740993, 9007199254740993]` (an integral float index converts, N5; the int value is stored exactly) + tag: four times `9007199254740992` (probed main) + shape: O witness: osr fill (the float counter keeps the loop native; the boxed int value takes `INDEX_SET`'s C helper; witness probed main with a double: `osr yes`, `oent 37`, `oadv 54`, 91 past `JUMP_BACK` at 88) ops: INDEX_SET LT ADD ### N6 - `N6.float-repr` [R1.7] `print of [3.0, 1e3, -0.0, 0.1 + 0.2, 1e15, 1e16, 1e-05, 0.0001]` @@ -215,6 +367,14 @@ Every mapped row must FAIL on the tag and PASS on the branch in every tier. - `N8.bit-builtins-int64` [R1.5] `print of [bit_or of [4611686018427387904, 1], bit_shl of [1, 64]]` -> `[4611686018427387905, 0]` tag: `4.611686018427388e+18`, ... +- `N8.fn-bitwise` [R1.5] `define b(a, c) as: t is a & c / return t`, called 60 times with `[9007199254740993, 9007199254740993]`; print the last result + -> `9007199254740993` + tag: `9007199254740992` (probed main) + shape: F witness: fn-stop b BAND (the JIT scanner refuses the bitwise ops in round 1) ops: BAND +- `N8.fn-bitwise-all` [R1.5] `define bits(a, c) as: o is a | c / x is a ^ c / l is a << 1 / r is a >> 1 / n is ~a / return [o, x, l, r, n]`, called 60 times with `[9007199254740993, 2]`; print the last result + -> `[9007199254740995, 9007199254740995, 18014398509481986, 4503599627370496, -9007199254740994]` + tag: `[9007199254740994, 9007199254740994, 18014398509481984, 4503599627370496, -9007199254740992]` (probed main) + shape: F witness: fn-stop bits BOR (the scanner refuses the bitwise ops) ops: BOR ### N9 The builtin names are decided in round 1 (`` etc. below are placeholders the row files replace). @@ -261,6 +421,10 @@ The builtin names are decided in round 1 (`` etc. below are placehold - `N11.constant-1e308-converges` [R2.2] the #1746 row: a binding assigned the literal `1e308` 12 times; `print of (converged of x)` -> `true` tag: `false`, because saturation reads as diverging (#861; probed on the #1746 baseline) +- `N11.fn-overflow-inf` [R2.5] `define big(a) as: t is a * 10.0 / return t`, called 60 times with `1e308`; print the last result + -> `inf` (an inf result is not a NaN, so the JIT keeps it native) + tag: `1e+308`, the clamp (probed main) + shape: F witness: fn big ops: MUL CONST ### N12 - `N12.f64-bits` [R2.4] `print of [f64_bits of 1.0, f64_bits of -0.0, f64_from_bits of 4607182418800017408]` @@ -275,6 +439,14 @@ The builtin names are decided in round 1 (`` etc. below are placehold - `N12.payload-through-ints` [R2.4] `i is 9218868437227405313 / print of [f64_bits of (f64_from_bits of i), of ( of [buffer of 1, 0, i])]` -> `[9221120237041090560, 9218868437227405313]`. Ints and buffer bits keep the payload; a float does not. tag: undefined +- `N12.fn-nan-canonical` [R2.4] `define nz(a) as: t is a - a / return t`, called 60 times with `x is 1e308 * 10`; `print of (f64_bits of (nz of x))` + -> `9221120237041090560` (the JIT bails on the NaN result; the interpreter's single writer canonicalizes) + tag: `f64_bits` undefined + shape: F witness: fn-stop nz SUB ops: SUB +- `N12.leaf-nan-canonical` [R2.4] `define dif(a, b) as: return a - b / x is 1e308 * 10 / print of (f64_bits of (dif of [x, x]))` + -> `9221120237041090560` (computed in the leaf, written through `slot_from_f64`) + tag: `f64_bits` undefined + shape: L witness: leaf dif ops: SUB ### N13 - `N13.json-refuses-inf` [R2.3] `x is 1e308 * 10 / {try print of (json_encode of [x]) catch}`, printing `e.kind` @@ -297,23 +469,35 @@ The builtin names are decided in round 1 (`` etc. below are placehold - `N14.decode-overflow-raises` [R2.5] `{try print of (json_decode of "1e400") catch}` -> `value` tag: `1e+308` (read: strtod gives inf, then the clamp) +- `N14.store-exact-digits` [R1.7] `s is store_open of "/db" / k is store_put of [s, "c", {"v": 1234567890123456, "f": 0.1 + 0.2, "t": 9007199254740991}] / r is store_get of [s, "c", 1] / print of [r["v"] == 1234567890123456, r["f"] == 0.1 + 0.2, r["t"] == 9007199254740991]` + -> `[true, true, true]` + tag: `[false, false, false]`: the record encoder's `%.15g` (#1762's reproduction, identical on main and the tag) +- `gate.N14.db-param-exact` [R1.7] `make db-params-test`: `tests/test_db_params.c` drives `db_build_query` without a server; its number rows bind `1234567`, `9007199254740993` and `0.1 + 0.2` + -> each bound as exact text (`1234567`, `9007199254740993`, `0.30000000000000004`) + tag: n/a (a C test, not a program); today's `"%g"` binds `1.23457e+06` (#1762). It needs no PostgreSQL server, so it runs in CI as a gate. ### T1 - `T1.v7-header` [R1.3] (sh row) `EIGS_TRACE=t.tape eigenscript p.eigs; head -1 t.tape | cut -d' ' -f1-2` -> `V 7` tag: `V 6` -- `T1.int-float-on-tape` [R1.3] (sh row) record `x is 3 / y is 3.0 / print of [x, y]`; grep the tape's A records for `x=3` and `y=3.0`; replay with `EIGS_REPLAY_STRICT=1`; the output is byte-identical - -> `A x=3`, `A y=3.0`, `replay identical` - tag: `A y=3` (read: `%.17g`) +- `T1.twice-int` [R1.3] (sh row) the Done-when's "record twice": record `define sq(x) as: return x * x / x is 9007199254740993 / y is sq of 94906267 / print of [x, y]` twice (`EIGS_TRACE=t1.tape`, then `t2.tape`); print whether `cmp t1.tape t2.tape` finds them identical; replay `t1.tape` with `EIGS_REPLAY_STRICT=1` and print whether its stdout byte-equals the live run's (the live run computes `sq` in the leaf, the recording on the generic path); print the A records for `x` and `y` + -> `tapes identical`, `replay identical`, `A 0 x=9007199254740993`, `A 0 y=9007199515875289` + tag: `A 0 x=9007199254740992`, `A 0 y=9007199515875288` (the tape machinery is deterministic today: two recordings of a program without randomness differ only in recorded nondeterminism, probed main) +- `T1.twice-float` [R1.7] (sh row) the same procedure for `x is 3.0 / y is 0.1 + 0.2 / z is -0.0 / print of [x, y, z]` + -> `tapes identical`, `replay identical`, `A 0 x=3.0`, `A 0 y=0.30000000000000004`, `A 0 z=-0.0` (the kind on the tape; the exact text is N6's, R1.7) + tag: `A 0 x=3` and `A 0 z=-0` (read: `%.17g`) - `T1.int-replay-kind` [R1.3] (sh row) record `r is random_int of [1, 6] / print of [r, num_type of r]`, then replay -> the same line twice, kind `"int"` on replay tag: `num_type` undefined - `T1.v6-refused` [R1.3] (sh row) `EIGS_REPLAY=tests/phase2/fixtures/v6.tape eigenscript p.eigs`; print the rc and whether stderr names version 6 -> `rc!=0 names-6` tag: rc 0 (the fixture is its own version). **Plant 7's named check.** -- `T1.nonfinite-on-tape` [R2.5] (sh row) record inf, -inf and nan values; the tape holds the tokens `inf`, `-inf`, `nan`; strict replay is byte-identical - -> as stated - tag: the program raises +- `T1.twice-inf` [R2.5] (sh row) the same procedure for `x is 1e308 * 10 / y is -x / print of [x, y]` + -> `tapes identical`, `replay identical`, `A 0 x=inf`, `A 0 y=-inf` + tag: `A 0 x=1e+308` (the clamp) +- `T1.twice-nan` [R2.5] (sh row) the same procedure for `x is (1e308 * 10) - (1e308 * 10) / print of (x == x)` + -> `tapes identical`, `replay identical`, `A 0 x=nan` + tag: `A 0 x=0` (the clamp, then `inf - inf` collapses to 0) The `O cfg` record's v7 shape is pinned by `O3.ocfg-no-hlow` (its file lists `# ITEMS: O3 T1`). @@ -341,7 +525,7 @@ The `O cfg` record's v7 shape is pinned by `O3.ocfg-no-hlow` (its file lists ### O4 - `O4.why-is-displacement` [R3] `x is 1 / x is 4 / print of (why is x)` - -> `3`, or `3.0` (the int-or-float question is design §11 Q5) + -> `3`: an int, because Δv fits int64 (Q5, decided) tag: `-0.2780719051126377`, a dH (probed main) - `O4.how-is-settledness` [R3] a binding held constant for one window; `print of (how is x)` -> the R3 settledness value at full rest (to be fixed by the R3 design) diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index 17087a655..5454f6f54 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -78,6 +78,7 @@ 'buffer_read_num': 'READ', 'num_to_i64_exact': 'READ', 'finite_num_to_byte': 'READ', + 'buffer_read_byte': 'READ', # a buffer element as a byte (Q1: N5, no wrap) 'buf_num_arg': 'READ', # builtins_buf.c wrapper of eigs_list_num 'eigs_value_as_num': 'READ', # embed API accessor 'num_val': 'RAW', # lexer token payload (double) @@ -166,7 +167,22 @@ r'builtin_(str|print|write|hex))$'), ] +# Functions that dispatch on an opcode, and how an arm is spelled. Sites in +# them are attributed per arm (`fn/OP_X`), and executor_arms() below derives +# the executor matrix from the same arms. +DISPATCHERS = { + 'vm_run_ex': 'CASE', # the interpreter + 'jit_supported_prefix': 'IF', # the JIT scanner + 'jit_compile_to_thunk': 'IF', # the JIT emitter + 'chunk_scan_leaf_accessor': 'LABEL', # the leaf scanner (#366) + 'vm_leaf_accessor_exec': 'LABEL', # the leaf evaluator (#366) +} + TOKEN_RE = re.compile(r'\b(' + '|'.join(sorted(VOCAB, key=len, reverse=True)) + r')\b') +# Raw union members: the Value's double (`num_`) and the slot's (`d_`). Only +# the accessor macros may name them; anywhere else is a bypass. +RAW_MEMBER = re.compile(r'(?:\.|->)(d_|num_)\b') +RAW_MEMBER_HOMES = {'#define VAL_NUM_RAW', '#define SLOT_NUM_RAW', '#define VAL_NUM_OFFSET'} C_KEYWORDS = {'if', 'while', 'for', 'switch', 'return', 'sizeof', 'do', 'else', 'case', 'defined', '__attribute__', '__typeof__', '_Generic'} @@ -225,6 +241,8 @@ def scopes_for(stripped, fname, sigs=None): sig = '' # text since the last top-level ; or } (signature) cur = '' sub = None # dispatcher sub-scope (CASE(X) / OP_X) + arm_depth = None # brace depth of a LABEL dispatcher's arms + prev_label = False in_macro = None for ln, line in enumerate(lines, 1): # #define bodies (with continuations) are their own scope @@ -242,16 +260,29 @@ def scopes_for(stripped, fname, sigs=None): if re.match(r'\s*#', line): scope[ln] = cur if depth > 0 else '' continue - if depth > 0 and cur == 'vm_run_ex': - mc = re.match(r'\s*CASE\((\w+)\)', line) - if mc: - sub = 'CASE(%s)' % mc.group(1) - if depth > 0 and cur == 'jit_compile_to_thunk': - mo = re.search(r'\b(?:if|else if)\s*\(\s*op\s*==\s*(OP_\w+)', line) - if mo and depth <= 3: - sub = mo.group(1) + if depth > 0 and cur in DISPATCHERS: + style = DISPATCHERS[cur] + if style == 'CASE': + mc = re.match(r'\s*CASE\((\w+)\)', line) + if mc: + sub = 'CASE(%s)' % mc.group(1) + elif style == 'IF': + mo = re.search(r'\b(?:if|else if)\s*\(\s*op\s*==\s*(OP_\w+)', line) + if mo and depth <= 3: + sub = mo.group(1) + else: # LABEL: the outermost `case OP_X:` labels of the dispatch switch + labels = re.findall(r'\bcase\s+(OP_\w+)\s*:', line) + if labels and arm_depth is None: + arm_depth = depth + if labels and depth == arm_depth: + # consecutive label lines name one grouped arm + sub = (sub + '|' if prev_label and sub else '') + '|'.join(labels) + # a line holding only labels continues into the next label line + prev_label = line.rstrip().endswith(':') + elif line.strip(): + prev_label = False line_scope = cur if depth > 0 else '' - if depth > 0 and sub and cur in ('vm_run_ex', 'jit_compile_to_thunk'): + if depth > 0 and sub and cur in DISPATCHERS: line_scope = cur + '/' + sub for ch in line: if ch == '{': @@ -260,6 +291,7 @@ def scopes_for(stripped, fname, sigs=None): if sigs is not None and not cur.startswith('<'): sigs.setdefault(cur, sig) sub = None + arm_depth = None line_scope = cur depth += 1 elif ch == '}': @@ -361,6 +393,9 @@ def scan_file(path, rel): tok = m.group(1) tok = 'TAG-IMM ' + tok[:6] if tok.lower().startswith('0xfff') else tok sites.append((rel, ln, scope[ln], tok, 'EMIT')) + for m in RAW_MEMBER.finditer(line): + kind = 'RAW' if scope[ln] in RAW_MEMBER_HOMES else 'BYPASS' + sites.append((rel, ln, scope[ln], m.group(1), kind)) for m in AST_NUM_FIELD.finditer(line): rest = line[m.end():].lstrip() kind = 'WRITE' if re.match(r'=(?!=)', rest) else 'RAW' @@ -370,7 +405,7 @@ def scan_file(path, rel): def classify(site): rel, ln, scope, tok, kind = site - if kind == 'UNKNOWN': + if kind in ('UNKNOWN', 'BYPASS'): return None, None base = scope.split('/')[-1] if '/' in scope else scope for idx, (cat, frx, srx) in enumerate(ROLE_RULES): @@ -381,7 +416,8 @@ def classify(site): # ---- derived accessor check ---------------------------------------------- READ_IN_BODY = re.compile(r'\b(VAL_NUM_RAW|SLOT_NUM_RAW|eigs_num_arg|eigs_list_num|' - r'eigs_slot_num|list_get_num|dict_value_get_num|slot_as_double)\b') + r'eigs_slot_num|list_get_num|dict_value_get_num|slot_as_double)\b|' + r'(?:\.|->)(?:d_|num_)\b') def derived_accessors(stripped_by_file, scope_by_file, sigs_by_file): @@ -492,6 +528,123 @@ def numeric_builtins(regs, sites, bodies): return result +# ---- opcode executors, derived from the DISPATCHERS' arms ------------------ +ROLE_OF = {'vm_run_ex': 'interp', 'jit_supported_prefix': 'jit_scan', + 'jit_compile_to_thunk': 'jit_emit', 'chunk_scan_leaf_accessor': 'leaf_scan', + 'vm_leaf_accessor_exec': 'leaf_exec'} +ROLES = ['interp', 'jit_scan', 'jit_emit', 'leaf_scan', 'leaf_exec'] + + +def executor_arms(stripped_by_file, scope_by_file): + """opcode -> set of roles that have an arm for it; and each dispatcher + arm's opcode chain, keyed by its scope (`fn/sub`).""" + arms, chains = {}, {} + # a macro whose body spells CASE() generates an + # interpreter arm at each invocation (NUM_BINOP(SUB, ...), NUM_CMP(LT, ...)) + defs = [] + for stripped in stripped_by_file.values(): + for m in re.finditer(r'#\s*define\s+(\w+)\(\s*(\w+)[^)]*\)((?:[^\n]*\\\n)*[^\n]*)', stripped): + defs.append((m.group(1), m.group(2), m.group(3))) + case_macros, grew = set(), True + while grew: # closed over chains: INT_BINOP -> INT_BINOP_R -> CASE(NAME) + grew = False + for name, p1, body in defs: + if name in case_macros: + continue + calls = ['CASE'] + sorted(case_macros) + if re.search(r'\b(%s)\(\s*%s\b' % ('|'.join(calls), re.escape(p1)), body): + case_macros.add(name); grew = True + gen = re.compile(r'^\s*(%s)\(\s*(\w+)' % '|'.join(sorted(case_macros))) if case_macros else None + for rel, stripped in stripped_by_file.items(): + scope = scope_by_file[rel] + for ln, line in enumerate(stripped.split('\n'), 1): + fn, _, sub = scope[ln].partition('/') + if gen and fn == 'vm_run_ex': + mg = gen.match(line) + if mg: + arms.setdefault('OP_' + mg.group(2), set()).add('interp') + if fn not in DISPATCHERS: + continue + if DISPATCHERS[fn] == 'IF': + ops = re.findall(r'\bop\s*==\s*(OP_\w+)', line) + elif sub.startswith('CASE('): + ops = ['OP_' + sub[5:-1]] + else: + ops = [o for o in sub.split('|') if o] + for op in ops: + arms.setdefault(op, set()).add(ROLE_OF[fn]) + if sub and ops: + chains.setdefault(fn + '/' + sub, set()).update(ops) + return arms, chains + + +# ---- slot classifiers (R1.1's worklist) ------------------------------------ +# Every function (or dispatcher arm) that tests, dereferences or types an +# EigsSlot. D1 holds a number test, so the rename forces it; D2 dereferences +# with no number test; D3 tests other tags or bits; T only reads slot_type. +# Every D2 and D3 entry needs a reviewed disposition in the design doc. +SLOT_TEST = {'slot_is_num', 'slot_is_numeric', 'slot_as_double'} +SLOT_OTHER = {'slot_is_null', 'slot_is_bool', 'slot_is_heap', 'slot_is_ptr'} +SLOT_DEREF = {'slot_as_ptr', 'slot_as_heap', 'eigs_slot_ref'} +SLOT_TYPE = {'slot_type', 'list_elem_type', 'dict_value_type'} +SLOT_BITS = {'SLOT_QNAN_MASK', 'SLOT_TAG_MASK', 'SLOT_PAYLOAD_MASK', 'TAG_HEAP', 'TAG_BOOL', + 'TAG_SENTINEL', 'SLOT_NULL_BITS', 'SLOT_TRUE_BITS', 'SLOT_FALSE_BITS'} +SLOT_RE = re.compile(r'\b(' + '|'.join(sorted(SLOT_TEST | SLOT_OTHER | SLOT_DEREF | SLOT_TYPE | SLOT_BITS, + key=len, reverse=True)) + r')\b') +DISPOSITIONS = {'guarded', 'smi-arm', 'refuse', 'not-a-classifier'} + + +def slot_classifiers(stripped_by_file, scope_by_file): + toks = {} + for rel, stripped in stripped_by_file.items(): + scope = scope_by_file[rel] + for ln, line in enumerate(stripped.split('\n'), 1): + for m in SLOT_RE.finditer(line): + k = scope[ln] + if k.split('/')[0] not in DISPATCHERS: + k = k.split('/')[0] + if k.startswith('#define ') and k[8:] in SLOT_BITS: + continue # the constant's own definition + toks.setdefault((rel, k), {}).setdefault(m.group(1), 0) + toks[(rel, k)][m.group(1)] += 1 + out = {} + for key, c in toks.items(): + t = set(c) + cls = ('D1' if t & SLOT_TEST else 'D2' if t & SLOT_DEREF else + 'D3' if t & (SLOT_OTHER | SLOT_BITS) else 'T') + out[key] = (cls, c) + return out + + +def read_marked_table(doc, tag, row_re): + """Rows between and ; an unparsed + line inside the markers is refused, never skipped.""" + rows, bad = {}, [] + if not os.path.exists(doc): + return None, ['%s missing' % doc] + inside = False + with open(doc, encoding='utf-8') as f: + for ln, line in enumerate(f, 1): + if line.startswith('' % tag): + inside = True; continue + if line.startswith('' % tag): + inside = False; continue + if not inside or not line.strip(): + continue + m = row_re.match(line) + if not m: + if not re.match(r'^\|\s*(name|builtin|-+)\s*\|', line.strip()): + bad.append('%s:%d: unparsed %s line: %s' % (doc, ln, tag, line.strip()[:60])) + continue + if m.group(1) in rows: + bad.append('%s:%d: `%s` has two %s rows' % (doc, ln, m.group(1), tag)) + rows[m.group(1)] = (ln,) + m.groups()[1:] + return rows, bad + + +SLOT_ROW = re.compile(r'^\|\s*`([^`]+)`\s*\|\s*([a-z-]+)\s*\|') + + TABLE_ROW = re.compile(r'^\|\s*`([A-Za-z_]\w*)`\s*\|\s*([a-z-]+)\s*\|\s*(\S+)\s*\|') CLASSES = {'int-preserving', 'float-producing', 'int-requiring', 'other'} LOSS_MARKS = {'LOSS', '-'} @@ -555,12 +708,15 @@ def main(): classified, unclassified = [], [] rule_hits = [0] * len(ROLE_RULES) token_hits = {t: 0 for t in VOCAB} + token_hits.update({'d_': 0, 'num_': 0}) for site in sites: cat, rule = classify(site) if site[3] in token_hits: token_hits[site[3]] += 1 if cat is None: - unclassified.append((site, 'VAL_NUM/AST_NUM in an unrecognized position')) + why = ('raw union member outside its accessor macro' if site[4] == 'BYPASS' + else 'VAL_NUM/AST_NUM in an unrecognized position') + unclassified.append((site, why)) continue if rule is not None: rule_hits[rule] += 1 @@ -591,6 +747,34 @@ def main(): for n, (c, l) in (table or {}).items(): class_count[c] = class_count.get(c, 0) + 1 + # executors: the leaf scanner and evaluator must name the same opcodes + arms, chains = executor_arms(stripped_by_file, scope_by_file) + leaf_scan = {o for o, r in arms.items() if 'leaf_scan' in r} + leaf_exec = {o for o, r in arms.items() if 'leaf_exec' in r} + exec_bad = ['leaf scanner admits %s but the leaf evaluator has no arm' % o + for o in sorted(leaf_scan - leaf_exec)] + exec_bad += ['leaf evaluator has an arm for %s the leaf scanner never admits' % o + for o in sorted(leaf_exec - leaf_scan)] + found = {r for rs in arms.values() for r in rs} + exec_bad += ['dispatcher %s (%s) attributed no opcode arm' % (f, r) + for f, r in sorted(ROLE_OF.items()) if r not in found] + + # slot classifiers: every D2/D3 entry has a reviewed disposition row + slots = slot_classifiers(stripped_by_file, scope_by_file) + slot_cls = {} + for key, (cls, c) in slots.items(): + slot_cls[cls] = slot_cls.get(cls, 0) + 1 + need = {'%s:%s' % k for k, (cls, c) in slots.items() if cls in ('D2', 'D3')} + srows, sbad = read_marked_table(args.doc, 'slot-table', SLOT_ROW) + srows = srows or {} + for name, (ln, disp) in srows.items(): + if disp not in DISPOSITIONS: + sbad.append('%s:%d: `%s` has unknown disposition %r' % (args.doc, ln, name, disp)) + slot_missing = sorted(need - set(srows)) + slot_stale = sorted(set(srows) - need) + if not any(slot_cls.get(k) for k in ('D1', 'D2', 'D3')): + sbad.append('slot classifiers: examined=0 (no D1/D2/D3 entry found)') + # ---- report ---- cats = 'abcdefghij' per_cat = {c: 0 for c in cats} @@ -629,6 +813,31 @@ def main(): if per_cat_file.get(c, {}).get(rel, 0)) out.append('%-24s %5d %s' % (rel, per_file[rel], parts)) out.append('') + out.append('## Executors (arms per opcode; roles: %s)' % ' '.join(ROLES)) + interesting = sorted(o for o, r in arms.items() if r - {'interp'}) + for o in interesting: + out.append('%-24s %s' % (o, ' '.join(r if r in arms[o] else '-' for r in ROLES))) + out.append('') + # the MAP's L/F/O rows must exercise every JIT-emitter and leaf arm that + # holds a numeric site (tests/phase2/MAP.md `ops:`; design §9.2) + num_arms = sorted({sc.split(' ')[0] for (r_, l_, sc, t_, k_), c_ in classified + if sc.split('/')[0] in ('jit_compile_to_thunk', 'vm_leaf_accessor_exec') + and '/' in sc.split(' ')[0]}) + out.append('## Numeric arms (JIT emitter and leaf evaluator arms holding a numeric site)') + for sc in num_arms: + out.append('%-9s %-24s %s' % (ROLE_OF[sc.split('/')[0]], sc.split('/', 1)[1], + ' '.join(sorted(chains.get(sc, ()))))) + out.append('') + out.append('## Slot classifiers (R1.1 worklist)') + out.append(' '.join('%s=%d' % (k, slot_cls.get(k, 0)) for k in ('D1', 'D2', 'D3', 'T')) + + ' dispositions=%d missing=%d stale=%d' % (len(srows), len(slot_missing), len(slot_stale))) + for key in sorted(slots, key=lambda k: (slots[k][0], k)): + cls, c = slots[key] + if cls in ('D1', 'D2', 'D3'): + disp = 'forced' if cls == 'D1' else srows.get('%s:%s' % key, (0, '-'))[1] + out.append('%s %-42s %-16s %s' % (cls, '%s:%s' % key, disp, + ' '.join('%s=%d' % kv for kv in sorted(c.items())))) + out.append('') out.append('## Builtins') out.append('registered=%d numeric=%d classified=%d unclassified=%d stale=%d' % ( len(regs), len(nb), len(nb) - len(b_unclassified), len(b_unclassified), len(b_stale))) @@ -670,10 +879,21 @@ def main(): fail.append('numeric builtin `%s` (%s) has no classification row' % (n, nb[n][0])) for n in b_stale: fail.append('classification row `%s` names no numeric registered builtin' % n) + fail.extend(exec_bad) + fail.extend(sbad) + for n in slot_missing: + fail.append('slot classifier `%s` has no disposition row' % n) + for n in slot_stale: + fail.append('disposition row `%s` names no D2/D3 slot classifier' % n) for f_ in fail: print('FAIL: ' + f_) print('builtins: registered=%d numeric=%d classified=%d unclassified=%d stale=%d' % ( len(regs), len(nb), len(nb) - len(b_unclassified), len(b_unclassified), len(b_stale))) + print('slot classifiers: %s dispositions=%d missing=%d stale=%d' % ( + ' '.join('%s=%d' % (k, slot_cls.get(k, 0)) for k in ('D1', 'D2', 'D3', 'T')), + len(srows), len(slot_missing), len(slot_stale))) + print('executors: leaf_scan=%d leaf_exec=%d mismatches=%d' % ( + len(leaf_scan), len(leaf_exec), len(exec_bad))) print('examined=%d classified=%d unclassified=%d' % (examined + len(unreviewed), len(classified), len(unclassified))) if examined <= 0 or not regs or unclassified or fail: From e3c9b23ce875b34fe6ea3acb5e75ffe4ce988cc5 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 13:43:08 -0500 Subject: [PATCH 003/188] phase2 design r3: osr witness reaches the return sentinel, the bridge, landed-round filter (#1758) Design round 3 of #1758, after the round-2 critic's FAIL. Still no src/ change. - The osr witness proves the loop body ran natively: every OSR row is a `loop while true:` whose only exit is a return right after the claimed ops, and the witness requires the OSR record to reach the return sentinel (oadv == len). Every witness kind (leaf, leaf-gen, fn, fn-stop, osr, osr-stop) was calibrated on main against a negative plant: the honest row holds, the plant is VACUOUS. The critic's osr plant (0 native INDEX_SET calls under gdb) passed the round-2 rule and fails the new one. The two truthiness controls now end on the int call. - R1.2 is behaviour-preserving: the builtin readers and producers are a named bridge that R1.6 deletes, so every builtin behaviour change lands with a token change; a per-builtin behaviour table gates R1.6. The first int value appears at R1.3 (make_int is introduced there; an int-source check guards R1.1-R1.2), and every int consumer is converted in that commit. - `phase2_check.sh --through ` checks a round against exactly its landed rows; R1.1, R1.2 and R2.1 are mechanical rounds with named gates. - The observer's boxed-int path is mapped (observer_slot_update's number arm) and routed at R1.3, with a MAP row for an int of 2^47 and up. - buffer_read_num is renamed in R1.6 (index reads in gather/scatter_add and byte reads such as buf_from_pcm16le are re-decided); the compile count is re-measured under the Makefile's exact flags and attributed per commit: 1,488 of 1,798 sites stop compiling (R1.1 223, R1.2 464, R1.3 11, R1.6 743, R2.2 47); the 257 others are classified. - Q7 and Q8 are folded in as decided: a validated q7 column in the builtin table, a geometry reader that clips the whole shape, IEEE totalOrder for sorting and NaN propagation through min/max. Inventory plants A-T all red. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 463 +++++----- docs/design/phase2-numbers.md | 1365 ++++++++++++++++++------------ tests/phase2/MAP.md | 81 +- tools/phase2_inventory.py | 29 +- 4 files changed, 1148 insertions(+), 790 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 962e42147..5740de05b 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -286,238 +286,239 @@ D3 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET) guarded slot_is_null=1 ## Builtins registered=311 numeric=230 classified=230 unclassified=0 stale=0 -classes: float-producing=58 int-preserving=37 int-requiring=84 other=51 +classes: float-producing=57 int-preserving=37 int-requiring=85 other=51 LOSS (42): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_execute db_query_json db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed -abs builtin_abs int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -acos builtin_acos float-producing - VAL_NUM,eigs_num_arg,make_num -add builtin_tensor_add int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard -append builtin_append other - VAL_NUM -asin builtin_asin float-producing - VAL_NUM,eigs_num_arg,make_num -assert builtin_assert other - eigs_num_text -atan builtin_atan float-producing - VAL_NUM,eigs_num_arg,make_num -atan2 builtin_atan2 float-producing - VAL_NUM,eigs_num_arg,make_num -audio_capture_open builtin_audio_capture_open int-requiring - VAL_NUM,eigs_list_num,make_num -audio_envelope builtin_audio_envelope float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num -audio_gain builtin_audio_gain float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num -audio_mix builtin_audio_mix float-producing - VAL_NUM,eigs_slot_num,make_num -audio_music_play builtin_audio_music_play int-requiring - VAL_NUM,eigs_list_num -audio_music_volume builtin_audio_music_volume other - VAL_NUM,eigs_list_num,eigs_num_arg -audio_noise builtin_audio_noise float-producing - VAL_NUM,eigs_list_num,make_num -audio_open builtin_audio_open int-requiring - VAL_NUM,eigs_list_num,make_num -audio_pause builtin_audio_pause int-requiring - VAL_NUM,eigs_num_arg -audio_play builtin_audio_play other - VAL_NUM,buffer_read_num,eigs_slot_num,make_num -audio_play_loop builtin_audio_play_loop int-requiring - VAL_NUM,buffer_read_num,eigs_list_num,eigs_slot_num,make_num -audio_queue_size builtin_audio_queue_size int-preserving - make_num -audio_saw builtin_audio_saw float-producing - VAL_NUM,eigs_list_num,make_num -audio_sine builtin_audio_sine float-producing - VAL_NUM,eigs_list_num,make_num -audio_square builtin_audio_square float-producing - VAL_NUM,eigs_list_num,make_num -audio_stop builtin_audio_stop int-requiring - VAL_NUM,eigs_num_arg,make_num -audio_stream_open builtin_audio_stream_open int-requiring - VAL_NUM,eigs_list_num,make_num -audio_stream_push builtin_audio_stream_push other - VAL_NUM,buffer_read_num,eigs_slot_num -audio_stream_queued builtin_audio_stream_queued int-preserving - make_num -audio_sweep builtin_audio_sweep float-producing - VAL_NUM,eigs_list_num,make_num -audio_volume builtin_audio_volume int-requiring - VAL_NUM,eigs_slot_num,make_num -bit_and builtin_bit_and int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_not builtin_bit_not int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_or builtin_bit_or int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_shl builtin_bit_shift_left int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_shr builtin_bit_shift_right int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_xor builtin_bit_xor int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -buf_copy builtin_buf_copy int-requiring - VAL_NUM,eigs_slot_num -buf_deinterleave builtin_buf_deinterleave int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_num -buf_dot builtin_buf_dot float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,make_num,num_guard -buf_fill builtin_buf_fill float-producing - VAL_NUM,buf_num_arg,eigs_slot_num -buf_from_list builtin_buf_from_list float-producing - VAL_NUM,eigs_slot_num -buf_from_pcm16le builtin_buf_from_pcm16le float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,num_guard -buf_get builtin_buf_get int-requiring - buffer_read_num,eigs_list_num,make_num -buf_len builtin_buf_len int-preserving - make_num -buf_mix builtin_buf_mix float-producing - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard -buf_peak builtin_buf_peak float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,make_num -buf_resample_linear builtin_buf_resample_linear float-producing - VAL_NUM,eigs_slot_num,num_guard -buf_scale_range builtin_buf_scale_range float-producing - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard -buf_set builtin_buf_set int-requiring - VAL_NUM,eigs_list_num -buf_to_pcm16le builtin_buf_to_pcm16le other - VAL_NUM,buffer_read_num,eigs_slot_num,num_guard -buffer builtin_buffer int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg -build_corpus builtin_build_corpus int-requiring - VAL_NUM,eigs_num_arg,eigs_opt_num,make_num,num_val -ceil builtin_ceil int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -channel builtin_channel int-preserving - make_num -channel_closed builtin_channel_closed int-requiring - VAL_NUM,eigs_num_arg -char_at builtin_char_at int-requiring - VAL_NUM,eigs_num_arg -chr builtin_chr int-requiring - VAL_NUM,eigs_num_arg -clock_unix builtin_clock_unix float-producing - make_num -close_channel builtin_close_channel int-requiring - VAL_NUM,eigs_num_arg -copy_into builtin_copy_into int-requiring - VAL_NUM,eigs_num_arg -cos builtin_cos float-producing - VAL_NUM,eigs_num_arg,make_num -db_execute builtin_db_execute other LOSS VAL_NUM,eigs_num_arg -db_query_json builtin_db_query_json other LOSS VAL_NUM,eigs_num_arg -db_query_value builtin_db_query_value other LOSS VAL_NUM,eigs_num_arg,make_num,strtod -dispatch builtin_dispatch int-requiring - VAL_NUM,eigs_num_arg,make_num -divide builtin_tensor_divide float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard -dot builtin_dot float-producing - buffer_read_num,make_num,num_guard -eigen_eval_loss builtin_eigen_eval_loss float-producing - VAL_NUM,eigs_list_num,eigs_slot_num,make_num -eigen_generate builtin_eigen_generate int-requiring - eigs_slot_num,eigs_slot_opt_num,make_num -eigen_model_load builtin_eigen_model_load other - strtod -exec_capture builtin_exec_capture other - VAL_NUM,eigs_list_num,list_append_num -exit builtin_exit int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg -exp builtin_tensor_exp float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard -f64_from_bytes builtin_f64_from_bytes int-requiring - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named -f64_to_bytes builtin_f64_to_bytes other - VAL_NUM,eigs_num_arg,make_num -fill builtin_fill int-requiring - eigs_list_num -floor builtin_floor int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -gather builtin_tensor_gather int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num -get_at builtin_get_at int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,make_num -get_observer_thresholds builtin_get_observer_thresholds float-producing - make_num -gfx_circle builtin_gfx_circle other - VAL_NUM,eigs_list_num -gfx_clear builtin_gfx_clear other - VAL_NUM,eigs_list_num -gfx_clip builtin_gfx_clip other - VAL_NUM,eigs_list_num -gfx_delay builtin_gfx_delay other - VAL_NUM,eigs_num_arg -gfx_fb builtin_gfx_fb int-requiring - VAL_NUM,buffer_read_byte,eigs_list_num -gfx_line builtin_gfx_line other - VAL_NUM,eigs_list_num -gfx_open builtin_gfx_open other - VAL_NUM,eigs_list_num -gfx_point builtin_gfx_point other - VAL_NUM,eigs_list_num -gfx_poll builtin_gfx_poll int-preserving - make_num -gfx_read builtin_gfx_read other - VAL_NUM,eigs_list_num,make_num -gfx_rect builtin_gfx_rect other - VAL_NUM,eigs_list_num -gfx_rrect builtin_gfx_rrect other - VAL_NUM,eigs_list_num -gfx_text builtin_gfx_text other - VAL_NUM,eigs_list_num -gfx_text_height builtin_gfx_text_height int-preserving - VAL_NUM,eigs_list_num,eigs_num_arg,make_num -gfx_text_width builtin_gfx_text_width int-preserving - VAL_NUM,eigs_list_num,make_num -gfx_ticks builtin_gfx_ticks int-preserving - make_num -hex builtin_hex int-requiring LOSS VAL_NUM,eigs_list_num,eigs_num_arg -http_early_bind builtin_http_early_bind int-requiring - VAL_NUM,eigs_opt_num -http_post builtin_http_post other - eigs_num_text -http_route builtin_http_route other - eigs_num_text -http_route_authed builtin_http_route_authed other - eigs_num_text -http_serve builtin_http_serve int-requiring - eigs_num_text,eigs_opt_num -http_static builtin_http_static other - eigs_num_text -index_of builtin_index_of int-preserving - make_num -inflate builtin_inflate int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num -join builtin_join other - eigs_num_text -json_build builtin_json_build other LOSS VAL_NUM,eigs_num_arg,eigs_num_text -json_decode builtin_json_decode other LOSS make_num,strtod -json_encode builtin_json_encode other LOSS VAL_NUM,eigs_num_arg,eigs_num_text -json_path builtin_json_path other LOSS VAL_NUM,eigs_num_arg,eigs_num_text,make_num,strtod -leaky_relu builtin_tensor_leaky_relu float-producing - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num -len builtin_len int-preserving - make_num -list_contains builtin_list_contains other - values_equal -list_index_of builtin_list_index_of int-preserving - make_num,values_equal -list_insert_at builtin_list_insert_at int-requiring - VAL_NUM,eigs_num_arg -list_remove_at builtin_list_remove_at int-requiring - VAL_NUM,eigs_num_arg -list_slice builtin_list_slice int-requiring - VAL_NUM,eigs_num_arg -list_truncate builtin_list_truncate int-requiring - VAL_NUM,eigs_num_arg -log builtin_tensor_log float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard -log_softmax builtin_tensor_log_softmax float-producing - VAL_NUM,eigs_slot_num,make_num -matmul builtin_tensor_matmul float-producing - SLOT_NUM_RAW,VAL_NUM,eigs_slot_num,make_num,num_guard_named -matmul_at builtin_tensor_matmul_at float-producing - VAL_NUM,eigs_slot_num,make_num -matmul_bt builtin_tensor_matmul_bt float-producing - VAL_NUM,eigs_slot_num,make_num -max builtin_max int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -mean builtin_tensor_mean float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard -min builtin_min int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -model_load_weights builtin_eigen_model_load other - strtod -monotonic_ms builtin_monotonic_ms float-producing - make_num -monotonic_ns builtin_monotonic_ns int-preserving LOSS make_num -multiply builtin_tensor_multiply int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard -native_train_step_builtin builtin_native_train_step int-requiring - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod -nearest_in_range builtin_nearest_in_range float-producing - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num -nearest_in_range_all builtin_nearest_in_range_all float-producing - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num -negative builtin_tensor_negative int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -net_accept builtin_net_accept int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_opt_num,make_num -net_close builtin_net_close int-requiring - VAL_NUM,eigs_num_arg -net_dial builtin_net_dial int-requiring - eigs_slot_opt_num,make_num -net_listen builtin_net_listen int-requiring - VAL_NUM,eigs_num_arg,make_num -net_port builtin_net_port int-requiring - VAL_NUM,eigs_num_arg,make_num -net_recv builtin_net_recv int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_opt_num -net_send builtin_net_send int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num -norm builtin_tensor_norm float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard -num builtin_num other LOSS VAL_NUM,make_num,num_guard_named,strtod -num_copy builtin_num_copy int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -numerical_grad builtin_numerical_grad float-producing - VAL_NUM,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num -numerical_grad_cols builtin_numerical_grad_cols float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num -numerical_grad_rows builtin_numerical_grad_rows float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num -observe builtin_observe other - make_num -ord builtin_ord int-preserving - make_num -pi builtin_pi float-producing - make_num -pow builtin_tensor_pow float-producing - VAL_NUM,eigs_num_arg,make_num,num_guard_named -ppu_render_frame builtin_ppu_render_frame int-requiring - buffer_read_byte -print builtin_print other - eigs_num_text -proc_read_buf builtin_proc_read_buf int-requiring - VAL_NUM,eigs_num_arg -random builtin_random float-producing - make_num -random_hex builtin_random_hex int-requiring - VAL_NUM,eigs_num_arg -random_int builtin_random_int int-requiring LOSS VAL_NUM,eigs_num_arg,make_num -random_normal builtin_random_normal float-producing - eigs_list_num,make_num -range builtin_range int-preserving - VAL_NUM,eigs_list_num,eigs_num_arg,make_num -read_bytes builtin_read_bytes int-preserving - make_num -read_bytes_buf builtin_read_bytes_buf int-requiring - VAL_NUM,eigs_num_arg,make_num -record_history builtin_record_history other - VAL_NUM,eigs_num_arg,make_num -recv builtin_recv int-requiring - VAL_NUM,eigs_num_arg -recv_timeout builtin_recv_timeout int-requiring - VAL_NUM,eigs_num_arg -relu builtin_tensor_relu float-producing - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num -reshape builtin_reshape int-requiring - VAL_NUM,eigs_list_num -round builtin_round int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -sandbox_run builtin_sandbox_run int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg,make_num -scan_int_tokens builtin_scan_int_tokens int-preserving LOSS make_num -scan_ints builtin_scan_ints int-preserving LOSS make_num -scatter_add builtin_tensor_scatter_add float-producing - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard -seed_random builtin_seed_random int-requiring LOSS VAL_NUM,eigs_num_arg -send builtin_send int-requiring - VAL_NUM,eigs_num_arg -set_at builtin_set_at int-requiring - VAL_NUM,eigs_num_arg -sgd_update builtin_sgd_update float-producing - VAL_NUM,eigs_slot_num,eigs_slot_opt_num,list_set_num -sgd_update_cols builtin_sgd_update_cols float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num -sgd_update_rows builtin_sgd_update_rows float-producing - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num -shape builtin_tensor_shape int-preserving - VAL_NUM,make_num -shared_delete builtin_shared_delete int-preserving - make_num -shared_incr builtin_shared_incr int-preserving LOSS VAL_NUM,eigs_num_arg,make_num -shared_size builtin_shared_size int-preserving - make_num -sign_extend builtin_sign_extend int-requiring LOSS VAL_NUM,eigs_num_arg,make_num -sin builtin_sin float-producing - VAL_NUM,eigs_num_arg,make_num -softmax builtin_tensor_softmax float-producing - VAL_NUM,eigs_slot_num,make_num -sort builtin_sort other LOSS VAL_NUM,eigs_slot_num -sort_by builtin_sort_by other LOSS VAL_NUM,eigs_num_arg -spawn builtin_spawn int-preserving - make_num -sqrt builtin_tensor_sqrt float-producing - VAL_NUM,eigs_num_arg,make_num -state_at builtin_state_at int-requiring - VAL_NUM,eigs_num_arg -store_close builtin_store_close int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num -store_collections builtin_store_collections int-requiring - VAL_NUM,eigs_num_arg -store_count builtin_store_count int-requiring - VAL_NUM,eigs_num_arg,make_num -store_delete builtin_store_delete int-requiring LOSS VAL_NUM,eigs_num_arg -store_drop builtin_store_drop int-requiring - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num -store_get builtin_store_get int-requiring LOSS VAL_NUM,eigs_num_arg,make_num,strtod -store_open builtin_store_open int-preserving - VAL_NUM,eigs_num_arg,make_num,strtod -store_put builtin_store_put other LOSS VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num -store_query builtin_store_query other LOSS VAL_NUM,eigs_num_arg,make_num,strtod -store_update builtin_store_update other LOSS VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num -str builtin_str other - eigs_num_text -str_from_bytes builtin_str_from_bytes int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte -stream_open builtin_stream_open int-requiring - VAL_NUM,eigs_num_arg -stream_write builtin_stream_write float-producing - VAL_NUM,eigs_num_arg -substr builtin_substr int-requiring - VAL_NUM,eigs_num_arg -subtract builtin_tensor_subtract int-preserving LOSS VAL_NUM,eigs_num_arg,make_num,num_guard -sum builtin_tensor_sum int-preserving LOSS VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard -tan builtin_tan float-producing - VAL_NUM,eigs_num_arg,make_num -task_alive builtin_task_alive int-requiring - VAL_NUM,eigs_num_arg -task_detach builtin_task_detach int-requiring - VAL_NUM,eigs_num_arg,make_num -task_join builtin_task_join int-requiring - VAL_NUM,eigs_num_arg -task_kill builtin_task_kill int-requiring - VAL_NUM,eigs_num_arg -task_sched_seed builtin_task_sched_seed int-requiring LOSS VAL_NUM,eigs_num_arg -task_self builtin_task_self int-preserving - make_num -task_send builtin_task_send int-requiring - VAL_NUM,eigs_num_arg -task_sleep builtin_task_sleep other - VAL_NUM,eigs_num_arg -task_spawn builtin_task_spawn int-preserving - make_num -tensor_load builtin_tensor_load float-producing - VAL_NUM,eigs_list_num,make_num,num_guard_named -tensor_save builtin_tensor_save float-producing - VAL_NUM,eigs_slot_num -text_builder_append builtin_text_builder_append other - eigs_num_text -text_builder_append_line builtin_text_builder_append_line other - eigs_num_text -thread_join builtin_thread_join int-requiring - VAL_NUM,eigs_num_arg -throw builtin_throw other - eigs_num_text -token_name builtin_token_name int-requiring - VAL_NUM,eigs_num_arg -try_recv builtin_try_recv int-requiring - VAL_NUM,eigs_num_arg -type builtin_type other - VAL_NUM -usleep builtin_usleep other - VAL_NUM,eigs_num_arg -vm_run_bytecode builtin_vm_run_bytecode int-requiring - VAL_NUM,eigs_num_arg -write builtin_write other - eigs_num_text -write_bytes builtin_write_bytes int-requiring - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num -zeros builtin_tensor_zeros int-requiring - VAL_NUM,eigs_list_num,eigs_num_arg,make_num -zeros_like builtin_tensor_zeros_like float-producing - VAL_NUM,make_num +Q7: geometry=9 bounded=13 magnitude=13 +abs builtin_abs int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +acos builtin_acos float-producing - - VAL_NUM,eigs_num_arg,make_num +add builtin_tensor_add int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard +append builtin_append other - - VAL_NUM +asin builtin_asin float-producing - - VAL_NUM,eigs_num_arg,make_num +assert builtin_assert other - - eigs_num_text +atan builtin_atan float-producing - - VAL_NUM,eigs_num_arg,make_num +atan2 builtin_atan2 float-producing - - VAL_NUM,eigs_num_arg,make_num +audio_capture_open builtin_audio_capture_open int-requiring - - VAL_NUM,eigs_list_num,make_num +audio_envelope builtin_audio_envelope float-producing - magnitude VAL_NUM,eigs_list_num,eigs_slot_num,make_num +audio_gain builtin_audio_gain float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num +audio_mix builtin_audio_mix float-producing - - VAL_NUM,eigs_slot_num,make_num +audio_music_play builtin_audio_music_play int-requiring - - VAL_NUM,eigs_list_num +audio_music_volume builtin_audio_music_volume other - bounded VAL_NUM,eigs_list_num,eigs_num_arg +audio_noise builtin_audio_noise float-producing - magnitude VAL_NUM,eigs_list_num,make_num +audio_open builtin_audio_open int-requiring - - VAL_NUM,eigs_list_num,make_num +audio_pause builtin_audio_pause int-requiring - - VAL_NUM,eigs_num_arg +audio_play builtin_audio_play other - bounded VAL_NUM,buffer_read_num,eigs_slot_num,make_num +audio_play_loop builtin_audio_play_loop int-requiring - bounded VAL_NUM,buffer_read_num,eigs_list_num,eigs_slot_num,make_num +audio_queue_size builtin_audio_queue_size int-preserving - - make_num +audio_saw builtin_audio_saw float-producing - magnitude VAL_NUM,eigs_list_num,make_num +audio_sine builtin_audio_sine float-producing - magnitude VAL_NUM,eigs_list_num,make_num +audio_square builtin_audio_square float-producing - magnitude VAL_NUM,eigs_list_num,make_num +audio_stop builtin_audio_stop int-requiring - - VAL_NUM,eigs_num_arg,make_num +audio_stream_open builtin_audio_stream_open int-requiring - - VAL_NUM,eigs_list_num,make_num +audio_stream_push builtin_audio_stream_push other - bounded VAL_NUM,buffer_read_num,eigs_slot_num +audio_stream_queued builtin_audio_stream_queued int-preserving - - make_num +audio_sweep builtin_audio_sweep float-producing - magnitude VAL_NUM,eigs_list_num,make_num +audio_volume builtin_audio_volume int-requiring - bounded VAL_NUM,eigs_slot_num,make_num +bit_and builtin_bit_and int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_not builtin_bit_not int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_or builtin_bit_or int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_shl builtin_bit_shift_left int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_shr builtin_bit_shift_right int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_xor builtin_bit_xor int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +buf_copy builtin_buf_copy int-requiring - - VAL_NUM,eigs_slot_num +buf_deinterleave builtin_buf_deinterleave int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num +buf_dot builtin_buf_dot float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,make_num,num_guard +buf_fill builtin_buf_fill float-producing - - VAL_NUM,buf_num_arg,eigs_slot_num +buf_from_list builtin_buf_from_list float-producing - - VAL_NUM,eigs_slot_num +buf_from_pcm16le builtin_buf_from_pcm16le int-requiring - - VAL_NUM,buffer_read_num,eigs_slot_num,num_guard +buf_get builtin_buf_get int-requiring - - buffer_read_num,eigs_list_num,make_num +buf_len builtin_buf_len int-preserving - - make_num +buf_mix builtin_buf_mix float-producing - - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard +buf_peak builtin_buf_peak float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,make_num +buf_resample_linear builtin_buf_resample_linear float-producing - - VAL_NUM,eigs_slot_num,num_guard +buf_scale_range builtin_buf_scale_range float-producing - - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard +buf_set builtin_buf_set int-requiring - - VAL_NUM,eigs_list_num +buf_to_pcm16le builtin_buf_to_pcm16le other - bounded VAL_NUM,buffer_read_num,eigs_slot_num,num_guard +buffer builtin_buffer int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg +build_corpus builtin_build_corpus int-requiring - - VAL_NUM,eigs_num_arg,eigs_opt_num,make_num,num_val +ceil builtin_ceil int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +channel builtin_channel int-preserving - - make_num +channel_closed builtin_channel_closed int-requiring - - VAL_NUM,eigs_num_arg +char_at builtin_char_at int-requiring - - VAL_NUM,eigs_num_arg +chr builtin_chr int-requiring - - VAL_NUM,eigs_num_arg +clock_unix builtin_clock_unix float-producing - - make_num +close_channel builtin_close_channel int-requiring - - VAL_NUM,eigs_num_arg +copy_into builtin_copy_into int-requiring - - VAL_NUM,eigs_num_arg +cos builtin_cos float-producing - - VAL_NUM,eigs_num_arg,make_num +db_execute builtin_db_execute other LOSS - VAL_NUM,eigs_num_arg +db_query_json builtin_db_query_json other LOSS - VAL_NUM,eigs_num_arg +db_query_value builtin_db_query_value other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod +dispatch builtin_dispatch int-requiring - - VAL_NUM,eigs_num_arg,make_num +divide builtin_tensor_divide float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard +dot builtin_dot float-producing - - buffer_read_num,make_num,num_guard +eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num +eigen_generate builtin_eigen_generate int-requiring - - eigs_slot_num,eigs_slot_opt_num,make_num +eigen_model_load builtin_eigen_model_load other - - strtod +exec_capture builtin_exec_capture other - magnitude VAL_NUM,eigs_list_num,list_append_num +exit builtin_exit int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg +exp builtin_tensor_exp float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard +f64_from_bytes builtin_f64_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named +f64_to_bytes builtin_f64_to_bytes other - - VAL_NUM,eigs_num_arg,make_num +fill builtin_fill int-requiring - - eigs_list_num +floor builtin_floor int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +gather builtin_tensor_gather int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num +get_at builtin_get_at int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num +get_observer_thresholds builtin_get_observer_thresholds float-producing - - make_num +gfx_circle builtin_gfx_circle other - geometry,bounded VAL_NUM,eigs_list_num +gfx_clear builtin_gfx_clear other - bounded VAL_NUM,eigs_list_num +gfx_clip builtin_gfx_clip other - geometry VAL_NUM,eigs_list_num +gfx_delay builtin_gfx_delay other - magnitude VAL_NUM,eigs_num_arg +gfx_fb builtin_gfx_fb int-requiring - geometry VAL_NUM,buffer_read_byte,eigs_list_num +gfx_line builtin_gfx_line other - geometry,bounded VAL_NUM,eigs_list_num +gfx_open builtin_gfx_open other - magnitude VAL_NUM,eigs_list_num +gfx_point builtin_gfx_point other - geometry,bounded VAL_NUM,eigs_list_num +gfx_poll builtin_gfx_poll int-preserving - - make_num +gfx_read builtin_gfx_read other - geometry VAL_NUM,eigs_list_num,make_num +gfx_rect builtin_gfx_rect other - geometry,bounded VAL_NUM,eigs_list_num +gfx_rrect builtin_gfx_rrect other - geometry,bounded VAL_NUM,eigs_list_num +gfx_text builtin_gfx_text other - geometry,bounded VAL_NUM,eigs_list_num +gfx_text_height builtin_gfx_text_height int-preserving - magnitude VAL_NUM,eigs_list_num,eigs_num_arg,make_num +gfx_text_width builtin_gfx_text_width int-preserving - magnitude VAL_NUM,eigs_list_num,make_num +gfx_ticks builtin_gfx_ticks int-preserving - - make_num +hex builtin_hex int-requiring LOSS - VAL_NUM,eigs_list_num,eigs_num_arg +http_early_bind builtin_http_early_bind int-requiring - - VAL_NUM,eigs_opt_num +http_post builtin_http_post other - - eigs_num_text +http_route builtin_http_route other - - eigs_num_text +http_route_authed builtin_http_route_authed other - - eigs_num_text +http_serve builtin_http_serve int-requiring - - eigs_num_text,eigs_opt_num +http_static builtin_http_static other - - eigs_num_text +index_of builtin_index_of int-preserving - - make_num +inflate builtin_inflate int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num +join builtin_join other - - eigs_num_text +json_build builtin_json_build other LOSS - VAL_NUM,eigs_num_arg,eigs_num_text +json_decode builtin_json_decode other LOSS - make_num,strtod +json_encode builtin_json_encode other LOSS - VAL_NUM,eigs_num_arg,eigs_num_text +json_path builtin_json_path other LOSS - VAL_NUM,eigs_num_arg,eigs_num_text,make_num,strtod +leaky_relu builtin_tensor_leaky_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num +len builtin_len int-preserving - - make_num +list_contains builtin_list_contains other - - values_equal +list_index_of builtin_list_index_of int-preserving - - make_num,values_equal +list_insert_at builtin_list_insert_at int-requiring - - VAL_NUM,eigs_num_arg +list_remove_at builtin_list_remove_at int-requiring - - VAL_NUM,eigs_num_arg +list_slice builtin_list_slice int-requiring - - VAL_NUM,eigs_num_arg +list_truncate builtin_list_truncate int-requiring - - VAL_NUM,eigs_num_arg +log builtin_tensor_log float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard +log_softmax builtin_tensor_log_softmax float-producing - - VAL_NUM,eigs_slot_num,make_num +matmul builtin_tensor_matmul float-producing - - SLOT_NUM_RAW,VAL_NUM,eigs_slot_num,make_num,num_guard_named +matmul_at builtin_tensor_matmul_at float-producing - - VAL_NUM,eigs_slot_num,make_num +matmul_bt builtin_tensor_matmul_bt float-producing - - VAL_NUM,eigs_slot_num,make_num +max builtin_max int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +mean builtin_tensor_mean float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +min builtin_min int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +model_load_weights builtin_eigen_model_load other - - strtod +monotonic_ms builtin_monotonic_ms float-producing - - make_num +monotonic_ns builtin_monotonic_ns int-preserving LOSS - make_num +multiply builtin_tensor_multiply int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard +native_train_step_builtin builtin_native_train_step int-requiring - - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod +nearest_in_range builtin_nearest_in_range float-producing - - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num +nearest_in_range_all builtin_nearest_in_range_all float-producing - - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num +negative builtin_tensor_negative int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +net_accept builtin_net_accept int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num,make_num +net_close builtin_net_close int-requiring - - VAL_NUM,eigs_num_arg +net_dial builtin_net_dial int-requiring - - eigs_slot_opt_num,make_num +net_listen builtin_net_listen int-requiring - - VAL_NUM,eigs_num_arg,make_num +net_port builtin_net_port int-requiring - - VAL_NUM,eigs_num_arg,make_num +net_recv builtin_net_recv int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num +net_send builtin_net_send int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +norm builtin_tensor_norm float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +num builtin_num other LOSS - VAL_NUM,make_num,num_guard_named,strtod +num_copy builtin_num_copy int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +numerical_grad builtin_numerical_grad float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +numerical_grad_cols builtin_numerical_grad_cols float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +numerical_grad_rows builtin_numerical_grad_rows float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +observe builtin_observe other - - make_num +ord builtin_ord int-preserving - - make_num +pi builtin_pi float-producing - - make_num +pow builtin_tensor_pow float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard_named +ppu_render_frame builtin_ppu_render_frame int-requiring - - buffer_read_byte +print builtin_print other - - eigs_num_text +proc_read_buf builtin_proc_read_buf int-requiring - - VAL_NUM,eigs_num_arg +random builtin_random float-producing - - make_num +random_hex builtin_random_hex int-requiring - - VAL_NUM,eigs_num_arg +random_int builtin_random_int int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num +random_normal builtin_random_normal float-producing - - eigs_list_num,make_num +range builtin_range int-preserving - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +read_bytes builtin_read_bytes int-preserving - - make_num +read_bytes_buf builtin_read_bytes_buf int-requiring - - VAL_NUM,eigs_num_arg,make_num +record_history builtin_record_history other - - VAL_NUM,eigs_num_arg,make_num +recv builtin_recv int-requiring - - VAL_NUM,eigs_num_arg +recv_timeout builtin_recv_timeout int-requiring - magnitude VAL_NUM,eigs_num_arg +relu builtin_tensor_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num +reshape builtin_reshape int-requiring - - VAL_NUM,eigs_list_num +round builtin_round int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +sandbox_run builtin_sandbox_run int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +scan_int_tokens builtin_scan_int_tokens int-preserving LOSS - make_num +scan_ints builtin_scan_ints int-preserving LOSS - make_num +scatter_add builtin_tensor_scatter_add float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard +seed_random builtin_seed_random int-requiring LOSS - VAL_NUM,eigs_num_arg +send builtin_send int-requiring - - VAL_NUM,eigs_num_arg +set_at builtin_set_at int-requiring - - VAL_NUM,eigs_num_arg +sgd_update builtin_sgd_update float-producing - - VAL_NUM,eigs_slot_num,eigs_slot_opt_num,list_set_num +sgd_update_cols builtin_sgd_update_cols float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num +sgd_update_rows builtin_sgd_update_rows float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num +shape builtin_tensor_shape int-preserving - - VAL_NUM,make_num +shared_delete builtin_shared_delete int-preserving - - make_num +shared_incr builtin_shared_incr int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +shared_size builtin_shared_size int-preserving - - make_num +sign_extend builtin_sign_extend int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num +sin builtin_sin float-producing - - VAL_NUM,eigs_num_arg,make_num +softmax builtin_tensor_softmax float-producing - - VAL_NUM,eigs_slot_num,make_num +sort builtin_sort other LOSS - VAL_NUM,eigs_slot_num +sort_by builtin_sort_by other LOSS - VAL_NUM,eigs_num_arg +spawn builtin_spawn int-preserving - - make_num +sqrt builtin_tensor_sqrt float-producing - - VAL_NUM,eigs_num_arg,make_num +state_at builtin_state_at int-requiring - - VAL_NUM,eigs_num_arg +store_close builtin_store_close int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num +store_collections builtin_store_collections int-requiring - - VAL_NUM,eigs_num_arg +store_count builtin_store_count int-requiring - - VAL_NUM,eigs_num_arg,make_num +store_delete builtin_store_delete int-requiring LOSS - VAL_NUM,eigs_num_arg +store_drop builtin_store_drop int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num +store_get builtin_store_get int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,strtod +store_open builtin_store_open int-preserving - - VAL_NUM,eigs_num_arg,make_num,strtod +store_put builtin_store_put other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num +store_query builtin_store_query other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod +store_update builtin_store_update other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num +str builtin_str other - - eigs_num_text +str_from_bytes builtin_str_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte +stream_open builtin_stream_open int-requiring - - VAL_NUM,eigs_num_arg +stream_write builtin_stream_write float-producing - - VAL_NUM,eigs_num_arg +substr builtin_substr int-requiring - - VAL_NUM,eigs_num_arg +subtract builtin_tensor_subtract int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard +sum builtin_tensor_sum int-preserving LOSS - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +tan builtin_tan float-producing - - VAL_NUM,eigs_num_arg,make_num +task_alive builtin_task_alive int-requiring - - VAL_NUM,eigs_num_arg +task_detach builtin_task_detach int-requiring - - VAL_NUM,eigs_num_arg,make_num +task_join builtin_task_join int-requiring - - VAL_NUM,eigs_num_arg +task_kill builtin_task_kill int-requiring - - VAL_NUM,eigs_num_arg +task_sched_seed builtin_task_sched_seed int-requiring LOSS - VAL_NUM,eigs_num_arg +task_self builtin_task_self int-preserving - - make_num +task_send builtin_task_send int-requiring - - VAL_NUM,eigs_num_arg +task_sleep builtin_task_sleep other - - VAL_NUM,eigs_num_arg +task_spawn builtin_task_spawn int-preserving - - make_num +tensor_load builtin_tensor_load float-producing - - VAL_NUM,eigs_list_num,make_num,num_guard_named +tensor_save builtin_tensor_save float-producing - - VAL_NUM,eigs_slot_num +text_builder_append builtin_text_builder_append other - - eigs_num_text +text_builder_append_line builtin_text_builder_append_line other - - eigs_num_text +thread_join builtin_thread_join int-requiring - - VAL_NUM,eigs_num_arg +throw builtin_throw other - - eigs_num_text +token_name builtin_token_name int-requiring - - VAL_NUM,eigs_num_arg +try_recv builtin_try_recv int-requiring - - VAL_NUM,eigs_num_arg +type builtin_type other - - VAL_NUM +usleep builtin_usleep other - magnitude VAL_NUM,eigs_num_arg +vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_NUM,eigs_num_arg +write builtin_write other - - eigs_num_text +write_bytes builtin_write_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +zeros builtin_tensor_zeros int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +zeros_like builtin_tensor_zeros_like float-producing - - VAL_NUM,make_num ## Sites (file:line scope token kind category) builtins.c:164 builtin_usleep VAL_NUM TEST a diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 8806d944e..e72bf9abf 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1,9 +1,11 @@ -# Phase 2 numbers (#1758): design (round 0, revised in design round 2) - -Status: design for blind review, before round 1 builds. Nothing here changes -`src/`. Spec: issue #1758 (Revision 1), its owner decisions (A), (B), (C), and -the Q1-Q6 decisions -([comment](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6171744498)). +# Phase 2 numbers (#1758): design (round 0, revised in design rounds 2 and 3) + +Status: the last design round before round 1 builds. Nothing here changes +`src/`. Spec: issue #1758 (Revision 1), its owner decisions (A), (B), (C), the +Q1-Q6 decisions +([comment](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6171744498)) +and the Q7-Q8 decisions +([comment](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6174302316)). Evidence base: issue #1746 and the `exp-ieee-p1` branch (canonical NaN, the single slot writer, the JIT bailing on NaN, refusal inside writers). @@ -34,6 +36,29 @@ Companion artifacts: found; §11 records Q1-Q6 as decided. - The test plan has row shapes and tier witnesses (§9). +**What design round 3 changed** (after the critic's FAIL on round 2): +- The `osr` witness proves the loop BODY ran natively: every OSR row is a + `loop while true:` whose only exit is a `return` right after the claimed + ops, and the witness requires the OSR record to reach the return sentinel + (§9.1). Every witness kind now has a negative plant, calibrated on main + (§9.2); the old form passed a plant with 0 native `INDEX_SET` calls. +- R1.2 is behaviour-preserving and stays so: the builtin readers and + producers are a named BRIDGE that R1.6 deletes, so every builtin behaviour + change coincides with a token change, and a per-builtin behaviour table + gates R1.6 (§2.7, §8, §9.4). The first int value appears at R1.3, and + §8 lists every consumer converted in that commit. +- `phase2_check.sh --through Rk` checks a round against exactly the rows that + have landed; R1.1 and R1.2 are mechanical rounds with named gates (§9.2). +- The observer's boxed-int path is mapped and routed (§7, MAP + `O1.int-observed-numeric`). +- `buffer_read_num` is renamed in R1.6, so the index reads (`gather`, + `scatter_add`) and the byte reads (`buf_from_pcm16le` and the byte + consumers) are re-decided there; the compile count is re-measured under the + Makefile's exact flags and attributed per commit (§2.3a). +- Q7 and Q8 are decided and folded in: a validated `q7` column in the builtin + table, a geometry reader that clips the whole shape, and IEEE `totalOrder` + for sorting with NaN propagating through `min`/`max` (§2.6, §6, §11). + Contents: 1. The inventory 2. Representation @@ -45,7 +70,7 @@ Contents: 8. Round plan 9. Test plan 10. Lua differential tool -11. Decided questions (Q1-Q6) and what stays open +11. Decided questions (Q1-Q8) --- @@ -195,7 +220,7 @@ allowed tokens, or a `LOSS` row has no double path in its closure. **Calibration: every check turns red on its plant.** Each plant runs against a scratch copy of `src/` and of this document (`--src`, `--doc`, -`--no-write`), never the worktree; the unplanted copy passes first. All 18 +`--no-write`), never the worktree; the unplanted copy passes first. All 20 were KILLED on this tree, each by its own FAIL line: | plant | mutation | the red line | @@ -218,8 +243,14 @@ were KILLED on this tree, each by its own FAIL line: | P | a disposition row for a function that does not exist | ``disposition row `vm.c:p2_gone` names no D2/D3 slot classifier`` | | Q | disposition `fine` | `` `vm.c:slot_type_name` has unknown disposition 'fine' `` | | R | `vm_leaf_accessor_exec` renamed | `dispatcher vm_leaf_accessor_exec (leaf_exec) attributed no opcode arm` | +| S | `gfx_clear`'s `q7` column set to `size` | `` `gfx_clear` has a bad Q7 column 'size' (want `-` or an ordered subset of geometry,bounded,magnitude) `` | +| T | `gfx_clear`'s `q7` column set to `-` (its note says continuous) | `` `gfx_clear`: Q7 column '-' disagrees with its note (a continuous parameter must be named in both) `` | -M is the critic's plant verbatim; on the round-0 oracle it stayed green. +M is the critic's plant verbatim; on the round-0 oracle it stayed green. (On +its first run the plant driver reported T as SURVIVED although the gate +exited 1 with the right FAIL line: the driver's expected-message pattern +did not allow for the quotes around `-`. The pattern was fixed and T +re-run; the gate was never green on it.) --- @@ -347,99 +378,132 @@ computed from the site list. | | sites that must be revisited | how the revisit is forced | what a MISSED site does | |---|---|---|---| | **Alt 1** | the 382 TEST and 63 CASE sites (all categories) that should admit ints; reads after them; every producer that should yield an int; JIT producers | CASE only: 62 of the 63 `case VAL_NUM:`/`case AST_NUM:` switches have no `default:`, so `-Werror=switch` names them. TEST sites are not forced. | The int fails `== VAL_NUM` and takes the non-number branch. That raises a type error where the branch raises (loud, acceptable), but returns a **soft default** where the branch is soft. Examples: `what is 5` answers 0 and `who is 5` answers "unknown" (vm.c:5465-5484); `json_encode of 5` writes `null` (builtins.c:998, the one switch with a `default:`). Silently wrong, but never a lossy double. | -| **Alt 1R** | the same sites | **Measured (§2.3a): 1,416 of the 1,798 sites stop compiling (1,380 non-JIT, 36 in the JIT files)**, plus 44 inside a deleted definition. The other 338 keep a token on purpose, each class with its reason in §2.3a: the AST kind (52), the clamp R2.2 deletes (60), the decided embed accessor (48), f64 buffer reads (26), the libc parsers (15), the exact-conversion and formatter helpers (9), definitions (38), 87 JIT emitter immediates and helpers reviewed per guard (§4), and 3 `offsetof` uses that a real member rename does reach (measured). | **A compile error.** It cannot exist in code that names the vocabulary. The meaning changes that carry no token are listed with the token event that forces them (§2.7); the last `default:` that could absorb `VAL_INT` (builtins.c:998) is removed first in round 1. | +| **Alt 1R** | the same sites | **Measured (§2.3a), under the Makefile's exact flags: 1,488 of the 1,798 sites stop compiling (1,450 non-JIT, 38 in the JIT files)**, each attributed to the commit that first forces it (R1.1 223, R1.2 464, R1.3 11, R1.6 743, R2.2 47), plus 53 inside a deleted definition. The other 257 keep a token on purpose, each class with its reason in §2.3a: the AST kind (52), the decided embed accessor (48), the libc parsers (15), the exact-conversion and formatter helpers (9), definitions (44), 86 JIT emitter immediates and helpers reviewed per guard (§4), and 3 `offsetof` uses that a real member rename does reach (measured). | **A compile error.** It cannot exist in code that names the vocabulary. The meaning changes that carry no token are listed with the gate that catches a miss (§2.7); the last `default:` that could absorb `VAL_INT` (builtins.c:998) is removed first in R1.2a. | | **Alt 2** | payload reads and producers (enforced only if `num_` is renamed); the type tests keep compiling and now admit ints | none for the 382+63 type tests and the 484 checked reads | **A silent wrong number.** After `== VAL_NUM`, a `VAL_NUM_RAW` read of an int reads its int64 bits as a double (5 reads as 2.5e-323). An accessor that converts loses precision above 2^53 silently. In the JIT, three emitters misread with no compiler to catch them: `emit_load_numeric_operand`'s heap arm (jit.c:2343) loads `data.num_` of a boxed int; the `OP_SET_LOCAL` in-place branch (jit.c:3410) writes double bits into an int Value; the `OP_CONST` emitter (jit.c:2816) pushes `VAL_NUM_RAW` bits of an int constant. Constant dedup `const_equal` (chunk.c:212) merges `3` and `3.0`. | | **Alt 3** | only the sites that need exactness (N2, N3, N6, N8, N14, tape) | none: every existing read compiles and works below 2^53 | **A silently lossy double**, exact below 2^53, so ordinary tests cannot see it. This is precisely the class the brief says to design out. | -### 2.3a The compile measurement (design round 2) +### 2.3a The compile measurement (design rounds 2 and 3) -Round 0 claimed 1,449 non-JIT sites stop compiling. That was a token count, -not a compile. The critic compiled it and found 1,331, with 118 sites -carrying tokens round 0 never renamed (`AST_NUM` 52, `list_set_num` 21, -`slot_as_double` 16, `data.num` 7, `num_val` 5, and 17 more). This round -extends the rename list and measures again, the critic's way. +Round 0 claimed 1,449 non-JIT sites stop compiling; that was a token count, +and the critic's compile measured 1,331. Round 2 extended the rename list +and measured 1,416 of 1,798, under three hand-written configurations; the +one it called `server-db` was really every TU with every extension, ZLIB +included (the critic reproduced the count only with ZLIB). Round 3 does two +things: it adds the two token events the plan still lacked (`buffer_read_num`, +renamed in R1.6 so every buffer element read is re-decided, and the clamp, +deleted in R2.2), and it measures under the Makefile's exact flags. **Method.** -- A scratch copy of `src/` (never the worktree). Each token Alt 1R renames - or deletes gets a declaration with clang's +- A scratch copy of `src/`, never the worktree. Each token the plan renames + or deletes gets a declaration carrying clang's `__attribute__((unavailable("P2 ...")))`, so every USE is a compile error - and the definition stays legal. `SLOT_NUM_RAW`, a macro, is routed - through an unavailable `extern` so each expansion errors; `VAL_NUM_RAW` - expands to the unavailable member `num_` and errors with a macro note. -- The list: the enumerator `VAL_NUM`; the members `num_` (Value), `num` - (AST literal payload) and `num_val` (token); `eigs_num_arg`, - `eigs_num_arg_slow`, `eigs_list_num`, `eigs_elem_num`, `eigs_opt_num`, - `eigs_slot_num`, `eigs_slot_elem_num`, `eigs_slot_opt_num` and - `buf_num_arg` (deleted); `make_num` and `make_num_permanent`; - `finite_num_to_byte` and `buffer_read_byte` (deleted: Q1 byte values - follow N5); `SLOT_NUM_RAW`, - `slot_is_num`, `slot_from_num` and `slot_is_numeric` (deleted); - `slot_as_double` (deleted in R1.1, §2.7); and the container f64 helpers - `list_set_num`, `list_append_num`, `list_rewrite_num`, - `dict_value_set_num`, `dict_value_rewrite_num`, `list_get_num`, - `dict_value_get_num` (renamed `_f64`). -- clang 18.1.3, `-fsyntax-only -ferror-limit=0 - -Werror=implicit-function-declaration` plus `tools/werror_flags.txt`, one - translation unit at a time. The three configurations take their TU sets - from the Makefile at run time (`make print-`): - - `server-db`: every `src/*.c` (41 TUs), all extensions on; - - `release`: `HOSTED_SOURCES` (29 TUs), gfx on, http/model/db off; - - `freestanding`: `SOURCES` minus `CLI_ONLY` (23 TUs), `-ffreestanding - -DEIGENSCRIPT_FREESTANDING=1`, every extension off. -- The generated `lsp_stdlib_index.h` is produced into the scratch copy - (`tools/gen_lsp_stdlib_index.sh /lsp_stdlib_index.h`), so - `eigenlsp.c` compiles. -- An error line, and each macro-expansion note under it, is mapped back to + and the definition stays legal. The macros `SLOT_NUM_RAW` and + `EIGS_NUM_MAX` are routed through an unavailable `extern`; `VAL_NUM_RAW` + expands to the unavailable member `num_`. +- The tokens, by the commit that removes them (§2.7): + + | commit | tokens | + |---|---| + | R1.1 | `slot_is_num`, `slot_is_numeric`, `SLOT_NUM_RAW`, `slot_from_num`, `slot_as_double` | + | R1.2 | `VAL_NUM`, the member `num_` (so `VAL_NUM_RAW`), `VAL_NUM_OFFSET` | + | R1.3 | the AST literal payload `num`, the token payload `num_val` | + | R1.6 | the bridge (§2.7): `eigs_num_arg`, `eigs_num_arg_slow`, `eigs_list_num`, `eigs_elem_num`, `eigs_opt_num`, `eigs_slot_num`, `eigs_slot_elem_num`, `eigs_slot_opt_num`, `buf_num_arg`, `make_num`, `make_num_permanent`, the container helpers `list_set_num`, `list_append_num`, `list_rewrite_num`, `dict_value_set_num`, `dict_value_rewrite_num`, `list_get_num`, `dict_value_get_num`; `finite_num_to_byte`, `buffer_read_byte`, `buffer_read_num` | + | R2.2 | `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` | +- clang 18.1.3, `-fsyntax-only -ferror-limit=0`, one translation unit at a + time, five configurations. Three are the Makefile's own build variants, + with flags and TU lists read at run time (`make print-FLAGS_`, + `make print-SRC_V_`); `freestanding` takes `tools/freestanding_check.sh`'s + flags; `all` adds the TUs no build variant compiles (`eigenlsp.c`, + `eigsdap.c`, the embed and JIT smoke programs), with every extension on: + + ``` + release (29 TUs) -Wall -Wextra -Werror=implicit-function-declaration -Werror=switch -Werror=comment + -Werror=misleading-indentation -O2 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE + -DEIGENSCRIPT_EXT_HTTP=0 -DEIGENSCRIPT_EXT_MODEL=0 -DEIGENSCRIPT_EXT_DB=0 + -DEIGENSCRIPT_EXT_GFX=1 -DEIGENSCRIPT_VERSION="0.46.0" + server-db (35 TUs) the same CFLAGS, -I/usr/include/postgresql -DEIGENSCRIPT_EXT_HTTP=1 + -DEIGENSCRIPT_EXT_MODEL=1 -DEIGENSCRIPT_EXT_DB=1 -DEIGENSCRIPT_EXT_NET=1 + -DEIGENSCRIPT_EXT_GFX=1 (no ZLIB: the Makefile's FLAGS_server-db omits it) + zlib (29 TUs) release's flags plus -DEIGENSCRIPT_EXT_ZLIB=1 + freestanding (23 TUs) -O2 -ffreestanding -fno-stack-protector -U_FORTIFY_SOURCE + -Werror=implicit-function-declaration -Werror=switch -Werror=comment + -Werror=misleading-indentation -DEIGENSCRIPT_FREESTANDING=1 + -DEIGENSCRIPT_EXT_HTTP=0 -DEIGENSCRIPT_EXT_MODEL=0 -DEIGENSCRIPT_EXT_DB=0 + all (41 TUs) CFLAGS plus every extension, -DEIGENSCRIPT_EXT_ZLIB=1 included + ``` +- The generated `lsp_stdlib_index.h` is produced into the copy + (`tools/gen_lsp_stdlib_index.sh /lsp_stdlib_index.h`). +- An error line and each macro-expansion note under it are mapped back to the unmutated copy's line (difflib). A site is **flagged** when its - file:line carries an error. + file:line carries an error. A flagged site is attributed to the FIRST + commit whose token errors on its line: that is when a migrator must first + visit it. **Results** (the unmutated copy first, as the control): ``` -base: cfg=server-db tus=41 errors=0 unparsed_failures=0 - cfg=release tus=29 errors=0 unparsed_failures=0 - cfg=freestanding tus=23 errors=0 unparsed_failures=0 -R: cfg=server-db tus=41 errors=2756 unparsed_failures=0 - cfg=release tus=29 errors=2293 unparsed_failures=0 - cfg=freestanding tus=23 errors=1740 unparsed_failures=0 +base: cfg=release tus=29 errors=0 cfg=server-db tus=35 errors=0 cfg=zlib tus=29 errors=0 + cfg=freestanding tus=23 errors=0 cfg=all tus=41 errors=0 (unparsed_failures=0 everywhere) +R3: cfg=release tus=29 errors=2501 cfg=server-db tus=35 errors=2780 cfg=zlib tus=29 errors=2506 + cfg=freestanding tus=23 errors=1920 cfg=all tus=41 errors=3011 (unparsed_failures=0 everywhere) inventory sites=1798 (non-JIT 1671, JIT-file 127) -cfg=server-db distinct_flagged_lines=1245 sites_flagged=1416 (non-JIT 1380, JIT-file 36) -cfg=release distinct_flagged_lines=1151 sites_flagged=1315 (non-JIT 1310, JIT-file 5) -cfg=freestanding distinct_flagged_lines=812 sites_flagged=960 (non-JIT 960, JIT-file 0) -UNION: flagged=1416 (non-JIT 1380, JIT-file 36) inside-deleted-definitions=44 not-flagged=338 (non-JIT 247, JIT-file 91) +cfg=release distinct_flagged_lines=1209 sites_flagged=1384 (non-JIT 1377, JIT-file 7) +cfg=server-db distinct_flagged_lines=1265 sites_flagged=1442 (non-JIT 1435, JIT-file 7) +cfg=zlib distinct_flagged_lines=1213 sites_flagged=1389 (non-JIT 1382, JIT-file 7) +cfg=freestanding distinct_flagged_lines=866 sites_flagged=1024 (non-JIT 1024, JIT-file 0) +cfg=all distinct_flagged_lines=1307 sites_flagged=1488 (non-JIT 1450, JIT-file 38) +UNION of the four build configs: sites_flagged=1447; all-TU config adds 41 +UNION: flagged=1488 (non-JIT 1450, JIT-file 38) inside-deleted-definitions=53 not-flagged=257 (non-JIT 168, JIT-file 89) +first forced in: R1.1=223 R1.2=464 R1.3=11 R1.6=743 R2.2=47 +errors not naming a planned token: {"cannot take the address of an rvalue of type 'double'": 5} ``` -The error totals count a header's error once per TU that includes it; -the distinct lines and the sites are what matter. The union equals -`server-db`, because every TU is in it. `release` and -`freestanding` matter for what a build of that configuration forces (a -freestanding build cannot see the JIT, for instance), not for the union. +The error totals count a header's error once per TU that includes it; the +distinct lines and the sites are what matter. The five errors that name no +token are an artifact of the `SLOT_NUM_RAW` reroute (it takes an address, +and five uses pass an rvalue); every one sits on a line that also carries +an `unavailable` error, so no site depends on them. Every flagged site has a +first commit. -**The 338 sites that do not stop compiling, every one classified:** +**The 257 sites that never stop compiling, every one classified:** | class | sites | why it keeps compiling, and what forces it instead | |---|---:|---| -| `AST_NUM` | 52 | Under (B) the node kind still means "number literal". Its payload `num` is renamed, so all 7 reads of the literal's value are flagged; a site that only tests the kind is right for both kinds. The critic made the same call. | -| the clamp: `num_guard` 48, `num_guard_named` 4, `EIGS_NUM_MAX` 8 | 60 | A float clamp whose meaning does not change in round 1. R2.2 deletes all three, so every one of these sites stops compiling in that round: a token event of its own. | -| `eigs_value_as_num` | 48 | The embed accessor, used by the embed test harnesses (`embed_smoke.c` 42, `embed_concurrent.c` 6). Q3 decided it converts an int as `lua_tonumber` does, so "this value as a double" is unchanged. Exact ints get `eigs_value_as_int`/`eigs_value_is_int`. | -| `buffer_read_num` | 26 | Buffers are f64 storage (Q2): the read is a float by contract. Of its other 12 sites, 11 share a line with a renamed token and one is inside the deleted `buffer_read_byte`. | -| `strtod` 14, `atof` 1 | 15 | The libc parsers. The lexer's result reaches the renamed `num_val` through `tok_add`, whose store is flagged; the literal's kind changes `tok_add`'s parameter, which forces the call. The JSON, store and trace scalar parsers return `make_num(d)` a few lines on (flagged); trace.c:2324 fills a buffer's f64 storage (Q2). The rest parse model hyperparameters (float), the tape's observer config, and `tape_read.c:368`, which feeds the observer replay a double (`tape_read.c:635`); round 1 observes ints as doubles live and on replay alike (§8 risks), and round 3's change to `observer_slot_record_value`'s parameter forces this line. | -| `num_to_i64_exact` 6, `eigs_num_text` 3 | 9 | Pure helpers over a double, unchanged in meaning; every input reaches them through a renamed reader. N6 changes the formatter's output on purpose (pinned by the N6 rows), not silently. | -| definitions | 38 | Declarations and bodies of the renamed and deleted names themselves. | +| JIT emitter immediates and helpers | 86 | Tag compares (`0xFFF8`/`0xFFF9`/`0xFFFB`/`0xFFFD`) and the `emit_*` helpers. Reviewed per guard in §4.1: an SMI or a `VAL_INT` box fails every consuming guard and bails; the producer emitters keep their float meaning (§4.2). | +| `AST_NUM` | 52 | Under (B) the node kind still means "number literal". Its payload `num` is renamed in R1.3, so all 7 reads of the literal's value are flagged; a site that only tests the kind is right for both kinds. The critic made the same call. | +| `eigs_value_as_num` | 48 | The embed accessor: 40 call sites in `embed_smoke.c` and 6 in `embed_concurrent.c` (the embed test harnesses), plus its definition (`eigs_embed.c`) and declaration (`eigs_embed.h`). Q3 decided it converts an int as `lua_tonumber` does, so "this value as a double" is unchanged; exact ints get `eigs_value_as_int`/`eigs_value_is_int` (R1.8). | +| definitions | 44 | Declarations and bodies of the renamed and deleted names themselves. | +| `strtod` 14, `atof` 1 | 15 | The libc parsers. The lexer's result reaches the renamed `num_val` through `tok_add`, whose store is flagged; the literal's kind changes `tok_add`'s parameter, which forces the call. The JSON, store and trace scalar parsers return `make_num(d)` a few lines on (flagged, R1.6); trace.c:2324 fills a buffer's f64 storage (Q2). The rest parse model hyperparameters (float), the tape's observer config, and `tape_read.c:368`, which feeds the observer replay a double (`tape_read.c:635`); round 1 observes ints as doubles live and on replay alike (§8 risks), and round 3's change to `observer_slot_record_value`'s parameter forces this line. | +| `num_to_i64_exact` 6, `eigs_num_text` 3 | 9 | Pure helpers over a double, unchanged in meaning; every input reaches them through a renamed reader. N6 changes the formatter's output on purpose in R1.7, a token-less change listed in §2.7 with its rows. | | `VAL_NUM_OFFSET` in jit.c | 3 | `offsetof` uses, which the attribute does not reach. A real rename does: renaming `num_` to `f64_` (and the macro) in a further scratch copy gives exactly 3 errors, jit.c:2367, 2368 and 3471. | -| JIT emitter immediates and helpers | 87 | Tag compares (`0xFFF8`/`0xFFF9`/`0xFFFB`/`0xFFFD`) and the `emit_*` helpers. Reviewed per guard in §4.1: an SMI or a `VAL_INT` box fails every consuming guard and bails; the producer emitters keep their float meaning (§4.2). | -| **total** | **338** | | - -So the round-0 headline becomes: **1,416 of 1,798 sites stop compiling** -(1,380 non-JIT, 36 JIT-file), 44 more are inside deleted definitions, and -338 keep a token for the reasons above. None of the 338 changes meaning -without a token event: the ones that change meaning later change it in -R2.2 (the clamp) or round 3 (the observer), each forced then. +| **total** | **257** | | + +**What round 2 got wrong here, and round 3 fixes.** Round 2 kept +`buffer_read_num` (26 unflagged sites) as "a float by contract". Ten of its +38 sites read a value that is NOT a float: byte values (`str_from_bytes` +builtins_buf.c:240, `f64_from_bytes` :284, the zlib input :351, +`buf_from_pcm16le` :754 and :756, `write_bytes` builtins_host.c:1548, +`net_send` ext_net.c:361, and inside `buffer_read_byte` eigenscript.h:1920) +and indices (`scatter_add` builtins_tensor.c:1036, `flat_index_at` :1436, the +`gather` path the critic probed: an index of 1.5 truncates to 1 today). With +`buffer_read_num` renamed in R1.6, all 38 sites are flagged in that commit, +and each is re-decided: `buffer_read_f64` for data, the Q1 byte reader for a +byte, the N5 index reader for an index (§2.6). Without the rename, nine of +the ten lines stayed unflagged in round 2; most sit in a function another +token forces anyway (the `finite_num_to_byte` call a line later), but +`buf_from_pcm16le` names no other token before R2.2's clamp deletion, so +nothing would have made R1.6 visit it. + +So the headline is: **1,488 of 1,798 sites stop compiling across the +plan** (first forced: R1.1 223, R1.2 464, R1.3 11, R1.6 743, R2.2 47), 53 +more sit inside deleted definitions, and 257 keep a token for the reasons +above. None of the 257 changes meaning without a token event: the ones that +change meaning later do so in a commit listed in §2.7. ### 2.4 The choice: Alt 1R 1. **It is the only alternative whose missed site is loud by construction.** - Measured: 1,416 of 1,798 sites stop compiling until a person decides, + Measured: 1,488 of 1,798 sites stop compiling until a person decides, site by site, whether the site admits ints and with what semantics (§2.3a). Alt 2 and Alt 3 leave 445 type tests and cases plus 484 checked reads compiling with a widened or lossy meaning. @@ -461,7 +525,8 @@ deprecation warnings, so the compiler's warning count is the progress meter and the final commit deletes the old names. A mechanical `sed` from old name to new would reintroduce the silent class (`len` returning `make_float(count)`), so the migration is per site, with the builtin table -(§6) deciding each builtin's accessor and the int-fuzz gate (§9) checking it. +(§6) deciding each builtin's accessor and the per-builtin behaviour table +(§9.4) checking it. ### 2.5 The slot classifiers, derived @@ -560,7 +625,7 @@ R1.1, before any program can produce an SMI. | `value_slot.h:slot_true` | not-a-classifier | constructor (D3) | | `vm.c:jit_helper_dot_get` | guarded | a non-null field is pushed as its bits; an SMI is a valid stack slot (D3) | | `vm.c:jit_helper_local_idx_dot_get` | guarded | as `jit_helper_dot_get` (D3) | -| `vm.c:obs_slot_observable` | refuse | answers "pointer or bool", so an SMI is silently unobserved. Its callers test `slot_is_num` first (compile-forced) and must route an SMI into the numeric channel; R1.1 aborts here on an SMI, so a missed caller fails loudly (D3) | +| `vm.c:obs_slot_observable` | refuse | answers "pointer or bool", so an SMI is silently unobserved. Its callers test `slot_is_num` first (compile-forced) and must route an SMI into the numeric channel; R1.1 aborts here on an SMI, so a missed caller fails loudly. A BOXED int is a pointer, so it passes this test and goes to `observer_slot_update(Value *)`, whose number arm (eigenscript.c:785) R1.2's `VAL_NUM` rename forces (§7, O map) (D3) | | `vm.c:vm_local_is_null` | guarded | exact null test (D3) | | `vm.c:vm_run_ex/CASE(DOT_GET)` | guarded | exact null test of a field (D3) | | `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET)` | guarded | exact null test of a field (D3) | @@ -569,38 +634,50 @@ R1.1, before any program can produce an SMI. ### 2.6 The accessor API after round 1 (Alt 1R) ``` -/* slots (R1.1) */ +/* slots (R1.1: readers and the SMI encoding; no int VALUE can exist yet) */ int slot_is_f64(EigsSlot); /* high16 < 0xFFF8 */ int slot_is_smi(EigsSlot); /* high16 == 0xFFFA */ int slot_is_int(EigsSlot); /* SMI or heap VAL_INT */ int slot_is_number(EigsSlot); /* f64 or int */ EigsSlot slot_from_f64(double); /* the ONE double writer; round 2: canonical NaN */ -EigsSlot slot_from_int(int64_t); /* the ONE int writer: SMI in range, else a box */ +EigsSlot slot_from_int(int64_t); /* the ONE int writer: SMI in range, else a box. + Until R1.3 its only callers convert an + existing VAL_INT (§8, the int-source check) */ int slot_f64_value(EigsSlot, double *); /* an immediate double or a VAL_FLOAT box; 0 for anything else, ints included. Replaces slot_as_double. */ int slot_int_value(EigsSlot, int64_t *); /* an SMI or a VAL_INT box */ #define SLOT_F64_RAW(s) /* was SLOT_NUM_RAW */ -/* container f64 storage helpers (R1.1): list_set_f64, list_append_f64, - list_rewrite_f64, dict_value_set_f64, dict_value_rewrite_f64, - list_get_f64, dict_value_get_f64 (were *_num) */ -/* Values (R1.2) */ +/* Values (R1.2a; make_int lands in R1.3, the first int producer) */ Value *make_float(double); Value *make_float_permanent(double); Value *make_int(int64_t); #define VAL_F64_RAW(v) /* member f64_; were VAL_NUM_RAW and num_ */ #define VAL_F64_OFFSET /* was VAL_NUM_OFFSET (the JIT's fixed-offset load) */ +#define VAL_I64_RAW(v) /* member i64_ of a VAL_INT */ + +/* the final readers, which replace the bridge in R1.6 (§2.7) */ EigsNum eigs_number_arg(const Value *, const char *who); /* int-preserving */ double eigs_float_arg(const Value *, const char *who); /* float-producing: int converts */ int64_t eigs_int_arg(const Value *, const char *who); /* int-requiring: N5 exact rule */ int eigs_int_arg_range(const Value *, int64_t lo, int64_t hi, int64_t *out, const char *who); /* N5, then the C range */ uint8_t eigs_byte_arg(const Value *, const char *who); /* Q1: N5, then 0..255 */ -int eigs_round_arg(const Value *, int *out, const char *who); - /* Q1 continuous: round to nearest, half away - from zero (as Q4's round); non-finite is - refused (N13); finite but outside the C int - range is open: §11 Q7 */ +/* buffer elements (buffer_read_num renamed in R1.6; every site re-decided) */ +double buffer_read_f64(const Value *buf, int64_t i); /* data: an f64 element (Q2) */ +int buffer_byte_at(const Value *buf, int64_t i, uint8_t *out, const char *who); + /* a byte value: N5, then 0..255 (Q1) */ +int buffer_index_at(const Value *buf, int64_t i, int64_t *out, const char *who); + /* an index: N5 (gather, scatter_add) */ +/* the container f64/int helpers (R1.6): list_set_f64, list_append_f64, + list_get_f64, dict_value_set_f64, ... and their _int twins (were *_num) */ + +/* Q7 (decided): continuous parameters, by the quantity they represent */ +int eigs_geom_shape(const Value *args, int first, EigsShapeKind kind, + const EigsRect *drawable, EigsShape *out, const char *who); +int eigs_bounded_arg(const Value *, double lo, double hi, int *out, const char *who); +int eigs_magnitude_arg(const Value *, int64_t lo, int64_t hi, int64_t *out, + const char *who); /* literals (R1.3) */ OP_INT_ZERO, OP_INT_ONE, OP_INT_CONST /* appended to OpCode; §2.7 */ @@ -610,45 +687,103 @@ OP_INT_ZERO, OP_INT_ONE, OP_INT_CONST /* appended to OpCode; §2.7 */ Each `_arg` reader also has the list, slot and optional forms of today's checked accessors. +**The Q7 readers** (decided in +[#1758 comment 6174302316](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6174302316); +the builtin table's `q7` column, §6, names each builtin's classes): +- **Geometry** (coordinates and sizes): clip the WHOLE shape in float + space against the drawable area, then round to nearest. A per-argument + reader cannot do that: saturating each endpoint of + `gfx_rect of [-3e9, 0, 6e9, 10]` separately covers half the screen + instead of all of it, so the reader takes the shape. `eigs_geom_shape` + reads all of a shape's numbers as doubles (a non-finite one raises + `value`, N13), then clips by kind and only then converts: + - `POINT` (x, y): outside the drawable rect, the shape is empty; + - `RECT` (x, y, w, h; also the clip rect, the framebuffer's destination + `dx, dy, w*scale, h*scale`, and a glyph cell of `gfx_text`): intersect + with the drawable rect in float space; an empty intersection draws + nothing; + - `LINE` (x1, y1, x2, y2): Liang-Barsky clipping of the segment in float + space, so the visible part keeps its slope; + - `CIRCLE` (cx, cy, r) and `RRECT` (x, y, w, h, r): reject when the + bounding box misses the drawable rect; otherwise clamp the span loop to + the drawable rows and columns before converting, so a radius of `3e9` + costs the visible rows, not 6e9 iterations; + - every surviving coordinate is then rounded half away from zero (Q4's + rule) into a C `int`, which the clip guarantees holds it. + `EigsShape.empty` tells the caller to draw nothing; that is the only + outcome a finite out-of-range shape has. +- **Bounded** (colour channels, gain, volume, PCM samples): clamp to the + domain, then round (`eigs_bounded_arg`); a NaN raises `value` (N13). +- **Magnitude** (durations, sleeps, timeouts, sample counts, window sizes, a + measurement's scale): round, and raise `value` naming the builtin when the + result does not fit what the C call can honour (`eigs_magnitude_arg`). + ### 2.7 Every meaning change coincides with a token change Round 0's order changed meanings with no token change: R1.1 widened `slot_as_double` with an SMI arm, and R1.3 re-meant `OP_NUM_ZERO`/`OP_NUM_ONE` as ints. Neither produces a compile error, so a missed caller or a missed executor (the critic found the leaf evaluator's `OP_NUM_ZERO`/`OP_NUM_ONE` -arms, vm.c:1872-1877) would keep compiling with the old meaning. The rule -now: **a meaning change lands in the same commit as the token change that -stops every affected site**, or it is listed below with the reason no token -exists and the gate that catches a miss instead. - -| meaning change | commit | token change in that commit | a missed site | +arms, vm.c:1872-1877) would keep compiling with the old meaning. Round 2's +order had a second flaw the critic found: R1.2 deleted the builtin readers +(a compile error) while claiming to preserve behaviour, and R1.6 then changed +about 114 builtin rows with no token event at all. + +The rule: **a meaning change lands in the same commit as the token change +that stops every affected site**, or it is listed below with the reason no +token exists and the gate that catches a miss instead. + +**The bridge.** The builtin-facing readers and producers are kept, under +their current names, until R1.6, and they are the bridge: `eigs_num_arg` and +its family, `buf_num_arg`, `make_num`/`make_num_permanent`, the container +`*_num` helpers, `finite_num_to_byte`, `buffer_read_byte` and +`buffer_read_num`. Through R1.5 they keep exactly today's meaning: a number +read is a double (an int converts, as every number already is on the tag), a +number produced is a float. R1.6 deletes the bridge, so every builtin site +stops compiling in the commit that gives it its §6 semantics. R1.2 touches +no builtin's behaviour. + +| commit | meaning change | token change in that commit | a missed site | |---|---|---|---| -| a slot may hold an int (SMI tag 0xFFFA) | R1.1 | `slot_is_num` -> `slot_is_f64`, `SLOT_NUM_RAW` -> `SLOT_F64_RAW`, `slot_from_num` -> `slot_from_f64`; `slot_is_numeric` deleted; the container helpers `*_num` -> `*_f64` | compile error (D1, 58 entries) | -| "a number from an immediate or a box" (`slot_as_double`) | R1.1 | **deleted**. Its 15 calls (leaf `INDEX_GET` and `ADD/SUB/MUL`, `ARITH_FAST`, `INT_BINOP_R`, `NEG`, `BNOT`, `EQ`, `NE`, `NUM_CMP`) are rewritten with an explicit int decision: the float fast path reads `slot_f64_value` (float only), an int takes the slow path that R1.2/R1.3 give int semantics, and the leaf bails | compile error at all 15 | -| a slot classifier without a number test meets an SMI | R1.1 | none can exist (they name no number token) | the derived D2/D3 table (§2.5): `refuse` entries abort, `smi-arm` entries answer; the inventory fails on an unreviewed entry | -| raw access to a slot's or Value's double | R1.1/R1.2 | the members and macros renamed (`SLOT_F64_RAW`, `VAL_F64_RAW`, `f64_`) | a spelled-out `.d_`/`.num_` is refused by `tools/num_read_check.sh` and by the inventory (BYPASS) | -| a Value number may be an int (`VAL_INT`) | R1.2a | `VAL_NUM` -> `VAL_FLOAT`; `VAL_INT` appended, so `-Werror=switch` stops every default-less ValType switch; the one `default:` (builtins.c:998) is removed in the same commit | compile error | -| the checked readers' contract (number in, double out) | R1.2 | `eigs_num_arg` family, `eigs_slot_num` family and `buf_num_arg` deleted; the replacements name the intent (§2.6) | compile error | -| the number constructors | R1.2 | `make_num` -> `make_float`, `make_num_permanent` -> `make_float_permanent`; `make_int` added | compile error | -| equality, ordering and hashing across kinds | R1.2 | their `VAL_NUM` arms and cross-type test renamed (`values_equal_impl`'s type-mismatch block names `VAL_NUM`; `sort_cmp_num`; `const_hash_value`/`const_equal`) | compile error | -| `VAL_NUM_OFFSET` (the JIT's fixed-offset load) | R1.2 | renamed `VAL_F64_OFFSET` with the member | compile error (jit.c:2367, 2368, 3471; measured) | -| an int literal | R1.3 | **new opcodes `OP_INT_ZERO`, `OP_INT_ONE`, `OP_INT_CONST`, appended** (the opcode-ABI rule, no `EIGS_BYTECODE_ABI` bump); the AST payload `num` and the token's `num_val` renamed to an `EigsNum` in the same commit | the four exhaustive OpCode switches stop compiling (`op_name` chunk.c:337, `op_verify_operands` chunk.c:466, `op_verify_stack_effect` chunk.c:615, `op_stack_effect` compiler.c:305), and `tools/obs_marker_check.sh` requires each new enumerator's `/*obs:NONE*/` marker (`opcode_is_observer_reader`, chunk.c:1302, has a `default:` that correctly answers "not a reader"); the JIT scanner and the leaf scanner refuse an opcode they do not know (their `default:`), so the literal runs interpreted; the interpreter's computed-goto table is the one executor the compiler cannot check, and a missing entry is a NULL jump that crashes the first int-literal row (loud) | -| `OP_NUM_ZERO`, `OP_NUM_ONE` | none | **no meaning change**: they keep pushing float 0.0 and 1.0, so their three executors (interpreter vm.c:3257, JIT emitter jit.c:2797, leaf evaluator vm.c:1872) and two scanners stay correct untouched. The compiler emits them only for a float literal (compiler.c:2073, which reads the renamed payload) | n/a | -| `OP_CONST` | none | **no meaning change**: an int is never an `OP_CONST` operand (`OP_INT_CONST` carries it). Its three executors already push any non-number constant as a box, and the leaf scanner refuses a non-`VAL_FLOAT` constant (renamed test, chunk.c:1090) | a stray int constant is a box: correct, merely slow | -| the byte conversion (wrap modulo 256 -> N5, Q1) | R1.6 | `finite_num_to_byte` deleted (7 calls), and with it `buffer_read_byte` (21 calls in `gfx_fb` and `ppu_render_frame`), replaced by a reader that raises on a non-byte | compile error | -| the observer's numeric channel receives an int | R1.1 (refusal), R1.3 (routing) | `obs_slot_observable` refuses an SMI (D3 `refuse`); its callers are D1 (forced in R1.1) and route an SMI into the numeric channel as a double once ints exist | abort | -| `tape_read.c:368`'s double (the observer replay's input) | round 3 | none in round 1: live and replayed observers both see an int as its double. Round 3 changes `observer_slot_record_value`'s parameter to the numeric kind, which forces this line | n/a in round 1 | -| the embed accessor `eigs_value_as_num` given an int | R1.8 | none, **by decision** (Q3): it converts, like `lua_tonumber`; `eigs_value_as_int`, `eigs_value_is_int` and `eigs_value_new_int` are added | n/a | -| the clamp's removal: NaN and inf become reachable | R2.2 | `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` deleted (74 sites forced: 60, 6 and 8) | compile error | +| R1.1 | a slot may hold an SMI (no producer yet) | `slot_is_num` -> `slot_is_f64`, `SLOT_NUM_RAW` -> `SLOT_F64_RAW`, `slot_from_num` -> `slot_from_f64`; `slot_is_numeric` and **`slot_as_double`** deleted | compile error: 223 sites first forced here (§2.3a), the 58 D1 classifiers among them | +| R1.1 | a slot classifier without a number test meets an SMI | none can exist (they name no number token) | the derived D2/D3 table (§2.5): `refuse` entries abort, `smi-arm` entries answer; the inventory fails on an unreviewed entry | +| R1.2a | a Value number may be an int (`VAL_INT`; no producer yet) | `VAL_NUM` -> `VAL_FLOAT`, `num_` -> `f64_`, `VAL_NUM_RAW`/`VAL_NUM_OFFSET` renamed; `VAL_INT` appended, so `-Werror=switch` stops every default-less ValType switch; the one `default:` (builtins.c:998) removed in the same commit | compile error: 464 sites first forced here. Each forced site gets its final int arm, live from R1.3; a builtin's number test admits an int and reads it through the bridge | +| R1.3 | **the first int values**: int literals, and int arithmetic on them | the AST payload `num` and the token's `num_val` become an `EigsNum`; **new opcodes `OP_INT_ZERO`, `OP_INT_ONE`, `OP_INT_CONST`, appended** (the opcode-ABI rule; no `EIGS_BYTECODE_ABI` bump); `make_int` introduced | compile error at the 11 payload sites and the four exhaustive OpCode switches (`op_name` chunk.c:337, `op_verify_operands` chunk.c:466, `op_verify_stack_effect` chunk.c:615, `op_stack_effect` compiler.c:305; `tools/obs_marker_check.sh` requires each new enumerator's `/*obs:NONE*/`); the JIT and leaf scanners refuse an opcode they do not know (their `default:`); the interpreter's dispatch table is the one executor the compiler cannot check, and a missing entry is a NULL jump that crashes the first int-literal row (loud) | +| R1.3 | `OP_NUM_ZERO`, `OP_NUM_ONE`, `OP_CONST` | **no meaning change**: they keep their float meaning in all three executors (interpreter vm.c:3257, JIT emitter jit.c:2797, leaf evaluator vm.c:1872); an int is never an `OP_CONST` operand | n/a | +| R1.4 | `//` | `OP_IDIV` appended, `TOK_SLASH_SLASH` appended (and `//=`, Q6) | compile error at the exhaustive switches | +| R1.6 | **every builtin's §6 semantics** (N5 raises, int results, Q1 byte and Q7 continuous readers, the index readers of `gather`/`scatter_add`) | **the bridge is deleted** (21 tokens, §2.3a) | compile error: 743 sites first forced here; the per-builtin behaviour table (§9.4) checks every row's result against §6, on the tag and the branch | +| R1.8 | the embed API gains ints | `eigs_value_new_int`, `eigs_value_as_int`, `eigs_value_is_int` added; `eigs_value_as_num` keeps its name **by decision** (Q3: it converts, like `lua_tonumber`) | the embed gate row (MAP `gate.N7.embed-int`) | +| R2.2 | NaN and inf become reachable | `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` deleted | compile error: 47 sites first forced here (the rest of the clamp's 74 sites were forced earlier) | **The meaning changes that cannot carry a token**, each with the gate that catches a miss: -- **The leaf evaluator vs the generic path.** The leaf has no frame and no - `OP_LINE`, so nothing marks it when the generic path's semantics change. - The gate is the leaf differential (§9.2, the `trace` tier): every row runs - with the leaf on and off, and the outputs must be byte-identical. -- **Consumers that assumed a finite double (R2.2).** No token marks code that - merely receives a NaN or an inf after the clamp is gone: +- **R1.3, the int arms written in R1.1 and R1.2 go live.** They were forced + then and written with their final semantics while no int could reach them. + Gate: R1.3's 42 MAP rows and the C slot test; and the int-source check + (§8) proves nothing before R1.3 could produce an int, so nothing earlier + could have exercised an unfinished arm. +- **R1.3, the tape parser.** `parse_value_p` (trace.c:2284) reads digits as + an int from v7 on; the version bump refuses an older tape. Gate: the T1 + rows (`T1.twice-int`, `T1.v6-refused`). +- **R1.3, the leaf evaluator vs the generic path.** The leaf has no frame and + no `OP_LINE`, so nothing marks it when the generic path's semantics change. + Gate: the `trace` tier of §9.2, which runs every row with the leaf off and + requires byte-identical output. +- **R1.4 `%` and R1.5 the shift rules.** Each has one live executor in round + 1: the interpreter (`CASE(MOD)`, `INT_BINOP_R`). The JIT scanner refuses + MOD and the bitwise ops from R1.3, the leaf admits neither, and nothing + folds constants (checked: the compiler and parser evaluate no operator at + compile time). Gate: the N4 and N8 rows, including their `F` shapes. +- **R1.7, the float text.** N6 changes `eigs_num_text`, the one shared + float formatter, and in the same commit the writers that format a float on + their own: the JSON encoder, `store_json_encode` and `db_build_query` + (#1762), and trace.c's `%.17g` writers (2817, 2836, 2950). (The decoders' + int kinds for integer text, `json_decode`, `json_path`, `store_query`, + `db_query_value` and `num of`, land in R1.6, where deleting `make_num` + forces them.) Gate: one row per writer (`N6.*`, `N14.encode-kinds`, + `N14.store-exact-digits`, `gate.N14.db-param-exact`, `T1.twice-float`). +- **R2.2, consumers that assumed a finite double.** No token marks code that + merely receives a NaN or an inf once the clamp is gone: - `values_equal_impl`'s identity shortcut (`if (a == b && ...) return 1;`) would call a NaN box equal to itself. No program path reaches it with one float box on both sides today (EQ compares two floats in its @@ -656,11 +791,13 @@ catches a miss: not probed, since no NaN exists yet), so R2.2 excludes floats from the shortcut as #1417 excluded buffers, and the C slot test calls it with one NaN box on both sides; - - C casts of a double to an integer type (undefined on NaN/inf): every + - C casts of a double to an integer type (undefined on NaN or inf): every builtin argument goes through a §2.6 reader, which refuses a non-finite value (N13); the internal casts left are the #1746 residue (R2.6); - - the sort comparators: NaN has no order, and the order a sort should - give it is not decided (§11 Q8). + - the sort comparators and `min`/`max` (Q8, decided): `sort` and `sort_by` + order floats by IEEE 754 `totalOrder`, the canonical NaN after +inf; + `min` and `max` propagate NaN. Gate: `N11.sort-total-order`, + `N11.min-max-nan`. --- @@ -871,7 +1008,7 @@ leaf off under trace (the tape records every line, and the leaf skips | `OP_INT_ZERO/ONE/CONST` | do not exist | **not admitted**: the scanner's `default:` refuses the chunk, so an int literal sends every call down the generic path. Round 5 adds scanner and evaluator arms together (the inventory requires both directions) | | `GET_LOCAL` (1878) | borrows the argument slot | unchanged (an SMI argument is a valid slot) | | `LOCAL_DOT_GET` (1883) | the target must be a pointer to a dict, else bail; a missing field is null; a field is borrowed as its bits | unchanged: an SMI field is borrowed as an SMI (§2.5 row `guarded`) | -| `INDEX_GET` (1907) | the index through `slot_as_double` (an immediate or a boxed `VAL_NUM`) then `vm_index_is_int`; a list element is borrowed; a buffer element is `slot_from_num(buffer_read_num(...))` | `slot_as_double` is deleted (R1.1), so this arm stops compiling. It reads the index with `slot_f64_value` and **bails on an int index**; the buffer element is `slot_from_f64` (Q2: f64 storage). Round 5 adds the SMI index | +| `INDEX_GET` (1907) | the index through `slot_as_double` (an immediate or a boxed `VAL_NUM`) then `vm_index_is_int`; a list element is borrowed; a buffer element is `slot_from_num(buffer_read_num(...))` | `slot_as_double` is deleted (R1.1), so this arm stops compiling. It reads the index with `slot_f64_value` and **bails on an int index**; the buffer element is `slot_from_f64` (Q2: f64 storage), read through `buffer_read_f64` once R1.6 renames `buffer_read_num`. Round 5 adds the SMI index | | `ADD`/`SUB`/`MUL` (1933) | both operands through `slot_as_double`; `r = a op b`; the underflow flag for MUL (#1079); `slot_from_num(num_guard(r))` | stops compiling (R1.1). Reads with `slot_f64_value` and **bails unless both operands are floats**, so an int or mixed operation runs on the generic path with N2/N3/(A) semantics. Round 5 adds int arms whose overflow bails (never raises inside the leaf: the generic path raises with the caller's line). R2.2 deletes `num_guard` here with the others | | `RETURN` (1957) | increfs the result, pops args and fn, pushes the result | unchanged (`slot_incref` ignores an SMI) | | `default` (1966) | unreachable; returns 0 | unchanged | @@ -964,11 +1101,13 @@ exactly as an int. That is the path the bar critic found missing: payload - `type` ((B)); - continuous parameters (Q1, decided): gfx coordinates and sizes, colour channels, durations and audio gain accept an int or a float. Where the - C API needs an int, `eigs_round_arg` rounds to nearest (half away from - zero, as `round`), replacing today's truncation toward zero, which gets - negative coordinates wrong; a finite value outside the C range is §11 - Q7, still open. (Byte consumers, which truncated and - wrapped modulo 256 here in round 0, are int-requiring under Q1.) + C API needs an int the value rounds to nearest (half away from zero, as + `round`), replacing today's truncation toward zero, which gets negative + coordinates wrong. What a finite value outside the C range does follows + the quantity (Q7, decided): geometry is clipped as a whole shape in + float space, a bounded quantity is clamped, a magnitude raises `value` + (§2.6). (Byte consumers, which truncated and wrapped modulo 256 here in + round 0, are int-requiring under Q1.) **The `loss` column.** `LOSS` marks a builtin whose *current* body reads its argument through a double accessor, or builds its result from a computed @@ -1004,12 +1143,21 @@ Two consequences of the definition, made explicit in design round 2: R1.7 inherits the fix and only adds the int arm. Its MAP entries are the row `N14.store-exact-digits` and the gate `gate.N14.db-param-exact`. +**The `q7` column** (design round 3) names the Q7 class of each continuous +parameter a builtin converts: an ordered subset of `geometry`, `bounded`, +`magnitude`, or `-`. The inventory refuses any other token, and checks the +column against the note both ways: a row's note says "continuous" exactly +when its `q7` column is not `-`. Counts: geometry 9, bounded 13, magnitude 13. + **Counts** (from the table below, checked by `tools/phase2_inventory.py`, which prints them): 230 numeric builtins (`ppu_render_frame` joined when -`buffer_read_byte` entered the vocabulary). By class: 37 int-preserving, 58 -float-producing, 84 int-requiring, 51 other. The decided Q1 moved 16 rows +`buffer_read_byte` entered the vocabulary). By class: 37 int-preserving, 57 +float-producing, 85 int-requiring, 51 other. The decided Q1 moved 16 rows from other to int-requiring (counts, byte values, handles, flags and -selectors), and `ppu_render_frame` is a new int-requiring row. 42 are LOSS: +selectors); `ppu_render_frame` is a new int-requiring row; design round 3 +moved `buf_from_pcm16le` from float-producing to int-requiring (its inputs are +byte values, #1758 comment 6174964306) and corrected `gather` (its indices +truncate today). 42 are LOSS: - arithmetic: `abs`, `add`, `subtract`, `multiply`, `negative`, `sum`, `num_copy`; - min/max and rounding: `min`, `max`, `floor`, `ceil`, `round`; @@ -1040,238 +1188,238 @@ current state behind several rows: `eigs_int_arg` for the key closes it if it is still open then). -| builtin | class | loss | note | -|---|---|---|---| -| `abs` | int-preserving | LOSS | Lua math.abs (integer/float); abs of INT64_MIN raises (N4b) | -| `acos` | float-producing | - | Lua math.acos | -| `add` | int-preserving | LOSS | scalar arm mirrors `+` (overflow raises, (A)); buffer arms stay float | -| `append` | other | - | appends any value; VAL_NUM appears only as a diagnostic default | -| `asin` | float-producing | - | Lua math.asin | -| `assert` | other | - | message via value_to_string (N6) | -| `atan` | float-producing | - | Lua math.atan | -| `atan2` | float-producing | - | Lua math.atan(y, x) | -| `audio_capture_open` | int-requiring | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | -| `audio_envelope` | float-producing | - | float samples; times in seconds | -| `audio_gain` | float-producing | - | float samples | -| `audio_mix` | float-producing | - | float samples | -| `audio_music_play` | int-requiring | - | loop count: N5, then the C int range (Q1) | -| `audio_music_volume` | other | - | volume is a gain: continuous, rounds to nearest for the C int API (Q1) | -| `audio_noise` | float-producing | - | float samples | -| `audio_open` | int-requiring | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | -| `audio_pause` | int-requiring | - | the pause flag is discrete, not continuous: N5 (Q1; today `(int)0.5` silently un-pauses) | -| `audio_play` | other | - | float samples in; returns a channel number | -| `audio_play_loop` | int-requiring | - | loop count: N5, then the C int range (Q1); returns a channel | -| `audio_queue_size` | int-preserving | - | byte count (computed in a double, below 2^53) | -| `audio_saw` | float-producing | - | float samples | -| `audio_sine` | float-producing | - | float samples | -| `audio_square` | float-producing | - | float samples | -| `audio_stop` | int-requiring | - | channel number | -| `audio_stream_open` | int-requiring | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | -| `audio_stream_push` | other | - | float samples quantized to int16 | -| `audio_stream_queued` | int-preserving | - | sample count | -| `audio_sweep` | float-producing | - | float samples; frequencies, duration and amplitude are continuous; the wave selector is integer-valued: N5 (Q1) | -| `audio_volume` | int-requiring | - | channel index: N5 (Q1); the volume is a float gain | -| `bit_and` | int-requiring | LOSS | Lua `&` (§3.4.2): N5 operands, int64-pattern result (N8); today a double result | -| `bit_not` | int-requiring | LOSS | Lua unary `~` | -| `bit_or` | int-requiring | LOSS | Lua `\|` | -| `bit_shl` | int-requiring | LOSS | Lua `<<`; today masks the count mod 64, N8 needs >=64 gives 0 and negative shifts right | -| `bit_shr` | int-requiring | LOSS | Lua `>>` is logical (N8); today an arithmetic shift with `& 63` | -| `bit_xor` | int-requiring | LOSS | Lua binary `~` | -| `buf_copy` | int-requiring | - | offsets and counts | -| `buf_deinterleave` | int-requiring | - | channel count and index | -| `buf_dot` | float-producing | - | buffer dot product | -| `buf_fill` | float-producing | - | fills float storage; offsets by N5 | -| `buf_from_list` | float-producing | - | buffer storage is float: an int element converts (Q2) | -| `buf_from_pcm16le` | float-producing | - | decodes bytes to floats | -| `buf_get` | int-requiring | - | index; returns the float element | -| `buf_len` | int-preserving | - | element count | -| `buf_mix` | float-producing | - | float storage | -| `buf_peak` | float-producing | - | float max abs | -| `buf_resample_linear` | float-producing | - | float storage | -| `buf_scale_range` | float-producing | - | float storage | -| `buf_set` | int-requiring | - | index; the value converts to float storage (Q2) | -| `buf_to_pcm16le` | other | - | quantizes floats to byte values | -| `buffer` | int-requiring | - | size or [rows, cols] | -| `build_corpus` | int-requiring | - | counts; returns counts | -| `ceil` | int-preserving | LOSS | Lua math.ceil: an int when the result fits int64, else a float | -| `channel` | int-preserving | - | handle dict with int id/gen fields | -| `channel_closed` | int-requiring | - | channel handle ids | -| `char_at` | int-requiring | - | string position (Lua string.sub) | -| `chr` | int-requiring | - | byte 1..255, already exactness-checked (Lua string.char) | -| `clock_unix` | float-producing | - | fractional seconds | -| `close_channel` | int-requiring | - | channel handle ids | -| `copy_into` | int-requiring | - | offset; values convert to float storage | -| `cos` | float-producing | - | Lua math.cos | -| `db_execute` | other | LOSS | binds every numeric parameter with `%g`, 6 significant digits (ext_db.c:57-58, #1762). R1.7: the N6/N14 writer | -| `db_query_json` | other | LOSS | binds parameters with `%g` (#1762); encodes rows (N14) | -| `db_query_value` | other | LOSS | binds parameters with `%g` (#1762); decodes a numeric column with strtod, so integer text beyond 2^53 rounds | -| `dispatch` | int-requiring | - | integer table key, already exactness-checked | -| `divide` | float-producing | - | mirrors `/` (Lua §3.4.1: always float) | -| `dot` | float-producing | - | buffer dot product | -| `eigen_eval_loss` | float-producing | - | token ids are indices; the loss is a float | -| `eigen_generate` | int-requiring | - | token ids and max_tokens are integer-valued (N5, Q1); temperature and top_p are floats | -| `eigen_model_load` | other | - | parses model JSON numbers with strtod | -| `exec_capture` | other | - | the timeout is a duration in seconds (continuous, a float; Q1); returns exit status ints | -| `exit` | int-requiring | - | exit code: N5, then the C int range (Q1) | -| `exp` | float-producing | - | Lua math.exp | -| `f64_from_bytes` | int-requiring | - | 8 byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone); the float result's NaN is canonical (N12) | -| `f64_to_bytes` | other | - | float to 8 byte ints; f64_bits (N12) is the int-valued sibling | -| `fill` | int-requiring | - | count | -| `floor` | int-preserving | LOSS | Lua math.floor: an int when the result fits int64, else a float | -| `gather` | int-requiring | - | index or index vector; returns elements unchanged | -| `get_at` | int-requiring | - | index, row and col; returns the element | -| `get_observer_thresholds` | float-producing | - | observer thresholds (O3 drops h_low) | -| `gfx_circle` | other | - | centre, radius and colour are continuous: round to nearest (Q1), replacing truncation | -| `gfx_clear` | other | - | colour channels are continuous: round to nearest (Q1) | -| `gfx_clip` | other | - | the clip rect is continuous: round to nearest (Q1) | -| `gfx_delay` | other | - | milliseconds are a duration: continuous, round to nearest into Uint32 (Q1) | -| `gfx_fb` | int-requiring | - | w and h lay out the pixel buffer (integer-valued: N5, Q1); its elements are palette bytes read through `buffer_read_byte` (N5, then 0..255); dx, dy and scale are drawing coordinates and size (continuous: round to nearest, Q1) | -| `gfx_line` | other | - | endpoints and colour are continuous: round to nearest (Q1) | -| `gfx_open` | other | - | window width and height are gfx sizes: continuous, round to nearest (Q1) | -| `gfx_point` | other | - | position and colour are continuous: round to nearest (Q1) | -| `gfx_poll` | int-preserving | - | event fields x, y, scancode, button are ints | -| `gfx_read` | other | - | the origin is continuous: round to nearest (Q1); returns the channel values as ints | -| `gfx_rect` | other | - | rect and colour are continuous: round to nearest (Q1) | -| `gfx_rrect` | other | - | rect, radius and colour are continuous: round to nearest (Q1) | -| `gfx_text` | other | - | position, colour and scale are continuous: round to nearest (Q1) | -| `gfx_text_height` | int-preserving | - | pixel height, an int; the scale is continuous: round to nearest (Q1) | -| `gfx_text_width` | int-preserving | - | pixel width, an int; the scale is continuous: round to nearest (Q1) | -| `gfx_ticks` | int-preserving | - | SDL ticks (Uint32 ms) | -| `hex` | int-requiring | LOSS | refuses above 2^53 by a double compare, so int 2^53+1 reads as 2^53 and passes silently | -| `http_early_bind` | int-requiring | - | port | -| `http_post` | other | - | header values via value_to_string (N6) | -| `http_route` | other | - | formats via value_to_string | -| `http_route_authed` | other | - | formats via value_to_string | -| `http_serve` | int-requiring | - | port | -| `http_static` | other | - | formats via value_to_string | -| `index_of` | int-preserving | - | byte index or -1 | -| `inflate` | int-requiring | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone) | -| `join` | other | - | elements via value_to_string (N6) | -| `json_build` | other | LOSS | N14 encoder; reads values through eigs_num_arg (a double) | -| `json_decode` | other | LOSS | N14 decoder; integer text decodes through strtod (a double) | -| `json_encode` | other | LOSS | N13/N14 encoder; reads values through eigs_num_arg; its `default:` writes null (builtins.c:998) | -| `json_path` | other | LOSS | decodes with strtod, then formats (N14, N6) | -| `leaky_relu` | float-producing | - | ML activation (float tensors; no Lua counterpart) | -| `len` | int-preserving | - | count (Lua `#` is an integer) | -| `list_contains` | other | - | equality via values_equal (N2) | -| `list_index_of` | int-preserving | - | returns an index; equality via values_equal (N2) | -| `list_insert_at` | int-requiring | - | position (Lua table.insert) | -| `list_remove_at` | int-requiring | - | position (Lua table.remove) | -| `list_slice` | int-requiring | - | start and end indices | -| `list_truncate` | int-requiring | - | new length | -| `log` | float-producing | - | Lua math.log; log of 0 is -inf (N11) | -| `log_softmax` | float-producing | - | ML (float) | -| `matmul` | float-producing | - | float tensors | -| `matmul_at` | float-producing | - | float tensors | -| `matmul_bt` | float-producing | - | float tensors | -| `max` | int-preserving | LOSS | Lua math.max returns the winning argument with its own subtype | -| `mean` | float-producing | - | arithmetic mean | -| `min` | int-preserving | LOSS | Lua math.min | -| `model_load_weights` | other | - | alias of eigen_model_load | -| `monotonic_ms` | float-producing | - | fractional milliseconds | -| `monotonic_ns` | int-preserving | LOSS | exact below 2^53 ns (104 days of uptime), a rounded double after; an exact int under N1 | -| `multiply` | int-preserving | LOSS | scalar arm mirrors `*` (overflow raises, (A)); buffer arms float | -| `native_train_step_builtin` | int-requiring | - | token ids are integer-valued (N5, Q1); lr is a float (a numeric string is accepted through strtod) | -| `nearest_in_range` | float-producing | - | geometry floats; the `index` field is an int | -| `nearest_in_range_all` | float-producing | - | geometry floats; the `index` field is an int | -| `negative` | int-preserving | LOSS | mirrors unary `-`; negating INT64_MIN raises (N4b) | -| `net_accept` | int-requiring | - | socket handle | -| `net_close` | int-requiring | - | socket handle | -| `net_dial` | int-requiring | - | port; returns a handle | -| `net_listen` | int-requiring | - | port; returns a handle | -| `net_port` | int-requiring | - | socket handle; returns a port | -| `net_recv` | int-requiring | - | handle and max bytes | -| `net_send` | int-requiring | - | the handle and the byte values: N5, bytes then 0..255 (Q1; the modulo-256 wrap is gone) | -| `norm` | float-producing | - | L2 norm | -| `num` | other | LOSS | N10 parser: integer text decodes through strtod today (a double) | -| `num_copy` | int-preserving | LOSS | copies a number and must keep its subtype; today re-boxes through a double | -| `numerical_grad` | float-producing | - | finite differences | -| `numerical_grad_cols` | float-producing | - | finite differences; column indices int | -| `numerical_grad_rows` | float-producing | - | finite differences; row indices int | -| `observe` | other | - | observer readouts (O4) | -| `ord` | int-preserving | - | byte code (Lua string.byte) | -| `pi` | float-producing | - | Lua math.pi | -| `pow` | float-producing | - | mirrors `^` (Lua §3.4.1: exponentiation is always float) | -| `ppu_render_frame` | int-requiring | - | reads the emulated memory buffer through `buffer_read_byte`: byte values by N5, then 0..255 (Q1; the modulo-256 wrap is gone) | -| `print` | other | - | N6 printing via value_to_string | -| `proc_read_buf` | int-requiring | - | fd and max bytes; bytes stored as floats | -| `random` | float-producing | - | Lua math.random() in [0,1) | -| `random_hex` | int-requiring | - | digit count | -| `random_int` | int-requiring | LOSS | Lua math.random(m, n) is an integer; bounds read as doubles today | -| `random_normal` | float-producing | - | dims int; samples float | -| `range` | int-preserving | - | bounds by N5; the elements are ints (floats today, inside int range) | -| `read_bytes` | int-preserving | - | byte values 0..255 | -| `read_bytes_buf` | int-requiring | - | cap and length; bytes stored as floats | -| `record_history` | other | - | truthiness flag in; previous flag out | -| `recv` | int-requiring | - | channel handle ids | -| `recv_timeout` | int-requiring | - | the channel handle: N5 (Q1); milliseconds are a duration (continuous, a float) | -| `relu` | float-producing | - | ML activation (float tensors; no Lua counterpart) | -| `reshape` | int-requiring | - | rows and cols | -| `round` | int-preserving | LOSS | no Lua counterpart; follows floor and ceil (Q4) | -| `sandbox_run` | int-requiring | - | iteration, byte and work limits; returns line ints | -| `scan_int_tokens` | int-preserving | LOSS | integers accumulate in a double | -| `scan_ints` | int-preserving | LOSS | integers accumulate in a double | -| `scatter_add` | float-producing | - | indices exactness-checked; float accumulation | -| `seed_random` | int-requiring | LOSS | `(long)` of a double; Lua randomseed takes integers | -| `send` | int-requiring | - | channel handle ids | -| `set_at` | int-requiring | - | index, row and col; a buffer value converts to float | -| `sgd_update` | float-producing | - | float update | -| `sgd_update_cols` | float-producing | - | column indices int | -| `sgd_update_rows` | float-producing | - | row indices int | -| `shape` | int-preserving | - | dimension counts | -| `shared_delete` | int-preserving | - | removed count | -| `shared_incr` | int-preserving | LOSS | shared counter: delta and stored value in doubles | -| `shared_size` | int-preserving | - | entry count | -| `sign_extend` | int-requiring | LOSS | `(int64_t)` of a double | -| `sin` | float-producing | - | Lua math.sin | -| `softmax` | float-producing | - | ML (float) | -| `sort` | other | LOSS | sort_cmp_num compares doubles: ints beyond 2^53 tie (N2 needs exact) | -| `sort_by` | other | LOSS | key results compared as doubles | -| `spawn` | int-preserving | - | handle dict with int id/gen fields | -| `sqrt` | float-producing | - | Lua math.sqrt; sqrt of -1 is NaN (N11) | -| `state_at` | int-requiring | - | step index | -| `store_close` | int-requiring | - | handle id/gen | -| `store_collections` | int-requiring | - | handle id | -| `store_count` | int-requiring | - | handle and page ids; returns a count | -| `store_delete` | int-requiring | LOSS | key formatted `%d` of an `(int)` cast: 1.9 finds "1"; keys above INT_MAX are UB (probed) | -| `store_drop` | int-requiring | - | handle and page ids | -| `store_get` | int-requiring | LOSS | same key cast as store_delete; decodes records (N14) | -| `store_open` | int-preserving | - | handle dict with int id/gen fields | -| `store_put` | other | LOSS | the record encoder writes a non-int32 number with `%.15g`: 1234567890123456 is stored as 1234567890123460 and 0.1 + 0.2 as 0.3, on main and the tag (#1762). R1.7: the N6/N14 writer; R2.3: refusal inside the encoder | -| `store_query` | other | LOSS | decodes records; integer text through strtod (N14) | -| `store_update` | other | LOSS | same key cast as store_delete; re-puts through the `%.15g` encoder (#1762); N13/N14 | -| `str` | other | - | N6 printing via value_to_string | -| `str_from_bytes` | int-requiring | - | byte values: N5, then 0..255 (Q1; Lua string.char raises on 65.5 and on 256) | -| `stream_open` | int-requiring | - | element count, already floor-checked | -| `stream_write` | float-producing | - | writes a raw f64 | -| `substr` | int-requiring | - | start and length (Lua string.sub) | -| `subtract` | int-preserving | LOSS | scalar arm mirrors `-` (overflow raises, (A)) | -| `sum` | int-preserving | LOSS | an all-int input sums exactly, and overflow raises (A); today a guarded double sum | -| `tan` | float-producing | - | Lua math.tan | -| `task_alive` | int-requiring | - | task handle (packed below 2^53, exactness-checked) | -| `task_detach` | int-requiring | - | task handle | -| `task_join` | int-requiring | - | task handle | -| `task_kill` | int-requiring | - | task handle | -| `task_sched_seed` | int-requiring | LOSS | `(int64_t)` of a double | -| `task_self` | int-preserving | - | task handle | -| `task_send` | int-requiring | - | task handle | -| `task_sleep` | other | - | milliseconds are a duration: continuous, a float (Q1) | -| `task_spawn` | int-preserving | - | returns a task handle | -| `tensor_load` | float-producing | - | float tensor; shape ints | -| `tensor_save` | float-producing | - | writes float cells | -| `text_builder_append` | other | - | formats via value_to_string (N6) | -| `text_builder_append_line` | other | - | formats via value_to_string (N6) | -| `thread_join` | int-requiring | - | thread handle id/gen | -| `throw` | other | - | message via value_to_string | -| `token_name` | int-requiring | - | token id | -| `try_recv` | int-requiring | - | channel handle ids | -| `type` | other | - | `type of` an int or a float is "num" ((B)) | -| `usleep` | other | - | microseconds are a duration: continuous, round to nearest (Q1) | -| `vm_run_bytecode` | int-requiring | - | opcode bytes and ABI numbers | -| `write` | other | - | N6 printing | -| `write_bytes` | int-requiring | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone); returns bytes written | -| `zeros` | int-requiring | - | size or [rows, cols]; elements are float 0.0 | -| `zeros_like` | float-producing | - | float zeros | +| builtin | class | loss | q7 | note | +|---|---|---|---|---| +| `abs` | int-preserving | LOSS | - | Lua math.abs (integer/float); abs of INT64_MIN raises (N4b) | +| `acos` | float-producing | - | - | Lua math.acos | +| `add` | int-preserving | LOSS | - | scalar arm mirrors `+` (overflow raises, (A)); buffer arms stay float | +| `append` | other | - | - | appends any value; VAL_NUM appears only as a diagnostic default | +| `asin` | float-producing | - | - | Lua math.asin | +| `assert` | other | - | - | message via value_to_string (N6) | +| `atan` | float-producing | - | - | Lua math.atan | +| `atan2` | float-producing | - | - | Lua math.atan(y, x) | +| `audio_capture_open` | int-requiring | - | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | +| `audio_envelope` | float-producing | - | magnitude | float samples; the attack and release times are continuous durations: a sample count the C int cannot hold raises (Q7 magnitude) | +| `audio_gain` | float-producing | - | - | float samples | +| `audio_mix` | float-producing | - | - | float samples | +| `audio_music_play` | int-requiring | - | - | loop count: N5, then the C int range (Q1) | +| `audio_music_volume` | other | - | bounded | the volume is a continuous gain: clamped to SDL_mixer's 0..128, then rounded (Q7 bounded) | +| `audio_noise` | float-producing | - | magnitude | float samples; the duration is continuous: a sample count the C int cannot hold raises (Q7 magnitude) | +| `audio_open` | int-requiring | - | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | +| `audio_pause` | int-requiring | - | - | the pause flag is discrete: N5 (Q1; today `(int)0.5` silently un-pauses) | +| `audio_play` | other | - | bounded | the samples are continuous: clamped to [-1, 1], then rounded to int16 (Q7 bounded; today they truncate); returns a channel number | +| `audio_play_loop` | int-requiring | - | bounded | loop count: N5, then the C int range (Q1); the samples are continuous: clamped and rounded to int16 (Q7 bounded); returns a channel | +| `audio_queue_size` | int-preserving | - | - | byte count (computed in a double, below 2^53) | +| `audio_saw` | float-producing | - | magnitude | float samples; the duration is continuous: a sample count the C int cannot hold raises (Q7 magnitude) | +| `audio_sine` | float-producing | - | magnitude | float samples; the duration is continuous: a sample count the C int cannot hold raises (Q7 magnitude) | +| `audio_square` | float-producing | - | magnitude | float samples; the duration is continuous: a sample count the C int cannot hold raises (Q7 magnitude) | +| `audio_stop` | int-requiring | - | - | channel number | +| `audio_stream_open` | int-requiring | - | - | freq (samples per second) and channels are counts: N5, then the C int range (Q1); returns a device id | +| `audio_stream_push` | other | - | bounded | the samples are continuous: clamped to [-1, 1], then rounded to int16 (Q7 bounded) | +| `audio_stream_queued` | int-preserving | - | - | sample count | +| `audio_sweep` | float-producing | - | magnitude | float samples; frequencies and amplitude stay floats; the duration is continuous: a sample count the C int cannot hold raises (Q7 magnitude); the wave selector is integer-valued: N5 (Q1) | +| `audio_volume` | int-requiring | - | bounded | channel index: N5 (Q1); the volume is a continuous gain: clamped to the mixer's range (Q7 bounded) | +| `bit_and` | int-requiring | LOSS | - | Lua `&` (§3.4.2): N5 operands, int64-pattern result (N8); today a double result | +| `bit_not` | int-requiring | LOSS | - | Lua unary `~` | +| `bit_or` | int-requiring | LOSS | - | Lua `\|` | +| `bit_shl` | int-requiring | LOSS | - | Lua `<<`; today masks the count mod 64, N8 needs >=64 gives 0 and negative shifts right | +| `bit_shr` | int-requiring | LOSS | - | Lua `>>` is logical (N8); today an arithmetic shift with `& 63` | +| `bit_xor` | int-requiring | LOSS | - | Lua binary `~` | +| `buf_copy` | int-requiring | - | - | offsets and counts | +| `buf_deinterleave` | int-requiring | - | - | channel count and index | +| `buf_dot` | float-producing | - | - | buffer dot product | +| `buf_fill` | float-producing | - | - | fills float storage; offsets by N5 | +| `buf_from_list` | float-producing | - | - | buffer storage is float: an int element converts (Q2) | +| `buf_from_pcm16le` | int-requiring | - | - | its input elements are byte values: each is read through the Q1 byte reader (N5, then 0..255), so a byte of 300 or 1.5 raises `value` (#1758 comment 6174964306; today 300 and 1.5 decode silently); the decoded samples are floats | +| `buf_get` | int-requiring | - | - | index; returns the float element | +| `buf_len` | int-preserving | - | - | element count | +| `buf_mix` | float-producing | - | - | float storage | +| `buf_peak` | float-producing | - | - | float max abs | +| `buf_resample_linear` | float-producing | - | - | float storage | +| `buf_scale_range` | float-producing | - | - | float storage | +| `buf_set` | int-requiring | - | - | index; the value converts to float storage (Q2) | +| `buf_to_pcm16le` | other | - | bounded | the samples are continuous: clamped to [-1, 1] and rounded (Q7 bounded, today's behaviour); the result is byte values | +| `buffer` | int-requiring | - | - | size or [rows, cols] | +| `build_corpus` | int-requiring | - | - | counts; returns counts | +| `ceil` | int-preserving | LOSS | - | Lua math.ceil: an int when the result fits int64, else a float | +| `channel` | int-preserving | - | - | handle dict with int id/gen fields | +| `channel_closed` | int-requiring | - | - | channel handle ids | +| `char_at` | int-requiring | - | - | string position (Lua string.sub) | +| `chr` | int-requiring | - | - | byte 1..255, already exactness-checked (Lua string.char) | +| `clock_unix` | float-producing | - | - | fractional seconds | +| `close_channel` | int-requiring | - | - | channel handle ids | +| `copy_into` | int-requiring | - | - | offset; values convert to float storage | +| `cos` | float-producing | - | - | Lua math.cos | +| `db_execute` | other | LOSS | - | binds every numeric parameter with `%g`, 6 significant digits (ext_db.c:57-58, #1762). R1.7: the N6/N14 writer | +| `db_query_json` | other | LOSS | - | binds parameters with `%g` (#1762); encodes rows (N14) | +| `db_query_value` | other | LOSS | - | binds parameters with `%g` (#1762); decodes a numeric column with strtod, so integer text beyond 2^53 rounds | +| `dispatch` | int-requiring | - | - | integer table key, already exactness-checked | +| `divide` | float-producing | - | - | mirrors `/` (Lua §3.4.1: always float) | +| `dot` | float-producing | - | - | buffer dot product | +| `eigen_eval_loss` | float-producing | - | - | token ids are indices; the loss is a float | +| `eigen_generate` | int-requiring | - | - | token ids and max_tokens are integer-valued (N5, Q1); temperature and top_p are floats | +| `eigen_model_load` | other | - | - | parses model JSON numbers with strtod | +| `exec_capture` | other | - | magnitude | the timeout is a continuous duration in seconds: a poll interval the C int cannot hold raises (Q7 magnitude); returns exit status ints | +| `exit` | int-requiring | - | - | exit code: N5, then the C int range (Q1) | +| `exp` | float-producing | - | - | Lua math.exp | +| `f64_from_bytes` | int-requiring | - | - | 8 byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone); the float result's NaN is canonical (N12) | +| `f64_to_bytes` | other | - | - | float to 8 byte ints; f64_bits (N12) is the int-valued sibling | +| `fill` | int-requiring | - | - | count | +| `floor` | int-preserving | LOSS | - | Lua math.floor: an int when the result fits int64, else a float | +| `gather` | int-requiring | - | - | each index, from a list or an index buffer, is integer-valued: N5 raises on 1.5 (today `flat_index_at` truncates: `gather of [t, ib]` with `ib[0]` = 1.5 returns `[11, 22]`, probed); returns elements unchanged | +| `get_at` | int-requiring | - | - | index, row and col; returns the element | +| `get_observer_thresholds` | float-producing | - | - | observer thresholds (O3 drops h_low) | +| `gfx_circle` | other | - | geometry,bounded | centre and radius are continuous geometry: the circle is clipped in float space against the drawable area, then rounded; the colour channels are continuous and bounded: clamped to 0..255, then rounded (Q7) | +| `gfx_clear` | other | - | bounded | the colour channels are continuous and bounded: clamped to 0..255, then rounded (Q7) | +| `gfx_clip` | other | - | geometry | the clip rect is continuous geometry: intersected with the drawable area in float space, then rounded (Q7) | +| `gfx_delay` | other | - | magnitude | the milliseconds are a continuous duration: rounded; a delay Uint32 cannot hold raises (Q7 magnitude) | +| `gfx_fb` | int-requiring | - | geometry | w and h lay out the pixel buffer (integer-valued: N5, Q1); its elements are palette bytes read through the Q1 byte reader; dx, dy and scale are continuous geometry: the destination rect is clipped in float space, then rounded (Q7) | +| `gfx_line` | other | - | geometry,bounded | the endpoints are continuous geometry: the segment is clipped in float space against the drawable area, then rounded; the colour is bounded (Q7) | +| `gfx_open` | other | - | magnitude | window width and height are continuous sizes with no drawable area yet to clip against: rounded, and a size the C int cannot hold raises (Q7 magnitude) | +| `gfx_point` | other | - | geometry,bounded | the position is continuous geometry: a point outside the drawable area draws nothing; the colour is bounded (Q7) | +| `gfx_poll` | int-preserving | - | - | event fields x, y, scancode, button are ints | +| `gfx_read` | other | - | geometry | the origin is continuous geometry: rounded, and a point outside the drawable area reads nothing (Q7); returns the channel values as ints | +| `gfx_rect` | other | - | geometry,bounded | the rect is continuous geometry: intersected with the drawable area in float space, then rounded; the colour is bounded (Q7) | +| `gfx_rrect` | other | - | geometry,bounded | the rect and radius are continuous geometry: clipped in float space, then rounded; the colour is bounded (Q7) | +| `gfx_text` | other | - | geometry,bounded | the position and scale are continuous geometry: each glyph cell is clipped in float space, then rounded; the colour is bounded (Q7) | +| `gfx_text_height` | int-preserving | - | magnitude | pixel height, an int; the scale is continuous, and a measurement has no drawable area to clip against: rounded, and a scale the C int cannot hold raises (Q7 magnitude) | +| `gfx_text_width` | int-preserving | - | magnitude | pixel width, an int; the scale is continuous, and a measurement has no drawable area to clip against: rounded, and a scale the C int cannot hold raises (Q7 magnitude) | +| `gfx_ticks` | int-preserving | - | - | SDL ticks (Uint32 ms) | +| `hex` | int-requiring | LOSS | - | refuses above 2^53 by a double compare, so int 2^53+1 reads as 2^53 and passes silently | +| `http_early_bind` | int-requiring | - | - | port | +| `http_post` | other | - | - | header values via value_to_string (N6) | +| `http_route` | other | - | - | formats via value_to_string | +| `http_route_authed` | other | - | - | formats via value_to_string | +| `http_serve` | int-requiring | - | - | port | +| `http_static` | other | - | - | formats via value_to_string | +| `index_of` | int-preserving | - | - | byte index or -1 | +| `inflate` | int-requiring | - | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone) | +| `join` | other | - | - | elements via value_to_string (N6) | +| `json_build` | other | LOSS | - | N14 encoder; reads values through eigs_num_arg (a double) | +| `json_decode` | other | LOSS | - | N14 decoder; integer text decodes through strtod (a double) | +| `json_encode` | other | LOSS | - | N13/N14 encoder; reads values through eigs_num_arg; its `default:` writes null (builtins.c:998) | +| `json_path` | other | LOSS | - | decodes with strtod, then formats (N14, N6) | +| `leaky_relu` | float-producing | - | - | ML activation (float tensors; no Lua counterpart) | +| `len` | int-preserving | - | - | count (Lua `#` is an integer) | +| `list_contains` | other | - | - | equality via values_equal (N2) | +| `list_index_of` | int-preserving | - | - | returns an index; equality via values_equal (N2) | +| `list_insert_at` | int-requiring | - | - | position (Lua table.insert) | +| `list_remove_at` | int-requiring | - | - | position (Lua table.remove) | +| `list_slice` | int-requiring | - | - | start and end indices | +| `list_truncate` | int-requiring | - | - | new length | +| `log` | float-producing | - | - | Lua math.log; log of 0 is -inf (N11) | +| `log_softmax` | float-producing | - | - | ML (float) | +| `matmul` | float-producing | - | - | float tensors | +| `matmul_at` | float-producing | - | - | float tensors | +| `matmul_bt` | float-producing | - | - | float tensors | +| `max` | int-preserving | LOSS | - | Lua math.max returns the winning argument with its own subtype; a NaN argument makes the result NaN (Q8: IEEE 754-2019 maximum) | +| `mean` | float-producing | - | - | arithmetic mean | +| `min` | int-preserving | LOSS | - | Lua math.min; a NaN argument makes the result NaN (Q8: IEEE 754-2019 minimum) | +| `model_load_weights` | other | - | - | alias of eigen_model_load | +| `monotonic_ms` | float-producing | - | - | fractional milliseconds | +| `monotonic_ns` | int-preserving | LOSS | - | exact below 2^53 ns (104 days of uptime), a rounded double after; an exact int under N1 | +| `multiply` | int-preserving | LOSS | - | scalar arm mirrors `*` (overflow raises, (A)); buffer arms float | +| `native_train_step_builtin` | int-requiring | - | - | token ids are integer-valued (N5, Q1); lr is a float (a numeric string is accepted through strtod) | +| `nearest_in_range` | float-producing | - | - | geometry floats; the `index` field is an int | +| `nearest_in_range_all` | float-producing | - | - | geometry floats; the `index` field is an int | +| `negative` | int-preserving | LOSS | - | mirrors unary `-`; negating INT64_MIN raises (N4b) | +| `net_accept` | int-requiring | - | - | socket handle | +| `net_close` | int-requiring | - | - | socket handle | +| `net_dial` | int-requiring | - | - | port; returns a handle | +| `net_listen` | int-requiring | - | - | port; returns a handle | +| `net_port` | int-requiring | - | - | socket handle; returns a port | +| `net_recv` | int-requiring | - | - | handle and max bytes | +| `net_send` | int-requiring | - | - | the handle and the byte values: N5, bytes then 0..255 (Q1; the modulo-256 wrap is gone) | +| `norm` | float-producing | - | - | L2 norm | +| `num` | other | LOSS | - | N10 parser: integer text decodes through strtod today (a double) | +| `num_copy` | int-preserving | LOSS | - | copies a number and must keep its subtype; today re-boxes through a double | +| `numerical_grad` | float-producing | - | - | finite differences | +| `numerical_grad_cols` | float-producing | - | - | finite differences; column indices int | +| `numerical_grad_rows` | float-producing | - | - | finite differences; row indices int | +| `observe` | other | - | - | observer readouts (O4) | +| `ord` | int-preserving | - | - | byte code (Lua string.byte) | +| `pi` | float-producing | - | - | Lua math.pi | +| `pow` | float-producing | - | - | mirrors `^` (Lua §3.4.1: exponentiation is always float) | +| `ppu_render_frame` | int-requiring | - | - | reads the emulated memory buffer through `buffer_read_byte`: byte values by N5, then 0..255 (Q1; the modulo-256 wrap is gone) | +| `print` | other | - | - | N6 printing via value_to_string | +| `proc_read_buf` | int-requiring | - | - | fd and max bytes; bytes stored as floats | +| `random` | float-producing | - | - | Lua math.random() in [0,1) | +| `random_hex` | int-requiring | - | - | digit count | +| `random_int` | int-requiring | LOSS | - | Lua math.random(m, n) is an integer; bounds read as doubles today | +| `random_normal` | float-producing | - | - | dims int; samples float | +| `range` | int-preserving | - | - | bounds by N5; the elements are ints (floats today, inside int range) | +| `read_bytes` | int-preserving | - | - | byte values 0..255 | +| `read_bytes_buf` | int-requiring | - | - | cap and length; bytes stored as floats | +| `record_history` | other | - | - | truthiness flag in; previous flag out | +| `recv` | int-requiring | - | - | channel handle ids | +| `recv_timeout` | int-requiring | - | magnitude | the channel handle: N5 (Q1); the milliseconds are a continuous duration: a timeout the C long cannot hold raises (Q7 magnitude) | +| `relu` | float-producing | - | - | ML activation (float tensors; no Lua counterpart) | +| `reshape` | int-requiring | - | - | rows and cols | +| `round` | int-preserving | LOSS | - | no Lua counterpart; follows floor and ceil (Q4) | +| `sandbox_run` | int-requiring | - | - | iteration, byte and work limits; returns line ints | +| `scan_int_tokens` | int-preserving | LOSS | - | integers accumulate in a double | +| `scan_ints` | int-preserving | LOSS | - | integers accumulate in a double | +| `scatter_add` | float-producing | - | - | indices are exactness-checked today, but raise an index error for 1.5; R1.6 reads them through the N5 index reader (`value`); float accumulation | +| `seed_random` | int-requiring | LOSS | - | `(long)` of a double; Lua randomseed takes integers | +| `send` | int-requiring | - | - | channel handle ids | +| `set_at` | int-requiring | - | - | index, row and col; a buffer value converts to float | +| `sgd_update` | float-producing | - | - | float update | +| `sgd_update_cols` | float-producing | - | - | column indices int | +| `sgd_update_rows` | float-producing | - | - | row indices int | +| `shape` | int-preserving | - | - | dimension counts | +| `shared_delete` | int-preserving | - | - | removed count | +| `shared_incr` | int-preserving | LOSS | - | shared counter: delta and stored value in doubles | +| `shared_size` | int-preserving | - | - | entry count | +| `sign_extend` | int-requiring | LOSS | - | `(int64_t)` of a double | +| `sin` | float-producing | - | - | Lua math.sin | +| `softmax` | float-producing | - | - | ML (float) | +| `sort` | other | LOSS | - | sort_cmp_num compares doubles: ints beyond 2^53 tie (N2 needs exact); from R2.2 floats sort by IEEE totalOrder, NaN after +inf (Q8) | +| `sort_by` | other | LOSS | - | key results compared as doubles; from R2.2 by IEEE totalOrder, NaN after +inf (Q8) | +| `spawn` | int-preserving | - | - | handle dict with int id/gen fields | +| `sqrt` | float-producing | - | - | Lua math.sqrt; sqrt of -1 is NaN (N11) | +| `state_at` | int-requiring | - | - | step index | +| `store_close` | int-requiring | - | - | handle id/gen | +| `store_collections` | int-requiring | - | - | handle id | +| `store_count` | int-requiring | - | - | handle and page ids; returns a count | +| `store_delete` | int-requiring | LOSS | - | key formatted `%d` of an `(int)` cast: 1.9 finds "1"; keys above INT_MAX are UB (probed) | +| `store_drop` | int-requiring | - | - | handle and page ids | +| `store_get` | int-requiring | LOSS | - | same key cast as store_delete; decodes records (N14) | +| `store_open` | int-preserving | - | - | handle dict with int id/gen fields | +| `store_put` | other | LOSS | - | the record encoder writes a non-int32 number with `%.15g`: 1234567890123456 is stored as 1234567890123460 and 0.1 + 0.2 as 0.3, on main and the tag (#1762). R1.7: the N6/N14 writer; R2.3: refusal inside the encoder | +| `store_query` | other | LOSS | - | decodes records; integer text through strtod (N14) | +| `store_update` | other | LOSS | - | same key cast as store_delete; re-puts through the `%.15g` encoder (#1762); N13/N14 | +| `str` | other | - | - | N6 printing via value_to_string | +| `str_from_bytes` | int-requiring | - | - | byte values: N5, then 0..255 (Q1; Lua string.char raises on 65.5 and on 256) | +| `stream_open` | int-requiring | - | - | element count, already floor-checked | +| `stream_write` | float-producing | - | - | writes a raw f64 | +| `substr` | int-requiring | - | - | start and length (Lua string.sub) | +| `subtract` | int-preserving | LOSS | - | scalar arm mirrors `-` (overflow raises, (A)) | +| `sum` | int-preserving | LOSS | - | an all-int input sums exactly, and overflow raises (A); today a guarded double sum | +| `tan` | float-producing | - | - | Lua math.tan | +| `task_alive` | int-requiring | - | - | task handle (packed below 2^53, exactness-checked) | +| `task_detach` | int-requiring | - | - | task handle | +| `task_join` | int-requiring | - | - | task handle | +| `task_kill` | int-requiring | - | - | task handle | +| `task_sched_seed` | int-requiring | LOSS | - | `(int64_t)` of a double | +| `task_self` | int-preserving | - | - | task handle | +| `task_send` | int-requiring | - | - | task handle | +| `task_sleep` | other | - | - | milliseconds of virtual time, kept as a float: no C integer conversion, so Q7 does not apply | +| `task_spawn` | int-preserving | - | - | returns a task handle | +| `tensor_load` | float-producing | - | - | float tensor; shape ints | +| `tensor_save` | float-producing | - | - | writes float cells | +| `text_builder_append` | other | - | - | formats via value_to_string (N6) | +| `text_builder_append_line` | other | - | - | formats via value_to_string (N6) | +| `thread_join` | int-requiring | - | - | thread handle id/gen | +| `throw` | other | - | - | message via value_to_string | +| `token_name` | int-requiring | - | - | token id | +| `try_recv` | int-requiring | - | - | channel handle ids | +| `type` | other | - | - | `type of` an int or a float is "num" ((B)) | +| `usleep` | other | - | magnitude | the microseconds are a continuous duration: rounded; a sleep the C int cannot hold raises (Q7 magnitude) | +| `vm_run_bytecode` | int-requiring | - | - | opcode bytes and ABI numbers | +| `write` | other | - | - | N6 printing | +| `write_bytes` | int-requiring | - | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone); returns bytes written | +| `zeros` | int-requiring | - | - | size or [rows, cols]; elements are float 0.0 | +| `zeros_like` | float-producing | - | - | float zeros | **Builtins to add**, outside the checked table until they exist: @@ -1367,7 +1515,8 @@ numbers are at `0740af03`. - eigenscript.h:1910 `num_to_i64_exact` (#1740); - every int-requiring row of §6, through `eigs_int_arg` (with `eigs_int_arg_range`, `eigs_byte_arg` for Q1's integer-valued - parameters; `eigs_round_arg` for its continuous ones); + parameters; the Q7 readers `eigs_geom_shape`, `eigs_bounded_arg` and + `eigs_magnitude_arg` for its continuous ones); - vm.c index paths (`jit_helper_index_get`/`set`, `CASE(INDEX_*)`) and `range_bound` (builtins.c:3877); - the JIT `OP_INDEX_SET` integrality guard (jit.c:4100-4112) stays @@ -1376,7 +1525,18 @@ numbers are at `0740af03`. int index (the generic path applies N5), and a float index still goes through `vm_index_is_int`; - `buffer_read_byte` and `finite_num_to_byte` (Q1 byte values), deleted - in R1.6 (§2.7). + in R1.6 (§2.7), and the byte reads `buffer_read_num` performs today: + `buf_from_pcm16le` (builtins_buf.c:754, :756; #1758 comment 6174964306), + `str_from_bytes` (:240), `f64_from_bytes` (:284), the zlib input (:351), + `write_bytes` (builtins_host.c:1548) and `net_send` (ext_net.c:361), each + through `buffer_byte_at` after R1.6 renames `buffer_read_num`; + - the index reads: `gather`'s `flat_index_at` (builtins_tensor.c:1428-1440, + both its list path and its buffer path truncate today) and + `scatter_add` (:1036, exactness-checked but raising an index error), + each through `buffer_index_at` or `eigs_int_arg` (N5, `value`); + - the Q7 readers (§2.6) for every continuous parameter the `q7` column + names: the gfx shapes (ext_gfx.c), the audio samples, gains and + durations, `usleep`, `gfx_delay`, `exec_capture`, `recv_timeout`. - **N6 (printing):** - eigenscript.c:2938 `eigs_num_text` (today integral doubles below 2^53 print without `.0`) and 2957 `value_to_string`; @@ -1413,7 +1573,10 @@ numbers are at `0740af03`. - the leaf's `num_guard(r)` (vm.c:1954), deleted with the others; - the consumers no token marks (§2.7): `values_equal_impl`'s identity shortcut (eigenscript.c, first line of the function) must not call a - NaN box equal to itself; the sort comparators (NaN order: §11 Q8). + NaN box equal to itself; the sort comparators (`sort_cmp_num`, + builtins.c:5868, and `sort_by`'s key comparison, 5815) order floats by + IEEE `totalOrder`, NaN after +inf; `minmax_reduce` (builtins.c:2086-2088, + `min`/`max`) propagates NaN (Q8, decided). - **N12 (canonical NaN; payload fidelity through ints):** - value_slot.h:73 `slot_from_num`, becoming `slot_from_f64`: the single writer, including the leaf's five calls (vm.c:1869, 1873, 1876, 1927, @@ -1469,9 +1632,29 @@ numbers are at `0740af03`. `observer_slot_update_num`, the `obs_num_*` predicates (935-1193) and `compute_entropy_impl` (435), from which entropy is removed for numerics; - vm.c `obs_slot_observable` (1630); - - the observe helpers `jit_helper_observe_assign_local` (1661) and - `jit_sample_num_gated`, which must route an SMI into the numeric channel - in round 1 already, converting to double for the distance (§2.5); + - **the routing of an int into the numeric channel, from R1.3 (when the + first int exists), converted to a double for the distance until round + 3.** Two paths, both forced before R1.3 and both live in R1.3: + - **an SMI**: the observe sites test `slot_is_num` first (D1, forced in + R1.1): `CASE(OBSERVE_ASSIGN_LOCAL)` (vm.c:5189, its elided + `unobserved:` path at 5202), `CASE(OBSERVE_NAME_POST)` (5431), + `jit_helper_observe_assign_local` (1678-1684) and + `jit_helper_observe_name_post` (1730). Each gains `slot_is_smi(s)` -> + `observer_slot_update_num(e, slot, (double)smi)` (or the sample form); + `obs_slot_observable` aborts on an SMI that reaches it (§2.5); + - **a boxed int** (an int outside [-2^47, 2^47), or any int a lift + boxed): `obs_slot_observable` answers true for any pointer, so it goes + to `observer_slot_update(Value *)` (eigenscript.c:769), whose number + arm (`newval->type == VAL_NUM`, :785) feeds the value channel and whose + `else` ends the numeric trajectory (#861). R1.2's `VAL_NUM` rename + forces that arm; it gains `VAL_INT` -> + `observer_slot_record_value(s, (double)i)`. The same holds for the + elided `observer_slot_sample_gated` (:851, its arm at :852) and for + `compute_entropy_impl`'s exhaustive switch (:437), whose `VAL_INT` arm + gives an int the entropy of its double; + - the MAP row `O1.int-observed-numeric` (R1.3) pins both: an SMI and a + boxed int (2^47 and up) must answer every observer readout exactly as + their float twins do; - vm.c:5460 `CASE(INTERROGATE)` (`where`/`why`/`how`); - `builtin_observe`; - the `O cfg` record; @@ -1500,129 +1683,152 @@ numbers are at `0740af03`. Every commit builds, passes the full suite, and carries its own MAP rows. "Unchanged" means a differential against the baseline binary captured before the commit (the verify-and-fix rule), not "the suite passed". Every -meaning change lands in the commit that carries its token change (§2.7). +meaning change lands in the commit that carries its token change, or is in +§2.7's token-less list with its gate. `phase2_check.sh --through ` +checks each commit against exactly the rows that have landed (§9.2). + +### Where the first int value appears: R1.3 + +No int VALUE exists before R1.3, and this is structural, not a promise: +- `make_int` is introduced in R1.3, so nothing earlier can call it; +- `slot_from_int` exists from R1.1 (the C slot test needs it), but until R1.3 + its only production callers are the canonicalizing writers of §2.1, which + convert an existing `VAL_INT`, and none exists. `phase2_check.sh --through + R1.2` checks this: it derives the callers of `slot_from_int` and + `make_int` from the source and fails on any caller outside that list + (the int-source check); +- the lexer produces only float literals until R1.3, and the tape cannot + carry an int until v7 (R1.3). + +**Every consumer of an int is converted AT R1.3**, either by code forced and +written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: + +| consumer | converted by | how it treats an int at R1.3 | +|---|---|---| +| VM arithmetic, comparison, negation (N2, N3, N4b, (A)) | R1.1 forced the arms (`slot_as_double` deleted); R1.3 adds the int semantics | exact int64, overflow raises | +| `/` and `%` | R1.3 (transitional) | converted to doubles, today's semantics, until R1.4 | +| bitwise operators | R1.3 (transitional) | exact int64 operands (#1740's rule), today's shift rule until R1.5 | +| equality, ordering, hashing, the constant pool | R1.2 (forced arms) | by value across kinds (N2); the pool keys on kind | +| printing (`value_to_string`, f-strings) | R1.2a (the exhaustive switch) | exact digits, as today for small ints | +| `type of`, `num_type` | R1.2a (`val_type_name`), R1.3 (`num_type`) | `"num"`; `"int"` | +| containers | R1.2 (the four canonicalizing writers) | an SMI, or a box outside the SMI range (§2.1) | +| the observer | R1.1 (SMI sites, D1) and R1.2 (the boxed arm at eigenscript.c:785, the entropy switch) | the numeric channel, as a double until round 3 (§7) | +| the tape | R1.3: v7 writer and parser | ints as digits, floats marked as floats; a v6 tape is refused | +| the JIT | nothing to convert: its guards bail on an SMI or a `VAL_INT` box (§4.1), and its scanner refuses `OP_INT_*` | interpreted | +| the leaf evaluator | R1.1 (its arithmetic and index arms bail) | the generic path computes it | +| builtins | the bridge (R1.2's number tests admit ints) | a double, exactly as the tag sees every number, until R1.6 | +| JSON, store and db encoders | R1.2a (their `VAL_INT` arms) | exact digits | +| the embed API (`eigs_value_as_num`) | R1.2 (its forced `VAL_NUM` test) | converts to a double (Q3) | +| lint and the LSP | R1.3 (the AST payload rename) | the literal's kind | ### Round 1: the core model (Alt 1R) 1. **R1.1, the slot layer: the SMI exists, every slot reader is forced (no - producer yet).** + producer).** - Add `TAG_SMI`, `slot_is_smi`, `slot_from_int`, `slot_smi_val`, `slot_f64_value` and `slot_int_value` (§2.6). - - The token changes of this commit: `slot_is_num` -> `slot_is_f64`, - `SLOT_NUM_RAW` -> `SLOT_F64_RAW`, `slot_from_num` -> `slot_from_f64`, - the container helpers `*_num` -> `*_f64`; `slot_is_numeric` deleted; - **`slot_as_double` deleted**. Its 15 calls are rewritten with an - explicit int decision: the arithmetic and compare arms take their float - fast path through `slot_f64_value` and send anything else to the slow - path; the leaf evaluator's `INDEX_GET` and `ADD`/`SUB`/`MUL` arms bail - on anything that is not a float. + - The token changes: `slot_is_num` -> `slot_is_f64`, `SLOT_NUM_RAW` -> + `SLOT_F64_RAW`, `slot_from_num` -> `slot_from_f64`; `slot_is_numeric` + deleted; **`slot_as_double` deleted**. Its 15 calls are rewritten with + an explicit int decision: the arithmetic and compare arms take their + float fast path through `slot_f64_value` and send anything else to the + slow path; the leaf evaluator's `INDEX_GET` and `ADD`/`SUB`/`MUL` arms + bail on anything that is not a float. 223 sites first forced (§2.3a). - The D2/D3 dispositions (§2.5): `eigs_slot_ref`, `obs_slot_observable`, `slot_as_ptr` and `slot_as_heap` refuse an SMI (abort; `slot_as_ptr` - in ASan and debug builds); `slot_type_name` gains its SMI arm. Every D1 - function gets its SMI arm as the compiler stops at it. - - `tools/phase2_check.sh` (§9.2) lands here with its calibration, and - runs the rows whose round has landed. - - Test: the C slot test (§2.5), through the amalgamation, built from the - inventory's D1-D3 list and run under ASan; plant 1 (§9.3). Language - behaviour is unchanged (differential over the suite's `.eigs` corpus), - because nothing produces an SMI yet. -2. **R1.2, the Value layer and the renames (deprecate, then delete).** - - R1.2a: `VAL_INT` (appended), `make_int`, the §2.6 readers and - `val_type_name(VAL_INT) = "num"`. **Delete the `default:` arm of - `eigs_json_encode_value` (builtins.c:998)**, enumerating the types, so + in ASan and debug builds); `slot_type_name` gains its SMI arm. + - `tools/phase2_check.sh` lands here with its calibration (§9.2). + - Gates (a mechanical round, zero MAP rows): the compile errors, the C + slot test (§2.5) and plant 1 (§9.3); the int-source check; language + behaviour unchanged (differential over the suite's `.eigs` corpus). +2. **R1.2, the Value layer (behaviour-preserving; no builtin decision).** + - R1.2a: `VAL_INT` appended; `VAL_NUM` -> `VAL_FLOAT`, `num_` -> `f64_`, + `VAL_NUM_RAW`/`VAL_NUM_OFFSET` renamed, with deprecated aliases as the + progress meter; `val_type_name(VAL_INT) = "num"`; **the `default:` arm + of `eigs_json_encode_value` (builtins.c:998) deleted**, so `-Werror=switch` reaches the last switch that could absorb `VAL_INT` - silently. The old names stay, marked `__attribute__((deprecated))`; - macros are routed through a deprecated inline. - - R1.2b-n: one commit per file group (vm.c; builtins.c; tensor; buf; - host; gfx; net/http/db/model; store; trace; observer; embed; lint and - LSP). Each migrates its sites by the §6 table and lowers the - deprecation-warning count. `VAL_INT` exists and is handled (the int - arms are written against the final semantics), but nothing produces - it, so behaviour is unchanged (differential). - - R1.2z: delete the old names (`VAL_NUM`, `num_`, `VAL_NUM_RAW`, - `VAL_NUM_OFFSET`, `make_num`, `make_num_permanent`, the `eigs_num_arg` - and `eigs_slot_num` families, `buf_num_arg`). A straggler fails to - compile (§2.3a measured which sites). - - Risk: the size (1,416 compile-forced sites across R1.1-R1.2); and a - mis-migration that picks `eigs_float_arg` for an int-preserving - builtin, caught by the int-fuzz gate (§9.4). -3. **R1.3, the flip: int literals and exact int arithmetic.** + silently. + - R1.2b-n: one commit per file group. Each forced site gets its final + int arm (dead until R1.3), and a builtin's number test admits an int + and reads it through the bridge (§2.7). The bridge's names are NOT + touched: no builtin's behaviour changes. 464 sites first forced. + - R1.2z: delete the deprecated aliases. A straggler fails to compile. + - Gates (a mechanical round, zero MAP rows): the compile errors; the + differential over the suite's `.eigs` corpus (identical to the + baseline); the int-source check. +3. **R1.3, the flip: the first int values.** See the table above. - N1, with its token changes in this same commit: the lexer produces an int literal; the AST payload `num` and the token's `num_val` become an - `EigsNum` (renamed, so the parser, compiler, lint and LSP sites stop - compiling here); **`OP_INT_ZERO`, `OP_INT_ONE` and `OP_INT_CONST` are - appended** to `OpCode` (the four exhaustive OpCode switches stop - compiling until they name them; three new interpreter CASEs; the JIT - scanner and the leaf scanner refuse them by their `default:`); - `OP_NUM_ZERO`/`OP_NUM_ONE`/`OP_CONST` keep their float meaning in all - three executors. The constant pool keys on kind and bits. - - N3 with (A) overflow raise, N2 exact cross-kind comparison, N4b `-x`, - N7 `num_type`. - - EQ/NE: the only bit fast path is "both SMI"; anything boxed compares by - value (§2.1). + `EigsNum`; **`OP_INT_ZERO`, `OP_INT_ONE` and `OP_INT_CONST` are + appended** (the four exhaustive OpCode switches; three new interpreter + CASEs; the JIT and leaf scanners refuse them by their `default:`); + `make_int` is introduced. `OP_NUM_ZERO`/`OP_NUM_ONE`/`OP_CONST` keep + their float meaning in all three executors. + - N3 with (A), N2's exact cross-kind comparison, N4b `-x`, N7 `num_type`; + EQ/NE's only bit fast path is "both SMI" (§2.1). - The JIT scanner refuses `BAND`/`BOR`/`BXOR`/`SHL`/`SHR`/`BNOT`/`MOD`. - - **The tape goes to v7 in this commit.** The moment ints exist, a v6 - writer would print `3` for both kinds and replay would turn ints into - floats. The float token marks its kind now (`3.0`); N6's full repr - replaces it in R1.7, still inside v7. - - The observer routes an SMI into the numeric channel (converted to - double); `obs_slot_observable`'s refusal (R1.1) catches a missed caller. - - The `trace` tier (§9.2, the leaf differential) and the tier witnesses - start gating here, because ints now reach all three evaluators. - - The visible change is small: ints print as today. The rest waits for - N4/N6. - - Risks: - - JIT int loops leave the JIT (§3: +70% Ir on a counter loop), and the - leaf evaluator stops computing int helpers. Declare the CodSpeed - baseline move first. - - Consumer hashes that relied on double rounding now raise ((A)); they - move to the N9 wrapping builtins. + - **Tape v7 in this commit**: a v6 writer would print `3` for both kinds + and replay would turn ints into floats. The float token marks its kind + now (`3.0`); N6's repr replaces it in R1.7, still inside v7. + - The observer routes an SMI and a boxed int into the numeric channel + (§7). + - The `trace` tier (the leaf differential) and the tier witnesses gate + from here. + - Risks: JIT int loops leave the JIT (§3: +70% Ir on a counter loop), + and the leaf stops computing int helpers; declare the CodSpeed baseline + move first. Consumer hashes that relied on double rounding now raise + ((A)); they move to the N9 wrapping builtins. 4. **R1.4, N4.** `//` (token, parser, `OP_IDIV` appended, - `op_name`/`op_stack_effect`/obs marker/ABI test), `//=` beside `/=` - (Q6, decided), `%` floor modulo for ints and floats, int division by - zero raises, `INT64_MIN % -1` is 0. -5. **R1.5, N8.** Bitwise ops on ints with Lua's shift rules; `bit_*` - returns ints. -6. **R1.6, N5, N9, N10 and the §6 builtins.** Every int-preserving and - int-requiring row, the 42 LOSS rows first; Q1 (decided): integer-valued - parameters through `eigs_int_arg_range`/`eigs_byte_arg` - (`finite_num_to_byte` and `buffer_read_byte` deleted in this commit), - continuous ones through `eigs_round_arg` once §11 Q7 is decided (until - then they keep R1.2's behaviour-preserving truncation); Q4 `round`; - `num of` (#1638); the N9 width family. -7. **R1.7, N6 and N14's int half.** + `op_name`/`op_stack_effect`/obs marker/ABI test), `//=` beside `/=` (Q6), + `%` floor modulo for ints and floats, int division by zero raises, + `INT64_MIN % -1` is 0. +5. **R1.5, N8.** Bitwise operators on ints with Lua's shift rules. +6. **R1.6, the bridge deletion: every builtin's §6 semantics.** The bridge's + 21 tokens are deleted (743 sites first forced), in per-file-group commits + that each migrate their sites off the deprecated bridge and give those + builtins their final behaviour in the same commit: + - every int-preserving and int-requiring row, the 42 LOSS rows first; + - Q1: integer-valued parameters through `eigs_int_arg_range`, + `eigs_byte_arg`, `buffer_byte_at` and `buffer_index_at`; + - Q7: continuous parameters through `eigs_geom_shape`, + `eigs_bounded_arg` and `eigs_magnitude_arg` (§2.6); + - Q4 `round`; `num of` (#1638) and the decoders' int kinds for integer + text (`json_decode`, `json_path`, `store_query`, `db_query_value`); the + N9 width family; + - gate: the per-builtin behaviour table (§9.4), on the tag and the branch. +7. **R1.7, the float text (N6) and N14's writers.** - Python-repr floats; ints as exact digits. - The constant dedup compares bits, so `-0.0` survives. - - JSON writes ints as digits and floats with `.0`; integer text within - int64 decodes as an int; `1e400` raises. - - #1762's writers: `store_json_encode` and `db_build_query` go through - the same N6 writer (§6), unless #1762 landed on main first. + - JSON writes floats with `.0`; #1762's writers (`store_json_encode`, + `db_build_query`) go through the same N6 writer, unless #1762 landed on + main first. - `src/freestanding/mini_fmt.c` and `mini_strtod.c` follow, gated by `make freestanding-libc-diff`. - This is the largest visible change: every golden that prints an integral float. -8. **R1.8, the embed API (Q3, decided), lint/LSP type knowledge and docs.** +8. **R1.8, the embed API (Q3), lint/LSP type knowledge and docs.** `eigs_value_as_num` converts an int (like `lua_tonumber`); `eigs_value_new_int`, `eigs_value_as_int` (with a success flag, like `lua_tointegerx`) and `eigs_value_is_int` are added; `EIGS_TYPE_NUM` - covers both kinds. Docs: SPEC, COMPARISON, README, llms.txt executed - fences. The CLAUDE.md same-PR docs rule applies to the integration PR as - a whole. + covers both kinds. Gate: `gate.N7.embed-int` (the embed smoke test), the + executed doc fences (suite [89]/[90]) and the LSP and lint suite sections. + Docs: SPEC, COMPARISON, README, llms.txt; the CLAUDE.md same-PR docs rule + applies to the integration PR as a whole. ### Round 2: IEEE (N11-N14 remainder), on the experiment's evidence 1. **R2.1, canonical NaN at the single double writer** (`slot_from_f64`) **and the JIT NaN bails** (§4.3), while `num_guard` still keeps NaN out: - memory safety first. - - Test: the C slot test writes every tag-spelling NaN payload. The - #1746 plant (a raw store) segfaults in `slot_incref`. + memory safety first. A mechanical round (no program can make a NaN yet): + the C slot test writes every tag-spelling NaN payload, and the #1746 + plant (a raw store) segfaults in `slot_incref`. 2. **R2.2, retire `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` and the - 1e308 clamp** (74 sites, the leaf's included). `EIGS_STRICT` becomes an - opt-in trap - (state.c:62). `sqrt of -1` is NaN, `log of 0` is -inf, `x/0` is ±inf, - `0/0` and float `x%0` are NaN. The consumers no token marks (§2.7): - `values_equal_impl`'s identity shortcut excludes floats; NaN order in - sort follows §11 Q8 once decided. + 1e308 clamp** (74 sites, the leaf's included; 47 first forced here). + `EIGS_STRICT` becomes an opt-in trap (state.c:62). `sqrt of -1` is NaN, + `log of 0` is -inf, `x/0` is ±inf, `0/0` and float `x%0` are NaN. Q8: + `sort`/`sort_by` order floats by IEEE `totalOrder` (NaN after +inf), and + `min`/`max` propagate NaN. `values_equal_impl`'s identity shortcut + excludes floats. 3. **R2.3, N13 refusal inside the writers:** the JSON encoder, the store encoder (delete the pre-walk `store_nonfinite_scalar`), the byte encoders and the int conversion. This removes the class #1746 chased for @@ -1632,9 +1838,10 @@ meaning change lands in the commit that carries its token change (§2.7). 5. **R2.5, tape v7 `inf`/`-inf`/`nan` tokens; N6 non-finite printing; N14 `1e400` raises.** 6. **R2.6, the #1746 residue:** - - the gfx/net/model `fix_trunc` sites; + - the internal `(int)` casts the Q7 readers do not cover (the audio + generators' `dur * rate`, the model builtins); - `net_send` continuing after a raise (ext_net.c:364); - - `buf_to_pcm16le` NaN; + - `buf_to_pcm16le` with a NaN sample; - the `numerical_grad` waiver. ### Risks across both rounds @@ -1652,7 +1859,8 @@ meaning change lands in the commit that carries its token change (§2.7). - Consumers. N6 printing moves goldens in all 16; N4 changes `%` on negatives; (A) raises where doubles lost precision silently; Q1 raises on a non-integral count, handle or byte, and on a byte outside 0..255 that - used to wrap. The DMG emulator feeds `ppu_render_frame` its memory buffer + used to wrap; Q7 raises on a duration or window size the C call cannot + honour. The DMG emulator feeds `ppu_render_frame` its memory buffer through `buffer_read_byte`; the consumer acceptance run (Done-when) shows whether any program stored a non-byte there. - Observer. Until round 3, ints are observed as their double value (the @@ -1695,8 +1903,18 @@ now has one of four shapes: times: the leaf evaluator's shape (§4.5). - `F`: a multi-statement function called at least 60 times, above the default entry threshold of 50 (jit.c:2478): the function JIT's shape. -- `O`: a loop, in a function or at module level, run in the `osr` tier - (`EIGS_JIT_OSR_THRESHOLD=1`): the OSR shape. + `EIGS_JIT_HOT` records a chunk's LAST run, so the witnessed call must be + the function's last call (round 2's two truthiness controls ended on a + float call and could not hold; both are reordered). +- `O`: a `loop while true:` loop, in a function or at module level, run in + the `osr` tier (`EIGS_JIT_OSR_THRESHOLD=1`), **whose only exit is a + `return` placed right after the claimed ops** (`if : return `; at + module level, `print of ` first). The OSR thunk's record holds only its + last entry, and with a `loop while :` header that entry is always the + final condition check, which exits through the header whether or not the + body ever ran natively. With the return inside the body, the only way the + last entry ends at the return sentinel is to run the whole body natively + first. The `L`, `F` and `O` rows (35 in the MAP) cover every JIT-emitter and leaf arm that holds a numeric site (the inventory's `## Numeric arms`, 20 today; @@ -1719,8 +1937,8 @@ witness may name several helpers, each of which must hold), followed by | `leaf-gen ` | the normal run and the `trace` run both show the same K >= 1 entries: every call took the generic path (the scanner refused the chunk, or the leaf bailed) | | `fn ` | in the default and `osr` tiers, ``'s row has `jit yes` and `adv RET`: its last call ran natively to its return | | `fn-stop ` | `jit yes`, and the opcode at offset `adv` of ``'s bytecode (`EIGS_DUMP_BC=1`) is ``: the thunk handed back at ``, by a compile stop or a guard bail | -| `osr ` | in the `osr` tier, ``'s row has `osr yes`, and `oent + oadv` lies past the loop's `JUMP_BACK`: the thunk ran the loop to its exit | -| `osr-stop ` | `osr yes`, and the opcode at `oent + oadv` is `` | +| `osr ` | in the `osr` tier, ``'s row has `osr yes` and `oadv == len`: the OSR thunk's last entry reached the return sentinel (jit_advance -1, which `EIGS_JIT_HOT` prints as the chunk length, jit.c:244), so it ran the whole body natively on the way. Round 2's form (`oent + oadv` past `JUMP_BACK`) is withdrawn: the critic's plant ran native `INDEX_SET` 0 times and still passed it | +| `osr-stop ` | `osr yes`, `oadv != len`, and the opcode at `oent + oadv` is ``: every entry handed back at `` | Why `EIGS_JIT_HOT` and not only `EIGS_JIT_STATS`/`EIGS_JIT_STOPS`: `STATS` counts are process-wide (`scanned`, `compiled`), and `STOPS` records @@ -1731,22 +1949,26 @@ operation natively. `HOT` records, per chunk, the last run's native advance must show `compiled >= 1` for an `fn`/`osr` claim, and for a `-stop` claim whose stop is a compile stop, `STOPS` must name ``. The leaf has no counter; its witness is the entry count, because both generic call paths -count an entry (vm.c:2617, vm.c:4353) and the leaf path never does. The -witness uses only existing diagnostics: nothing in production changes so a -test can observe it. - -**Calibrated on the main binary this round** (each predicate holds where it -should and fails where it should not): -- `leaf sq`: `sq` called 200 times has no `HOT` row in the `off`, default and - `osr` tiers; with `EIGS_TRACE` set it shows `sq 200 yes ... RET`. The same - predicate is false for the leaf-off run. -- `fn g`: `g` called 60 times shows `g 60 yes ... RET ... RETURN`. -- `fn-stop h ADD`: `h` called 55 times with numbers and then once with a - string operand (the program raises there) shows `h 56 yes ... 30`; offset - 30 of `h` is `ADD`: the thunk's guard bailed there and the interpreter - raised. -- `osr f`: `f`'s loop under `EIGS_JIT_OSR_THRESHOLD=1` shows `osr yes`, - `oent 31`, `oadv 57`: 31 + 57 = 88, past `JUMP_BACK` at 85. +count an entry (vm.c:2617, vm.c:4353) and the leaf path never does. + +**Calibrated on the main binary: every kind holds on its honest row and is +VACUOUS on a plant where the claimed op did not run as claimed** (design +round 3; a scratch model of the predicates read `EIGS_JIT_HOT` and +`EIGS_DUMP_BC`; the `osr` pair also counted native `jit_helper_index_set` +calls under gdb, with the critic's `gdbcount.gdb`): + +| kind | honest row (main) | evidence | plant | evidence | +|---|---|---|---|---| +| `leaf sq` | `define sq(x) as: return x * x`, one call with 1.5 | `sq normal=0 trace=1`: HOLDS | the body split into two statements (not leaf-eligible) | `sq normal=1 trace=1`: VACUOUS | +| `leaf-gen nth` | `define nth(xs, i) as: return xs[i]`, called on a string (the leaf's `INDEX_GET` bails) | `nth normal=1 trace=1`: HOLDS | called on a list (the leaf computes it) | `nth normal=0 trace=1`: VACUOUS | +| `fn keep` | `t is q / return t`, 60 calls with 2.5 | `keep jit=yes adv=RET`: HOLDS | `zz is [q]` first (the scanner stops at `LIST`) | `keep jit=no stop=LIST`: VACUOUS | +| `fn-stop cat ADD` | `t is a + b / return t`, 60 calls with two strings (the `ADD` guard bails) | `cat jit=yes adv=11`, offset 11 is `ADD`: HOLDS | 60 calls with two floats | `adv=RET`: VACUOUS | +| `osr fill` | the critic's `osr_ret`: `loop while true: (xs[i] is big / i is i + 1.0 / if i >= n: return xs)` | `osr=yes oadv=123 len=123 oent=37`; 3 native `INDEX_SET` helper calls: HOLDS | the critic's `osr_ret_PLANT2`: `s is s + "a"` first in the body | `oadv=20 len=157`; 0 native calls: VACUOUS | +| `osr fill`, round 2's shape | `loop while i < n:` (the critic's `osr_index_set`) | 3 native calls, but no sentinel: VACUOUS under the new rule | `zz is [i]` first (`osr_index_set_PLANT`) | 0 native calls; `oent + oadv` = 109, past `JUMP_BACK` at 106: the round-2 rule PASSED it; the new rule is VACUOUS | +| `osr-stop g ADD` | `loop while true: (s is s + "a" / i is i + 1.0 / if i >= n: return s)` | `oent=33 oadv=20`, offset 53 is `ADD`: HOLDS | `s` a float (`s is s + 1.5`) | `oadv=122=len` (the sentinel): VACUOUS | + +The witness uses only existing diagnostics: nothing in production changes so +a test can observe it. **What the witnesses expect in round 1.** The JIT and the leaf bail on an int that meets an arithmetic, comparison, bitwise or index op, and refuse an @@ -1755,14 +1977,45 @@ int literal, until round 5 (§4), so such a row's honest witness is scanner refused) and the interpreter produced the row's output. An int that only moves, into a local, a field, a list element or a module binding, passes through the JIT's C helpers and the leaf's borrows, so those rows -(`N1.fn-int-local`, `N1.fn-dot-fields`, `N1.osr-module-int-store`, +(`N1.fn-int-local`, `N1.fn-dot-fields`, `N1.osr-global-int-store`, `N5.osr-index-set`, `N1.leaf-dot-get`) have native witnesses already in round 1. A float row's witness is native too: it proves the float meaning of `NUM_ZERO`/`NUM_ONE`/`CONST` survived in the JIT and the leaf. Round 5 flips the int witnesses to native, one row at a time, and each flip is a deliberate edit of the row. -### 9.2 `tools/phase2_check.sh ` (R1.1 builds it) +### 9.2 `tools/phase2_check.sh [--through ] ` (R1.1 builds it) + +**The landed-round filter.** Each MAP row names the commit that makes it +pass (`[R1.3]`; a row needing two commits names both, `[R2.1/R2.4]`, and +lands with the later). `--through Rk` selects the rows that have landed by +Rk, in the order R1.1 < R1.2 < ... < R1.8 < R2.1 < ... < R2.6 < R3; controls +run in every mode; the default is the whole plan. A round is checked against +exactly its landed rows, so R1.3's check cannot fail on an R1.7 row, and the +final check runs all of them. Each round has a non-zero set of its own rows, +or a mechanical guarantee stated here, which `--through` runs instead of +failing on zero rows: + +| round | its own MAP rows | its gates, or the mechanical guarantee | +|---|---:|---| +| R1.1 | 0 | mechanical: the compile errors (223 sites), the C slot test (§2.5; `examined` equals the derived classifier count), plant 1, the int-source check, and the differential over the suite's `.eigs` corpus | +| R1.2 | 0 | mechanical: the compile errors (464 sites), the int-source check, and the differential over the suite's `.eigs` corpus (behaviour-preserving) | +| R1.3 | 43 | | +| R1.4 | 6 | | +| R1.5 | 7 | | +| R1.6 | 18 | `gate.N5.q7-readers`, and the per-builtin behaviour table (§9.4) | +| R1.7 | 12 | `gate.N14.db-param-exact` | +| R1.8 | 0 | `gate.N7.embed-int` (the embed smoke test), the executed doc fences (suite [89]/[90]), the LSP and lint suite sections | +| R2.1 | 0 | mechanical: the C slot test's NaN-payload rows and plant 2 (no program can make a NaN before R2.2) | +| R2.2 | 9 | | +| R2.3 | 3 | | +| R2.4 | 6 | | +| R2.5 | 6 | | +| R2.6 | 1 | | +| R3 | 5 | `gate.O1.oracle-floor`, `gate.O2.predicate-floors` | + +(The counts are the MAP's at this commit; `phase2_check.sh` derives them, and +fails if a round named here has neither rows nor its mechanical gates.) - **Rows** live in `tests/phase2/rows/.eigs`. Each has a header `# ROW: `, `# ITEMS: N1 N2`, `# EXPECT-RC: `, `# SHAPE: S|L|F|O`, @@ -1780,7 +2033,8 @@ deliberate edit of the row. arms today, each with its opcode chain; an arm is covered when some row's `ops:` names an opcode of its chain that the row runs natively or stops exactly at; the MAP's shaped rows cover all 20); - - zero rows is a FAIL. + - zero rows is a FAIL, except a mechanical round under `--through` + (the table above), which runs its named gates instead. - **Tiers:** - `off` = `EIGS_JIT_OFF=1`; - `default`; @@ -1809,7 +2063,8 @@ deliberate edit of the row. branch_pass=N vacuous=0 tag_timeout=K tag_signal=K`, then `controls=M both_pass=M`, `witnessed=W` (the rows whose witness held), and an environment banner (both binaries' `--version` and sha256). -- **Exit 0** iff in every tier examined == tag_fail == branch_pass > 0, +- **Exit 0** iff in every tier examined == tag_fail == branch_pass > 0 + (or, for a mechanical round under `--through`, its named gates pass), vacuous == 0, the controls all pass on both, and the population checks pass. - **Calibration** (one-time, in the commit that adds it): @@ -1824,7 +2079,18 @@ deliberate edit of the row. (the JIT never compiled it); - an `L` row run against a scratch build whose leaf `MUL` arm computes `a * b + 1`: the `trace` tier differs from the others, exit 1, naming - the row. + the row; + - **one negative plant per witness kind, each a row where the claimed op + did not run as claimed** (the rows of §9.1's calibration table, which + this design ran on main): `leaf` (the helper split into two statements), + `leaf-gen` (the helper computed by the leaf), `fn` (an unsupported op + before the claimed one), `fn-stop` (the claimed op runs natively), `osr` + (the critic's `osr_ret_PLANT2`: a string concat ahead of the claimed op, + 0 native `INDEX_SET` calls), `osr-stop` (the claimed op runs natively to + the sentinel). Each must give `vacuous=1`, exit 1, naming the row; + - `--through R1.2` on a tree with no R1.1/R1.2 rows: exit 0 by the + mechanical gates, `mapped=0`; and with the int-source check planted (a + production `slot_from_int(count)` call): exit 1. ### 9.3 `tools/phase2_plants.sh` (round 1 builds it; detached, about 7 release builds) @@ -1858,19 +2124,55 @@ The tier-witness and leaf-differential plants (§9.2's calibration) belong to `phase2_check.sh`'s own calibration, not to this list: they test the instrument, not the semantics. -### 9.4 The int-fuzz gate (round 1; the §6 table's enforcement) - -It follows `tests/test_bool_fuzz.sh` (which feeds bools to every builtin -`--api --json` lists): -- every numeric builtin of §6 is called with ints in each numeric slot; -- **int-preserving:** the result's `num_type` is "int" for int inputs; -- **int-requiring:** a float with a fraction raises `value` (N5), and an - integral float converts; -- **float-producing:** the result is a float; -- the population is derived from `--api --json` intersected with the table, - and the gate prints `examined=N` equal to the table's row count. - -It catches a mis-migrated accessor (R1.2) that compiles. +### 9.4 The per-builtin behaviour table (R1.6's gate; replaces the int-fuzz class check) + +Round 2 planned an int-fuzz gate asserting "the result is an int for int +inputs". The critic showed what it cannot see: builtins whose int result +comes from a non-numeric input (`len`, `ord`, `index_of`, `buf_len`, +`scan_ints`, `read_bytes`: fed an int they raise `type_mismatch` on both +binaries), and builtins that need a valid argument to run at all +(`shared_size` raises `value` on a bare int). R1.6 changes about 114 rows, so +its gate must exercise every builtin with a VALID call. + +`tests/phase2/builtins.tsv` (written in R1.6, checked by +`tools/phase2_builtins.sh `): +- **One row per numeric builtin of §6, both directions** (the population is + the inventory file's `## Builtins` list, not a hand list): `builtin`, + `class` (must equal §6's), `probe` (a short program that calls it validly + and prints the result, plus `num_type of` it where the result is a + number), `branch` (the exact expected stdout and rc), `tag` (the tag's + observed stdout and rc), `changes` (`yes`/`no`). +- **Checks:** + 1. the row set equals §6's numeric builtins, both directions; zero rows + is a FAIL; + 2. `class` equals §6's class, and the row's `branch` output is consistent + with it: an `int-preserving` row prints `"int"` for its result's + `num_type`; a `float-producing` row prints `"float"`; an + `int-requiring` row's probe passes a fractional value in an + integer-valued parameter and expects `value` (and a second line with + an integral float that converts); a Q7 row's probe exercises one + out-of-range value of each class it names (a clipped shape draws + nothing, a bounded value clamps, a magnitude raises); + 3. the branch's actual output equals `branch`, and the tag's equals + `tag`; + 4. `changes` is `yes` exactly when `branch` and `tag` differ, and every + `LOSS`, `int-requiring` and Q7 row has `changes: yes`: a probe that + does not show the tag/branch difference for a builtin §6 says changes + is VACUOUS. +- **What it sees that the fuzz could not:** `len of [1, 2]` must print + `[2, "int"]`; `ord of "A"` `[65, "int"]`; `shared_size` is probed with a + valid shared value; every `int-requiring` row raises on 1.5; `gather` and + `scatter_add` raise on an index of 1.5; `buf_from_pcm16le` raises on a + byte of 300 and of 1.5. +- **Calibration plants** (one-time, in the commit that adds it): `len` + reverted to `make_float`: its row red; an `int-requiring` builtin reverted + to truncation: red; a row deleted, and a stale row added: membership red + both ways; a class edited: red; a `LOSS` row whose probe stays below 2^53: + VACUOUS. + +The int-fuzz sweep, if kept, shrinks to what the table does not do: a +crash-only sweep (every builtin fed ints in every numeric slot must raise +or return, never crash), in the shape of `tests/test_bool_fuzz.sh`. --- @@ -1931,7 +2233,7 @@ disagree=0`. It exits 1 on any unexplained disagreement or on examined=0. --- -## 11. Decided questions (Q1-Q6) and what stays open +## 11. Decided questions (Q1-Q8) Q1-Q6 were open in round 0. They were decided on 2026-10-14 by the standard answer, each verified by probe, in @@ -1948,8 +2250,8 @@ The owner may overrule any of them; until then this design follows them. conversion rounds to nearest, replacing truncation toward zero (SDL3's float coordinates, LÖVE's numeric drawing API). - Applied: §6's rows (16 moved from other to int-requiring; byte - consumers no longer wrap), `eigs_byte_arg`, `eigs_int_arg_range` and - `eigs_round_arg` (§2.6), R1.6 (§8). + consumers no longer wrap), `eigs_byte_arg`, `eigs_int_arg_range`, and + the Q7 readers (§2.6), R1.6 (§8). - **Q2, an int stored into float storage: DECIDED.** Convert with IEEE round-to-nearest, documented as the container's contract (Python `float(2**53+1)`, numpy, JS `Float64Array`). Applied: `buf_set`, @@ -1965,28 +2267,35 @@ The owner may overrule any of them; until then this design follows them. - **Q4, `round`: DECIDED.** Keep half away from zero (C and Rust `round`); the result is an int when it fits int64 and a float otherwise, like Lua's `math.floor`/`math.ceil` (`math.floor(1e300)` stays `1e+300`). Applied: - §6 (`round` int-preserving, LOSS), R1.6; `eigs_round_arg` uses the same + §6 (`round` int-preserving, LOSS), R1.6; the Q7 readers use the same tie rule. - **Q5, `why is x` for an int binding: DECIDED.** An int when Δv fits in int64, otherwise a float. A readout never raises; (A) applies to operators, not to observer readouts. Applied: round 3 (O4). - **Q6, `//=`: DECIDED.** Add it beside `/=`. Applied: R1.4. -**Open, new in design round 2.** Round 1 must not pick these silently; each -needs the standard answer cited or an owner decision. -- **Q7. A finite continuous parameter outside the C type's range** - (`gfx_rect of [3e9, 0, 10, 10, ...]`). Q1 decides rounding to nearest, - and N13 already decides that a non-finite one is refused (it is an int - conversion). The finite out-of-range case is open; today the C cast is - undefined behaviour. Options: saturate to the C range (it draws - off-screen, as a huge float coordinate does in SDL3), or raise `value`. - This design does not pick: R1.2's gfx group re-points the reads to - `eigs_float_arg` with today's truncation (behaviour unchanged, like every - R1.2 commit), and the part of R1.6 that installs `eigs_round_arg` waits - for the decision. Nothing else in round 1 depends on it. -- **Q8. NaN in an ordering.** From R2.2 a NaN can reach `sort`, `sort_by`, - `min` and `max`. NaN has no order: C's `qsort` with an inconsistent - comparator gives an unspecified order, Python's `sorted` too, and Lua's - `table.sort` may raise "invalid order function". Options: raise `value` - when a NaN is compared for order, or define a total order (NaN last, as - IEEE `totalOrder` and numpy's `sort` do). +- **Q7, a finite continuous parameter outside the C range: DECIDED** + ([#1758 comment 6174302316](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6174302316)). + It follows the quantity it represents: + - geometry (coordinates and sizes): clip in float space against the + drawable area, then round to nearest. Saturating each argument + separately is wrong: `gfx_rect of [-3e9, 0, 6e9, 10]` would cover half + the screen instead of all of it; + - bounded quantities (colour channels, gain, volume): clamp to the domain; + - unbounded magnitudes the C call cannot honour (durations, sleeps): raise + `value`, naming the builtin (Python's `time.sleep(3e12)` raises + `OverflowError`). + - Applied: the builtin table's validated `q7` column (§6); the readers + `eigs_geom_shape`, `eigs_bounded_arg`, `eigs_magnitude_arg` (§2.6), + landing in R1.6. Two classifications this design made inside the + decided categories: a window size (`gfx_open`) and a measurement's + scale (`gfx_text_width`/`height`) have no drawable area to clip against, + so they are magnitudes. +- **Q8, NaN in an ordering: DECIDED** (same comment). IEEE 754-2019 + `totalOrder`: the canonical (positive, quiet) NaN sorts after +inf, + deterministically, in `sort` and `sort_by` (numpy's `sort` and Rust's + `f64::total_cmp` give the same order); `min` and `max` propagate NaN + (IEEE 754-2019 `minimum`/`maximum`). Lua and Python produce a garbage + order here (probed for #1758: Lua's `table.sort` left a list holding NaNs + unsorted without an error). Applied: R2.2, when NaN first becomes + reachable; rows `N11.sort-total-order` and `N11.min-max-nan`. diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index c1e9fc523..33b51130d 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -18,6 +18,10 @@ design doc) runs every row: Every mapped row must FAIL on the tag and PASS on the branch in every tier, and its witness must hold on the branch (design §9.1), or it is VACUOUS. +`phase2_check.sh --through ` checks only the rows whose `[Rn]` has +landed by that commit (a row tagged `[Ra/Rb]` lands with the later); R1.1, +R1.2 and R2.1 have no rows of their own and are checked by their mechanical +gates (design §9.2). ## Format (machine-read by `phase2_check.sh`) @@ -57,15 +61,20 @@ and its witness must hold on the branch (design §9.1), or it is VACUOUS. The other shapes carry a fourth line, `shape: witness: ... [] ops: ...`: - `L`: a one-line helper (the leaf evaluator); `F`: a multi-statement - function called at least 60 times (the function JIT); `O`: a loop, in a - function or at module level, witnessed in the `osr` tier (OSR). + function called at least 60 times (the function JIT), whose witnessed + call is its LAST call (`EIGS_JIT_HOT` records the last run); `O`: a + `loop while true:` loop, in a function or at module level, witnessed in + the `osr` tier, whose only exit is a `return` right after the claimed ops + (at module level, `print of ` first). - witness kinds (design §9.1): `leaf ` (no `EIGS_JIT_HOT` entries for `` in the normal run, K >= 1 in the `trace` run), `leaf-gen ` (the same K >= 1 entries in both: every call took the generic path), `fn ` (`jit yes`, `adv RET`), `fn-stop ` (`jit yes`, the - op at `adv` is ``), `osr ` (`osr yes`, `oent + oadv` past the - loop's `JUMP_BACK`), `osr-stop ` (the op at `oent + oadv` is - ``). + op at `adv` is ``), `osr ` (`osr yes` and `oadv == len`: the + last OSR entry reached the return sentinel, so it ran the body natively), + `osr-stop ` (`oadv != len`, and the op at `oent + oadv` is + ``). Each kind was calibrated on main against a plant where the + claimed op did not run as claimed (design §9.1). - `leaf` and `leaf-gen` may name several helpers; each must hold. - `ops:` lists the opcodes whose JIT or leaf arm the row exercises: run natively, or stopped at exactly (a `-stop` witness's ``, which proves @@ -127,24 +136,24 @@ and its witness must hold on the branch (design §9.1), or it is VACUOUS. -> `9007199254740993` (the field store and load take their C helpers for a non-double and the thunk runs on) tag: `9007199254740992` (probed main) shape: F witness: fn setx (witness probed main, with a double: `setx 60 yes ... RET`) ops: LOCAL_DOT_SET LOCAL_DOT_GET -- `ctl.N1.fn-int-truthiness` (control) `define truth(a) as: if a: return 1 / return 2`, called 60 times with `0`; `print of [truth of 0, truth of 5, truth of 0.0]` +- `ctl.N1.fn-int-truthiness` (control) `define truth(a) as: if a: return 1 / return 2`, called 60 times with `0`; `print of [truth of 0.0, truth of 5, truth of 0]` (the int call is LAST, so `EIGS_JIT_HOT` records it) -> `[2, 1, 2]` on both (0 and 0.0 are falsy) - shape: F witness: fn-stop truth JUMP_IF_FALSE (an SMI condition fails the bool and number checks; on main a double 0.0 instead leaves at the jump target, 21) ops: JUMP_IF_FALSE -- `ctl.N1.fn-int-not` (control) `define neg(a) as: r is not a / return r`, called 60 times with `0`; `print of [neg of 0, neg of 5, neg of 0.0]` + shape: F witness: fn-stop truth JUMP_IF_FALSE (an SMI condition fails the bool and number checks) ops: JUMP_IF_FALSE +- `ctl.N1.fn-int-not` (control) `define neg(a) as: r is not a / return r`, called 60 times with `0`; `print of [neg of 0.0, neg of 5, neg of 0]` (the int call is LAST) -> `[true, false, true]` on both shape: F witness: fn-stop neg NOT (an SMI fails NOT's number check) ops: NOT - `N1.fn-int-local` [R1.3] `define keep(q) as: t is q / return t`, called 60 times with `9007199254740993`; print the last result -> `9007199254740993` (an int stored into a local takes `SET_LOCAL`'s generic swap and the thunk runs on) tag: `9007199254740992` (probed main) shape: F witness: fn keep (witness probed main, with a double: `keep 60 yes ... RET`) ops: SET_LOCAL POP -- `N1.osr-module-int-store` [R1.3] module-level `big is 9007199254740993 / x is 0 / i is 0.0 / loop while i < 100.0: (x is big / i is i + 1.0) / print of x` +- `N1.osr-global-int-store` [R1.3] `x is 0 / define put(big, n) as: i is 0.0 / loop while true: (x is big / i is i + 1.0 / if i >= n: return x)`; `print of (put of [9007199254740993, 4.0])` (`x is big` inside `put` writes the module binding: `SET_NAME`) -> `9007199254740993` tag: `9007199254740992` (probed main) - shape: O witness: osr (witness probed main: `osr yes`, `oent 55`, `oadv 59`, 114 past `JUMP_BACK` at 111) ops: SET_NAME LT ADD -- `N1.osr-int-counter` [R1.3] `define count(n) as: i is 9007199254740990 / k is 0 / loop while k < n: (i is i + 1 / k is k + 1) / return i`; `print of (count of 10)` + shape: O witness: osr put (the boxed int moves through `SET_NAME` without a guard; witness probed main with a double: `oadv 106` = `len 106`) ops: SET_NAME NUM_ONE ADD GE JUMP_IF_FALSE +- `N1.osr-int-counter` [R1.3] `define count(n) as: i is 9007199254740990 / k is 0.0 / loop while true: (i is i + 1 / k is k + 1.0 / if k >= n: return i)`; `print of (count of 10.0)` -> `9007199254741000` tag: `9007199254740992`: the double counter stalls at 2^53 (probed main) - shape: O witness: osr-stop count LT (the SMI `k` fails LT's operand guard) ops: LT + shape: O witness: osr-stop count INT_ONE (the OSR scanner stops at the literal `1`, the body's first int op) ops: INT_ONE ### N2 - `N2.int-eq-float-kinds` [R1.3] `print of [1 == 1.0, 1 != 1.0, num_type of 1, num_type of 1.0]` @@ -200,17 +209,17 @@ and its witness must hold on the branch (design §9.1), or it is VACUOUS. -> `9007199515875289` tag: `9007199515875288` (probed main) shape: F witness: fn-stop f MUL ops: MUL -- `N3.osr-sum-exact` [R1.3] `define total(n) as: acc is 9007199254740000 / i is 0 / loop while i < n: (acc is acc + 1 / i is i + 1) / return acc`; `print of (total of 1000)` +- `N3.osr-sum-exact` [R1.3] `define total(n, step) as: acc is 9007199254740000 / i is 0.0 / loop while true: (acc is acc + step / i is i + 1.0 / if i >= n: return acc)`; `print of (total of [1000.0, 1])` -> `9007199254741000` tag: `9007199254740992`: the double sum stalls at 2^53 (probed main) - shape: O witness: osr-stop total LT ops: LT -- `N3.osr-module-sum` [R1.3] module-level `acc is 9007199254740000 / i is 0 / loop while i < 1000: (acc is acc + 1 / i is i + 1) / print of acc` + shape: O witness: osr-stop total ADD (a boxed int and an SMI fail ADD's operand guard) ops: ADD +- `N3.osr-module-sum` [R1.3] module-level `acc is 9007199254740000 / step is 1 / i is 0.0 / loop while true: (acc is acc + step / i is i + 1.0 / if i >= 1000.0: (print of acc / return acc))` -> `9007199254741000` tag: `9007199254740992` (probed main) - shape: O witness: osr-stop INT_CONST (the OSR scanner stops at the literal `1000`) ops: INT_CONST -- `ctl.N3.osr-float` (control) `define totalf(n) as: acc is 0.5 / i is 0.0 / loop while i < n: (acc is acc + 1.5 / i is i + 1.0) / return acc`; `print of (totalf of 100.0)` + shape: O witness: osr-stop ADD (module-level OSR; a boxed int fails ADD's operand guard) ops: ADD +- `ctl.N3.osr-float` (control) `define totalf(n) as: acc is 0.5 / i is 0.0 / loop while true: (acc is acc + 1.5 / i is i + 1.0 / if i >= n: return acc)`; `print of (totalf of 100.0)` -> `150.5` on both - shape: O witness: osr totalf (witness probed main: `osr yes`, `oent 33`, `oadv 57`; 90 is past `JUMP_BACK` at 87) ops: LT ADD NUM_ONE CONST JUMP_IF_FALSE SET_LOCAL POP + shape: O witness: osr totalf (witness probed main: `osr yes`, `oadv 122` = `len 122`, the return sentinel) ops: ADD CONST NUM_ONE GE JUMP_IF_FALSE SET_LOCAL POP ### A - `A.add-overflow-raises` [R1.3] `{try print of (9223372036854775807 + 1) catch}`, printing `[e.kind, (index_of of [e.message, "+"]) >= 0]` @@ -236,10 +245,10 @@ and its witness must hold on the branch (design §9.1), or it is VACUOUS. -> `value` tag: `9.223372036854776e+18`, no raise (probed main) shape: F witness: fn-stop inc INT_ONE ops: INT_ONE -- `A.osr-double-overflow` [R1.3] `define dbl(n) as: x is 1 / i is 0 / loop while i < n: (x is x * 2 / i is i + 1) / return x`; `{try print of (dbl of 63) catch}`, printing `e.kind` +- `A.osr-double-overflow` [R1.3] `define dbl(n, two) as: x is two / i is 1.0 / loop while true: (x is x * two / i is i + 1.0 / if i >= n: return x)`; `{try print of (dbl of [63.0, 2]) catch}`, printing `e.kind` -> `value` (2^63 overflows on the 63rd doubling) tag: `9.223372036854776e+18`, no raise (probed main) - shape: O witness: osr-stop dbl LT ops: LT + shape: O witness: osr-stop dbl MUL (two SMIs fail MUL's operand guard) ops: MUL ### B - `B.type-of-both-num` [R1.3] `print of [type of 3, type of 3.0, (type of 3) == (type of 3.0), num_type of 3]` @@ -315,6 +324,15 @@ and its witness must hold on the branch (design §9.1), or it is VACUOUS. - `N5.range-fraction-raises` [R1.6] `{try print of (range of 2.5) catch}`, printing `e.kind` -> `value` tag: no raise (read: `range_bound` accepts any double inside the int range) +- `N5.gather-index-fraction-raises` [R1.6] `t is buffer of [2, 3]` filled 10, 11, 12, 20, 21, 22 / `ib is buffer of 2 / ib[0] is 1.5 / ib[1] is 2.0 / {try g is gather of [t, ib] / print of [g[0], g[1]] catch}`, printing `e.kind` + -> `value` (an index is integer-valued: N5) + tag: `[11, 22]`: `flat_index_at` truncates 1.5 to 1 (probed main; the critic's `gather.eigs`) +- `N5.pcm16-byte-raises` [R1.6] `b is buffer of 2 / b[0] is 300 / b[1] is 0 / {try buf_from_pcm16le of [b, 0, 1] catch}` printing `e.kind`, then the same with `b[0] is 1.5` + -> `value` twice (byte values: N5, then 0..255; #1758 comment 6174964306) + tag: no raise, samples `0.009155552842799158` and `4.577776421399579e-05` (probed main) +- `gate.N5.q7-readers` [R1.6] `tests/phase2/q7_readers.c` (through the amalgamation, no SDL): `eigs_geom_shape` clips `RECT [-3e9, 0, 6e9, 10]` on a 640x480 drawable area to `[0, 0, 640, 10]` (saturating each argument would give half of that), clips a `LINE` with Liang-Barsky, bounds a `CIRCLE` of radius 3e9 to the visible rows; `eigs_bounded_arg` clamps 300 to 255; `eigs_magnitude_arg` raises `value` on 3e12 for a C `int` + -> every case as stated + tag: n/a (a C test of new readers), so it is a gate - `N5.leaf-buffer-index` [R1.7] `define bat(b, i) as: return b[i] / b is buffer of 3 / print of (bat of [b, 1])` -> `0.0` (a buffer element is an f64, Q2) tag: `0` (probed main) @@ -322,10 +340,10 @@ and its witness must hold on the branch (design §9.1), or it is VACUOUS. - `ctl.N5.leaf-float-index` (control) `define nth(xs, i) as: return xs[i] / print of (nth of [[10, 20, 30], 1.0])` -> `20` on both (an integral float index converts, N5) shape: L witness: leaf nth (witness probed main: no entries normally, 1 under trace) ops: INDEX_GET -- `N5.osr-index-set` [R1.3] `define fill(big, n) as: xs is [0, 0, 0, 0] / i is 0.0 / loop while i < n: (xs[i] is big / i is i + 1.0) / return xs`; `print of (fill of [9007199254740993, 4.0])` - -> `[9007199254740993, 9007199254740993, 9007199254740993, 9007199254740993]` (an integral float index converts, N5; the int value is stored exactly) +- `N5.osr-index-set` [R1.3] `define fill(big, n) as: xs is [0, 0, 0, 0] / i is 0.0 / loop while true: (xs[i] is big / i is i + 1.0 / if i >= n: return xs)`; `print of (fill of [9007199254740993, 4.0])` (the critic's `osr_ret`) + -> `[9007199254740993, 9007199254740993, 9007199254740993, 9007199254740993]` (an integral float index converts, N5; the int is stored exactly) tag: four times `9007199254740992` (probed main) - shape: O witness: osr fill (the float counter keeps the loop native; the boxed int value takes `INDEX_SET`'s C helper; witness probed main with a double: `osr yes`, `oent 37`, `oadv 54`, 91 past `JUMP_BACK` at 88) ops: INDEX_SET LT ADD + shape: O witness: osr fill (the float counter keeps the loop native; the boxed int takes `INDEX_SET`'s C helper; witness probed main: `oadv 123` = `len 123`, 3 native `jit_helper_index_set` calls under gdb) ops: INDEX_SET NUM_ONE ADD GE JUMP_IF_FALSE SET_LOCAL POP ### N6 - `N6.float-repr` [R1.7] `print of [3.0, 1e3, -0.0, 0.1 + 0.2, 1e15, 1e16, 1e-05, 0.0001]` @@ -356,6 +374,9 @@ and its witness must hold on the branch (design §9.1), or it is VACUOUS. - `N7.num-type-non-number` [R1.3] `print of [num_type of "3", num_type of null, num_type of true, num_type of [1]]` -> `[null, null, null, null]` (Lua `math.type` returns fail) tag: undefined +- `gate.N7.embed-int` [R1.8] `make embed-smoke` with new rows: `eigs_value_new_int` round-trips 9007199254740993 exactly; `eigs_value_as_int` succeeds on an int and on an integral float, and fails with its flag on 1.5; `eigs_value_is_int` tells the kinds apart; `eigs_value_as_num` converts an int (Q3); `EIGS_TYPE_NUM` answers for both + -> every case as stated + tag: n/a (a C test of new embed functions), so it is a gate ### N8 - `N8.bitwise-results-int` [R1.5] `print of [6 & 3, 6 | 3, 6 ^ 3, ~0, num_type of (6 & 3)]` @@ -425,6 +446,12 @@ The builtin names are decided in round 1 (`` etc. below are placehold -> `inf` (an inf result is not a NaN, so the JIT keeps it native) tag: `1e+308`, the clamp (probed main) shape: F witness: fn big ops: MUL CONST +- `N11.min-max-nan` [R2.2] `x is (1e308 * 10) - (1e308 * 10) / a is min of [1, x] / b is min of [x, 1] / c is max of [x, 1] / print of [a == a, b == b, c == c]` + -> `[false, false, false]` (NaN propagates in either argument order: Q8, IEEE 754-2019 `minimum`/`maximum`) + tag: `[true, true, true]`: the clamp turns `x` into 0 (probed main) +- `N11.sort-total-order` [R2.5] `x is (1e308 * 10) - (1e308 * 10) / inf is 1e308 * 10 / print of (sort of [3, x, 1, inf, 2])` + -> `[1, 2, 3, inf, nan]` (Q8: IEEE `totalOrder`, NaN after +inf) + tag: `[0, 1, 2, 3, 1e+308]` (probed main) ### N12 - `N12.f64-bits` [R2.4] `print of [f64_bits of 1.0, f64_bits of -0.0, f64_from_bits of 4607182418800017408]` @@ -458,12 +485,15 @@ The builtin names are decided in round 1 (`` etc. below are placehold - `N13.int-conversion-refuses` [R2.3] `x is 1e308 * 10 / {try print of (substr of ["abc", x, 1]) catch}` -> `value` tag: no raise (read: `(int)` of a clamped 1e308) +- `N13.pcm16-refuses-nan` [R2.6] `b is buffer of 1 / b[0] is (1e308 * 10) - (1e308 * 10) / {try o is buf_to_pcm16le of [b, 0, 1] catch}`, printing `e.kind` + -> `value` (the quantizer refuses a NaN sample: the #1746 residue) + tag: no raise, bytes `0, 0` (probed main) ### N14 - `N14.encode-kinds` [R1.7] `print of (json_encode of [3, 3.0, 0.1, -0.0])` -> `[3,3.0,0.1,-0.0]` tag: `[3,3,0.1,0]` (probed main for the first three) -- `N14.decode-kinds` [R1.7] `v is json_decode of "[3, 3.0, 9223372036854775807, 18446744073709551615]" / print of [num_type of v[0], num_type of v[1], v[2], num_type of v[3]]` +- `N14.decode-kinds` [R1.6] `v is json_decode of "[3, 3.0, 9223372036854775807, 18446744073709551615]" / print of [num_type of v[0], num_type of v[1], v[2], num_type of v[3]]` -> `["int", "float", 9223372036854775807, "float"]` tag: `num_type` undefined - `N14.decode-overflow-raises` [R2.5] `{try print of (json_decode of "1e400") catch}` @@ -509,6 +539,9 @@ The `O cfg` record's v7 shape is pinned by `O3.ocfg-no-hlow` (its file lists - `O1.where-is-value` [R3] `x is 2.5 / print of (where is x)` -> `2.5` tag: `0.7219...`, an entropy (probed main: `where is x` after 1 and 4 gives `0.7219280948873623`) +- `O1.int-observed-numeric` [R1.3] `a is 3 / b is 140737488355328 / af is 3.0 / bf is 140737488355328.0`, then 12 times `a is a * 2 / b is b * 2 / af is af * 2.0 / bf is bf * 2.0`; `print of [report of a, report of af, report of b, report of bf, num_type of b]` + -> `["diverging", "diverging", "diverging", "diverging", "int"]`: an SMI (`a`) and a boxed int (`b`, 2^47 and up) are observed exactly as their float twins (the numeric channel, as a double until round 3) + tag: `num_type` undefined (the reports alone are all `"diverging"` on main, where every number is a double) ### O2 - `gate.O2.predicate-floors` [R3] the post-#1754 corpus with per-predicate TP/TN floors (`floor.json`, the corpus sha256 recorded) diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index 5454f6f54..7ef6cf470 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -645,9 +645,12 @@ def read_marked_table(doc, tag, row_re): SLOT_ROW = re.compile(r'^\|\s*`([^`]+)`\s*\|\s*([a-z-]+)\s*\|') -TABLE_ROW = re.compile(r'^\|\s*`([A-Za-z_]\w*)`\s*\|\s*([a-z-]+)\s*\|\s*(\S+)\s*\|') +TABLE_ROW = re.compile(r'^\|\s*`([A-Za-z_]\w*)`\s*\|\s*([a-z-]+)\s*\|\s*(\S+)\s*\|\s*(\S+)\s*\|(.*)\|\s*$') CLASSES = {'int-preserving', 'float-producing', 'int-requiring', 'other'} LOSS_MARKS = {'LOSS', '-'} +# Q7 (decided, #1758 comment 6174302316): the class of each continuous +# parameter. A row names the classes it has, in this order, or `-`. +Q7_CLASSES = ['geometry', 'bounded', 'magnitude'] # A LOSS row claims the body computes through a double; it must have one. DOUBLE_PATH = {'eigs_num_arg', 'eigs_list_num', 'eigs_slot_num', 'eigs_opt_num', 'eigs_slot_opt_num', 'eigs_slot_elem_num', 'eigs_elem_num', 'buffer_read_num', 'make_num', 'slot_as_double', @@ -674,14 +677,22 @@ def read_table(doc): if line.strip() and not re.match(r'^\|\s*(builtin|-+)\s*\|', line.strip()): bad.append('%s:%d: unparsed table line: %s' % (doc, ln, line.strip()[:60])) continue - name, cls, loss = m.group(1), m.group(2), m.group(3) + name, cls, loss, q7, note = m.group(1), m.group(2), m.group(3), m.group(4), m.group(5) if cls not in CLASSES: bad.append('%s:%d: `%s` has unknown class %r' % (doc, ln, name, cls)) if loss not in LOSS_MARKS: bad.append('%s:%d: `%s` has unknown loss mark %r' % (doc, ln, name, loss)) + q7s = [] if q7 == '-' else q7.split(',') + if q7s != [c for c in Q7_CLASSES if c in q7s] or len(set(q7s)) != len(q7s): + bad.append('%s:%d: `%s` has a bad Q7 column %r (want `-` or an ordered subset of %s)' + % (doc, ln, name, q7, ','.join(Q7_CLASSES))) + # the column and the note make the same claim, both ways + if bool(q7s) != ('continuous' in note): + bad.append('%s:%d: `%s`: Q7 column %r disagrees with its note (a continuous ' + 'parameter must be named in both)' % (doc, ln, name, q7)) if name in rows: bad.append('%s:%d: `%s` has two rows' % (doc, ln, name)) - rows[name] = (cls, loss) + rows[name] = (cls, loss, q7) return rows, bad @@ -739,13 +750,16 @@ def main(): table, table_bad = read_table(args.doc) b_unclassified = sorted(n for n in nb if table is None or n not in table) b_stale = sorted(n for n in (table or {}) if n not in nb) - loss_rows = sorted(n for n, (c, l) in (table or {}).items() if l == 'LOSS') + loss_rows = sorted(n for n, (c, l, q) in (table or {}).items() if l == 'LOSS') for n in loss_rows: if n in nb and not (set(nb[n][1]) & DOUBLE_PATH): table_bad.append('`%s` is marked LOSS but its closure has no double-path token' % n) class_count = {} - for n, (c, l) in (table or {}).items(): + q7_count = {} + for n, (c, l, q) in (table or {}).items(): class_count[c] = class_count.get(c, 0) + 1 + for k in ([] if q == '-' else q.split(',')): + q7_count[k] = q7_count.get(k, 0) + 1 # executors: the leaf scanner and evaluator must name the same opcodes arms, chains = executor_arms(stripped_by_file, scope_by_file) @@ -843,10 +857,11 @@ def main(): len(regs), len(nb), len(nb) - len(b_unclassified), len(b_unclassified), len(b_stale))) out.append('classes: ' + ' '.join('%s=%d' % (c, class_count.get(c, 0)) for c in sorted(CLASSES))) out.append('LOSS (%d): %s' % (len(loss_rows), ' '.join(loss_rows))) + out.append('Q7: ' + ' '.join('%s=%d' % (c, q7_count.get(c, 0)) for c in Q7_CLASSES)) for name in sorted(nb): fn, toks = nb[name] - cls, loss = (table or {}).get(name, ('-', '-')) - out.append('%-28s %-34s %-16s %-5s %s' % (name, fn, cls, loss, ','.join(toks))) + cls, loss, q7 = (table or {}).get(name, ('-', '-', '-')) + out.append('%-28s %-34s %-16s %-5s %-24s %s' % (name, fn, cls, loss, q7, ','.join(toks))) out.append('') out.append('## Sites (file:line scope token kind category)') for (rel, ln, scope, tok, kind), cat in sorted(classified, key=lambda x: (x[0][0], x[0][1], x[0][3])): From ea83de5bfb493d30e058ee124a60236b06b6d0f8 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 17:55:02 -0500 Subject: [PATCH 004/188] phase2 R1.1: the slot layer -- the SMI tag, its readers, every slot classifier decided (#1758) Round R1.1 of docs/design/phase2-numbers.md section 8: the SMI exists as an encoding, every slot reader decided what an int does there, and nothing in the runtime produces an int yet, so no program behaves differently. - value_slot.h: TAG_SMI (0xFFFA) and the SMI range; slot_is_smi, slot_smi_val (bit-47 sign extension without a right shift), slot_from_int (an SMI in range; the VAL_INT box arm is unwired until R1.3), slot_f64_value (floats only; replaces vm.c's slot_as_double), slot_int_value. Tokens: slot_is_num -> slot_is_f64, SLOT_NUM_RAW -> SLOT_F64_RAW, slot_from_num -> slot_from_f64; slot_is_numeric and slot_as_double deleted. slot_as_double's 15 calls now read through slot_f64_value: the arithmetic, compare, negation and bitwise arms send an int to their slow path or type error (R1.3 gives them int semantics), and the leaf evaluator's INDEX_GET and ADD/SUB/MUL arms bail. - Refusals: eigs_slot_refuse (a broken caller contract) in eigs_slot_ref, obs_slot_observable, slot_type_name, slot_truthy, slot_to_value, vm_slot_lift, write_slot, and slot_as_ptr under ASan or -DEIGS_SLOT_CHECKED. The readers that turned an unknown tag into null or `` now refuse it. - eigs_int_unwired: the arms whose int answer needs the int Value kind or tape v7 (slot_to_value, the one SMI boxer; slot_type; slot_view; write_slot; slot_from_int's box arm). R1.3 deletes it, so each one stops compiling in the commit that makes ints reachable. - Final int arms where R1.1 can write them: truthiness (not 0), the type name "num", the bridge readers (an int converts to its double until R1.6), list_get_ref/dict_value_get_ref (NULL for a number), the observer's numeric channel (obs_slot_num: an int as its exact double until round 3), the store encoder and the SIGUSR1 dump (exact digits), dispatch keys and slice bounds (the int, range-checked into a C int); the four return-to-C conversions now share slot_bridge_unwrap's int arm. - tools/phase2_inventory.py: the renamed vocabulary; every D1, D2 and D3 slot classifier now needs a reviewed disposition row (98 in the design doc's table, with a fifth disposition, `unwired`); --slot-population prints the C slot test's population (33 entries). - tools/num_read_check.sh and its allowlist follow SLOT_F64_RAW. Gates (this commit): make -> 29 units, 0 compiler warnings; make jit-smoke -> "JIT smoke: all cases passed."; make embed-smoke -> "embed_smoke: OK"; tools/phase2_inventory.py -> "slot classifiers: D1=56 D2=19 D3=23 T=67 dispositions=98 missing=0 stale=0", "phase2-inventory: PASS"; tools/num_read_check.sh -> "num-read: PASS". Behaviour unchanged, measured on this source (the three R1.1 commits leave src/ as this one does): - the full release suite, env -u XAUTHORITY DISPLAY=:99 make test: "RESULTS: 4268/4268 passed, 0 failed, 9 skipped" (the skips: extensions not built, ASan-only checks, an archived bench asset, no ouroboros checkout beside the tree); - tools/phase2_corpus_diff.sh against main 0740af03, every .eigs under tests/: "corpus-diff: examined=441 same=433 same_under_replay=6 nondet=2 diff=0 new=14 deleted=0 crash_both=0 timeout_both=1" (new = the calibration fixtures; the timeout is _runaway_guard_selftest.eigs on both binaries). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-slot-layer.md | 2 + docs/design/phase2-inventory.txt | 1308 ++++++++++---------- docs/design/phase2-numbers.md | 133 +- src/builtins_tensor.c | 2 +- src/container.h | 87 +- src/eigenscript.c | 49 +- src/embed_smoke.c | 14 +- src/ext_store.c | 7 +- src/jit.c | 2 +- src/jit_smoke.c | 46 +- src/trace.c | 16 +- src/trace.h | 2 +- src/value_slot.h | 105 +- src/vm.c | 318 +++-- tests/sections/0fb-bool-type.sh | 2 +- tests/test_container_slots.c | 12 +- tests/test_error_line_fallback.c | 10 +- tests/test_loop_counter_sequential.c | 4 +- tests/test_trace_history_boundary.c | 34 +- tools/num_read_allowlist.txt | 69 +- tools/num_read_check.sh | 6 +- tools/phase2_inventory.py | 87 +- 22 files changed, 1335 insertions(+), 980 deletions(-) create mode 100644 changes/internal/1758-phase2-slot-layer.md diff --git a/changes/internal/1758-phase2-slot-layer.md b/changes/internal/1758-phase2-slot-layer.md new file mode 100644 index 000000000..bacf4edb9 --- /dev/null +++ b/changes/internal/1758-phase2-slot-layer.md @@ -0,0 +1,2 @@ +- #1758 Phase 2 round R1.1, the slot layer: the SMI tag (`0xFFFA`, an int in [-2^47, 2^47)) and its readers exist, and every + slot reader decided what an int does there, but nothing produces an int yet, so no program behaves differently. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 5740de05b..b16fc0303 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,37 +1,39 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1798 classified=1798 unclassified=0 -files=64 tokens=40 role_rules=8 derived_accessors=17 wrappers=6 +examined=1818 classified=1818 unclassified=0 +files=64 tokens=43 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 384 CASE=52 DATA=3 TEST=327 YIELD=2 -(b) payload reads 530 RAW=116 READ=414 -(c) producers 472 GUARD=71 PARSE=3 PRODUCE=373 TAGSET=3 WRITE=22 +(a) type tests 394 CASE=52 DATA=3 TEST=337 YIELD=2 +(b) payload reads 534 RAW=119 READ=415 +(c) producers 469 GUARD=71 PARSE=3 PRODUCE=370 TAGSET=3 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 -(e) number formatting 14 CASE=1 FORMAT=3 PARSE=1 RAW=2 READ=3 TEST=4 +(e) number formatting 16 CASE=1 FORMAT=3 PARSE=1 RAW=2 READ=3 TEST=6 (f) equality, ordering and hashing 27 CASE=1 PRODUCE=4 RAW=5 READ=9 TEST=8 -(g) tape encode and decode 20 CASE=2 DATA=2 PARSE=7 PRODUCE=5 RAW=3 TEST=1 -(h) JSON, store and db encoders 70 CASE=2 FORMAT=3 PARSE=5 PRODUCE=19 READ=24 TEST=17 -(i) observer numeric paths 90 CASE=4 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=5 TEST=22 +(g) tape encode and decode 21 CASE=2 DATA=2 PARSE=7 PRODUCE=5 RAW=3 TEST=2 +(h) JSON, store and db encoders 72 CASE=2 FORMAT=3 PARSE=5 PRODUCE=19 RAW=1 READ=24 TEST=18 +(i) observer numeric paths 94 CASE=4 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=5 TEST=24 (j) embed API 64 CASE=1 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 ## Per token -make_num 368 +make_num 364 VAL_NUM 329 eigs_num_arg 145 eigs_list_num 130 -SLOT_NUM_RAW 94 VAL_NUM_RAW 92 -slot_is_num 62 +SLOT_F64_RAW 83 num_guard 60 AST_NUM 52 eigs_slot_num 52 +slot_is_f64 50 eigs_value_as_num 48 -slot_from_num 41 +slot_from_f64 41 buffer_read_num 38 +slot_is_smi 29 buffer_read_byte 22 list_set_num 22 -slot_as_double 16 +slot_smi_val 17 +slot_f64_value 16 strtod 16 NUM_REUSE 15 eigs_slot_opt_num 12 @@ -57,31 +59,32 @@ d_ 1 dict_value_get_num 1 dict_value_set_num 1 list_get_num 1 -slot_is_numeric 1 +slot_from_int 1 +slot_int_value 1 data.num (AST) 7 ## Per file (category counts) builtins.c 319 a=74 b=94 c=111 e=6 f=8 h=15 i=11 -vm.c 304 a=78 b=105 c=72 f=6 i=43 +vm.c 288 a=72 b=97 c=68 e=2 f=6 i=43 ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 184 a=39 b=59 c=86 builtins_buf.c 97 a=21 b=37 c=39 jit.c 96 d=96 -eigenscript.c 83 a=13 b=13 c=12 e=5 f=7 i=33 -container.h 72 a=23 b=24 c=25 +container.h 89 a=35 b=29 c=25 +eigenscript.c 88 a=14 b=13 c=12 e=5 f=7 i=37 +ext_store.c 52 h=52 embed_smoke.c 50 j=50 -ext_store.c 50 h=50 builtins_host.c 47 a=11 b=24 c=12 eigenscript.h 33 a=3 b=18 c=11 e=1 jit_smoke.c 31 d=31 lint.c 29 a=29 compiler.c 21 a=13 b=5 c=1 i=2 +value_slot.h 20 a=7 b=10 c=3 ext_net.c 19 a=5 b=7 c=7 model_infer.c 16 a=1 b=6 c=9 -trace.c 15 g=15 +trace.c 16 g=16 ext_http.c 14 a=3 b=4 c=7 chunk.c 11 a=3 e=2 f=6 -value_slot.h 9 a=4 b=3 c=2 eigs_embed.c 7 j=7 model_train.c 7 a=1 b=4 c=1 i=1 embed_concurrent.c 6 j=6 @@ -181,78 +184,75 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=58 D2=20 D3=23 T=67 dispositions=43 missing=0 stale=0 -D1 container.h:dict_value_get_num forced slot_is_num=1 -D1 container.h:dict_value_get_ref forced eigs_slot_ref=1 slot_is_num=1 -D1 container.h:dict_value_get_return forced eigs_slot_ref=1 slot_is_num=1 -D1 container.h:eigs_slot_box forced eigs_slot_ref=1 slot_is_num=1 -D1 container.h:eigs_slot_elem_num forced eigs_slot_ref=1 slot_is_num=1 -D1 container.h:eigs_slot_num forced eigs_slot_ref=1 slot_as_ptr=2 slot_is_heap=1 slot_is_num=1 -D1 container.h:eigs_slot_opt_num forced eigs_slot_ref=1 slot_as_ptr=3 slot_is_heap=2 slot_is_null=1 slot_is_num=1 -D1 container.h:eigs_slot_store_borrow forced slot_as_ptr=1 slot_is_heap=1 slot_is_num=1 -D1 container.h:eigs_slot_store_owned forced slot_as_ptr=1 slot_is_heap=1 slot_is_num=1 -D1 container.h:list_get_num forced slot_is_num=1 -D1 container.h:list_get_ref forced eigs_slot_ref=1 slot_is_num=1 -D1 container.h:list_get_return forced eigs_slot_ref=1 slot_is_num=1 -D1 container.h:slot_type forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 slot_type=1 -D1 container.h:slot_view forced eigs_slot_ref=1 slot_as_ptr=1 slot_is_num=2 slot_type=1 -D1 eigenscript.c:ent_child_slot forced eigs_slot_ref=1 slot_is_num=1 -D1 eigenscript.c:module_ns_project forced slot_is_num=2 -D1 eigenscript.c:observer_entropy_now forced slot_as_ptr=1 slot_is_bool=1 slot_is_num=1 slot_is_ptr=1 -D1 eigenscript.c:slot_to_value forced slot_as_ptr=1 slot_is_bool=1 slot_is_heap=1 slot_is_null=1 slot_is_num=1 -D1 ext_store.c:store_json_encode_slot forced eigs_slot_ref=1 slot_is_num=1 -D1 trace.c:write_slot forced slot_as_ptr=1 slot_is_bool=1 slot_is_heap=1 slot_is_null=1 slot_is_num=1 -D1 value_slot.h:slot_is_num forced SLOT_QNAN_MASK=2 slot_is_num=1 -D1 value_slot.h:slot_is_numeric forced slot_is_num=1 slot_is_numeric=1 -D1 value_slot.h:slot_truthy_immediate forced SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 slot_is_null=1 slot_is_num=1 -D1 vm.c:#define ARITH_FAST forced slot_as_double=2 slot_as_ptr=2 slot_is_ptr=2 -D1 vm.c:#define INT_BINOP_R forced slot_as_double=2 slot_as_ptr=2 slot_is_ptr=2 -D1 vm.c:#define NUM_CMP forced slot_as_double=2 slot_as_ptr=2 slot_is_ptr=2 -D1 vm.c:#define READ_SLICE_BOUND forced slot_as_ptr=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:jit_helper_dot_set forced slot_as_ptr=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:jit_helper_index_get forced slot_as_ptr=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:jit_helper_index_set forced slot_as_ptr=1 slot_is_num=3 slot_is_ptr=1 -D1 vm.c:jit_helper_local_dot_set forced slot_is_num=1 -D1 vm.c:jit_helper_observe_assign_local forced slot_is_num=2 -D1 vm.c:jit_helper_observe_name_post forced slot_is_num=3 -D1 vm.c:loop_iter_store forced slot_is_num=1 -D1 vm.c:obs_dump_scope forced slot_as_ptr=3 slot_is_bool=1 slot_is_num=1 slot_is_ptr=3 -D1 vm.c:obs_dump_value forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:slot_as_double forced slot_as_double=1 slot_as_ptr=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:slot_bridge_unwrap forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 -D1 vm.c:slot_truthy forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 -D1 vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL forced slot_as_double=2 -D1 vm.c:vm_leaf_accessor_exec/OP_INDEX_GET forced slot_as_double=1 slot_as_ptr=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(BNOT) forced slot_as_double=1 slot_as_ptr=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(CALL) forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 -D1 vm.c:vm_run_ex/CASE(DISPATCH) forced slot_as_ptr=5 slot_is_bool=1 slot_is_null=1 slot_is_num=2 slot_is_ptr=2 -D1 vm.c:vm_run_ex/CASE(DOT_SET) forced slot_as_ptr=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(EQ) forced slot_as_double=2 -D1 vm.c:vm_run_ex/CASE(INDEX_GET) forced slot_as_ptr=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(INDEX_SET) forced slot_as_ptr=1 slot_is_num=3 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(JUMP_BACK) forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 -D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) forced slot_is_num=1 -D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) forced slot_is_num=1 -D1 vm.c:vm_run_ex/CASE(NE) forced slot_as_double=2 -D1 vm.c:vm_run_ex/CASE(NEG) forced slot_as_double=1 slot_as_ptr=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) forced slot_is_num=2 -D1 vm.c:vm_run_ex/CASE(OBSERVE_NAME_POST) forced slot_is_num=3 -D1 vm.c:vm_run_ex/CASE(RETURN) forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 -D1 vm.c:vm_slot_lift forced slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_num=1 slot_is_ptr=1 -D1 vm.c:vm_store_local_slot forced slot_as_ptr=1 slot_is_heap=1 slot_is_num=1 +D1=56 D2=19 D3=23 T=67 dispositions=98 missing=0 stale=0 +D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 +D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 +D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 +D1 container.h:eigs_slot_box smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 +D1 container.h:eigs_slot_elem_num smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 +D1 container.h:eigs_slot_num smi-arm eigs_slot_ref=1 slot_as_ptr=2 slot_is_f64=1 slot_is_heap=1 slot_is_smi=1 slot_smi_val=1 +D1 container.h:eigs_slot_opt_num smi-arm eigs_slot_ref=1 slot_as_ptr=3 slot_is_f64=1 slot_is_heap=2 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 +D1 container.h:eigs_slot_store_borrow guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 +D1 container.h:eigs_slot_store_owned guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 +D1 container.h:list_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 +D1 container.h:list_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 +D1 container.h:list_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 +D1 container.h:slot_type unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_type=1 +D1 container.h:slot_view unwired eigs_slot_ref=1 slot_as_ptr=1 slot_is_f64=2 slot_is_smi=1 slot_type=1 +D1 eigenscript.c:ent_child_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 +D1 eigenscript.c:module_ns_project guarded slot_is_f64=2 +D1 eigenscript.c:observer_entropy_now smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 +D1 eigenscript.c:slot_to_value unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 +D1 ext_store.c:store_json_encode_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 +D1 trace.c:write_slot unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 +D1 value_slot.h:slot_f64_value guarded slot_as_ptr=1 slot_f64_value=1 slot_is_f64=1 slot_is_heap=1 +D1 value_slot.h:slot_int_value smi-arm slot_int_value=1 slot_is_smi=1 slot_smi_val=1 +D1 value_slot.h:slot_is_f64 guarded SLOT_QNAN_MASK=2 slot_is_f64=1 +D1 value_slot.h:slot_is_smi smi-arm SLOT_TAG_MASK=1 TAG_SMI=1 slot_is_smi=1 +D1 value_slot.h:slot_smi_val smi-arm SLOT_PAYLOAD_MASK=1 SLOT_SMI_SIGN=2 slot_smi_val=1 +D1 value_slot.h:slot_truthy_immediate smi-arm SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 slot_is_f64=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:#define ARITH_FAST guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 +D1 vm.c:#define INT_BINOP_R guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 +D1 vm.c:#define NUM_CMP guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 +D1 vm.c:#define READ_SLICE_BOUND smi-arm slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:jit_helper_dot_set guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 +D1 vm.c:jit_helper_index_get guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 +D1 vm.c:jit_helper_index_set guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 +D1 vm.c:jit_helper_local_dot_set guarded slot_is_f64=1 +D1 vm.c:loop_iter_store guarded slot_is_f64=1 +D1 vm.c:obs_dump_scope smi-arm slot_as_ptr=3 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=3 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:obs_dump_value smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:obs_slot_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:obs_slot_observable refuse slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 +D1 vm.c:slot_bridge_unwrap smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_smi=1 +D1 vm.c:slot_truthy smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:slot_type_name smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 +D1 vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL guarded slot_f64_value=2 +D1 vm.c:vm_leaf_accessor_exec/OP_INDEX_GET guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(BNOT) guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(DISPATCH) smi-arm slot_as_ptr=4 slot_is_f64=1 slot_is_ptr=2 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:vm_run_ex/CASE(DOT_SET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(EQ) guarded slot_f64_value=2 +D1 vm.c:vm_run_ex/CASE(INDEX_GET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(INDEX_SET) guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) guarded slot_is_f64=1 +D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) guarded slot_is_f64=1 +D1 vm.c:vm_run_ex/CASE(NE) guarded slot_f64_value=2 +D1 vm.c:vm_run_ex/CASE(NEG) guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 +D1 vm.c:vm_slot_lift smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 +D1 vm.c:vm_store_local_slot guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 D2 builtins.c:bool_gate_name guarded slot_as_ptr=1 slot_is_ptr=1 D2 builtins.c:sort_cmp_str guarded slot_as_ptr=2 D2 builtins_host.c:ls_entry_cmp guarded slot_as_ptr=2 -D2 container.h:eigs_slot_ref refuse eigs_slot_ref=1 slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 +D2 container.h:eigs_slot_ref refuse eigs_slot_ref=1 slot_as_ptr=1 slot_is_bool=1 slot_is_heap=1 slot_is_null=1 D2 eigenscript.c:#define GC_EDGE_TABLE guarded slot_as_ptr=6 slot_is_ptr=3 D2 eigenscript.c:env_get_hashed guarded slot_as_ptr=1 slot_is_ptr=1 D2 eigenscript.c:env_get_local_hashed guarded slot_as_ptr=1 slot_is_ptr=1 D2 eigenscript.c:gc_collect_at_exit guarded slot_as_ptr=1 slot_is_ptr=1 D2 value_slot.h:#define slot_as_heap refuse slot_as_heap=1 slot_as_ptr=1 -D2 value_slot.h:slot_as_ptr refuse SLOT_PAYLOAD_MASK=1 slot_as_ptr=1 +D2 value_slot.h:slot_as_ptr refuse SLOT_PAYLOAD_MASK=1 slot_as_ptr=1 slot_is_heap=1 D2 vm.c:jit_helper_iter_next guarded list_elem_type=1 slot_as_ptr=1 slot_is_ptr=1 D2 vm.c:obs_slot_value guarded slot_as_ptr=1 slot_is_bool=1 -D2 vm.c:slot_type_name smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_null=1 slot_is_ptr=1 D2 vm.c:vm_borrow_scan guarded slot_as_ptr=2 slot_is_heap=2 D2 vm.c:vm_builtin_name_for guarded slot_as_ptr=1 slot_is_heap=1 D2 vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET guarded slot_as_ptr=1 slot_is_null=1 slot_is_ptr=1 @@ -270,6 +270,7 @@ D3 value_slot.h:slot_decref guarded SLOT_PAYLOAD_MASK D3 value_slot.h:slot_false not-a-classifier SLOT_FALSE_BITS=1 D3 value_slot.h:slot_from_bool not-a-classifier TAG_BOOL=1 D3 value_slot.h:slot_from_heap guarded SLOT_NULL_BITS=1 SLOT_PAYLOAD_MASK=1 TAG_HEAP=1 +D3 value_slot.h:slot_from_int not-a-classifier SLOT_PAYLOAD_MASK=1 SLOT_SMI_MAX=1 SLOT_SMI_MIN=1 TAG_SMI=1 D3 value_slot.h:slot_incref guarded SLOT_PAYLOAD_MASK=1 SLOT_QNAN_MASK=2 SLOT_TAG_MASK=1 TAG_HEAP=1 D3 value_slot.h:slot_is_bool guarded SLOT_TAG_MASK=1 TAG_BOOL=1 slot_is_bool=1 D3 value_slot.h:slot_is_heap guarded SLOT_TAG_MASK=1 TAG_HEAP=1 slot_is_heap=1 @@ -279,7 +280,6 @@ D3 value_slot.h:slot_null not-a-classifier SLOT_NULL_BITS=1 D3 value_slot.h:slot_true not-a-classifier SLOT_TRUE_BITS=1 D3 vm.c:jit_helper_dot_get guarded slot_is_null=1 D3 vm.c:jit_helper_local_idx_dot_get guarded slot_is_null=1 -D3 vm.c:obs_slot_observable refuse slot_is_bool=1 slot_is_ptr=1 D3 vm.c:vm_local_is_null guarded slot_is_null=1 D3 vm.c:vm_run_ex/CASE(DOT_GET) guarded slot_is_null=1 D3 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET) guarded slot_is_null=1 @@ -408,7 +408,7 @@ list_slice builtin_list_slice int-requiring list_truncate builtin_list_truncate int-requiring - - VAL_NUM,eigs_num_arg log builtin_tensor_log float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard log_softmax builtin_tensor_log_softmax float-producing - - VAL_NUM,eigs_slot_num,make_num -matmul builtin_tensor_matmul float-producing - - SLOT_NUM_RAW,VAL_NUM,eigs_slot_num,make_num,num_guard_named +matmul builtin_tensor_matmul float-producing - - SLOT_F64_RAW,VAL_NUM,eigs_slot_num,make_num,num_guard_named matmul_at builtin_tensor_matmul_at float-producing - - VAL_NUM,eigs_slot_num,make_num matmul_bt builtin_tensor_matmul_bt float-producing - - VAL_NUM,eigs_slot_num,make_num max builtin_max int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num @@ -477,16 +477,16 @@ sort_by builtin_sort_by other spawn builtin_spawn int-preserving - - make_num sqrt builtin_tensor_sqrt float-producing - - VAL_NUM,eigs_num_arg,make_num state_at builtin_state_at int-requiring - - VAL_NUM,eigs_num_arg -store_close builtin_store_close int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num +store_close builtin_store_close int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val store_collections builtin_store_collections int-requiring - - VAL_NUM,eigs_num_arg store_count builtin_store_count int-requiring - - VAL_NUM,eigs_num_arg,make_num store_delete builtin_store_delete int-requiring LOSS - VAL_NUM,eigs_num_arg -store_drop builtin_store_drop int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_num +store_drop builtin_store_drop int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val store_get builtin_store_get int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,strtod store_open builtin_store_open int-preserving - - VAL_NUM,eigs_num_arg,make_num,strtod -store_put builtin_store_put other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num +store_put builtin_store_put other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val store_query builtin_store_query other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod -store_update builtin_store_update other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_num +store_update builtin_store_update other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val str builtin_str other - - eigs_num_text str_from_bytes builtin_str_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte stream_open builtin_stream_open int-requiring - - VAL_NUM,eigs_num_arg @@ -1021,7 +1021,7 @@ builtins_tensor.c:705 tensor_unary make_num PRODUCE c builtins_tensor.c:718 op_exp num_guard GUARD c builtins_tensor.c:732 op_log_safe num_guard GUARD c builtins_tensor.c:734 op_log_safe num_guard GUARD c -builtins_tensor.c:797 builtin_tensor_matmul SLOT_NUM_RAW RAW b +builtins_tensor.c:797 builtin_tensor_matmul SLOT_F64_RAW RAW b builtins_tensor.c:828 builtin_tensor_matmul num_guard_named GUARD c builtins_tensor.c:995 builtin_tensor_scatter_add VAL_NUM TEST a builtins_tensor.c:1026 builtin_tensor_scatter_add VAL_NUM TEST a @@ -1203,160 +1203,182 @@ compiler.c:3844 obs_ast_scan_d AST_NUM CASE i container.h:26 eigs_container_slot VAL_NUM TEST a container.h:26 eigs_container_slot VAL_NUM_RAW RAW b container.h:26 eigs_container_slot num_guard GUARD c -container.h:26 eigs_container_slot slot_from_num PRODUCE c -container.h:42 eigs_slot_store_owned SLOT_NUM_RAW RAW b -container.h:42 eigs_slot_store_owned num_guard GUARD c -container.h:42 eigs_slot_store_owned slot_from_num PRODUCE c -container.h:42 eigs_slot_store_owned slot_is_num TEST a -container.h:45 eigs_slot_store_owned VAL_NUM TEST a -container.h:51 eigs_slot_store_borrow SLOT_NUM_RAW RAW b -container.h:51 eigs_slot_store_borrow num_guard GUARD c -container.h:51 eigs_slot_store_borrow slot_from_num PRODUCE c -container.h:51 eigs_slot_store_borrow slot_is_num TEST a -container.h:78 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c -container.h:80 dict_value_rewrite_num slot_from_num PRODUCE c -container.h:84 list_rewrite_num list_rewrite_num PRODUCE c -container.h:86 list_rewrite_num slot_from_num PRODUCE c -container.h:93 slot_type VAL_NUM YIELD a -container.h:93 slot_type slot_is_num TEST a -container.h:114 list_get_ref slot_is_num TEST a -container.h:118 dict_value_get_ref slot_is_num TEST a -container.h:125 eigs_slot_num eigs_slot_num READ b -container.h:126 eigs_slot_num SLOT_NUM_RAW RAW b -container.h:126 eigs_slot_num slot_is_num TEST a -container.h:127 eigs_slot_num VAL_NUM TEST a -container.h:128 eigs_slot_num eigs_num_arg READ b -container.h:129 eigs_slot_num eigs_num_arg_slow READ b -container.h:131 eigs_slot_elem_num eigs_slot_elem_num READ b -container.h:132 eigs_slot_elem_num SLOT_NUM_RAW RAW b -container.h:132 eigs_slot_elem_num slot_is_num TEST a -container.h:134 eigs_slot_elem_num VAL_NUM TEST a -container.h:134 eigs_slot_elem_num eigs_num_arg READ b -container.h:135 eigs_slot_elem_num eigs_num_arg_slow READ b -container.h:138 eigs_slot_opt_num eigs_slot_opt_num READ b -container.h:140 eigs_slot_opt_num SLOT_NUM_RAW RAW b -container.h:140 eigs_slot_opt_num slot_is_num TEST a -container.h:141 eigs_slot_opt_num VAL_NUM TEST a -container.h:142 eigs_slot_opt_num eigs_num_arg READ b -container.h:144 eigs_slot_opt_num eigs_num_arg_slow READ b -container.h:152 slot_view VAL_NUM TEST a -container.h:152 slot_view slot_is_num TEST a -container.h:153 slot_view VAL_NUM TAGSET c -container.h:154 slot_view SLOT_NUM_RAW RAW b -container.h:154 slot_view VAL_NUM_RAW WRITE c -container.h:154 slot_view slot_is_num TEST a -container.h:155 slot_view eigs_num_arg READ b -container.h:166 eigs_view_check VAL_NUM TEST a -container.h:191 list_get_return SLOT_NUM_RAW RAW b -container.h:191 list_get_return make_num PRODUCE c -container.h:191 list_get_return slot_is_num TEST a -container.h:198 dict_value_get_return SLOT_NUM_RAW RAW b -container.h:198 dict_value_get_return make_num PRODUCE c -container.h:198 dict_value_get_return slot_is_num TEST a -container.h:228 eigs_slot_box SLOT_NUM_RAW RAW b -container.h:228 eigs_slot_box make_num PRODUCE c -container.h:228 eigs_slot_box num_guard GUARD c -container.h:228 eigs_slot_box slot_is_num TEST a -container.h:250 list_set_num list_set_num PRODUCE c -container.h:251 list_set_num list_rewrite_num PRODUCE c -container.h:251 list_set_num num_guard GUARD c -container.h:253 list_append_num list_append_num PRODUCE c -container.h:254 list_append_num num_guard GUARD c -container.h:256 list_append_num slot_from_num PRODUCE c -container.h:258 dict_value_set_num dict_value_set_num PRODUCE c -container.h:259 dict_value_set_num dict_value_rewrite_num PRODUCE c -container.h:259 dict_value_set_num num_guard GUARD c -container.h:286 list_get_num list_get_num READ b -container.h:288 list_get_num slot_is_num TEST a -container.h:289 list_get_num SLOT_NUM_RAW RAW b -container.h:292 dict_value_get_num dict_value_get_num READ b -container.h:294 dict_value_get_num slot_is_num TEST a -container.h:295 dict_value_get_num SLOT_NUM_RAW RAW b +container.h:26 eigs_container_slot slot_from_f64 PRODUCE c +container.h:43 eigs_slot_store_owned SLOT_F64_RAW RAW b +container.h:43 eigs_slot_store_owned num_guard GUARD c +container.h:43 eigs_slot_store_owned slot_from_f64 PRODUCE c +container.h:43 eigs_slot_store_owned slot_is_f64 TEST a +container.h:46 eigs_slot_store_owned VAL_NUM TEST a +container.h:52 eigs_slot_store_borrow SLOT_F64_RAW RAW b +container.h:52 eigs_slot_store_borrow num_guard GUARD c +container.h:52 eigs_slot_store_borrow slot_from_f64 PRODUCE c +container.h:52 eigs_slot_store_borrow slot_is_f64 TEST a +container.h:79 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c +container.h:81 dict_value_rewrite_num slot_from_f64 PRODUCE c +container.h:85 list_rewrite_num list_rewrite_num PRODUCE c +container.h:87 list_rewrite_num slot_from_f64 PRODUCE c +container.h:96 slot_type VAL_NUM YIELD a +container.h:96 slot_type slot_is_f64 TEST a +container.h:100 slot_type slot_is_smi TEST a +container.h:124 list_get_ref slot_is_f64 TEST a +container.h:124 list_get_ref slot_is_smi TEST a +container.h:128 dict_value_get_ref slot_is_f64 TEST a +container.h:128 dict_value_get_ref slot_is_smi TEST a +container.h:138 eigs_slot_num eigs_slot_num READ b +container.h:139 eigs_slot_num SLOT_F64_RAW RAW b +container.h:139 eigs_slot_num slot_is_f64 TEST a +container.h:140 eigs_slot_num slot_is_smi TEST a +container.h:140 eigs_slot_num slot_smi_val RAW b +container.h:141 eigs_slot_num VAL_NUM TEST a +container.h:142 eigs_slot_num eigs_num_arg READ b +container.h:143 eigs_slot_num eigs_num_arg_slow READ b +container.h:145 eigs_slot_elem_num eigs_slot_elem_num READ b +container.h:146 eigs_slot_elem_num SLOT_F64_RAW RAW b +container.h:146 eigs_slot_elem_num slot_is_f64 TEST a +container.h:147 eigs_slot_elem_num slot_is_smi TEST a +container.h:147 eigs_slot_elem_num slot_smi_val RAW b +container.h:149 eigs_slot_elem_num VAL_NUM TEST a +container.h:149 eigs_slot_elem_num eigs_num_arg READ b +container.h:150 eigs_slot_elem_num eigs_num_arg_slow READ b +container.h:153 eigs_slot_opt_num eigs_slot_opt_num READ b +container.h:155 eigs_slot_opt_num SLOT_F64_RAW RAW b +container.h:155 eigs_slot_opt_num slot_is_f64 TEST a +container.h:156 eigs_slot_opt_num slot_is_smi TEST a +container.h:156 eigs_slot_opt_num slot_smi_val RAW b +container.h:157 eigs_slot_opt_num VAL_NUM TEST a +container.h:158 eigs_slot_opt_num eigs_num_arg READ b +container.h:160 eigs_slot_opt_num eigs_num_arg_slow READ b +container.h:169 slot_view slot_is_smi TEST a +container.h:170 slot_view VAL_NUM TEST a +container.h:170 slot_view slot_is_f64 TEST a +container.h:171 slot_view VAL_NUM TAGSET c +container.h:172 slot_view SLOT_F64_RAW RAW b +container.h:172 slot_view VAL_NUM_RAW WRITE c +container.h:172 slot_view slot_is_f64 TEST a +container.h:173 slot_view eigs_num_arg READ b +container.h:184 eigs_view_check VAL_NUM TEST a +container.h:211 list_get_return slot_is_smi TEST a +container.h:212 list_get_return SLOT_F64_RAW RAW b +container.h:212 list_get_return make_num PRODUCE c +container.h:212 list_get_return slot_is_f64 TEST a +container.h:219 dict_value_get_return slot_is_smi TEST a +container.h:220 dict_value_get_return SLOT_F64_RAW RAW b +container.h:220 dict_value_get_return make_num PRODUCE c +container.h:220 dict_value_get_return slot_is_f64 TEST a +container.h:250 eigs_slot_box SLOT_F64_RAW RAW b +container.h:250 eigs_slot_box make_num PRODUCE c +container.h:250 eigs_slot_box num_guard GUARD c +container.h:250 eigs_slot_box slot_is_f64 TEST a +container.h:251 eigs_slot_box slot_is_smi TEST a +container.h:273 list_set_num list_set_num PRODUCE c +container.h:274 list_set_num list_rewrite_num PRODUCE c +container.h:274 list_set_num num_guard GUARD c +container.h:276 list_append_num list_append_num PRODUCE c +container.h:277 list_append_num num_guard GUARD c +container.h:279 list_append_num slot_from_f64 PRODUCE c +container.h:281 dict_value_set_num dict_value_set_num PRODUCE c +container.h:282 dict_value_set_num dict_value_rewrite_num PRODUCE c +container.h:282 dict_value_set_num num_guard GUARD c +container.h:311 list_get_num list_get_num READ b +container.h:313 list_get_num slot_is_smi TEST a +container.h:313 list_get_num slot_smi_val RAW b +container.h:314 list_get_num slot_is_f64 TEST a +container.h:315 list_get_num SLOT_F64_RAW RAW b +container.h:318 dict_value_get_num dict_value_get_num READ b +container.h:320 dict_value_get_num slot_is_smi TEST a +container.h:320 dict_value_get_num slot_smi_val RAW b +container.h:321 dict_value_get_num slot_is_f64 TEST a +container.h:322 dict_value_get_num SLOT_F64_RAW RAW b eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a eigenscript.c:309 val_type_name VAL_NUM CASE a -eigenscript.c:431 ent_child_slot SLOT_NUM_RAW RAW i -eigenscript.c:431 ent_child_slot slot_is_num TEST i -eigenscript.c:439 compute_entropy_impl VAL_NUM CASE i -eigenscript.c:439 compute_entropy_impl VAL_NUM_RAW RAW i -eigenscript.c:788 observer_slot_update VAL_NUM TEST i -eigenscript.c:790 observer_slot_update VAL_NUM_RAW RAW i -eigenscript.c:852 observer_slot_sample_gated VAL_NUM TEST i -eigenscript.c:853 observer_slot_sample_gated VAL_NUM_RAW RAW i -eigenscript.c:936 observer_slot_saturated EIGS_NUM_MAX GUARD i -eigenscript.c:1384 observer_entropy_now slot_is_num TEST i -eigenscript.c:1386 observer_entropy_now SLOT_NUM_RAW RAW i -eigenscript.c:1431 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1432 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1435 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1439 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:431 ent_child_slot SLOT_F64_RAW RAW i +eigenscript.c:431 ent_child_slot slot_is_f64 TEST i +eigenscript.c:433 ent_child_slot slot_is_smi TEST i +eigenscript.c:433 ent_child_slot slot_smi_val RAW i +eigenscript.c:441 compute_entropy_impl VAL_NUM CASE i +eigenscript.c:441 compute_entropy_impl VAL_NUM_RAW RAW i +eigenscript.c:790 observer_slot_update VAL_NUM TEST i +eigenscript.c:792 observer_slot_update VAL_NUM_RAW RAW i +eigenscript.c:854 observer_slot_sample_gated VAL_NUM TEST i +eigenscript.c:855 observer_slot_sample_gated VAL_NUM_RAW RAW i +eigenscript.c:938 observer_slot_saturated EIGS_NUM_MAX GUARD i +eigenscript.c:1386 observer_entropy_now slot_is_f64 TEST i +eigenscript.c:1388 observer_entropy_now SLOT_F64_RAW RAW i +eigenscript.c:1389 observer_entropy_now slot_is_smi TEST i +eigenscript.c:1391 observer_entropy_now slot_smi_val RAW i +eigenscript.c:1436 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1437 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1440 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1441 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1442 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1448 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1480 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1480 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1481 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1481 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1481 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1483 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1497 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1497 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1502 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1503 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1512 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1517 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1530 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1535 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1638 free_value VAL_NUM TEST a -eigenscript.c:1720 free_value VAL_NUM CASE a -eigenscript.c:1729 make_num make_num PRODUCE c -eigenscript.c:1730 make_num num_guard GUARD c -eigenscript.c:1746 make_num VAL_NUM TAGSET c -eigenscript.c:1747 make_num VAL_NUM_RAW WRITE c -eigenscript.c:1753 recycle_intermediate VAL_NUM TEST a -eigenscript.c:1775 make_num_permanent make_num_permanent PRODUCE c -eigenscript.c:1776 make_num_permanent num_guard GUARD c -eigenscript.c:1778 make_num_permanent VAL_NUM TAGSET c -eigenscript.c:1779 make_num_permanent VAL_NUM_RAW WRITE c -eigenscript.c:1808 eigs_num_arg_slow eigs_num_arg_slow READ b -eigenscript.c:1809 eigs_num_arg_slow VAL_NUM TEST a -eigenscript.c:1809 eigs_num_arg_slow VAL_NUM_RAW RAW b -eigenscript.c:1816 eigs_list_num eigs_list_num READ b -eigenscript.c:1823 eigs_list_num eigs_slot_num READ b -eigenscript.c:1826 eigs_elem_num eigs_elem_num READ b -eigenscript.c:1827 eigs_elem_num eigs_slot_elem_num READ b -eigenscript.c:1830 eigs_opt_num eigs_opt_num READ b -eigenscript.c:1831 eigs_opt_num eigs_slot_opt_num READ b -eigenscript.c:1867 slot_from_value VAL_NUM TEST a -eigenscript.c:1871 slot_from_value VAL_NUM_RAW RAW b -eigenscript.c:1873 slot_from_value slot_from_num PRODUCE c -eigenscript.c:1886 slot_to_value SLOT_NUM_RAW RAW b -eigenscript.c:1886 slot_to_value make_num PRODUCE c -eigenscript.c:1886 slot_to_value slot_is_num TEST a -eigenscript.c:2380 module_ns_project slot_is_num TEST a -eigenscript.c:2380 module_ns_project slot_is_num TEST a -eigenscript.c:2383 module_ns_project SLOT_NUM_RAW RAW b -eigenscript.c:2383 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2628 chan_clone_rec VAL_NUM TEST a -eigenscript.c:2631 chan_clone_rec VAL_NUM CASE a -eigenscript.c:2631 chan_clone_rec VAL_NUM_RAW RAW b -eigenscript.c:2631 chan_clone_rec make_num PRODUCE c -eigenscript.c:2819 is_truthy VAL_NUM CASE a -eigenscript.c:2819 is_truthy VAL_NUM_RAW RAW b -eigenscript.c:2855 values_equal_impl VAL_NUM TEST f -eigenscript.c:2856 values_equal_impl VAL_NUM TEST f -eigenscript.c:2870 values_equal_impl VAL_NUM CASE f -eigenscript.c:2870 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2870 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2900 values_equal_impl buffer_read_num READ f -eigenscript.c:2902 values_equal_impl buffer_read_num READ f -eigenscript.c:2938 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:2953 eigs_num_text strtod PARSE e -eigenscript.c:2963 value_to_string VAL_NUM CASE e -eigenscript.c:2964 value_to_string VAL_NUM_RAW RAW e -eigenscript.c:2964 value_to_string eigs_num_text FORMAT e -eigenscript.c:4186 gc_value_is_node VAL_NUM CASE a +eigenscript.c:1444 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1445 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1446 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1447 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1453 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1485 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1485 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1486 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1486 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1486 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1488 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1502 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1502 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1507 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1508 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1517 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1522 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1535 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1540 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1643 free_value VAL_NUM TEST a +eigenscript.c:1725 free_value VAL_NUM CASE a +eigenscript.c:1734 make_num make_num PRODUCE c +eigenscript.c:1735 make_num num_guard GUARD c +eigenscript.c:1751 make_num VAL_NUM TAGSET c +eigenscript.c:1752 make_num VAL_NUM_RAW WRITE c +eigenscript.c:1758 recycle_intermediate VAL_NUM TEST a +eigenscript.c:1780 make_num_permanent make_num_permanent PRODUCE c +eigenscript.c:1781 make_num_permanent num_guard GUARD c +eigenscript.c:1783 make_num_permanent VAL_NUM TAGSET c +eigenscript.c:1784 make_num_permanent VAL_NUM_RAW WRITE c +eigenscript.c:1813 eigs_num_arg_slow eigs_num_arg_slow READ b +eigenscript.c:1814 eigs_num_arg_slow VAL_NUM TEST a +eigenscript.c:1814 eigs_num_arg_slow VAL_NUM_RAW RAW b +eigenscript.c:1821 eigs_list_num eigs_list_num READ b +eigenscript.c:1828 eigs_list_num eigs_slot_num READ b +eigenscript.c:1831 eigs_elem_num eigs_elem_num READ b +eigenscript.c:1832 eigs_elem_num eigs_slot_elem_num READ b +eigenscript.c:1835 eigs_opt_num eigs_opt_num READ b +eigenscript.c:1836 eigs_opt_num eigs_slot_opt_num READ b +eigenscript.c:1872 slot_from_value VAL_NUM TEST a +eigenscript.c:1876 slot_from_value VAL_NUM_RAW RAW b +eigenscript.c:1878 slot_from_value slot_from_f64 PRODUCE c +eigenscript.c:1897 slot_to_value SLOT_F64_RAW RAW b +eigenscript.c:1897 slot_to_value make_num PRODUCE c +eigenscript.c:1897 slot_to_value slot_is_f64 TEST a +eigenscript.c:1905 slot_to_value slot_is_smi TEST a +eigenscript.c:2405 module_ns_project slot_is_f64 TEST a +eigenscript.c:2405 module_ns_project slot_is_f64 TEST a +eigenscript.c:2410 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2410 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2655 chan_clone_rec VAL_NUM TEST a +eigenscript.c:2658 chan_clone_rec VAL_NUM CASE a +eigenscript.c:2658 chan_clone_rec VAL_NUM_RAW RAW b +eigenscript.c:2658 chan_clone_rec make_num PRODUCE c +eigenscript.c:2846 is_truthy VAL_NUM CASE a +eigenscript.c:2846 is_truthy VAL_NUM_RAW RAW b +eigenscript.c:2882 values_equal_impl VAL_NUM TEST f +eigenscript.c:2883 values_equal_impl VAL_NUM TEST f +eigenscript.c:2897 values_equal_impl VAL_NUM CASE f +eigenscript.c:2897 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2897 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2927 values_equal_impl buffer_read_num READ f +eigenscript.c:2929 values_equal_impl buffer_read_num READ f +eigenscript.c:2965 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:2980 eigs_num_text strtod PARSE e +eigenscript.c:2990 value_to_string VAL_NUM CASE e +eigenscript.c:2991 value_to_string VAL_NUM_RAW RAW e +eigenscript.c:2991 value_to_string eigs_num_text FORMAT e +eigenscript.c:4213 gc_value_is_node VAL_NUM CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a eigenscript.h:270 VAL_NUM DATA a @@ -1410,12 +1432,12 @@ embed_smoke.c:199 test_worker_exit_lifecycle eigs_slot_num READ j embed_smoke.c:214 test_worker_exit_lifecycle eigs_value_as_num READ j embed_smoke.c:288 host_add eigs_value_as_num READ j embed_smoke.c:288 host_add eigs_value_as_num READ j -embed_smoke.c:334 main SLOT_NUM_RAW WRITE j -embed_smoke.c:336 main SLOT_NUM_RAW WRITE j -embed_smoke.c:338 main SLOT_NUM_RAW RAW j -embed_smoke.c:341 main SLOT_NUM_RAW RAW j -embed_smoke.c:343 main SLOT_NUM_RAW RAW j -embed_smoke.c:345 main SLOT_NUM_RAW RAW j +embed_smoke.c:334 main SLOT_F64_RAW WRITE j +embed_smoke.c:336 main SLOT_F64_RAW WRITE j +embed_smoke.c:338 main SLOT_F64_RAW RAW j +embed_smoke.c:341 main SLOT_F64_RAW RAW j +embed_smoke.c:343 main SLOT_F64_RAW RAW j +embed_smoke.c:345 main SLOT_F64_RAW RAW j embed_smoke.c:373 main eigs_value_as_num READ j embed_smoke.c:381 main eigs_value_as_num READ j embed_smoke.c:391 main eigs_value_as_num READ j @@ -1434,7 +1456,7 @@ embed_smoke.c:616 main eigs_value_as_num READ j embed_smoke.c:845 main eigs_value_as_num READ j embed_smoke.c:898 main eigs_value_as_num READ j embed_smoke.c:908 main eigs_value_as_num READ j -embed_smoke.c:918 main SLOT_NUM_RAW WRITE j +embed_smoke.c:918 main SLOT_F64_RAW WRITE j embed_smoke.c:934 main eigs_value_as_num READ j embed_smoke.c:944 main eigs_value_as_num READ j embed_smoke.c:953 main eigs_value_as_num READ j @@ -1741,56 +1763,58 @@ ext_net.c:362 builtin_net_send eigs_slot_elem_num READ b ext_net.c:364 builtin_net_send finite_num_to_byte READ b ext_net.c:379 builtin_net_close VAL_NUM TEST a ext_net.c:385 builtin_net_close eigs_num_arg READ b -ext_store.c:173 store_json_encode_slot slot_is_num TEST h +ext_store.c:173 store_json_encode_slot slot_is_f64 TEST h ext_store.c:174 store_json_encode_slot eigs_slot_num READ h -ext_store.c:190 store_json_encode VAL_NUM CASE h -ext_store.c:191 store_json_encode eigs_num_arg READ h -ext_store.c:323 store_json_parse_number strtod PARSE h -ext_store.c:326 store_json_parse_number make_num PRODUCE h -ext_store.c:362 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:362 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:372 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:372 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:392 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:407 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:407 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:745 store_load_catalog VAL_NUM TEST h -ext_store.c:745 store_load_catalog VAL_NUM TEST h -ext_store.c:750 store_load_catalog eigs_num_arg READ h -ext_store.c:817 get_store_why VAL_NUM TEST h -ext_store.c:818 get_store_why eigs_num_arg READ h -ext_store.c:820 get_store_why VAL_NUM TEST h -ext_store.c:820 get_store_why eigs_num_arg READ h -ext_store.c:968 builtin_store_open make_num PRODUCE h -ext_store.c:969 builtin_store_open make_num PRODUCE h -ext_store.c:982 builtin_store_close VAL_NUM TEST h -ext_store.c:982 builtin_store_close eigs_num_arg READ h -ext_store.c:984 builtin_store_close VAL_NUM TEST h -ext_store.c:984 builtin_store_close eigs_num_arg READ h -ext_store.c:1030 builtin_store_put make_num PRODUCE h -ext_store.c:1031 builtin_store_put make_num PRODUCE h -ext_store.c:1045 builtin_store_put eigs_num_arg READ h -ext_store.c:1046 builtin_store_put eigs_num_arg READ h -ext_store.c:1058 builtin_store_put make_num PRODUCE h -ext_store.c:1182 builtin_store_get VAL_NUM TEST h -ext_store.c:1183 builtin_store_get eigs_num_arg READ h -ext_store.c:1192 builtin_store_get eigs_num_arg READ h -ext_store.c:1250 store_locate eigs_num_arg READ h -ext_store.c:1346 builtin_store_delete VAL_NUM TEST h -ext_store.c:1347 builtin_store_delete eigs_num_arg READ h -ext_store.c:1393 builtin_store_query eigs_num_arg READ h -ext_store.c:1428 builtin_store_count make_num PRODUCE h -ext_store.c:1436 builtin_store_count make_num PRODUCE h -ext_store.c:1437 builtin_store_count make_num PRODUCE h -ext_store.c:1440 builtin_store_count make_num PRODUCE h -ext_store.c:1446 builtin_store_count make_num PRODUCE h -ext_store.c:1450 builtin_store_count make_num PRODUCE h -ext_store.c:1451 builtin_store_count eigs_num_arg READ h -ext_store.c:1462 builtin_store_count make_num PRODUCE h -ext_store.c:1468 builtin_store_count make_num PRODUCE h -ext_store.c:1502 builtin_store_update VAL_NUM TEST h -ext_store.c:1503 builtin_store_update eigs_num_arg READ h -ext_store.c:1644 builtin_store_drop eigs_num_arg READ h +ext_store.c:181 store_json_encode_slot slot_is_smi TEST h +ext_store.c:183 store_json_encode_slot slot_smi_val RAW h +ext_store.c:195 store_json_encode VAL_NUM CASE h +ext_store.c:196 store_json_encode eigs_num_arg READ h +ext_store.c:328 store_json_parse_number strtod PARSE h +ext_store.c:331 store_json_parse_number make_num PRODUCE h +ext_store.c:367 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:367 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:377 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:377 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:397 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:412 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:412 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:750 store_load_catalog VAL_NUM TEST h +ext_store.c:750 store_load_catalog VAL_NUM TEST h +ext_store.c:755 store_load_catalog eigs_num_arg READ h +ext_store.c:822 get_store_why VAL_NUM TEST h +ext_store.c:823 get_store_why eigs_num_arg READ h +ext_store.c:825 get_store_why VAL_NUM TEST h +ext_store.c:825 get_store_why eigs_num_arg READ h +ext_store.c:973 builtin_store_open make_num PRODUCE h +ext_store.c:974 builtin_store_open make_num PRODUCE h +ext_store.c:987 builtin_store_close VAL_NUM TEST h +ext_store.c:987 builtin_store_close eigs_num_arg READ h +ext_store.c:989 builtin_store_close VAL_NUM TEST h +ext_store.c:989 builtin_store_close eigs_num_arg READ h +ext_store.c:1035 builtin_store_put make_num PRODUCE h +ext_store.c:1036 builtin_store_put make_num PRODUCE h +ext_store.c:1050 builtin_store_put eigs_num_arg READ h +ext_store.c:1051 builtin_store_put eigs_num_arg READ h +ext_store.c:1063 builtin_store_put make_num PRODUCE h +ext_store.c:1187 builtin_store_get VAL_NUM TEST h +ext_store.c:1188 builtin_store_get eigs_num_arg READ h +ext_store.c:1197 builtin_store_get eigs_num_arg READ h +ext_store.c:1255 store_locate eigs_num_arg READ h +ext_store.c:1351 builtin_store_delete VAL_NUM TEST h +ext_store.c:1352 builtin_store_delete eigs_num_arg READ h +ext_store.c:1398 builtin_store_query eigs_num_arg READ h +ext_store.c:1433 builtin_store_count make_num PRODUCE h +ext_store.c:1441 builtin_store_count make_num PRODUCE h +ext_store.c:1442 builtin_store_count make_num PRODUCE h +ext_store.c:1445 builtin_store_count make_num PRODUCE h +ext_store.c:1451 builtin_store_count make_num PRODUCE h +ext_store.c:1455 builtin_store_count make_num PRODUCE h +ext_store.c:1456 builtin_store_count eigs_num_arg READ h +ext_store.c:1467 builtin_store_count make_num PRODUCE h +ext_store.c:1473 builtin_store_count make_num PRODUCE h +ext_store.c:1507 builtin_store_update VAL_NUM TEST h +ext_store.c:1508 builtin_store_update eigs_num_arg READ h +ext_store.c:1649 builtin_store_drop eigs_num_arg READ h jit.c:1282 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d jit.c:1406 emit_addsd_xmm0_xmm1 emit_addsd_xmm0_xmm1 EMIT d jit.c:1410 emit_subsd_xmm0_xmm1 emit_subsd_xmm0_xmm1 EMIT d @@ -1887,37 +1911,37 @@ jit.c:4108 jit_compile_to_thunk/OP_INDEX_SET emit_cvtsi2sd_r8d_xmm1 EMIT d jit.c:4109 jit_compile_to_thunk/OP_INDEX_SET emit_ucomisd_xmm0_xmm1 EMIT d jit.c:4117 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rax EMIT d jit.c:4375 jit_compile_to_thunk/OP_POP VAL_NUM TEST d -jit_smoke.c:103 jit_helper_local_idx_get slot_from_num PRODUCE d -jit_smoke.c:138 jit_helper_iter_next SLOT_NUM_RAW RAW d -jit_smoke.c:142 jit_helper_iter_next slot_from_num PRODUCE d -jit_smoke.c:149 jit_helper_index_get SLOT_NUM_RAW RAW d -jit_smoke.c:149 jit_helper_index_get SLOT_NUM_RAW RAW d -jit_smoke.c:153 jit_helper_index_get slot_from_num PRODUCE d -jit_smoke.c:172 jit_helper_set_name SLOT_NUM_RAW RAW d -jit_smoke.c:172 jit_helper_set_name SLOT_NUM_RAW RAW d -jit_smoke.c:173 jit_helper_set_name SLOT_NUM_RAW RAW d -jit_smoke.c:176 jit_helper_set_name SLOT_NUM_RAW RAW d -jit_smoke.c:329 run_store_cases slot_from_num PRODUCE d -jit_smoke.c:343 run_store_cases slot_from_num PRODUCE d -jit_smoke.c:360 run_store_cases SLOT_NUM_RAW RAW d -jit_smoke.c:360 run_store_cases SLOT_NUM_RAW RAW d -jit_smoke.c:361 run_store_cases SLOT_NUM_RAW RAW d -jit_smoke.c:368 run_store_cases SLOT_NUM_RAW RAW d -jit_smoke.c:444 run_index_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:444 run_index_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:536 run_reader_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:537 run_reader_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:538 run_reader_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:538 run_reader_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:539 run_reader_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:540 run_reader_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:541 run_reader_bail_cases SLOT_NUM_RAW RAW d -jit_smoke.c:541 run_reader_bail_cases SLOT_NUM_RAW RAW d +jit_smoke.c:103 jit_helper_local_idx_get slot_from_f64 PRODUCE d +jit_smoke.c:138 jit_helper_iter_next SLOT_F64_RAW RAW d +jit_smoke.c:142 jit_helper_iter_next slot_from_f64 PRODUCE d +jit_smoke.c:149 jit_helper_index_get SLOT_F64_RAW RAW d +jit_smoke.c:149 jit_helper_index_get SLOT_F64_RAW RAW d +jit_smoke.c:153 jit_helper_index_get slot_from_f64 PRODUCE d +jit_smoke.c:172 jit_helper_set_name SLOT_F64_RAW RAW d +jit_smoke.c:172 jit_helper_set_name SLOT_F64_RAW RAW d +jit_smoke.c:173 jit_helper_set_name SLOT_F64_RAW RAW d +jit_smoke.c:176 jit_helper_set_name SLOT_F64_RAW RAW d +jit_smoke.c:329 run_store_cases slot_from_f64 PRODUCE d +jit_smoke.c:343 run_store_cases slot_from_f64 PRODUCE d +jit_smoke.c:360 run_store_cases SLOT_F64_RAW RAW d +jit_smoke.c:360 run_store_cases SLOT_F64_RAW RAW d +jit_smoke.c:361 run_store_cases SLOT_F64_RAW RAW d +jit_smoke.c:368 run_store_cases SLOT_F64_RAW RAW d +jit_smoke.c:444 run_index_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:444 run_index_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:536 run_reader_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:537 run_reader_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:538 run_reader_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:538 run_reader_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:539 run_reader_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:540 run_reader_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:541 run_reader_bail_cases SLOT_F64_RAW RAW d +jit_smoke.c:541 run_reader_bail_cases SLOT_F64_RAW RAW d jit_smoke.c:601 run_exit_cases VAL_NUM TAGSET d jit_smoke.c:602 run_exit_cases VAL_NUM_RAW WRITE d -jit_smoke.c:628 run_exit_cases slot_from_num PRODUCE d -jit_smoke.c:637 run_exit_cases SLOT_NUM_RAW RAW d -jit_smoke.c:642 run_exit_cases SLOT_NUM_RAW RAW d +jit_smoke.c:628 run_exit_cases slot_from_f64 PRODUCE d +jit_smoke.c:637 run_exit_cases SLOT_F64_RAW RAW d +jit_smoke.c:642 run_exit_cases SLOT_F64_RAW RAW d lexer.c:42 tok_add num_val RAW b lexer.c:647 tokenize_at_line num_val RAW b lexer.c:750 tokenize_at_line strtod PARSE c @@ -1991,10 +2015,10 @@ task.c:289 task_sched_trace_read make_num PRODUCE c task.c:290 task_sched_trace_read make_num PRODUCE c task.c:291 task_sched_trace_read make_num PRODUCE c task.c:559 task_do_kill make_num PRODUCE c -trace.c:742 trace_query_at slot_from_num PRODUCE g -trace.c:757 trace_query_at slot_from_num PRODUCE g -trace.c:806 trace_query_when slot_from_num PRODUCE g -trace.c:827 trace_query_when slot_from_num PRODUCE g +trace.c:742 trace_query_at slot_from_f64 PRODUCE g +trace.c:757 trace_query_at slot_from_f64 PRODUCE g +trace.c:806 trace_query_when slot_from_f64 PRODUCE g +trace.c:827 trace_query_when slot_from_f64 PRODUCE g trace.c:1927 #define TK_NUM_ VAL_NUM DATA g trace.c:2018 kinds_text VAL_NUM DATA g trace.c:2324 parse_value_p strtod PARSE g @@ -2002,320 +2026,316 @@ trace.c:2407 parse_value_p strtod PARSE g trace.c:2410 parse_value_p make_num PRODUCE g trace.c:2820 write_value_ptr VAL_NUM CASE g trace.c:2820 write_value_ptr VAL_NUM_RAW RAW g -trace.c:2837 write_slot SLOT_NUM_RAW RAW g -trace.c:2837 write_slot slot_is_num TEST g -trace.c:2954 write_value_ptr_full VAL_NUM CASE g -trace.c:2954 write_value_ptr_full VAL_NUM_RAW RAW g -value_slot.h:50 slot_is_num slot_is_num TEST a -value_slot.h:59 slot_is_numeric slot_is_num TEST a -value_slot.h:59 slot_is_numeric slot_is_numeric TEST a -value_slot.h:66 #define SLOT_NUM_RAW SLOT_NUM_RAW RAW b -value_slot.h:66 #define SLOT_NUM_RAW d_ RAW b -value_slot.h:73 slot_from_num SLOT_NUM_RAW WRITE c -value_slot.h:73 slot_from_num slot_from_num PRODUCE c -value_slot.h:143 slot_truthy_immediate SLOT_NUM_RAW RAW b -value_slot.h:143 slot_truthy_immediate slot_is_num TEST a +trace.c:2837 write_slot SLOT_F64_RAW RAW g +trace.c:2837 write_slot slot_is_f64 TEST g +trace.c:2844 write_slot slot_is_smi TEST g +trace.c:2958 write_value_ptr_full VAL_NUM CASE g +trace.c:2958 write_value_ptr_full VAL_NUM_RAW RAW g +value_slot.h:89 slot_is_f64 slot_is_f64 TEST a +value_slot.h:94 slot_is_smi slot_is_smi TEST a +value_slot.h:105 #define SLOT_F64_RAW SLOT_F64_RAW RAW b +value_slot.h:105 #define SLOT_F64_RAW d_ RAW b +value_slot.h:116 slot_smi_val slot_smi_val RAW b +value_slot.h:123 slot_from_f64 SLOT_F64_RAW WRITE c +value_slot.h:123 slot_from_f64 slot_from_f64 PRODUCE c +value_slot.h:128 slot_from_int slot_from_int PRODUCE c +value_slot.h:202 slot_truthy_immediate SLOT_F64_RAW RAW b +value_slot.h:202 slot_truthy_immediate slot_is_f64 TEST a +value_slot.h:205 slot_truthy_immediate slot_is_smi TEST a +value_slot.h:205 slot_truthy_immediate slot_smi_val RAW b +value_slot.h:214 slot_f64_value slot_f64_value READ b +value_slot.h:215 slot_f64_value SLOT_F64_RAW RAW b +value_slot.h:215 slot_f64_value slot_is_f64 TEST a +value_slot.h:218 slot_f64_value VAL_NUM TEST a +value_slot.h:218 slot_f64_value VAL_NUM_RAW RAW b +value_slot.h:224 slot_int_value slot_int_value READ b +value_slot.h:225 slot_int_value slot_is_smi TEST a +value_slot.h:225 slot_int_value slot_smi_val RAW b vm.c:107 obs_dump_num eigs_num_text FORMAT i -vm.c:118 obs_dump_value SLOT_NUM_RAW RAW i -vm.c:118 obs_dump_value slot_is_num TEST i -vm.c:124 obs_dump_value VAL_NUM CASE i -vm.c:124 obs_dump_value VAL_NUM_RAW RAW i -vm.c:213 obs_dump_scope slot_is_num TEST i -vm.c:214 obs_dump_scope SLOT_NUM_RAW RAW i -vm.c:705 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c -vm.c:785 slot_bridge_unwrap slot_is_num TEST a -vm.c:787 slot_bridge_unwrap SLOT_NUM_RAW RAW b -vm.c:787 slot_bridge_unwrap make_num PRODUCE c -vm.c:830 vm_slot_lift SLOT_NUM_RAW RAW b -vm.c:830 vm_slot_lift make_num PRODUCE c -vm.c:830 vm_slot_lift slot_is_num TEST a -vm.c:863 slot_truthy SLOT_NUM_RAW RAW b -vm.c:863 slot_truthy slot_is_num TEST a -vm.c:872 slot_as_double slot_as_double READ b -vm.c:873 slot_as_double SLOT_NUM_RAW RAW b -vm.c:873 slot_as_double slot_is_num TEST a -vm.c:876 slot_as_double VAL_NUM TEST a -vm.c:876 slot_as_double VAL_NUM_RAW RAW b -vm.c:925 make_iter_state make_num PRODUCE c -vm.c:938 make_iter_state make_num PRODUCE c -vm.c:1157 vm_store_local_slot slot_is_num TEST a -vm.c:1161 vm_store_local_slot VAL_NUM TEST a -vm.c:1163 vm_store_local_slot SLOT_NUM_RAW RAW b -vm.c:1163 vm_store_local_slot VAL_NUM_RAW WRITE c -vm.c:1354 jit_helper_local_idx_get buffer_read_num READ b -vm.c:1354 jit_helper_local_idx_get slot_from_num PRODUCE c -vm.c:1515 jit_helper_dot_set slot_is_num TEST a -vm.c:1518 jit_helper_dot_set SLOT_NUM_RAW RAW b -vm.c:1585 jit_helper_local_dot_set slot_is_num TEST a -vm.c:1586 jit_helper_local_dot_set SLOT_NUM_RAW RAW b -vm.c:1677 jit_helper_observe_assign_local SLOT_NUM_RAW RAW b -vm.c:1677 jit_helper_observe_assign_local slot_is_num TEST a -vm.c:1681 jit_helper_observe_assign_local slot_is_num TEST a -vm.c:1682 jit_helper_observe_assign_local SLOT_NUM_RAW RAW b -vm.c:1730 jit_helper_observe_name_post slot_is_num TEST a -vm.c:1737 jit_helper_observe_name_post SLOT_NUM_RAW RAW b -vm.c:1737 jit_helper_observe_name_post slot_is_num TEST a -vm.c:1742 jit_helper_observe_name_post SLOT_NUM_RAW RAW b -vm.c:1742 jit_helper_observe_name_post slot_is_num TEST a -vm.c:1774 jit_helper_iter_next VAL_NUM TEST a -vm.c:1775 jit_helper_iter_next eigs_slot_num READ b -vm.c:1785 jit_helper_iter_next VAL_NUM TEST a -vm.c:1786 jit_helper_iter_next VAL_NUM_RAW RAW b -vm.c:1793 jit_helper_iter_next buffer_read_num READ b -vm.c:1793 jit_helper_iter_next num_guard GUARD c -vm.c:1793 jit_helper_iter_next slot_from_num PRODUCE c -vm.c:1799 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1869 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b -vm.c:1869 vm_leaf_accessor_exec/OP_CONST slot_from_num PRODUCE c -vm.c:1873 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_num PRODUCE c -vm.c:1876 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_num PRODUCE c -vm.c:1913 vm_leaf_accessor_exec/OP_INDEX_GET slot_as_double READ b -vm.c:1927 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1927 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_num PRODUCE c -vm.c:1935 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_as_double READ b -vm.c:1936 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_as_double READ b -vm.c:1954 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:1954 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_num PRODUCE c -vm.c:2037 loop_iter_store make_num PRODUCE c -vm.c:2044 loop_iter_store slot_is_num TEST a -vm.c:2045 loop_iter_store SLOT_NUM_RAW WRITE c -vm.c:2050 loop_iter_store make_num PRODUCE c -vm.c:2172 jit_helper_index_set slot_is_num TEST a -vm.c:2174 jit_helper_index_set SLOT_NUM_RAW RAW b -vm.c:2175 jit_helper_index_set slot_is_num TEST a -vm.c:2177 jit_helper_index_set SLOT_NUM_RAW RAW b -vm.c:2179 jit_helper_index_set SLOT_NUM_RAW RAW b -vm.c:2189 jit_helper_index_set slot_is_num TEST a -vm.c:2191 jit_helper_index_set SLOT_NUM_RAW RAW b -vm.c:2192 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2194 jit_helper_index_set SLOT_NUM_RAW RAW b -vm.c:2206 jit_helper_index_set VAL_NUM TEST a -vm.c:2208 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2209 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2216 jit_helper_index_set VAL_NUM TEST a -vm.c:2218 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2219 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2222 jit_helper_index_set VAL_NUM TEST a -vm.c:2223 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2242 jit_helper_index_get slot_is_num TEST a -vm.c:2244 jit_helper_index_get SLOT_NUM_RAW RAW b -vm.c:2251 jit_helper_index_get SLOT_NUM_RAW RAW b -vm.c:2262 jit_helper_index_get buffer_read_num READ b -vm.c:2264 jit_helper_index_get slot_from_num PRODUCE c -vm.c:2266 jit_helper_index_get SLOT_NUM_RAW RAW b -vm.c:2282 jit_helper_index_get VAL_NUM TEST a -vm.c:2284 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2285 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2297 jit_helper_index_get VAL_NUM TEST a -vm.c:2299 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2300 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2309 jit_helper_index_get VAL_NUM TEST a -vm.c:2311 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:118 obs_dump_value SLOT_F64_RAW RAW i +vm.c:118 obs_dump_value slot_is_f64 TEST i +vm.c:119 obs_dump_value slot_is_smi TEST i +vm.c:119 obs_dump_value slot_smi_val RAW i +vm.c:125 obs_dump_value VAL_NUM CASE i +vm.c:125 obs_dump_value VAL_NUM_RAW RAW i +vm.c:214 obs_dump_scope slot_is_f64 TEST i +vm.c:215 obs_dump_scope SLOT_F64_RAW RAW i +vm.c:216 obs_dump_scope slot_is_smi TEST i +vm.c:217 obs_dump_scope slot_smi_val RAW i +vm.c:708 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c +vm.c:788 slot_bridge_unwrap slot_is_f64 TEST a +vm.c:790 slot_bridge_unwrap SLOT_F64_RAW RAW b +vm.c:790 slot_bridge_unwrap make_num PRODUCE c +vm.c:799 slot_bridge_unwrap slot_is_smi TEST a +vm.c:835 vm_slot_lift SLOT_F64_RAW RAW b +vm.c:835 vm_slot_lift make_num PRODUCE c +vm.c:835 vm_slot_lift slot_is_f64 TEST a +vm.c:840 vm_slot_lift slot_is_smi TEST a +vm.c:872 slot_truthy SLOT_F64_RAW RAW b +vm.c:872 slot_truthy slot_is_f64 TEST a +vm.c:876 slot_truthy slot_is_smi TEST a +vm.c:876 slot_truthy slot_smi_val RAW b +vm.c:931 make_iter_state make_num PRODUCE c +vm.c:944 make_iter_state make_num PRODUCE c +vm.c:1163 vm_store_local_slot slot_is_f64 TEST a +vm.c:1167 vm_store_local_slot VAL_NUM TEST a +vm.c:1169 vm_store_local_slot SLOT_F64_RAW RAW b +vm.c:1169 vm_store_local_slot VAL_NUM_RAW WRITE c +vm.c:1360 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1360 jit_helper_local_idx_get slot_from_f64 PRODUCE c +vm.c:1521 jit_helper_dot_set slot_is_f64 TEST a +vm.c:1524 jit_helper_dot_set SLOT_F64_RAW RAW b +vm.c:1591 jit_helper_local_dot_set slot_is_f64 TEST a +vm.c:1592 jit_helper_local_dot_set SLOT_F64_RAW RAW b +vm.c:1642 obs_slot_observable slot_is_f64 TEST i +vm.c:1649 obs_slot_num SLOT_F64_RAW RAW i +vm.c:1649 obs_slot_num slot_is_f64 TEST i +vm.c:1650 obs_slot_num slot_is_smi TEST i +vm.c:1650 obs_slot_num slot_smi_val RAW i +vm.c:1797 jit_helper_iter_next VAL_NUM TEST a +vm.c:1798 jit_helper_iter_next eigs_slot_num READ b +vm.c:1808 jit_helper_iter_next VAL_NUM TEST a +vm.c:1809 jit_helper_iter_next VAL_NUM_RAW RAW b +vm.c:1816 jit_helper_iter_next buffer_read_num READ b +vm.c:1816 jit_helper_iter_next num_guard GUARD c +vm.c:1816 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1822 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1892 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b +vm.c:1892 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1896 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1899 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1938 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:1952 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1952 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:1963 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1964 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1982 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:1982 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2065 loop_iter_store make_num PRODUCE c +vm.c:2072 loop_iter_store slot_is_f64 TEST a +vm.c:2073 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2078 loop_iter_store make_num PRODUCE c +vm.c:2200 jit_helper_index_set slot_is_f64 TEST a +vm.c:2202 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2203 jit_helper_index_set slot_is_f64 TEST a +vm.c:2205 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2207 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2217 jit_helper_index_set slot_is_f64 TEST a +vm.c:2219 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2220 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2222 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2234 jit_helper_index_set VAL_NUM TEST a +vm.c:2236 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2237 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2244 jit_helper_index_set VAL_NUM TEST a +vm.c:2246 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2247 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2250 jit_helper_index_set VAL_NUM TEST a +vm.c:2251 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2270 jit_helper_index_get slot_is_f64 TEST a +vm.c:2272 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2279 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2290 jit_helper_index_get buffer_read_num READ b +vm.c:2292 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2294 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2310 jit_helper_index_get VAL_NUM TEST a vm.c:2312 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2314 jit_helper_index_get buffer_read_num READ b -vm.c:2314 jit_helper_index_get make_num PRODUCE c -vm.c:2900 vm_take_error_value make_num PRODUCE c -vm.c:3243 vm_run_ex/CASE(CONST) VAL_NUM TEST a -vm.c:3244 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b -vm.c:3244 vm_run_ex/CASE(CONST) slot_from_num PRODUCE c -vm.c:3258 vm_run_ex/CASE(NUM_ZERO) slot_from_num PRODUCE c -vm.c:3263 vm_run_ex/CASE(NUM_ONE) slot_from_num PRODUCE c -vm.c:3283 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3283 #define NUM_REUSE VAL_NUM TEST a -vm.c:3294 #define ARITH_FAST slot_as_double READ b -vm.c:3294 #define ARITH_FAST slot_as_double READ b -vm.c:3295 #define ARITH_FAST num_guard GUARD c -vm.c:3300 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3301 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3309 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3310 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3318 #define ARITH_FAST slot_from_num PRODUCE c -vm.c:3328 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3328 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3329 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3329 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3329 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3330 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3330 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3331 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3331 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3332 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3381 #define NUM_BINOP VAL_NUM TEST a -vm.c:3381 #define NUM_BINOP VAL_NUM TEST a -vm.c:3382 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3382 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3382 #define NUM_BINOP num_guard GUARD c -vm.c:3383 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3383 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3385 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3385 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3386 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3386 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3387 #define NUM_BINOP make_num PRODUCE c -vm.c:3391 #define NUM_BINOP make_num PRODUCE c -vm.c:3409 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3409 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3410 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3412 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3414 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3414 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3414 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3417 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3419 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3419 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3420 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3420 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3421 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3426 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3434 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3434 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3434 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3435 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3435 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3435 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3436 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3436 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3437 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3437 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3438 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3440 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3440 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3445 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3464 #define INT_BINOP_R slot_as_double READ b -vm.c:3464 #define INT_BINOP_R slot_as_double READ b -vm.c:3466 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3467 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3470 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3471 #define INT_BINOP_R slot_from_num PRODUCE c -vm.c:3478 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3478 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3482 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3482 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3485 #define INT_BINOP_R slot_from_num PRODUCE c -vm.c:3498 #define INT_BINOP_R slot_from_num PRODUCE c -vm.c:3525 vm_run_ex/CASE(NEG) slot_as_double READ b -vm.c:3528 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3528 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c -vm.c:3531 vm_run_ex/CASE(NEG) slot_from_num PRODUCE c -vm.c:3536 vm_run_ex/CASE(NEG) slot_from_num PRODUCE c -vm.c:3551 vm_run_ex/CASE(BNOT) slot_as_double READ b -vm.c:3553 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b -vm.c:3556 vm_run_ex/CASE(BNOT) slot_from_num PRODUCE c -vm.c:3562 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a -vm.c:3562 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c -vm.c:3565 vm_run_ex/CASE(BNOT) slot_from_num PRODUCE c -vm.c:3573 vm_run_ex/CASE(BNOT) slot_from_num PRODUCE c -vm.c:3583 vm_run_ex/CASE(EQ) slot_as_double READ f -vm.c:3583 vm_run_ex/CASE(EQ) slot_as_double READ f -vm.c:3604 vm_run_ex/CASE(NE) slot_as_double READ f -vm.c:3604 vm_run_ex/CASE(NE) slot_as_double READ f -vm.c:3626 #define NUM_CMP slot_as_double READ f -vm.c:3626 #define NUM_CMP slot_as_double READ f -vm.c:4035 vm_run_ex/CASE(JUMP_BACK) SLOT_NUM_RAW RAW b -vm.c:4035 vm_run_ex/CASE(JUMP_BACK) make_num PRODUCE c -vm.c:4035 vm_run_ex/CASE(JUMP_BACK) slot_is_num TEST a -vm.c:4398 vm_run_ex/CASE(CALL) SLOT_NUM_RAW RAW b -vm.c:4398 vm_run_ex/CASE(CALL) make_num PRODUCE c -vm.c:4398 vm_run_ex/CASE(CALL) slot_is_num TEST a -vm.c:4480 vm_run_ex/CASE(RETURN) SLOT_NUM_RAW RAW b -vm.c:4480 vm_run_ex/CASE(RETURN) make_num PRODUCE c -vm.c:4480 vm_run_ex/CASE(RETURN) slot_is_num TEST a -vm.c:4564 vm_run_ex/CASE(INDEX_GET) slot_is_num TEST a -vm.c:4566 vm_run_ex/CASE(INDEX_GET) SLOT_NUM_RAW RAW b -vm.c:4573 vm_run_ex/CASE(INDEX_GET) SLOT_NUM_RAW RAW b -vm.c:4583 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4585 vm_run_ex/CASE(INDEX_GET) slot_from_num PRODUCE c -vm.c:4587 vm_run_ex/CASE(INDEX_GET) SLOT_NUM_RAW RAW b -vm.c:4602 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4604 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4605 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4615 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4617 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4618 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4625 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4627 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4628 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4630 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4630 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c -vm.c:4647 vm_run_ex/CASE(INDEX_SET) slot_is_num TEST a -vm.c:4649 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b -vm.c:4650 vm_run_ex/CASE(INDEX_SET) slot_is_num TEST a -vm.c:4652 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b -vm.c:4654 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b -vm.c:4664 vm_run_ex/CASE(INDEX_SET) slot_is_num TEST a -vm.c:4666 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b -vm.c:4666 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4668 vm_run_ex/CASE(INDEX_SET) SLOT_NUM_RAW RAW b -vm.c:4680 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4682 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4683 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4690 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4692 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4693 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4696 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4697 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4753 vm_run_ex/CASE(DOT_SET) slot_is_num TEST a -vm.c:4756 vm_run_ex/CASE(DOT_SET) SLOT_NUM_RAW RAW b -vm.c:4817 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_num TEST a -vm.c:4818 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_NUM_RAW RAW b -vm.c:4844 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4844 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_num PRODUCE c -vm.c:4950 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_num TEST a -vm.c:4951 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_NUM_RAW RAW b -vm.c:4996 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5002 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5010 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5011 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5024 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5028 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5028 vm_run_ex/CASE(ITER_NEXT) slot_from_num PRODUCE c -vm.c:5186 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) slot_is_num TEST i -vm.c:5187 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) SLOT_NUM_RAW RAW i -vm.c:5201 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) SLOT_NUM_RAW RAW i -vm.c:5201 vm_run_ex/CASE(OBSERVE_ASSIGN_LOCAL) slot_is_num TEST i -vm.c:5366 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5367 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5368 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5402 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5403 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5404 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5431 vm_run_ex/CASE(OBSERVE_NAME_POST) slot_is_num TEST i -vm.c:5439 vm_run_ex/CASE(OBSERVE_NAME_POST) SLOT_NUM_RAW RAW i -vm.c:5439 vm_run_ex/CASE(OBSERVE_NAME_POST) slot_is_num TEST i -vm.c:5442 vm_run_ex/CASE(OBSERVE_NAME_POST) SLOT_NUM_RAW RAW i -vm.c:5442 vm_run_ex/CASE(OBSERVE_NAME_POST) slot_is_num TEST i -vm.c:5466 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5466 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i -vm.c:5466 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5470 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5471 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5472 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5473 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5477 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5491 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5492 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5493 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5494 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5514 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5540 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5543 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5544 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5547 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5563 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i -vm.c:5570 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i -vm.c:5590 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i -vm.c:5591 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i -vm.c:5721 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a -vm.c:5738 #define READ_SLICE_BOUND slot_is_num TEST a -vm.c:5739 #define READ_SLICE_BOUND SLOT_NUM_RAW RAW b -vm.c:5741 #define READ_SLICE_BOUND SLOT_NUM_RAW RAW b -vm.c:5748 #define READ_SLICE_BOUND VAL_NUM TEST a -vm.c:5749 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5752 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:6348 vm_run_ex/CASE(DISPATCH) slot_is_num TEST a -vm.c:6349 vm_run_ex/CASE(DISPATCH) SLOT_NUM_RAW RAW b -vm.c:6351 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a -vm.c:6352 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b -vm.c:6496 vm_run_ex/CASE(DISPATCH) SLOT_NUM_RAW RAW b -vm.c:6496 vm_run_ex/CASE(DISPATCH) make_num PRODUCE c -vm.c:6496 vm_run_ex/CASE(DISPATCH) slot_is_num TEST a +vm.c:2313 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2325 jit_helper_index_get VAL_NUM TEST a +vm.c:2327 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2328 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2337 jit_helper_index_get VAL_NUM TEST a +vm.c:2339 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2340 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2342 jit_helper_index_get buffer_read_num READ b +vm.c:2342 jit_helper_index_get make_num PRODUCE c +vm.c:2928 vm_take_error_value make_num PRODUCE c +vm.c:3032 slot_type_name slot_is_f64 TEST e +vm.c:3033 slot_type_name slot_is_smi TEST e +vm.c:3273 vm_run_ex/CASE(CONST) VAL_NUM TEST a +vm.c:3274 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b +vm.c:3274 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3288 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3293 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3313 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3313 #define NUM_REUSE VAL_NUM TEST a +vm.c:3324 #define ARITH_FAST slot_f64_value READ b +vm.c:3324 #define ARITH_FAST slot_f64_value READ b +vm.c:3325 #define ARITH_FAST num_guard GUARD c +vm.c:3330 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3331 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3339 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3340 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3348 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3358 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3358 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3359 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3359 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3359 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3360 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3360 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3361 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3361 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3362 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3411 #define NUM_BINOP VAL_NUM TEST a +vm.c:3411 #define NUM_BINOP VAL_NUM TEST a +vm.c:3412 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3412 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3412 #define NUM_BINOP num_guard GUARD c +vm.c:3413 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3413 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3415 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3415 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3416 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3416 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3417 #define NUM_BINOP make_num PRODUCE c +vm.c:3421 #define NUM_BINOP make_num PRODUCE c +vm.c:3439 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3439 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3440 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3442 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3444 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3447 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3449 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3449 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3450 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3450 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3451 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3456 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3464 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3464 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3464 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3465 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3465 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3465 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3466 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3466 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3467 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3467 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3468 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3475 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3494 #define INT_BINOP_R slot_f64_value READ b +vm.c:3494 #define INT_BINOP_R slot_f64_value READ b +vm.c:3496 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3497 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3500 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3501 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3508 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3508 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3512 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3512 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3515 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3528 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3555 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3558 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3558 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c +vm.c:3561 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3566 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3581 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3583 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b +vm.c:3586 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3592 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a +vm.c:3592 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c +vm.c:3595 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3603 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3613 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3613 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3634 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3634 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3656 #define NUM_CMP slot_f64_value READ f +vm.c:3656 #define NUM_CMP slot_f64_value READ f +vm.c:4591 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4593 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4600 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4610 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4612 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4614 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4629 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4631 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4632 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4642 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4644 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4645 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4652 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4654 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4655 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4657 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4657 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c +vm.c:4674 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4676 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4677 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4679 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4681 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4691 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4693 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4693 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4695 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4707 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4709 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4710 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4717 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4719 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4720 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4723 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4724 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4780 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4783 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4844 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4845 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4871 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4871 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:4977 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:4978 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5023 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5029 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5037 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5038 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5051 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5055 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5055 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5395 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5396 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5397 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5431 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5432 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5433 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5497 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5497 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i +vm.c:5497 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5501 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5502 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5503 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5504 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5508 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5522 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5523 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5524 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5525 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5545 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5571 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5574 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5575 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5578 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5594 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i +vm.c:5601 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i +vm.c:5621 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i +vm.c:5622 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i +vm.c:5752 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a +vm.c:5769 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5770 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5772 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5779 #define READ_SLICE_BOUND VAL_NUM TEST a +vm.c:5780 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5783 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5794 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5797 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6391 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6392 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6393 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6396 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6406 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a +vm.c:6407 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index e72bf9abf..7071aa28b 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -583,52 +583,138 @@ child), and every other entry must return without a sanitizer report, with the int's Value, type name or truthiness where it returns one. This runs in R1.1, before any program can produce an SMI. +**As implemented in R1.1 (reported as design deviations in the R1.1 +result).** +- **The table covers D1 too.** The rename made the compiler stop at every D1 + entry, but a rename can be typed without a decision, so every D1, D2 and + D3 entry now has a reviewed row below (98 after R1.1), and the inventory + fails on a slot classifier of any class without one. +- **A fifth disposition, `unwired`.** Some D1 arms need what R1.1 does not + have: an int Value (`make_int`, R1.3), the int ValType (R1.2a), or tape v7 + (R1.3). Each calls `eigs_int_unwired(who, bits)`, which aborts naming the + reader. R1.3 deletes `eigs_int_unwired`, so each one stops compiling in the + commit that makes ints reachable (2.7). They are `slot_to_value` (the one + place that boxes an SMI: the lifts, `slot_bridge_unwrap`, `eigs_slot_box` + and the `*_get_return` readers route there), `slot_type`, `slot_view`, + `write_slot`, and `slot_from_int`'s out-of-range arm (the `VAL_INT` box). +- **The permanent refusals** (`refuse`) go through `eigs_slot_refuse(who, + slot)`, which prints the bits and aborts; `slot_as_ptr` refuses a non-heap + slot under ASan and `-DEIGS_SLOT_CHECKED`. Readers that used to turn an + unknown tag into null or `` (`slot_to_value`, `vm_slot_lift`, + `write_slot`) refuse it now; no slot carries such a tag today. +- **The C slot test's population** is + `tools/phase2_inventory.py --slot-population` (33 entries after R1.1); + `tests/phase2/slot_layer.sh` compares it with the entries the test + examined, both ways. The test also runs a tag matrix (a double, the + canonical NaN, -0.0, null, both bools, an SMI, a heap pointer, the + reserved tags and the sentinel against the predicates and the deciding + readers) and plant 1's named check (`slot_from_int` over the boundary + values). Its ABORT rows run in forked children and must name the reader. +- **"The int's Value"** cannot be checked in R1.1: no int Value kind exists, + so `slot_to_value` and the readers that route to it are ABORT rows until + R1.3 turns them into RETURN rows. + -| name | disposition | why an SMI is safe there, or what R1.1 does | +| name | disposition | what an int (an SMI) does there, as of R1.1 | |---|---|---| | `builtins.c:bool_gate_name` | guarded | skips every non-pointer slot (`!slot_is_ptr`); an SMI is never a builtin (D2) | | `builtins.c:sort_cmp_str` | guarded | reached only after `builtin_sort` proved every element a string (its homogeneity test names `VAL_NUM`, compile-forced) (D2) | | `builtins_host.c:ls_entry_cmp` | guarded | sorts the string entries `ls` built itself (D2) | -| `container.h:eigs_slot_ref` | refuse | today an immediate double or an SMI is dereferenced as a pointer; every caller tests `slot_is_num` first (compile-forced). R1.1 aborts on any slot that is not a pointer, null or bool, so a caller missed later fails loudly (D2) | +| `container.h:dict_value_get_num` | smi-arm | bridge reader (2.7): an int element converts to its double, exactly (|SMI| < 2^47), until R1.6 deletes the bridge (D1) | +| `container.h:dict_value_get_ref` | smi-arm | NULL for a number by contract, an int included; the caller then types the element (D1) | +| `container.h:dict_value_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value`, the one SMI boxer (unwired until R1.3) (D1) | +| `container.h:eigs_slot_adopt` | guarded | decides ownership from what `eigs_container_slot` returned (compile-forced); a small int comes back as an SMI and its box is released (D3) | +| `container.h:eigs_slot_box` | smi-arm | boxes an int through `slot_to_value`, kind-preserving (unwired until R1.3) (D1) | +| `container.h:eigs_slot_elem_num` | smi-arm | bridge reader: an int converts to its double (D1) | +| `container.h:eigs_slot_num` | smi-arm | bridge reader: an int converts to its double (D1) | +| `container.h:eigs_slot_opt_num` | smi-arm | bridge reader: an int converts to its double and answers present (D1) | +| `container.h:eigs_slot_ref` | refuse | an immediate double or an SMI was dereferenced as a pointer; every caller tests for a number first. R1.1 aborts on any slot that is not a pointer, null or bool, so a caller missed later fails loudly (D2) | +| `container.h:eigs_slot_store_borrow` | guarded | an SMI is canonical storage and comes back as it is, with no reference to take (D1) | +| `container.h:eigs_slot_store_owned` | guarded | an SMI is canonical storage and comes back as it is, with no reference to release (D1) | +| `container.h:list_get_num` | smi-arm | bridge reader: an int element converts to its double (D1) | +| `container.h:list_get_ref` | smi-arm | NULL for a number by contract, an int included (D1) | +| `container.h:list_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value` (unwired until R1.3) (D1) | +| `container.h:slot_type` | unwired | an SMI's type is the int ValType, which lands in R1.2a; any other unknown tag refuses instead of being read as a pointer (D1) | +| `container.h:slot_view` | unwired | an SMI's facade is a `VAL_INT` view (R1.2a) (D1) | | `eigenscript.c:#define GC_EDGE_TABLE` | guarded | a GC edge exists only for `slot_is_ptr`; an SMI has no edge (D2) | +| `eigenscript.c:ent_child_slot` | smi-arm | an int's entropy is its double's: the numeric channel until round 3 (design 7) (D1) | | `eigenscript.c:env_get_hashed` | guarded | a non-pointer slot goes through `slot_to_value` (compile-forced) and comes back boxed: the lift boxes on purpose (§2.1) (D2) | | `eigenscript.c:env_get_local_hashed` | guarded | as `env_get_hashed` (D2) | | `eigenscript.c:gc_collect_at_exit` | guarded | skips every non-pointer slot (D2) | -| `value_slot.h:#define slot_as_heap` | refuse | alias of `slot_as_ptr` (D2) | -| `value_slot.h:slot_as_ptr` | refuse | the raw dereference: R1.1 asserts the heap tag in ASan and debug builds (D2) | -| `vm.c:jit_helper_iter_next` | guarded | a non-pointer state slot returns 1 (bail); its index-kind test `!= VAL_NUM` is compile-forced (D2) | -| `vm.c:obs_slot_value` | guarded | called only after `obs_slot_observable` answered true (pointer or bool) (D2) | -| `vm.c:slot_type_name` | smi-arm | today an SMI reaches the final `return "num"` by accident. R1.1 adds an explicit SMI arm ("num") and aborts on an unknown tag (D2) | -| `vm.c:vm_borrow_scan` | guarded | compares heap slots with the result pointer; an SMI is not heap (D2) | -| `vm.c:vm_builtin_name_for` | guarded | skips every non-heap slot (D2) | -| `vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET` | guarded | a non-pointer target bails (`return 0`); a non-null field is borrowed as its bits, an SMI included (D2) | -| `vm.c:vm_local_lift` | guarded | a non-pointer, non-null slot goes through `slot_to_value` (compile-forced) and is boxed on purpose (D2) | -| `vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK)` | guarded | a non-pointer source takes the error path, which names the type through `slot_type_name` (D2) | -| `vm.c:vm_run_ex/CASE(SLICE_GET)` | guarded | as DESTRUCTURE_UNPACK (D2) | -| `vm.c:vm_slot_value_opaque` | guarded | only a pointer can be a fn or builtin; an SMI answers "not opaque", which is right (D2) | -| `container.h:eigs_slot_adopt` | guarded | decides ownership from what `eigs_container_slot` returned (compile-forced); a small int comes back as an SMI and its box is released (D3) | +| `eigenscript.c:module_ns_project` | guarded | an int skips the float-over-float rewrite: `slot_to_value` boxes it and the dict store re-canonicalizes it (D1) | +| `eigenscript.c:observer_entropy_now` | smi-arm | an int is the numeric kind, as its double (D1) | +| `eigenscript.c:slot_to_value` | unwired | the one SMI boxer: a fresh int Value needs `make_int` (R1.3). Any other unknown tag now refuses; it used to read back as null (D1) | +| `ext_store.c:store_json_encode_slot` | smi-arm | an int is written as its exact digits (design 7) (D1) | | `jit.c:jit_compile_to_thunk/OP_EQ` | not-a-classifier | writes the bool result bits (D3) | | `jit.c:jit_compile_to_thunk/OP_NEG` | not-a-classifier | the NOT arm writes bool result bits (D3) | | `jit.c:jit_compile_to_thunk/OP_NULL` | not-a-classifier | the constant arm writes null and bool bits (D3) | | `jit_smoke.c:run_bool_cases` | not-a-classifier | test harness: expected bool bits (D3) | | `jit_smoke.c:run_index_bail_cases` | guarded | test harness: an exact null test of a result (D3) | +| `trace.c:write_slot` | unwired | an int needs tape v7 (ints as digits, floats marked), R1.3; a v6 tape would replay it as a float. Any other tag refuses; it was written as `` (D1) | +| `value_slot.h:#define slot_as_heap` | refuse | alias of `slot_as_ptr` (D2) | +| `value_slot.h:slot_as_ptr` | refuse | the raw dereference: R1.1 refuses a non-heap slot in ASan builds and under `-DEIGS_SLOT_CHECKED` (the C slot test) (D2) | | `value_slot.h:slot_decref` | guarded | acts only on tag `0xFFFB`; an SMI has no refcount (D3) | +| `value_slot.h:slot_f64_value` | guarded | the float reader (was vm.c's `slot_as_double`): answers 0 for an int, so each caller decided where an int goes (D1) | | `value_slot.h:slot_false` | not-a-classifier | constructor (D3) | | `value_slot.h:slot_from_bool` | not-a-classifier | constructor (D3) | | `value_slot.h:slot_from_heap` | guarded | maps null and bool Values to their immediates and every other Value to a heap slot, so a `VAL_INT` box stays a box: the lifts depend on that (§2.1) (D3) | +| `value_slot.h:slot_from_int` | not-a-classifier | the one int writer: an SMI inside [-2^47, 2^47); outside it the `VAL_INT` box is unwired until R1.3 (D3) | | `value_slot.h:slot_incref` | guarded | as `slot_decref` (D3) | +| `value_slot.h:slot_int_value` | smi-arm | an SMI's int; the `VAL_INT` box arm lands in R1.2a with the type it names (D1) | | `value_slot.h:slot_is_bool` | guarded | exact tag test (D3) | +| `value_slot.h:slot_is_f64` | guarded | the double test (was `slot_is_num`): an SMI answers 0 (D1) | | `value_slot.h:slot_is_heap` | guarded | exact tag test (D3) | | `value_slot.h:slot_is_null` | guarded | exact bit test (D3) | | `value_slot.h:slot_is_ptr` | guarded | exact tag test (D3) | +| `value_slot.h:slot_is_smi` | smi-arm | the SMI tag test (D1) | | `value_slot.h:slot_null` | not-a-classifier | constructor (D3) | +| `value_slot.h:slot_smi_val` | smi-arm | an SMI's int, sign-extending bit 47 without a right shift (2.1) (D1) | | `value_slot.h:slot_true` | not-a-classifier | constructor (D3) | +| `value_slot.h:slot_truthy_immediate` | smi-arm | an int is truthy when it is not 0, like a double (D1) | +| `vm.c:#define ARITH_FAST` | guarded | an int is not a float (`slot_f64_value`): the arm's slow path pops it through `slot_bridge_unwrap`; R1.3 gives that path int arithmetic (D1) | +| `vm.c:#define INT_BINOP_R` | guarded | an int is not a float: the type error, which names it `num` (`slot_type_name`); R1.3 adds the int arm (D1) | +| `vm.c:#define NUM_CMP` | guarded | an int is not a float: the type error naming `num`; R1.3 adds N2's exact compare (D1) | +| `vm.c:#define READ_SLICE_BOUND` | smi-arm | an int bound is its value when a C `int` holds it, else a value error (D1) | | `vm.c:jit_helper_dot_get` | guarded | a non-null field is pushed as its bits; an SMI is a valid stack slot (D3) | +| `vm.c:jit_helper_dot_set` | guarded | an int value skips the immediate store: the slow path pops it through `slot_bridge_unwrap` (D1) | +| `vm.c:jit_helper_index_get` | guarded | an int index skips the fast path: the slow path lifts it through `slot_to_value` (D1) | +| `vm.c:jit_helper_index_set` | guarded | an int index or value skips the fast path: the slow path pops it through `slot_bridge_unwrap` (D1) | +| `vm.c:jit_helper_iter_next` | guarded | a non-pointer state slot returns 1 (bail); its index-kind test `!= VAL_NUM` is compile-forced (D2) | +| `vm.c:jit_helper_local_dot_set` | guarded | an int value skips the immediate store: `vm_slot_lift` boxes it (D1) | | `vm.c:jit_helper_local_idx_dot_get` | guarded | as `jit_helper_dot_get` (D3) | -| `vm.c:obs_slot_observable` | refuse | answers "pointer or bool", so an SMI is silently unobserved. Its callers test `slot_is_num` first (compile-forced) and must route an SMI into the numeric channel; R1.1 aborts here on an SMI, so a missed caller fails loudly. A BOXED int is a pointer, so it passes this test and goes to `observer_slot_update(Value *)`, whose number arm (eigenscript.c:785) R1.2's `VAL_NUM` rename forces (§7, O map) (D3) | +| `vm.c:loop_iter_store` | guarded | the loop counter is a float the VM makes; a non-float slot takes the `make_num` path (D1) | +| `vm.c:obs_dump_scope` | smi-arm | an int's entropy, as its double (D1) | +| `vm.c:obs_dump_value` | smi-arm | an int prints as its exact digits (D1) | +| `vm.c:obs_slot_num` | smi-arm | the observer's numeric channel: a float, or an int as its exact double until round 3 (design 7) (D1) | +| `vm.c:obs_slot_observable` | refuse | answered "pointer or bool", so an SMI was silently unobserved. R1.1 aborts on an SMI or a reserved tag; every caller routes a number to `obs_slot_num` first. A BOXED int is a pointer and goes to `observer_slot_update(Value *)`, whose number arm (eigenscript.c:785) R1.2's `VAL_NUM` rename forces (§7, O map) (D1 since R1.1: it names `slot_is_f64`) | +| `vm.c:obs_slot_value` | guarded | called only after `obs_slot_observable` answered true (pointer or bool) (D2) | +| `vm.c:slot_bridge_unwrap` | smi-arm | an int materializes through `slot_to_value` (unwired until R1.3) (D1) | +| `vm.c:slot_truthy` | smi-arm | an int is truthy when it is not 0; a reserved tag refuses instead of being dereferenced (D1) | +| `vm.c:slot_type_name` | smi-arm | an SMI reached the final `return "num"` by accident. R1.1 adds the explicit SMI arm ("num", (B)) and aborts on a reserved tag (D1 since R1.1) | +| `vm.c:vm_borrow_scan` | guarded | compares heap slots with the result pointer; an SMI is not heap (D2) | +| `vm.c:vm_builtin_name_for` | guarded | skips every non-heap slot (D2) | +| `vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL` | guarded | bails unless both operands are floats, so the generic call computes an int or mixed operation (4.5) (D1) | +| `vm.c:vm_leaf_accessor_exec/OP_INDEX_GET` | guarded | bails on an int index; the generic call indexes (4.5) (D1) | +| `vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET` | guarded | a non-pointer target bails (`return 0`); a non-null field is borrowed as its bits, an SMI included (D2) | | `vm.c:vm_local_is_null` | guarded | exact null test (D3) | +| `vm.c:vm_local_lift` | guarded | a non-pointer, non-null slot goes through `slot_to_value` (compile-forced) and is boxed on purpose (D2) | +| `vm.c:vm_run_ex/CASE(BNOT)` | guarded | an int is not a float: the type error naming `num`; R1.3 adds the int arm (D1) | +| `vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK)` | guarded | a non-pointer source takes the error path, which names the type through `slot_type_name` (D2) | +| `vm.c:vm_run_ex/CASE(DISPATCH)` | smi-arm | an int key is its value when a C `int` holds it, else a value error; the result returns through `slot_bridge_unwrap` (D1) | | `vm.c:vm_run_ex/CASE(DOT_GET)` | guarded | exact null test of a field (D3) | +| `vm.c:vm_run_ex/CASE(DOT_SET)` | guarded | an int value skips the immediate store: the slow path pops it (D1) | +| `vm.c:vm_run_ex/CASE(EQ)` | guarded | an int is not a float: the slow path (`values_equal_op` on the lifted Values); R1.3 adds N2 (D1) | +| `vm.c:vm_run_ex/CASE(INDEX_GET)` | guarded | an int index skips the fast path: the slow path lifts it through `slot_to_value` (D1) | +| `vm.c:vm_run_ex/CASE(INDEX_SET)` | guarded | an int index or value skips the fast path: the slow path pops it (D1) | +| `vm.c:vm_run_ex/CASE(LOCAL_DOT_SET)` | guarded | an int value: `vm_slot_lift` boxes it (D1) | | `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET)` | guarded | exact null test of a field (D3) | +| `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET)` | guarded | an int value: `vm_slot_lift` boxes it (D1) | +| `vm.c:vm_run_ex/CASE(NE)` | guarded | an int is not a float: the slow path; R1.3 adds N2 (D1) | +| `vm.c:vm_run_ex/CASE(NEG)` | guarded | an int is not a float: the type error naming `num`; R1.3 adds N4b (D1) | +| `vm.c:vm_run_ex/CASE(SLICE_GET)` | guarded | as DESTRUCTURE_UNPACK (D2) | +| `vm.c:vm_slot_lift` | smi-arm | an int is boxed on purpose through `slot_to_value` (2.1; unwired until R1.3); a reserved tag refuses, where it became null (D1) | +| `vm.c:vm_slot_value_opaque` | guarded | only a pointer can be a fn or builtin; an SMI answers "not opaque", which is right (D2) | +| `vm.c:vm_store_local_slot` | guarded | an int skips the in-place float store; the generic swap stores the SMI (D1) | ### 2.6 The accessor API after round 1 (Alt 1R) @@ -642,7 +728,10 @@ int slot_is_number(EigsSlot); /* f64 or int */ EigsSlot slot_from_f64(double); /* the ONE double writer; round 2: canonical NaN */ EigsSlot slot_from_int(int64_t); /* the ONE int writer: SMI in range, else a box. Until R1.3 its only callers convert an - existing VAL_INT (§8, the int-source check) */ + existing VAL_INT (§8, the int-source check); + R1.1's box arm is eigs_int_unwired */ +void eigs_slot_refuse(const char *, EigsSlot); /* R1.1: a broken contract */ +void eigs_int_unwired(const char *, uint64_t); /* R1.1; R1.3 deletes it (2.5) */ int slot_f64_value(EigsSlot, double *); /* an immediate double or a VAL_FLOAT box; 0 for anything else, ints included. Replaces slot_as_double. */ @@ -748,7 +837,7 @@ no builtin's behaviour. | R1.1 | a slot may hold an SMI (no producer yet) | `slot_is_num` -> `slot_is_f64`, `SLOT_NUM_RAW` -> `SLOT_F64_RAW`, `slot_from_num` -> `slot_from_f64`; `slot_is_numeric` and **`slot_as_double`** deleted | compile error: 223 sites first forced here (§2.3a), the 58 D1 classifiers among them | | R1.1 | a slot classifier without a number test meets an SMI | none can exist (they name no number token) | the derived D2/D3 table (§2.5): `refuse` entries abort, `smi-arm` entries answer; the inventory fails on an unreviewed entry | | R1.2a | a Value number may be an int (`VAL_INT`; no producer yet) | `VAL_NUM` -> `VAL_FLOAT`, `num_` -> `f64_`, `VAL_NUM_RAW`/`VAL_NUM_OFFSET` renamed; `VAL_INT` appended, so `-Werror=switch` stops every default-less ValType switch; the one `default:` (builtins.c:998) removed in the same commit | compile error: 464 sites first forced here. Each forced site gets its final int arm, live from R1.3; a builtin's number test admits an int and reads it through the bridge | -| R1.3 | **the first int values**: int literals, and int arithmetic on them | the AST payload `num` and the token's `num_val` become an `EigsNum`; **new opcodes `OP_INT_ZERO`, `OP_INT_ONE`, `OP_INT_CONST`, appended** (the opcode-ABI rule; no `EIGS_BYTECODE_ABI` bump); `make_int` introduced | compile error at the 11 payload sites and the four exhaustive OpCode switches (`op_name` chunk.c:337, `op_verify_operands` chunk.c:466, `op_verify_stack_effect` chunk.c:615, `op_stack_effect` compiler.c:305; `tools/obs_marker_check.sh` requires each new enumerator's `/*obs:NONE*/`); the JIT and leaf scanners refuse an opcode they do not know (their `default:`); the interpreter's dispatch table is the one executor the compiler cannot check, and a missing entry is a NULL jump that crashes the first int-literal row (loud) | +| R1.3 | **the first int values**: int literals, and int arithmetic on them | the AST payload `num` and the token's `num_val` become an `EigsNum`; **new opcodes `OP_INT_ZERO`, `OP_INT_ONE`, `OP_INT_CONST`, appended** (the opcode-ABI rule; no `EIGS_BYTECODE_ABI` bump); `make_int` introduced; `eigs_int_unwired` deleted (the R1.1 placeholders, 2.5) | compile error at the 11 payload sites, at each `eigs_int_unwired` caller, and the four exhaustive OpCode switches (`op_name` chunk.c:337, `op_verify_operands` chunk.c:466, `op_verify_stack_effect` chunk.c:615, `op_stack_effect` compiler.c:305; `tools/obs_marker_check.sh` requires each new enumerator's `/*obs:NONE*/`); the JIT and leaf scanners refuse an opcode they do not know (their `default:`); the interpreter's dispatch table is the one executor the compiler cannot check, and a missing entry is a NULL jump that crashes the first int-literal row (loud) | | R1.3 | `OP_NUM_ZERO`, `OP_NUM_ONE`, `OP_CONST` | **no meaning change**: they keep their float meaning in all three executors (interpreter vm.c:3257, JIT emitter jit.c:2797, leaf evaluator vm.c:1872); an int is never an `OP_CONST` operand | n/a | | R1.4 | `//` | `OP_IDIV` appended, `TOK_SLASH_SLASH` appended (and `//=`, Q6) | compile error at the exhaustive switches | | R1.6 | **every builtin's §6 semantics** (N5 raises, int results, Q1 byte and Q7 continuous readers, the index readers of `gather`/`scatter_add`) | **the bridge is deleted** (21 tokens, §2.3a) | compile error: 743 sites first forced here; the per-builtin behaviour table (§9.4) checks every row's result against §6, on the tag and the branch | @@ -761,7 +850,9 @@ catches a miss: then and written with their final semantics while no int could reach them. Gate: R1.3's 42 MAP rows and the C slot test; and the int-source check (§8) proves nothing before R1.3 could produce an int, so nothing earlier - could have exercised an unfinished arm. + could have exercised an unfinished arm. The R1.1 arms that could not be + final (`unwired`, 2.5) are token-forced instead: R1.3 deletes + `eigs_int_unwired`. - **R1.3, the tape parser.** `parse_value_p` (trace.c:2284) reads digits as an int from v7 on; the version bump refuses an older tape. Gate: the T1 rows (`T1.twice-int`, `T1.v6-refused`). @@ -1770,6 +1861,10 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: - **Tape v7 in this commit**: a v6 writer would print `3` for both kinds and replay would turn ints into floats. The float token marks its kind now (`3.0`); N6's repr replaces it in R1.7, still inside v7. + - `eigs_int_unwired` is deleted: `slot_to_value` boxes an SMI with + `make_int`, `slot_type` answers `VAL_INT`, `slot_view` gives a + `VAL_INT` facade, `write_slot` writes v7 digits, and `slot_from_int` + boxes an int outside the SMI range (each R1.1 placeholder, 2.5). - The observer routes an SMI and a boxed int into the numeric channel (§7). - The `trace` tier (the leaf differential) and the tier witnesses gate diff --git a/src/builtins_tensor.c b/src/builtins_tensor.c index 937e1cdac..cc22315c2 100644 --- a/src/builtins_tensor.c +++ b/src/builtins_tensor.c @@ -794,7 +794,7 @@ Value* builtin_tensor_matmul(Value *arg) { "result is not a number (NaN has no defined value)"); break; } - res->data.buffer.data[i] = SLOT_NUM_RAW(slot_null()); + res->data.buffer.data[i] = SLOT_F64_RAW(slot_null()); } } return res; diff --git a/src/container.h b/src/container.h index b79c7e54b..705292323 100644 --- a/src/container.h +++ b/src/container.h @@ -23,7 +23,7 @@ typedef struct { Value v; } EigsView; * encodings, everything else is a heap pointer. C NULL encodes as null. */ static inline EigsSlot eigs_container_slot(Value *v) { if (!v || v->type == VAL_NULL) return slot_null(); - if (v->type == VAL_NUM) return slot_from_num(num_guard(VAL_NUM_RAW(v))); + if (v->type == VAL_NUM) return slot_from_f64(num_guard(VAL_NUM_RAW(v))); if (v->type == VAL_BOOL) return slot_from_bool(v->data.boolean); return slot_from_heap(v); } @@ -37,9 +37,10 @@ static inline EigsSlot eigs_slot_adopt(Value *v) { /* Normalise a slot for storage. Immediates are guarded; a heap slot that * points at a NUM / NULL / BOOL Value (a VM-internal box or a singleton) is * re-encoded as an immediate. _owned consumes the slot's reference, _borrow - * takes a new one for the container. */ + * takes a new one for the container. #1758: an SMI is already canonical + * storage and is returned as it is (it owns no reference). */ static inline EigsSlot eigs_slot_store_owned(EigsSlot s) { - if (slot_is_num(s)) return slot_from_num(num_guard(SLOT_NUM_RAW(s))); + if (slot_is_f64(s)) return slot_from_f64(num_guard(SLOT_F64_RAW(s))); if (slot_is_heap(s)) { Value *v = slot_as_ptr(s); if (v->type == VAL_NUM || v->type == VAL_NULL || v->type == VAL_BOOL) @@ -48,7 +49,7 @@ static inline EigsSlot eigs_slot_store_owned(EigsSlot s) { return s; } static inline EigsSlot eigs_slot_store_borrow(EigsSlot s) { - if (slot_is_num(s)) return slot_from_num(num_guard(SLOT_NUM_RAW(s))); + if (slot_is_f64(s)) return slot_from_f64(num_guard(SLOT_F64_RAW(s))); if (slot_is_heap(s)) { EigsSlot e = eigs_container_slot(slot_as_ptr(s)); slot_incref(e); @@ -77,28 +78,37 @@ static inline EigsSlot dict_value_slot(const Value *dict, int i) { * released after the store, so a destructor it runs sees the new value. */ static inline int dict_value_rewrite_num(const Value *dict, int i, double d) { EigsSlot old = dict->data.dict.vals[i]; - dict->data.dict.vals[i] = slot_from_num(d); + dict->data.dict.vals[i] = slot_from_f64(d); slot_decref(old); return 1; } static inline int list_rewrite_num(const Value *list, int i, double d) { EigsSlot old = list->data.list.items[i]; - list->data.list.items[i] = slot_from_num(d); + list->data.list.items[i] = slot_from_f64(d); slot_decref(old); return 1; } -/* Return the logical type of a borrowed slot without allocating. */ +/* Return the logical type of a borrowed slot without allocating. #1758: an + * SMI's type is the int ValType, which lands in R1.2a; until then it is + * refused loudly rather than read as a pointer. */ static inline ValType slot_type(EigsSlot s) { - if (slot_is_num(s)) return VAL_NUM; + if (slot_is_f64(s)) return VAL_NUM; if (slot_is_null(s)) return VAL_NULL; if (slot_is_bool(s)) return VAL_BOOL; - return slot_as_ptr(s)->type; -} + if (slot_is_heap(s)) return slot_as_ptr(s)->type; + if (slot_is_smi(s)) eigs_int_unwired("slot_type", s.u); + eigs_slot_refuse("slot_type", s); +} +/* A slot's Value for a reader that wants a pointer: null and bool become + * their singletons, a heap slot its Value. #1758 R1.1: anything else (a + * double, an SMI, a reserved tag) is a broken caller contract -- every caller + * tests for a number first -- and aborts instead of being dereferenced. */ static inline Value *eigs_slot_ref(EigsSlot s) { if (slot_is_null(s)) return make_null(); if (slot_is_bool(s)) return make_bool(slot_as_bool(s)); - return slot_as_ptr(s); + if (slot_is_heap(s)) return slot_as_ptr(s); + eigs_slot_refuse("eigs_slot_ref", s); } static inline ValType list_elem_type(const Value *list, int i) { return slot_type(list_slot(list, i)); @@ -108,28 +118,33 @@ static inline ValType dict_value_type(const Value *dict, int i) { } /* Return the real heap pointer (including the immortal null/bool singleton), - * or NULL when the element is numeric. */ + * or NULL when the element is numeric (#1758: an int included). */ static inline Value *list_get_ref(const Value *list, int i) { EigsSlot s = list_slot(list, i); - return slot_is_num(s) ? NULL : eigs_slot_ref(s); + return (slot_is_f64(s) || slot_is_smi(s)) ? NULL : eigs_slot_ref(s); } static inline Value *dict_value_get_ref(const Value *dict, int i) { EigsSlot s = dict_value_slot(dict, i); - return slot_is_num(s) ? NULL : eigs_slot_ref(s); + return (slot_is_f64(s) || slot_is_smi(s)) ? NULL : eigs_slot_ref(s); } /* Numeric readers have the same strict/bool behavior as the Value readers: * required raises for every non-number, element raises for bool or in strict * mode, and optional treats null as absent. The heap-VAL_NUM arms serve a - * slot that did not come from container storage (a VM-internal box). */ + * slot that did not come from container storage (a VM-internal box). + * #1758: these are the bridge (design 2.7) -- until R1.6 deletes them a + * number read is a double, so an int (an SMI) converts, exactly: |SMI| < + * 2^47. */ static inline double eigs_slot_num(EigsSlot s, const char *who) { - if (slot_is_num(s)) return SLOT_NUM_RAW(s); + if (slot_is_f64(s)) return SLOT_F64_RAW(s); + if (slot_is_smi(s)) return (double)slot_smi_val(s); if (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_NUM) return eigs_num_arg(slot_as_ptr(s), who); return eigs_num_arg_slow(eigs_slot_ref(s), who); } static inline double eigs_slot_elem_num(EigsSlot s, const char *who) { - if (slot_is_num(s)) return SLOT_NUM_RAW(s); + if (slot_is_f64(s)) return SLOT_F64_RAW(s); + if (slot_is_smi(s)) return (double)slot_smi_val(s); Value *v = eigs_slot_ref(s); if (v && v->type == VAL_NUM) return eigs_num_arg(v, who); if (g_strict || (v && v->type == VAL_BOOL)) return eigs_num_arg_slow(v, who); @@ -137,7 +152,8 @@ static inline double eigs_slot_elem_num(EigsSlot s, const char *who) { } static inline int eigs_slot_opt_num(EigsSlot s, double *out, const char *who) { if (slot_is_null(s) || (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_NULL)) return 0; - if (slot_is_num(s)) { *out = SLOT_NUM_RAW(s); return 1; } + if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } + if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } if (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_NUM) { *out = eigs_num_arg(slot_as_ptr(s), who); return 1; } @@ -147,11 +163,13 @@ static inline int eigs_slot_opt_num(EigsSlot s, double *out, const char *who) { /* A numeric view is a caller-owned, allocation-free Value facade. Reference * slots return their real pointer. The cleanup guard catches retaining or - * decrefing a numeric facade: its sentinel refcount must be unchanged. */ + * decrefing a numeric facade: its sentinel refcount must be unchanged. + * #1758: an SMI's facade is a VAL_INT view (R1.2a); refused until then. */ static inline Value *slot_view(EigsSlot s, EigsView *view) { - if (!slot_is_num(s) && slot_type(s) != VAL_NUM) return eigs_slot_ref(s); + if (slot_is_smi(s)) eigs_int_unwired("slot_view", s.u); + if (!slot_is_f64(s) && slot_type(s) != VAL_NUM) return eigs_slot_ref(s); view->v.type = VAL_NUM; - VAL_NUM_RAW(&view->v) = slot_is_num(s) ? SLOT_NUM_RAW(s) + VAL_NUM_RAW(&view->v) = slot_is_f64(s) ? SLOT_F64_RAW(s) : eigs_num_arg(slot_as_ptr(s), "slot_view"); view->v.refcount = EIGS_VIEW_RC; return &view->v; @@ -182,20 +200,24 @@ static inline void eigs_view_check(EigsView *view) { /* Owned/return reads make numeric storage independent. Reference values are * increfed by the owned form; return preserves the builtin direct-child - * borrow protocol for references while numbers are always fresh. */ + * borrow protocol for references while numbers are always fresh (#1758: an + * int's fresh Value comes from slot_to_value, the one place that boxes an + * SMI). */ static inline Value *list_get_owned(const Value *list, int i) { return slot_to_value(list_slot(list, i)); } static inline Value *list_get_return(const Value *list, int i) { EigsSlot s = list_slot(list, i); - return slot_is_num(s) ? make_num(SLOT_NUM_RAW(s)) : eigs_slot_ref(s); + if (slot_is_smi(s)) return slot_to_value(s); + return slot_is_f64(s) ? make_num(SLOT_F64_RAW(s)) : eigs_slot_ref(s); } static inline Value *dict_value_get_owned(const Value *dict, int i) { return slot_to_value(dict_value_slot(dict, i)); } static inline Value *dict_value_get_return(const Value *dict, int i) { EigsSlot s = dict_value_slot(dict, i); - return slot_is_num(s) ? make_num(SLOT_NUM_RAW(s)) : eigs_slot_ref(s); + if (slot_is_smi(s)) return slot_to_value(s); + return slot_is_f64(s) ? make_num(SLOT_F64_RAW(s)) : eigs_slot_ref(s); } /* Keyed reads (eigenscript.c). The slot is borrowed from the dict (for a @@ -225,7 +247,8 @@ static inline void dict_value_set_owned(Value *dict, int i, Value *v) { * append borrows it and therefore increfs. Every double path applies * num_guard. */ static inline Value *eigs_slot_box(EigsSlot s) { - if (slot_is_num(s)) return make_num(num_guard(SLOT_NUM_RAW(s))); + if (slot_is_f64(s)) return make_num(num_guard(SLOT_F64_RAW(s))); + if (slot_is_smi(s)) return slot_to_value(s); /* #1758: kind-preserving */ Value *v = eigs_slot_ref(s); val_incref(v); return v; } static inline __attribute__((always_inline)) void @@ -253,7 +276,7 @@ list_set_num(Value *list, int i, double d) { static inline void list_append_num(Value *list, double d) { d = num_guard(d); if (!list_reserve_one(list)) return; - list->data.list.items[list->data.list.count++] = slot_from_num(d); + list->data.list.items[list->data.list.count++] = slot_from_f64(d); } static inline void dict_value_set_num(Value *dict, int i, double d) { dict_value_rewrite_num(dict, i, num_guard(d)); @@ -283,16 +306,20 @@ static inline void list_sort(Value *list, int (*cmp)(const void *, const void *) qsort(list->data.list.items, (size_t)list->data.list.count, sizeof(EigsSlot), cmp); } +/* #1758: bridge readers (design 2.7): an int element converts to its double + * until R1.6 deletes them. */ static inline int list_get_num(const Value *list, int i, double *out) { EigsSlot s = list_slot(list, i); - if (!slot_is_num(s)) return 0; - *out = SLOT_NUM_RAW(s); + if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } + if (!slot_is_f64(s)) return 0; + *out = SLOT_F64_RAW(s); return 1; } static inline int dict_value_get_num(const Value *dict, int i, double *out) { EigsSlot s = dict_value_slot(dict, i); - if (!slot_is_num(s)) return 0; - *out = SLOT_NUM_RAW(s); + if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } + if (!slot_is_f64(s)) return 0; + *out = SLOT_F64_RAW(s); return 1; } static inline int list_iter_count(const Value *list) { return list->data.list.count; } diff --git a/src/eigenscript.c b/src/eigenscript.c index 26640313f..52b12788b 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -428,7 +428,9 @@ static double ent_child(Value *c) { } static double ent_child_slot(EigsSlot s) { - if (slot_is_num(s)) return entropy_of_num(SLOT_NUM_RAW(s)); + if (slot_is_f64(s)) return entropy_of_num(SLOT_F64_RAW(s)); + /* #1758: an int is observed as its double until round 3 (design 7). */ + if (slot_is_smi(s)) return entropy_of_num((double)slot_smi_val(s)); return ent_child(eigs_slot_ref(s)); } @@ -1381,9 +1383,12 @@ int observer_entropy_now(Env *e, int idx, double *out) { env_dump_lock(e); /* exported #607 lock wrapper (defined below) */ if (idx < e->count) { EigsSlot s = e->values[idx]; - if (slot_is_num(s)) { + if (slot_is_f64(s)) { kind = 1; - num = SLOT_NUM_RAW(s); + num = SLOT_F64_RAW(s); + } else if (slot_is_smi(s)) { + kind = 1; /* #1758: the numeric channel, as a double */ + num = (double)slot_smi_val(s); } else if (slot_is_bool(s)) { held = make_bool(slot_as_bool(s)); /* #1637: immortal; incref no-op */ kind = 2; @@ -1870,20 +1875,26 @@ EigsSlot slot_from_value(Value *v) { * is dead. */ double n = VAL_NUM_RAW(v); val_decref(v); - return slot_from_num(n); + return slot_from_f64(n); } if (v->type == VAL_BOOL) return slot_from_bool(v->data.boolean); /* singleton: borrowed */ return slot_from_heap(v); } /* slot_to_value: produces a Value* the caller owns a ref to. - * - immediate number -> make_num + * - immediate double -> make_num * - immediate null -> g_null_singleton * - immediate bool -> the true/false singleton (#1637) * - heap/tracked pointer -> incref and return + * - SMI (#1758) -> a fresh int Value. This is the ONE place that boxes an + * SMI (the lifts, slot_bridge_unwrap, eigs_slot_box and the *_get_return + * readers all route here); the int Value kind lands in R1.2a/R1.3, so + * until then it is refused (eigs_int_unwired, deleted in R1.3). + * - any other tag is a broken contract and aborts (it used to read back + * as null, silently). */ Value* slot_to_value(EigsSlot s) { - if (slot_is_num(s)) return make_num(SLOT_NUM_RAW(s)); + if (slot_is_f64(s)) return make_num(SLOT_F64_RAW(s)); if (slot_is_null(s)) return &g_null_singleton; if (slot_is_bool(s)) return make_bool(slot_as_bool(s)); if (slot_is_heap(s)) { @@ -1891,8 +1902,22 @@ Value* slot_to_value(EigsSlot s) { val_incref(v); return v; } - /* unknown tag: fall back to null */ - return &g_null_singleton; + if (slot_is_smi(s)) eigs_int_unwired("slot_to_value", s.u); + eigs_slot_refuse("slot_to_value", s); +} + +void eigs_slot_refuse(const char *who, EigsSlot s) { + fprintf(stderr, "EigenScript FATAL: %s: slot 0x%016llx (tag 0x%04llx) is not " + "a value this reader handles (#1758)\n", who, + (unsigned long long)s.u, (unsigned long long)(s.u >> 48)); + abort(); +} + +void eigs_int_unwired(const char *who, uint64_t bits) { + fprintf(stderr, "EigenScript FATAL: %s: int 0x%016llx reached a path whose " + "int arm lands with the int Value kind (#1758 R1.3)\n", who, + (unsigned long long)bits); + abort(); } Value* make_str(const char *s) { @@ -2377,10 +2402,12 @@ static EigsSlot module_ns_project(Value *d, Env *e, const char *key, uint32_t h, *found = 1; return cur; } - if (slot_is_num(s) && slot_is_num(cur)) { + if (slot_is_f64(s) && slot_is_f64(cur)) { /* Number over number: a plain slot store with nothing to - * release, so no destructor runs under the hold. */ - dict_value_rewrite_num(d, di, SLOT_NUM_RAW(s)); + * release, so no destructor runs under the hold. (#1758: an + * int takes the general path below; slot_to_value boxes it and + * the dict store re-canonicalizes it.) */ + dict_value_rewrite_num(d, di, SLOT_F64_RAW(s)); env_shared_unlock(e); *found = 1; return dict_value_slot(d, di); diff --git a/src/embed_smoke.c b/src/embed_smoke.c index 893407f80..c218e648b 100644 --- a/src/embed_smoke.c +++ b/src/embed_smoke.c @@ -331,18 +331,18 @@ int main(void) { int line_save = g_trace_current_line; g_trace_current_line = 10; - SLOT_NUM_RAW(s) = 11.0; trace_assign(NM, s); + SLOT_F64_RAW(s) = 11.0; trace_assign(NM, s); g_trace_current_line = 20; - SLOT_NUM_RAW(s) = 22.0; trace_assign(NM, s); + SLOT_F64_RAW(s) = 22.0; trace_assign(NM, s); - CHECK(trace_query_prev(NM, &out) && SLOT_NUM_RAW(out) == 11.0, + CHECK(trace_query_prev(NM, &out) && SLOT_F64_RAW(out) == 11.0, "#830: prev of a name recorded by a non-compiler producer"); /* TEMPORAL-BACKWARD: at 15 the answer is the line-10 assignment. */ - CHECK(trace_query_at(0, NM, 15, &out) && SLOT_NUM_RAW(out) == 11.0, + CHECK(trace_query_at(0, NM, 15, &out) && SLOT_F64_RAW(out) == 11.0, "#830: what-at from a non-compiler producer (line-10 value)"); - CHECK(trace_query_at(0, NM, 99, &out) && SLOT_NUM_RAW(out) == 22.0, + CHECK(trace_query_at(0, NM, 99, &out) && SLOT_F64_RAW(out) == 22.0, "#830: what-at past the last non-compiler assignment"); - CHECK(trace_query_at(2, NM, 99, &out) && SLOT_NUM_RAW(out) == 2.0, + CHECK(trace_query_at(2, NM, 99, &out) && SLOT_F64_RAW(out) == 2.0, "#830: when-at counts non-compiler assignments"); g_trace_current_line = line_save; @@ -915,7 +915,7 @@ int main(void) { { static const char *const NM = "native_after_callback"; EigsSlot s; - SLOT_NUM_RAW(s) = 1441.0; + SLOT_F64_RAW(s) = 1441.0; trace_assign(NM, s); g_tape[g_tape_len < sizeof g_tape ? g_tape_len : sizeof g_tape - 1] = 0; CHECK(strstr(g_tape, "S 0 0 0\nA 0 native_after_callback=1441\n") != NULL, diff --git a/src/ext_store.c b/src/ext_store.c index 0dd3cb8e7..813027191 100644 --- a/src/ext_store.c +++ b/src/ext_store.c @@ -170,7 +170,7 @@ static void store_json_encode(Value *v, strbuf *out); * inline number; format it through the same branch and format strings used by * the historical boxed-number path so persisted bytes remain identical. */ static void store_json_encode_slot(EigsSlot slot, strbuf *out) { - if (slot_is_num(slot)) { + if (slot_is_f64(slot)) { double n = eigs_slot_num(slot, __func__); if (fabs(n) < 2147483648.0 && n == (int)n) strbuf_append_fmt(out, "%d", (int)n); @@ -178,6 +178,11 @@ static void store_json_encode_slot(EigsSlot slot, strbuf *out) { strbuf_append_fmt(out, "%.15g", n); return; } + if (slot_is_smi(slot)) { + /* #1758: an int is written as its exact digits (design 7). */ + strbuf_append_fmt(out, "%lld", (long long)slot_smi_val(slot)); + return; + } store_json_encode(eigs_slot_ref(slot), out); } diff --git a/src/jit.c b/src/jit.c index 8238bb7f0..5e710a398 100644 --- a/src/jit.c +++ b/src/jit.c @@ -2329,7 +2329,7 @@ static uint8_t *emit_mov_disp32_rdi_to_rdx(uint8_t *w, int32_t disp) { /* Stage 5e: numeric-operand loader for the arith/compare templates. * - * Accepts what the interpreter's slot_as_double accepts MINUS the + * Accepts what the interpreter's slot_f64_value accepts MINUS the * NUM_REUSE candidates: an immediate double, or a heap/tracked pointer * to a VAL_NUM with refcount >= 2 (refcount 1 would make the * interpreter's NUM_REUSE in-place branch fire, so it routes to the diff --git a/src/jit_smoke.c b/src/jit_smoke.c index 7a8faf641..91fa3fcc4 100644 --- a/src/jit_smoke.c +++ b/src/jit_smoke.c @@ -100,7 +100,7 @@ int jit_helper_local_idx_get(int slot, int idx) { VM *vm = eigs_current->vm; index_receipt.calls++; if (slot != 0 || idx != 0 || vm->sp != 0) index_receipt.bad++; - vm->stack[vm->sp++] = index_receipt.status ? slot_null() : slot_from_num(42); + vm->stack[vm->sp++] = index_receipt.status ? slot_null() : slot_from_f64(42); return index_receipt.status; } @@ -135,22 +135,22 @@ int jit_helper_iter_next(void) { VM *vm = eigs_current->vm; reader_receipt.calls++; if (reader_receipt.kind != 1 || vm->sp != 1 || - SLOT_NUM_RAW(vm->stack[0]) != 0 || vm->frames[0].ip != reader_receipt.ip || + SLOT_F64_RAW(vm->stack[0]) != 0 || vm->frames[0].ip != reader_receipt.ip || vm->current_line != 71) reader_receipt.bad++; if (reader_receipt.status != 1) - vm->stack[vm->sp++] = slot_from_num(reader_receipt.status ? 0 : 42); + vm->stack[vm->sp++] = slot_from_f64(reader_receipt.status ? 0 : 42); return reader_receipt.status; } int jit_helper_index_get(void) { VM *vm = eigs_current->vm; reader_receipt.calls++; if (reader_receipt.kind != 0 || vm->sp != 2 || - SLOT_NUM_RAW(vm->stack[0]) != 0 || SLOT_NUM_RAW(vm->stack[1]) != 1 || + SLOT_F64_RAW(vm->stack[0]) != 0 || SLOT_F64_RAW(vm->stack[1]) != 1 || vm->frames[0].ip != reader_receipt.ip || vm->current_line != 71) reader_receipt.bad++; vm->sp -= 2; - vm->stack[vm->sp++] = slot_from_num(reader_receipt.status ? 0 : 42); + vm->stack[vm->sp++] = slot_from_f64(reader_receipt.status ? 0 : 42); return reader_receipt.status; } /* Remaining Stage 4q/4v helpers are linker-immediate stubs. */ @@ -169,11 +169,11 @@ static struct { void jit_helper_set_name(struct EigsChunk *chunk, int idx) { store_receipt.calls++; if (chunk != store_receipt.chunk || idx != 0 || g_vm.sp != 3 || - SLOT_NUM_RAW(g_vm.stack[0]) != 42 || SLOT_NUM_RAW(g_vm.stack[1]) != 0 || - SLOT_NUM_RAW(g_vm.stack[2]) != 1 || g_vm.frames[0].ip != store_receipt.ip) + SLOT_F64_RAW(g_vm.stack[0]) != 42 || SLOT_F64_RAW(g_vm.stack[1]) != 0 || + SLOT_F64_RAW(g_vm.stack[2]) != 1 || g_vm.frames[0].ip != store_receipt.ip) store_receipt.bad = 1; for (int i = 0; i < 3; i++) { - if (SLOT_NUM_RAW(store_receipt.values[i]) != 10 + i || + if (SLOT_F64_RAW(store_receipt.values[i]) != 10 + i || store_receipt.counts[i] != 17) store_receipt.bad = 1; } @@ -326,7 +326,7 @@ static int run_store_cases(void) { for (size_t c = 0; c < sizeof cases / sizeof cases[0]; c++) { row = cases[c].name; for (int i = 0; i < 3; i++) { - values[i] = slot_from_num(10 + i); + values[i] = slot_from_f64(10 + i); counts[i] = 17; } env[0].parent = cases[c].parent < 0 ? NULL : &env[cases[c].parent]; @@ -340,7 +340,7 @@ static int run_store_cases(void) { ic.walk_depth = cases[c].depth; ic.slot_idx = 0; vm->sp = 1; - vm->stack[0] = slot_from_num(42); + vm->stack[0] = slot_from_f64(42); vm->stack[1] = vm->stack[2] = slot_null(); vm->frame_count = 1; vm->frames[0].chunk = &chunk; @@ -357,15 +357,15 @@ static int run_store_cases(void) { STORE_ASSERT(store_receipt.calls == cases[c].helper); STORE_ASSERT(store_receipt.bad == 0); STORE_ASSERT(vm->sp == 3); - STORE_ASSERT(SLOT_NUM_RAW(vm->stack[0]) == 42 && SLOT_NUM_RAW(vm->stack[1]) == 0); - STORE_ASSERT(SLOT_NUM_RAW(vm->stack[2]) == 1); + STORE_ASSERT(SLOT_F64_RAW(vm->stack[0]) == 42 && SLOT_F64_RAW(vm->stack[1]) == 0); + STORE_ASSERT(SLOT_F64_RAW(vm->stack[2]) == 1); STORE_ASSERT(vm->frames[0].ip == store_receipt.ip); STORE_ASSERT((osr ? chunk.jit_osr[0].advance : chunk.jit_advance) == 5); STORE_ASSERT((osr ? chunk.jit_advance : chunk.jit_osr[0].advance) == -99); STORE_ASSERT(state->builtin_env == &env[2]); for (int i = 0; i < 3; i++) { int stored = !cases[c].helper && i == target; - STORE_ASSERT(SLOT_NUM_RAW(values[i]) == (stored ? 1 : 10 + i)); + STORE_ASSERT(SLOT_F64_RAW(values[i]) == (stored ? 1 : 10 + i)); STORE_ASSERT(counts[i] == 17 + stored); } helpers += store_receipt.calls; @@ -441,7 +441,7 @@ static int run_index_bail_cases(void) { advance == expected && index_receipt.calls == 1 && index_receipt.bad == 0 && vm->sp == (status ? 1 : 2) && (status ? slot_is_null(vm->stack[0]) : - SLOT_NUM_RAW(vm->stack[0]) == 42 && SLOT_NUM_RAW(vm->stack[1]) == 1); + SLOT_F64_RAW(vm->stack[0]) == 42 && SLOT_F64_RAW(vm->stack[1]) == 1); rows++; if (!good) { fprintf(stderr, "FAIL: index-bail %s status=%d r13=%" PRIx64 @@ -533,12 +533,12 @@ static int run_reader_bail_cases(void) { int expected_sp = kind ? (status ? 2 : 4) : (status ? 1 : 2); int expected_line = status ? 71 : 72; int stack_ok = kind - ? SLOT_NUM_RAW(vm->stack[0]) == 0 && - (status ? SLOT_NUM_RAW(vm->stack[1]) == 0 : - SLOT_NUM_RAW(vm->stack[1]) == 42 && SLOT_NUM_RAW(vm->stack[2]) == 1 && - SLOT_NUM_RAW(vm->stack[3]) == 0) - : (status ? SLOT_NUM_RAW(vm->stack[0]) == 0 : - SLOT_NUM_RAW(vm->stack[0]) == 42 && SLOT_NUM_RAW(vm->stack[1]) == 1); + ? SLOT_F64_RAW(vm->stack[0]) == 0 && + (status ? SLOT_F64_RAW(vm->stack[1]) == 0 : + SLOT_F64_RAW(vm->stack[1]) == 42 && SLOT_F64_RAW(vm->stack[2]) == 1 && + SLOT_F64_RAW(vm->stack[3]) == 0) + : (status ? SLOT_F64_RAW(vm->stack[0]) == 0 : + SLOT_F64_RAW(vm->stack[0]) == 42 && SLOT_F64_RAW(vm->stack[1]) == 1); int good = saved_r13 == UINT64_C(0x13579bdf2468ace0) && advance == expected && reader_receipt.calls == 1 && reader_receipt.bad == 0 && vm->sp == expected_sp && stack_ok && @@ -625,7 +625,7 @@ static int run_exit_cases(void) { thread->exit_scope = stop ? &stopped : &open; state->exit_scope = row == 2 ? &stopped : &open; vm->sp = vm->frame_count = 1; - vm->stack[0] = slot_from_num(0); + vm->stack[0] = slot_from_f64(0); vm->frames[0].chunk = &chunk; vm->frames[0].ip = chunk.code + entry; chunk.jit_advance = chunk.jit_osr[0].advance = -99; @@ -634,12 +634,12 @@ static int run_exit_cases(void) { int advance = osr ? chunk.jit_osr[0].advance : chunk.jit_advance; int other = osr ? chunk.jit_advance : chunk.jit_osr[0].advance; int want_advance = (stop ? 10 : 13) + (osr ? 2 : 0); - int ok = vm->sp == 1 && SLOT_NUM_RAW(vm->stack[0]) == (stop ? 1 : 4) && + int ok = vm->sp == 1 && SLOT_F64_RAW(vm->stack[0]) == (stop ? 1 : 4) && advance == want_advance && other == -99 && vm->frames[0].ip == chunk.code + entry; if (!ok) { fprintf(stderr, "FAIL native_exit %s row=%d sp=%d value=%g advance=%d other=%d\n", - osr ? "osr" : "entry", row, vm->sp, SLOT_NUM_RAW(vm->stack[0]), advance, other); + osr ? "osr" : "entry", row, vm->sp, SLOT_F64_RAW(vm->stack[0]), advance, other); rc = 1; } if (ok && stop) bailed++; diff --git a/src/trace.c b/src/trace.c index 69344f649..ba9b1cdf3 100644 --- a/src/trace.c +++ b/src/trace.c @@ -739,7 +739,7 @@ int trace_query_at(int kind, const char *interned_name, int line, EigsSlot *out) long long count = 0; for (int i = 0; i < e->lc_count && e->lc[i].line <= line; i++) count += e->lc[i].count; - *out = slot_from_num((double)count); + *out = slot_from_f64((double)count); return 1; } @@ -754,7 +754,7 @@ int trace_query_at(int kind, const char *interned_name, int line, EigsSlot *out) double r = (kind == 3) ? h->entropy : (kind == 4) ? h->dH : observer_settledness(h->dH); /* #412: how = f(dH) */ - *out = slot_from_num(r); + *out = slot_from_f64(r); return 1; } @@ -803,7 +803,7 @@ int trace_query_when(int kind, const char *interned_name, long long ordinal, * answerable without the entry, so it too only needs the range check. */ if (kind == 2) { if (ordinal < 1 || ordinal > e->occ_total) return TRACE_WHEN_MISS; - *out = slot_from_num((double)ordinal); + *out = slot_from_f64((double)ordinal); return TRACE_WHEN_HIT; } @@ -824,7 +824,7 @@ int trace_query_when(int kind, const char *interned_name, long long ordinal, double r = (kind == 3) ? o->entropy : (kind == 4) ? o->dH : observer_settledness(o->dH); /* #412: how = f(dH) */ - *out = slot_from_num(r); + *out = slot_from_f64(r); return TRACE_WHEN_HIT; } @@ -2834,11 +2834,15 @@ static void write_value_ptr(Value *v) { } static void write_slot(EigsSlot s) { - if (slot_is_num(s)) { tp_printf("%.17g", SLOT_NUM_RAW(s)); return; } + if (slot_is_f64(s)) { tp_printf("%.17g", SLOT_F64_RAW(s)); return; } if (slot_is_null(s)) { tp_puts("null"); return; } if (slot_is_bool(s)) { tp_puts(slot_as_bool(s) ? "true" : "false"); return; } if (slot_is_heap(s)) { write_value_ptr(slot_as_ptr(s)); return; } - tp_puts(""); + /* #1758: an int needs tape v7 (ints as digits, floats marked), which + * lands with the first int value in R1.3; a v6 tape would replay it as a + * float. Any other tag used to be written as ``, unreplayable. */ + if (slot_is_smi(s)) eigs_int_unwired("write_slot", s.u); + eigs_slot_refuse("write_slot", s); } static void trace_assign_ex(const char *name, EigsSlot value, int filtered, diff --git a/src/trace.h b/src/trace.h index 798856871..15f0fb8db 100644 --- a/src/trace.h +++ b/src/trace.h @@ -20,7 +20,7 @@ * with the same sentinel value_slot.h uses to avoid a re-typedef. */ #ifndef EIGENSCRIPT_EIGSSLOT_UNION_DEFINED #define EIGENSCRIPT_EIGSSLOT_UNION_DEFINED -typedef union { double d_; uint64_t u; } EigsSlot; /* d_: read via SLOT_NUM_RAW (#1637) */ +typedef union { double d_; uint64_t u; } EigsSlot; /* d_: read via SLOT_F64_RAW (#1637) */ #endif /* Tape format version (#411). Every tape's first line is a header record: diff --git a/src/value_slot.h b/src/value_slot.h index f2dbbe06d..0e0410535 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -1,15 +1,18 @@ /* * EigenScript NaN-boxed slot encoding. * - * An EigsSlot is a 64-bit union aliasing a double. Numbers live as + * An EigsSlot is a 64-bit union aliasing a double. Floats live as * immediate doubles. Pointers and other immediates encode into the * unused QNaN-with-sign-set bit pattern, which num_guard() makes * unreachable from user numbers (NaN -> 0, +/-Inf -> +/-1e308). * * Tag layout (high 16 bits): + * < 0xFFF8 : a double (slot_is_f64) * 0xFFF8 tag 0 : NULL (payload ignored) * 0xFFF9 tag 1 : BOOL (low bit = value) - * 0xFFFA tag 2 : reserved (SMI) (reserved for future small-int) + * 0xFFFA tag 2 : SMI (an int in [-2^47, 2^47): 48-bit two's + * complement payload; #1758. Nothing + * produces one before R1.3) * 0xFFFB tag 3 : HEAP pointer (str/list/dict/fn/builtin/buffer/tb) * 0xFFFC tag 4 : reserved (#262 Step E: was TRACKED — removed) * 0xFFFD tag 5 : reserved @@ -30,7 +33,7 @@ #ifndef EIGENSCRIPT_EIGSSLOT_UNION_DEFINED #define EIGENSCRIPT_EIGSSLOT_UNION_DEFINED -typedef union { double d_; uint64_t u; } EigsSlot; /* d_: read via SLOT_NUM_RAW (#1637) */ +typedef union { double d_; uint64_t u; } EigsSlot; /* d_: read via SLOT_F64_RAW (#1637) */ #endif #define SLOT_QNAN_MASK 0xFFF8000000000000ULL @@ -42,35 +45,91 @@ typedef union { double d_; uint64_t u; } EigsSlot; /* d_: read via SLOT_NUM_RA #define SLOT_TRUE_BITS 0xFFF9000000000001ULL #define TAG_BOOL 0xFFF9000000000000ULL +#define TAG_SMI 0xFFFA000000000000ULL #define TAG_HEAP 0xFFFB000000000000ULL #define TAG_SENTINEL 0xFFFF000000000000ULL +/* #1758: the SMI range, [-2^47, 2^47), and the payload's sign bit. */ +#define SLOT_SMI_MIN (-(INT64_C(1) << 47)) +#define SLOT_SMI_MAX ((INT64_C(1) << 47) - 1) +#define SLOT_SMI_SIGN 0x0000800000000000ULL + +/* A slot reached a reader that does not handle its tag: a broken caller + * contract, never a program's fault. Prints the reader and the bits, then + * aborts (eigenscript.c). */ +#if defined(__GNUC__) || defined(__clang__) +#define EIGS_SLOT_NORETURN __attribute__((noreturn, cold)) +#else +#define EIGS_SLOT_NORETURN +#endif +EIGS_SLOT_NORETURN void eigs_slot_refuse(const char *who, EigsSlot s); +/* #1758 R1.1: an int exists as an encoding (the SMI) before any int Value + * kind does (VAL_INT lands in R1.2a, make_int in R1.3). A reader whose int + * arm needs an int Value, the int's ValType or tape v7 calls this instead + * of guessing; nothing produces an int before R1.3, so it never runs. + * R1.3 DELETES it, so every caller stops compiling in the commit that makes + * ints reachable and gets its real arm there (design 2.7). */ +EIGS_SLOT_NORETURN void eigs_int_unwired(const char *who, uint64_t bits); + +/* slot_as_ptr refuses a slot that is not a heap pointer in sanitizer builds + * and under -DEIGS_SLOT_CHECKED (#1758 R1.1: an SMI must never be read as a + * pointer). Release keeps the bare mask: it is on every hot path. */ +#if defined(__SANITIZE_ADDRESS__) || defined(EIGS_SLOT_CHECKED) +# define EIGS_SLOT_CHECKS 1 +#elif defined(__has_feature) +# if __has_feature(address_sanitizer) +# define EIGS_SLOT_CHECKS 1 +# endif +#endif + /* Predicates */ -static inline int slot_is_num(EigsSlot s) { +/* #1758: a double. Was slot_is_f64; renamed so that every site that meant + * "a number" had to decide what an int (SMI) does there. */ +static inline int slot_is_f64(EigsSlot s) { return (s.u & SLOT_QNAN_MASK) != SLOT_QNAN_MASK; } static inline int slot_is_null(EigsSlot s) { return s.u == SLOT_NULL_BITS; } static inline int slot_is_bool(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_BOOL; } +static inline int slot_is_smi(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_SMI; } static inline int slot_is_heap(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_HEAP; } /* #262 Step E: TAG_TRACKED is gone — a number is always an immediate, never a * heap-boxed observer-tracked Value. Heap is the only pointer tag. */ static inline int slot_is_ptr(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_HEAP; } -static inline int slot_is_numeric(EigsSlot s) { return slot_is_num(s); } /* Accessors (caller must check the predicate first) */ /* #1637 round 4: the ONE raw way into a slot's double (an lvalue), for a slot - * proven a number (slot_is_num). Every use sits in a function listed in + * proven a double (slot_is_f64). Every use sits in a function listed in * tools/num_read_allowlist.txt with its count (tools/num_read_check.sh). */ -#define SLOT_NUM_RAW(s) ((s).d_) +#define SLOT_F64_RAW(s) ((s).d_) static inline int slot_as_bool(EigsSlot s) { return (int)(s.u & 1ULL); } -static inline Value *slot_as_ptr(EigsSlot s) { return (Value*)(uintptr_t)(s.u & SLOT_PAYLOAD_MASK); } +static inline Value *slot_as_ptr(EigsSlot s) { +#ifdef EIGS_SLOT_CHECKS + if (__builtin_expect(!slot_is_heap(s), 0)) eigs_slot_refuse("slot_as_ptr", s); +#endif + return (Value*)(uintptr_t)(s.u & SLOT_PAYLOAD_MASK); +} #define slot_as_heap slot_as_ptr +/* The int an SMI holds, sign-extending payload bit 47 without an + * implementation-defined right shift (design 2.1). */ +static inline int64_t slot_smi_val(EigsSlot s) { + return (int64_t)((s.u & SLOT_PAYLOAD_MASK) ^ SLOT_SMI_SIGN) - (int64_t)SLOT_SMI_SIGN; +} /* Constructors */ -static inline EigsSlot slot_from_num(double d) { EigsSlot s; SLOT_NUM_RAW(s) = d; return s; } +/* #1758: the ONE double writer. Round 2 canonicalizes a NaN here. */ +static inline EigsSlot slot_from_f64(double d) { EigsSlot s; SLOT_F64_RAW(s) = d; return s; } +/* #1758: the ONE int writer: an SMI inside [-2^47, 2^47). Outside it the + * int needs a VAL_INT box, which cannot exist before R1.3 (make_int). Until + * R1.3 nothing in the runtime calls this (tools/phase2_check.sh, the + * int-source check); tests/phase2/slot_layer.c drives it. */ +static inline EigsSlot slot_from_int(int64_t i) { + if (__builtin_expect(i < SLOT_SMI_MIN || i > SLOT_SMI_MAX, 0)) + eigs_int_unwired("slot_from_int", (uint64_t)i); + EigsSlot s; s.u = TAG_SMI | ((uint64_t)i & SLOT_PAYLOAD_MASK); return s; +} static inline EigsSlot slot_null(void) { EigsSlot s; s.u = SLOT_NULL_BITS; return s; } static inline EigsSlot slot_true(void) { EigsSlot s; s.u = SLOT_TRUE_BITS; return s; } static inline EigsSlot slot_false(void) { EigsSlot s; s.u = SLOT_FALSE_BITS; return s; } @@ -136,17 +195,37 @@ static inline void slot_decref(EigsSlot s) { } /* Truthiness — used by JUMP_IF_FALSE / JUMP_IF_TRUE fast paths. - * Immediate-number truthiness is a non-zero double; null and false - * are falsy; everything else (heap, tracked) defers to caller-side - * is_truthy() for now (Phase A keeps semantics identical). */ + * Immediate-number truthiness is a non-zero double, or a non-zero int + * (#1758: an SMI is 0 exactly when its payload is 0); null and false + * are falsy; everything else (heap) defers to caller-side is_truthy(). */ static inline int slot_truthy_immediate(EigsSlot s, int *out_decided) { - if (slot_is_num(s)) { *out_decided = 1; return SLOT_NUM_RAW(s) != 0.0; } + if (slot_is_f64(s)) { *out_decided = 1; return SLOT_F64_RAW(s) != 0.0; } if (slot_is_null(s) || s.u == SLOT_FALSE_BITS) { *out_decided = 1; return 0; } if (s.u == SLOT_TRUE_BITS) { *out_decided = 1; return 1; } + if (slot_is_smi(s)) { *out_decided = 1; return slot_smi_val(s) != 0; } *out_decided = 0; return 0; } +/* #1758: a float's double, from an immediate or a VAL_NUM box (the VM boxes + * numbers on purpose: the lifts, a for-in variable). 0 for anything else, + * an int (an SMI, later a VAL_INT box) included: the caller sends it to its + * slow path. Replaces vm.c's slot_as_double. */ +static inline int slot_f64_value(EigsSlot s, double *out) { + if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } + if (slot_is_heap(s)) { + Value *v = slot_as_ptr(s); + if (v->type == VAL_NUM) { *out = VAL_NUM_RAW(v); return 1; } + } + return 0; +} +/* #1758: an int's value. R1.1 knows the SMI; R1.2a adds the VAL_INT box + * arm with the type it names. */ +static inline int slot_int_value(EigsSlot s, int64_t *out) { + if (slot_is_smi(s)) { *out = slot_smi_val(s); return 1; } + return 0; +} + /* Boundary shims declared here, defined in eigenscript.c. * * slot_from_value (takes ownership of the input ref): diff --git a/src/vm.c b/src/vm.c index 3c216efac..a79fdac35 100644 --- a/src/vm.c +++ b/src/vm.c @@ -115,7 +115,8 @@ static void obs_dump_num(double n, char *buf, size_t nbuf) { * out-of-scope slot-value race class; a summary reads only the header * words). No allocation. */ static void obs_dump_value(EigsSlot s, char *buf, size_t nbuf) { - if (slot_is_num(s)) { obs_dump_num(SLOT_NUM_RAW(s), buf, nbuf); return; } + if (slot_is_f64(s)) { obs_dump_num(SLOT_F64_RAW(s), buf, nbuf); return; } + if (slot_is_smi(s)) { snprintf(buf, nbuf, "%lld", (long long)slot_smi_val(s)); return; } /* #1758: exact digits */ if (slot_is_null(s)) { snprintf(buf, nbuf, "null"); return; } if (slot_is_bool(s)) { snprintf(buf, nbuf, "%s", slot_as_bool(s) ? "true" : "false"); return; } if (slot_is_ptr(s)) { @@ -210,8 +211,10 @@ static void obs_dump_scope(const char *scope, Env *e, int shared, * so refresh inline — observer_entropy_now would self-deadlock). * The band classifies the same refreshed view. */ ObserverSlot qs = *os; - if (slot_is_num(s)) { - qs.entropy = observer_entropy_of_num(SLOT_NUM_RAW(s)); + if (slot_is_f64(s)) { + qs.entropy = observer_entropy_of_num(SLOT_F64_RAW(s)); + } else if (slot_is_smi(s)) { /* #1758: an int, as its double */ + qs.entropy = observer_entropy_of_num((double)slot_smi_val(s)); } else if (slot_is_bool(s)) { qs.entropy = compute_entropy(make_bool(slot_as_bool(s))); /* #1637 */ } else if (slot_is_ptr(s)) { @@ -782,9 +785,9 @@ static inline EigsSlot slot_bridge_wrap(Value *v) { } static inline Value *slot_bridge_unwrap(EigsSlot s) { - if (slot_is_num(s)) { + if (slot_is_f64(s)) { /* Materialize immediate -> fresh Value. Caller owns one ref. */ - return make_num(SLOT_NUM_RAW(s)); + return make_num(SLOT_F64_RAW(s)); } if (slot_is_null(s)) { return make_null(); @@ -792,6 +795,8 @@ static inline Value *slot_bridge_unwrap(EigsSlot s) { if (slot_is_bool(s)) { return make_bool(slot_as_bool(s)); } + /* #1758: an int materializes through slot_to_value, the one SMI boxer. */ + if (slot_is_smi(s)) return slot_to_value(s); /* Heap or tracked: just unwrap the pointer (ref already in slot). */ return slot_as_ptr(s); } @@ -827,10 +832,13 @@ static inline Value *vm_slot_lift(int idx) { EigsSlot s = g_vm.stack[idx]; if (slot_is_ptr(s)) return slot_as_ptr(s); Value *v; - if (slot_is_num(s)) v = make_num(SLOT_NUM_RAW(s)); + if (slot_is_f64(s)) v = make_num(SLOT_F64_RAW(s)); else if (slot_is_null(s)) v = make_null(); else if (slot_is_bool(s)) v = make_bool(slot_as_bool(s)); - else v = make_null(); + /* #1758: an int is boxed on purpose, like a double (design 2.1); a + * reserved tag used to become null here, silently. */ + else if (slot_is_smi(s)) v = slot_to_value(s); + else eigs_slot_refuse("vm_slot_lift", s); g_vm.stack[idx] = slot_from_heap(v); return v; } @@ -858,25 +866,23 @@ static inline void vm_push_slot(EigsSlot s) { } /* Slot-aware truthiness — covers immediate num, null, bool, and falls - * back to is_truthy() for heap/tracked. */ + * back to is_truthy() for heap/tracked. #1758: an int is truthy when it is + * not 0, like a double; a reserved tag aborts instead of being dereferenced. */ static inline int slot_truthy(EigsSlot s) { - if (slot_is_num(s)) return SLOT_NUM_RAW(s) != 0.0; + if (slot_is_f64(s)) return SLOT_F64_RAW(s) != 0.0; if (slot_is_null(s)) return 0; if (slot_is_bool(s)) return slot_as_bool(s); - return is_truthy(slot_as_ptr(s)); + if (slot_is_heap(s)) return is_truthy(slot_as_ptr(s)); + if (slot_is_smi(s)) return slot_smi_val(s) != 0; + eigs_slot_refuse("slot_truthy", s); } -/* Pull a double out of a slot if it represents a number. Covers both - * immediate doubles and heap/tracked VAL_NUMs (which still appear from - * env loads and from the constant pool until B-3 flips those). */ -static inline int slot_as_double(EigsSlot s, double *out) { - if (slot_is_num(s)) { *out = SLOT_NUM_RAW(s); return 1; } - if (slot_is_ptr(s)) { - Value *v = slot_as_ptr(s); - if (v->type == VAL_NUM) { *out = VAL_NUM_RAW(v); return 1; } - } - return 0; -} +/* #1758 R1.1: vm.c's slot_as_double is gone. Its readers now call + * slot_f64_value (value_slot.h), which answers only for a FLOAT; each one + * decided what an int does there: the arithmetic, comparison, negation and + * bitwise arms send it to their slow path or type error, which R1.3 gives + * the int semantics (design 8); the leaf evaluator bails, so the generic + * call computes it (design 4.5). */ static inline uint16_t read_u16(uint8_t *ip) { return ip[0] | (ip[1] << 8); @@ -1154,13 +1160,13 @@ static inline Env *env_resolve_store(Env *start, const char *name, uint32_t h, * speed: g_last_observer may alias the exclusive VAL_NUM being overwritten, * and a swap+decref would free it under the observer. */ static inline void vm_store_local_slot(Env *e, int slot, EigsSlot tos) { - if (slot_is_num(tos)) { + if (slot_is_f64(tos)) { EigsSlot ex_s = e->values[slot]; if (slot_is_heap(ex_s)) { Value *existing = slot_as_ptr(ex_s); if (existing && existing->type == VAL_NUM && existing->refcount == 1) { - VAL_NUM_RAW(existing) = SLOT_NUM_RAW(tos); + VAL_NUM_RAW(existing) = SLOT_F64_RAW(tos); return; } } @@ -1351,7 +1357,7 @@ int jit_helper_local_idx_get(int slot, int idx) { int i = idx; if (target->type == VAL_BUFFER) { if (i < target->data.buffer.count) { - vm_push_slot(slot_from_num(buffer_read_num(target, i))); + vm_push_slot(slot_from_f64(buffer_read_num(target, i))); } else { rt_error(EK_INDEX, g_vm.current_line, "buffer index %d out of range (length %d)", @@ -1512,10 +1518,10 @@ void jit_helper_dot_set(EigsChunk *chunk, int name_idx) { * per DMG step via the vm_pop materialization below. */ EigsSlot val_s = g_vm.stack[g_vm.sp - 1]; EigsSlot tgt_s = g_vm.stack[g_vm.sp - 2]; - if (slot_is_num(val_s) && slot_is_ptr(tgt_s)) { + if (slot_is_f64(val_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); if (target->type == VAL_DICT && - dict_set_cached_immediate(target, key, h, SLOT_NUM_RAW(val_s))) { + dict_set_cached_immediate(target, key, h, SLOT_F64_RAW(val_s))) { /* Same net stack effect as the slow path: pop val + target, * push val (val is immediate — no refcount sides). */ g_vm.sp -= 1; @@ -1582,8 +1588,8 @@ void jit_helper_local_dot_set(EigsChunk *chunk, int slot, int name_idx) { if (chunk->const_hashes) chunk->const_hashes[name_idx] = h; } EigsSlot tos = g_vm.stack[g_vm.sp - 1]; - if (slot_is_num(tos) && - dict_set_cached_immediate(target, key, h, SLOT_NUM_RAW(tos))) { + if (slot_is_f64(tos) && + dict_set_cached_immediate(target, key, h, SLOT_F64_RAW(tos))) { return; } Value *val = vm_slot_lift(g_vm.sp - 1); @@ -1627,8 +1633,22 @@ void jit_helper_observe_assign(EigsChunk *chunk, int name_idx) { * (entropy: false 0.0, true 1.0 — compute_entropy's VAL_BOOL band). Callers * test obs_slot_observable first: a heap pointer or a bool. Null is the only * value still not observed. */ +/* #1758 R1.1: an SMI (or a reserved tag) is refused: every caller first + * routes a number to the numeric channel (obs_slot_num), so an int that got + * here would be silently unobserved. A BOXED int is a pointer and goes to + * observer_slot_update's Value arm (R1.2). */ static inline int obs_slot_observable(EigsSlot s) { - return slot_is_ptr(s) || slot_is_bool(s); + if (slot_is_ptr(s) || slot_is_bool(s)) return 1; + if (slot_is_null(s) || slot_is_f64(s)) return 0; + eigs_slot_refuse("obs_slot_observable", s); +} +/* #1758: the observer's numeric channel takes a double -- a float's own, or + * an int's (exact: |SMI| < 2^47) until round 3 (design 7). 0 for anything + * that is not an immediate number. */ +static inline int obs_slot_num(EigsSlot s, double *out) { + if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } + if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } + return 0; } static inline Value *obs_slot_value(EigsSlot s) { return slot_is_bool(s) ? make_bool(slot_as_bool(s)) : slot_as_ptr(s); @@ -1672,14 +1692,15 @@ void jit_helper_observe_assign_local(int slot) { CallFrame *frame = &g_vm.frames[g_vm.frame_count - 1]; EigsSlot s = g_vm.stack[g_vm.sp - 1]; Env *e = frame->fn_env; + double d; if (g_unobserved_depth != 0) { /* #1049: elided — value-window sample only (mirrors the CASE body). */ - if (slot_is_num(s)) jit_sample_num_gated(e, slot, SLOT_NUM_RAW(s)); + if (obs_slot_num(s, &d)) jit_sample_num_gated(e, slot, d); else if (obs_slot_observable(s)) observer_slot_sample_gated(e, slot, obs_slot_value(s)); return; } - if (slot_is_num(s)) { - observer_slot_update_num(e, slot, SLOT_NUM_RAW(s)); + if (obs_slot_num(s, &d)) { + observer_slot_update_num(e, slot, d); g_last_obs_slot_env = e; g_last_obs_slot_idx = slot; } else if (obs_slot_observable(s)) { observer_slot_update(e, slot, obs_slot_value(s)); @@ -1727,19 +1748,21 @@ void jit_helper_observe_name_post(EigsChunk *chunk, int name_idx) { /* #262 Phase-3 D: TOS may be an immediate num (the default path no longer * promotes observed names to tracked Values) or a heap value — observe the * slot from whichever (#1637: a bool too). Skip null. */ - if (!slot_is_num(s) && !obs_slot_observable(s)) return; + double d; + int isnum = obs_slot_num(s, &d); /* #1758: a float or an int */ + if (!isnum && !obs_slot_observable(s)) return; const char *name = chunk->const_interns[name_idx]; uint32_t h = chunk->const_hashes ? chunk->const_hashes[name_idx] : 0; if (h == 0) { h = env_hash_name(name); if (chunk->const_hashes) chunk->const_hashes[name_idx] = h; } int oidx = -1, odepth = 0; Env *oe = env_resolve_chain(frame->env, name, h, &oidx, &odepth); if (oe && oidx >= 0 && g_unobserved_depth != 0) { - if (slot_is_num(s)) observer_slot_sample_num_gated(oe, oidx, SLOT_NUM_RAW(s)); - else observer_slot_sample_gated(oe, oidx, obs_slot_value(s)); + if (isnum) observer_slot_sample_num_gated(oe, oidx, d); + else observer_slot_sample_gated(oe, oidx, obs_slot_value(s)); return; } if (oe && oidx >= 0) { - if (slot_is_num(s)) observer_slot_update_num(oe, oidx, SLOT_NUM_RAW(s)); + if (isnum) observer_slot_update_num(oe, oidx, d); else observer_slot_update(oe, oidx, obs_slot_value(s)); g_last_obs_slot_env = oe; g_last_obs_slot_idx = oidx; @@ -1790,7 +1813,7 @@ int jit_helper_iter_next(void) { if (idx >= len) return 1; EigsSlot elem; if (iterable->type == VAL_BUFFER) { - elem = slot_from_num(num_guard(buffer_read_num(iterable, idx))); + elem = slot_from_f64(num_guard(buffer_read_num(iterable, idx))); } else { elem = slot_read_owned(list_slot(iterable, idx)); } @@ -1866,14 +1889,14 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { case OP_CONST: { uint16_t idx = read_u16(ip); ip += 2; /* Scanner guarantees VAL_NUM. */ - mini[msp++] = slot_from_num(VAL_NUM_RAW(c->constants[idx])); + mini[msp++] = slot_from_f64(VAL_NUM_RAW(c->constants[idx])); break; } case OP_NUM_ZERO: - mini[msp++] = slot_from_num(0.0); + mini[msp++] = slot_from_f64(0.0); break; case OP_NUM_ONE: - mini[msp++] = slot_from_num(1.0); + mini[msp++] = slot_from_f64(1.0); break; case OP_GET_LOCAL: { uint16_t slot = read_u16(ip); ip += 2; @@ -1908,9 +1931,11 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { EigsSlot idx_s = mini[--msp]; EigsSlot tgt_s = mini[--msp]; double idx_d; - /* slot_as_double: immediate OR boxed VAL_NUM index — a for-in - * loop variable arrives as a heap num, same as ARITH_FAST. */ - if (!slot_as_double(idx_s, &idx_d) || !slot_is_ptr(tgt_s)) return 0; + /* slot_f64_value: immediate OR boxed VAL_NUM index — a for-in + * loop variable arrives as a heap num, same as ARITH_FAST. + * #1758: an int index is not a float: bail, and the generic call + * indexes with it (design 4.5; round 5 adds the SMI index). */ + if (!slot_f64_value(idx_s, &idx_d) || !slot_is_ptr(tgt_s)) return 0; Value *target = slot_as_ptr(tgt_s); int i; if (!vm_index_is_int(idx_d, &i)) return 0; @@ -1924,7 +1949,7 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { * the indexed expression, before the guard can raise here. */ double raw = target->data.buffer.data[i]; if (g_strict && raw != raw) return 0; - mini[msp++] = slot_from_num(buffer_read_num(target, i)); + mini[msp++] = slot_from_f64(buffer_read_num(target, i)); } else { return 0; } @@ -1932,8 +1957,11 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { } case OP_ADD: case OP_SUB: case OP_MUL: { double a, b; - if (!slot_as_double(mini[msp - 2], &a) || - !slot_as_double(mini[msp - 1], &b)) + /* #1758: both operands must be floats. An int or mixed operation + * bails, so the generic path computes it with the caller's line + * (design 4.5; round 5 adds int arms whose overflow bails). */ + if (!slot_f64_value(mini[msp - 2], &a) || + !slot_f64_value(mini[msp - 1], &b)) return 0; double r; switch (ip[-1]) { @@ -1951,7 +1979,7 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { break; } msp--; - mini[msp - 1] = slot_from_num(num_guard(r)); + mini[msp - 1] = slot_from_f64(num_guard(r)); break; } case OP_RETURN: { @@ -2041,8 +2069,8 @@ static void loop_iter_store(Env *env, double n) { } LoopIterCache *c = &g_loop_iter_cache; if (c->env == env && c->version == env->binding_version && - slot_is_num(env->values[c->slot])) { - SLOT_NUM_RAW(env->values[c->slot]) = n; + slot_is_f64(env->values[c->slot])) { + SLOT_F64_RAW(env->values[c->slot]) = n; if (env->assign_counts) env->assign_counts[c->slot]++; return; @@ -2169,14 +2197,14 @@ void jit_helper_index_set(void) { EigsSlot val_s = g_vm.stack[g_vm.sp - 1]; EigsSlot idx_s = g_vm.stack[g_vm.sp - 2]; EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; - if (slot_is_num(idx_s) && slot_is_ptr(tgt_s)) { + if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_NUM_RAW(idx_s), &i); - if (target->type == VAL_BUFFER && slot_is_num(val_s)) { + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { - target->data.buffer.data[i] = SLOT_NUM_RAW(val_s); + target->data.buffer.data[i] = SLOT_F64_RAW(val_s); } else { - if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, g_vm.current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); } @@ -2186,12 +2214,12 @@ void jit_helper_index_set(void) { slot_decref(tgt_s); return; } - if (target->type == VAL_LIST && slot_is_num(val_s)) { + if (target->type == VAL_LIST && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { - double n = SLOT_NUM_RAW(val_s); /* already guarded in a slot */ + double n = SLOT_F64_RAW(val_s); /* already guarded in a slot */ list_rewrite_num(target, i, n); } else { - if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, g_vm.current_line, "index %d out of range (list length %d)", i, target->data.list.count); } @@ -2239,16 +2267,16 @@ int jit_helper_index_get(void) { EigsSlot idx_s = g_vm.stack[g_vm.sp - 1]; EigsSlot tgt_s = g_vm.stack[g_vm.sp - 2]; g_vm.sp -= 2; - if (slot_is_num(idx_s) && slot_is_ptr(tgt_s)) { + if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_NUM_RAW(idx_s), &i); + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_LIST) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { EigsSlot r = slot_read_owned(list_slot(target, i)); slot_decref(tgt_s); vm_push_slot(r); } else { - if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, g_vm.current_line, "index %d out of range (list length %d)", i, target->data.list.count); @@ -2261,9 +2289,9 @@ int jit_helper_index_get(void) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { double v = buffer_read_num(target, i); slot_decref(tgt_s); - vm_push_slot(slot_from_num(v)); + vm_push_slot(slot_from_f64(v)); } else { - if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, g_vm.current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); @@ -3001,7 +3029,9 @@ static const char *slot_type_name(EigsSlot s) { if (slot_is_null(s)) return "none"; if (slot_is_ptr(s)) { Value *v = slot_as_ptr(s); return v ? val_type_name(v->type) : "none"; } if (slot_is_bool(s)) return "bool"; /* #1637 */ - return "num"; /* immediate double */ + if (slot_is_f64(s)) return "num"; /* immediate double */ + if (slot_is_smi(s)) return "num"; /* #1758 (B): an int's type is "num" too */ + eigs_slot_refuse("slot_type_name", s); } /* #408: forward decls — the copying-stack save/restore and the "who is @@ -3241,7 +3271,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, /* Numeric constants without observer state ship as immediates — * skips an incref/decref pair on every push/pop. */ if (v->type == VAL_NUM) { - vm_push_slot(slot_from_num(VAL_NUM_RAW(v))); + vm_push_slot(slot_from_f64(VAL_NUM_RAW(v))); } else { val_incref(v); vm_push(v); @@ -3255,12 +3285,12 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } CASE(NUM_ZERO): { - vm_push_slot(slot_from_num(0.0)); + vm_push_slot(slot_from_f64(0.0)); DISPATCH(); } CASE(NUM_ONE): { - vm_push_slot(slot_from_num(1.0)); + vm_push_slot(slot_from_f64(1.0)); DISPATCH(); } @@ -3291,7 +3321,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ double _ad, _bd; \ - if (__builtin_expect(slot_as_double(_as, &_ad) & slot_as_double(_bs, &_bd), 1)) { \ + if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ double _r = num_guard(_ad OP _bd); \ if ((UF) && _r == 0.0 && _ad != 0.0 && _bd != 0.0) \ g_math_flags |= EIGS_MATH_UNDERFLOW; \ @@ -3315,7 +3345,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } \ } \ slot_decref(_as); slot_decref(_bs); \ - g_vm.stack[g_vm.sp - 2] = slot_from_num(_r); \ + g_vm.stack[g_vm.sp - 2] = slot_from_f64(_r); \ g_vm.sp--; \ DISPATCH(); \ } \ @@ -3461,14 +3491,14 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ double _ad, _bd; \ - if (__builtin_expect(slot_as_double(_as, &_ad) & slot_as_double(_bs, &_bd), 1)) { \ + if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ int64_t _ai, _bi; \ if (__builtin_expect(!num_to_i64_exact(_ad, &_ai) || \ !num_to_i64_exact(_bd, &_bi), 0)) { \ slot_decref(_as); slot_decref(_bs); \ rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, OPNAME, \ num_to_i64_exact(_ad, &_ai) ? _bd : _ad); \ - g_vm.stack[g_vm.sp - 2] = slot_from_num(0.0); \ + g_vm.stack[g_vm.sp - 2] = slot_from_f64(0.0); \ g_vm.sp--; \ DISPATCH(); \ } \ @@ -3482,7 +3512,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (NUM_REUSE(_b)) { VAL_NUM_RAW(_b) = _r; g_vm.stack[g_vm.sp - 2] = _bs; slot_decref(_as); g_vm.sp--; DISPATCH(); } \ } \ slot_decref(_as); slot_decref(_bs); \ - g_vm.stack[g_vm.sp - 2] = slot_from_num(_r); \ + g_vm.stack[g_vm.sp - 2] = slot_from_f64(_r); \ g_vm.sp--; \ DISPATCH(); \ } \ @@ -3495,7 +3525,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, rt_error(EK_TYPE, current_line, "cannot apply '%s' to %s and %s", \ OPNAME, _tna, _tnb); \ } \ - g_vm.stack[g_vm.sp - 2] = slot_from_num(0.0); \ + g_vm.stack[g_vm.sp - 2] = slot_from_f64(0.0); \ g_vm.sp--; \ DISPATCH(); \ } @@ -3522,18 +3552,18 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NEG): { EigsSlot s = g_vm.stack[g_vm.sp - 1]; double d; - if (__builtin_expect(slot_as_double(s, &d), 1)) { + if (__builtin_expect(slot_f64_value(s, &d), 1)) { if (slot_is_ptr(s)) { Value *v = slot_as_ptr(s); if (NUM_REUSE(v)) { VAL_NUM_RAW(v) = -d; DISPATCH(); } } slot_decref(s); - g_vm.stack[g_vm.sp - 1] = slot_from_num(-d); + g_vm.stack[g_vm.sp - 1] = slot_from_f64(-d); DISPATCH(); } rt_error(EK_TYPE, current_line, "cannot negate %s", slot_type_name(s)); /* #1637: names bool */ slot_decref(s); - g_vm.stack[g_vm.sp - 1] = slot_from_num(0.0); + g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); DISPATCH(); } @@ -3548,12 +3578,12 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(BNOT): { EigsSlot s = g_vm.stack[g_vm.sp - 1]; double d; - if (__builtin_expect(slot_as_double(s, &d), 1)) { + if (__builtin_expect(slot_f64_value(s, &d), 1)) { int64_t i; if (__builtin_expect(!num_to_i64_exact(d, &i), 0)) { /* #1740 */ slot_decref(s); rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, "~", d); - g_vm.stack[g_vm.sp - 1] = slot_from_num(0.0); + g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); DISPATCH(); } double r = (double)(~i); @@ -3562,7 +3592,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (NUM_REUSE(v)) { VAL_NUM_RAW(v) = r; DISPATCH(); } } slot_decref(s); - g_vm.stack[g_vm.sp - 1] = slot_from_num(r); + g_vm.stack[g_vm.sp - 1] = slot_from_f64(r); DISPATCH(); } { @@ -3570,7 +3600,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, slot_decref(s); rt_error(EK_TYPE, current_line, "cannot apply '~' to %s", _tn); } - g_vm.stack[g_vm.sp - 1] = slot_from_num(0.0); + g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); DISPATCH(); } @@ -3580,7 +3610,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; double _ad, _bd; - if (__builtin_expect(slot_as_double(_as, &_ad) & slot_as_double(_bs, &_bd), 1)) { + if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE * branches wrote a 0/1 result INTO a heap-number operand; a bool * cannot live there, so they are gone, not retagged. */ @@ -3601,7 +3631,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; double _ad, _bd; - if (__builtin_expect(slot_as_double(_as, &_ad) & slot_as_double(_bs, &_bd), 1)) { + if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE * branches wrote a 0/1 result INTO a heap-number operand; a bool * cannot live there, so they are gone, not retagged. */ @@ -3623,7 +3653,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ double _ad, _bd; \ - if (__builtin_expect(slot_as_double(_as, &_ad) & slot_as_double(_bs, &_bd), 1)) { \ + if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ /* #1637: a bool immediate; no NUM_REUSE (see CASE(EQ)). */ \ int _r = (_ad OP _bd); \ slot_decref(_as); slot_decref(_bs); \ @@ -4032,10 +4062,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, chunk_decref(chunk); if (g_vm.frame_count <= base_frame) { EigsSlot result_s = g_vm.stack[--g_vm.sp]; - if (slot_is_num(result_s)) return make_num(SLOT_NUM_RAW(result_s)); - if (slot_is_null(result_s)) return make_null(); - if (slot_is_bool(result_s)) return make_bool(slot_as_bool(result_s)); - return slot_as_ptr(result_s); + /* Transfer the slot's owned ref into a Value*: the one conversion, + * with its #1758 int arm (it was spelled out at four sites). */ + return slot_bridge_unwrap(result_s); } frame = &g_vm.frames[g_vm.frame_count - 1]; ip = frame->ip; @@ -4395,10 +4424,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, chunk_decref(fn_chunk); if (g_vm.frame_count <= base_frame) { EigsSlot result_s = g_vm.stack[--g_vm.sp]; - if (slot_is_num(result_s)) return make_num(SLOT_NUM_RAW(result_s)); - if (slot_is_null(result_s)) return make_null(); - if (slot_is_bool(result_s)) return make_bool(slot_as_bool(result_s)); - return slot_as_ptr(result_s); + /* Transfer the slot's owned ref into a Value*: the one conversion, + * with its #1758 int arm (it was spelled out at four sites). */ + return slot_bridge_unwrap(result_s); } frame = &g_vm.frames[g_vm.frame_count - 1]; ip = frame->ip; @@ -4476,11 +4504,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.frame_count--; if (g_vm.frame_count <= base_frame) { /* Return to C: transfer slot's owned ref into a Value*. - * Immediate -> materialize; pointer -> reuse slot's ref. */ - if (slot_is_num(result_s)) return make_num(SLOT_NUM_RAW(result_s)); - if (slot_is_null(result_s)) return make_null(); - if (slot_is_bool(result_s)) return make_bool(slot_as_bool(result_s)); - return slot_as_ptr(result_s); + * Immediate -> materialize; pointer -> reuse slot's ref. One + * conversion, with its #1758 int arm (it was spelled out at + * four sites). */ + return slot_bridge_unwrap(result_s); } frame = &g_vm.frames[g_vm.frame_count - 1]; ip = frame->ip; @@ -4561,16 +4588,16 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot idx_s = g_vm.stack[g_vm.sp - 1]; EigsSlot tgt_s = g_vm.stack[g_vm.sp - 2]; g_vm.sp -= 2; - if (slot_is_num(idx_s) && slot_is_ptr(tgt_s)) { + if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_NUM_RAW(idx_s), &i); + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_LIST) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { EigsSlot r = slot_read_owned(list_slot(target, i)); slot_decref(tgt_s); vm_push_slot(r); } else { - if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, current_line, "index %d out of range (list length %d)", i, target->data.list.count); slot_decref(tgt_s); @@ -4582,9 +4609,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { double v = buffer_read_num(target, i); slot_decref(tgt_s); - vm_push_slot(slot_from_num(v)); + vm_push_slot(slot_from_f64(v)); } else { - if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); slot_decref(tgt_s); @@ -4644,14 +4671,14 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot val_s = g_vm.stack[g_vm.sp - 1]; EigsSlot idx_s = g_vm.stack[g_vm.sp - 2]; EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; - if (slot_is_num(idx_s) && slot_is_ptr(tgt_s)) { + if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_NUM_RAW(idx_s), &i); - if (target->type == VAL_BUFFER && slot_is_num(val_s)) { + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { - target->data.buffer.data[i] = SLOT_NUM_RAW(val_s); + target->data.buffer.data[i] = SLOT_F64_RAW(val_s); } else { - if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); } @@ -4661,11 +4688,11 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, slot_decref(tgt_s); DISPATCH(); } - if (target->type == VAL_LIST && slot_is_num(val_s)) { + if (target->type == VAL_LIST && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { - list_set_num(target, i, SLOT_NUM_RAW(val_s)); + list_set_num(target, i, SLOT_F64_RAW(val_s)); } else { - if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_NUM_RAW(idx_s)); + if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, current_line, "index %d out of range (list length %d)", i, target->data.list.count); } @@ -4750,10 +4777,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, { EigsSlot val_s = g_vm.stack[g_vm.sp - 1]; EigsSlot tgt_s = g_vm.stack[g_vm.sp - 2]; - if (slot_is_num(val_s) && slot_is_ptr(tgt_s)) { + if (slot_is_f64(val_s) && slot_is_ptr(tgt_s)) { Value *t = slot_as_ptr(tgt_s); if (t->type == VAL_DICT && - dict_set_cached_immediate(t, key, h, SLOT_NUM_RAW(val_s))) { + dict_set_cached_immediate(t, key, h, SLOT_F64_RAW(val_s))) { g_vm.sp -= 1; g_vm.stack[g_vm.sp - 1] = val_s; slot_decref(tgt_s); @@ -4814,8 +4841,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, uint32_t h = chunk->const_hashes ? chunk->const_hashes[name_idx] : 0; if (h == 0) { h = env_hash_name(key); if (chunk->const_hashes) chunk->const_hashes[name_idx] = h; } EigsSlot tos = g_vm.stack[g_vm.sp - 1]; - if (slot_is_num(tos) && - dict_set_cached_immediate(target, key, h, SLOT_NUM_RAW(tos))) { + if (slot_is_f64(tos) && + dict_set_cached_immediate(target, key, h, SLOT_F64_RAW(tos))) { DISPATCH(); } Value *val = vm_slot_lift(g_vm.sp - 1); @@ -4841,7 +4868,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (target->type == VAL_BUFFER) { /* DMG hot path: mem[addr] — emit immediate, skip make_num. */ if (i < target->data.buffer.count) { - vm_push_slot(slot_from_num(buffer_read_num(target, i))); + vm_push_slot(slot_from_f64(buffer_read_num(target, i))); } else { rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); @@ -4947,8 +4974,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * mutate the existing dict slot's data.num in place * and leave the stack slot as an immediate (no lift). */ EigsSlot tos = g_vm.stack[g_vm.sp - 1]; - if (slot_is_num(tos) && - dict_set_cached_immediate(dict, key, h, SLOT_NUM_RAW(tos))) { + if (slot_is_f64(tos) && + dict_set_cached_immediate(dict, key, h, SLOT_F64_RAW(tos))) { eigs_view_check(&dict_view); DISPATCH(); } @@ -5025,7 +5052,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (iterable->type == VAL_BUFFER) { /* Push number immediate directly — skip make_num + immediate- * promote round-trip through vm_push. */ - vm_push_slot(slot_from_num(buffer_read_num(iterable, idx))); + vm_push_slot(slot_from_f64(buffer_read_num(iterable, idx))); } else { EigsSlot elem = slot_read_owned(list_slot(iterable, idx)); vm_push_slot(elem); @@ -5183,8 +5210,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * the slot persists across assignments, which is the #262 fix. */ EigsSlot s = g_vm.stack[g_vm.sp - 1]; Env *e = frame->fn_env; - if (slot_is_num(s)) { - observer_slot_update_num(e, (int)slot, SLOT_NUM_RAW(s)); + double d; + if (obs_slot_num(s, &d)) { /* #1758: a float or an int */ + observer_slot_update_num(e, (int)slot, d); g_last_obs_slot_env = e; g_last_obs_slot_idx = (int)slot; } else if (obs_slot_observable(s)) { observer_slot_update(e, (int)slot, obs_slot_value(s)); @@ -5197,8 +5225,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * observer_slot_sample_num (eigenscript.c). */ EigsSlot s = g_vm.stack[g_vm.sp - 1]; Env *e = frame->fn_env; + double d; eigs_obs_count_call(); - if (slot_is_num(s)) observer_slot_sample_num_gated(e, (int)slot, SLOT_NUM_RAW(s)); + if (obs_slot_num(s, &d)) observer_slot_sample_num_gated(e, (int)slot, d); else if (obs_slot_observable(s)) observer_slot_sample_gated(e, (int)slot, obs_slot_value(s)); } DISPATCH(); @@ -5428,7 +5457,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, /* #262 Phase-3 D: TOS is now an immediate num for an observed name * (default path no longer promotes), or a heap value. Observe the * slot from whichever (#1637: a bool too); skip null. */ - if (slot_is_num(s) || obs_slot_observable(s)) { + double d; + int isnum = obs_slot_num(s, &d); /* #1758: a float or an int */ + if (isnum || obs_slot_observable(s)) { const char *name = chunk->const_interns[name_idx]; uint32_t h = chunk->const_hashes ? chunk->const_hashes[name_idx] : 0; if (h == 0) { h = env_hash_name(name); if (chunk->const_hashes) chunk->const_hashes[name_idx] = h; } @@ -5436,10 +5467,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, Env *oe = env_resolve_chain(frame->env, name, h, &oidx, &odepth); if (oe && oidx >= 0 && g_unobserved_depth != 0) { eigs_obs_count_call(); - if (slot_is_num(s)) observer_slot_sample_num_gated(oe, oidx, SLOT_NUM_RAW(s)); - else observer_slot_sample_gated(oe, oidx, obs_slot_value(s)); + if (isnum) observer_slot_sample_num_gated(oe, oidx, d); + else observer_slot_sample_gated(oe, oidx, obs_slot_value(s)); } else if (oe && oidx >= 0) { - if (slot_is_num(s)) observer_slot_update_num(oe, oidx, SLOT_NUM_RAW(s)); + if (isnum) observer_slot_update_num(oe, oidx, d); else observer_slot_update(oe, oidx, obs_slot_value(s)); g_last_obs_slot_env = oe; g_last_obs_slot_idx = oidx; @@ -5735,10 +5766,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, #define READ_SLICE_BOUND(slot, defval, outvar) \ do { \ - if (slot_is_num(slot)) { \ - if (!vm_index_is_int(SLOT_NUM_RAW(slot), &(outvar))) { \ + if (slot_is_f64(slot)) { \ + if (!vm_index_is_int(SLOT_F64_RAW(slot), &(outvar))) { \ rt_error(EK_VALUE, g_vm.current_line, \ - "slice bound must be an integer, got %g", SLOT_NUM_RAW(slot));\ + "slice bound must be an integer, got %g", SLOT_F64_RAW(slot));\ bound_err = 1; \ } \ } else if (slot_is_ptr(slot)) { \ @@ -5760,6 +5791,18 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } \ } else if (slot_is_null(slot)) { \ (outvar) = (defval); /* an omitted bound */ \ + } else if (slot_is_smi(slot)) { \ + /* #1758: an int bound is its value, when an int \ + * (the C type) holds it. */ \ + int64_t _bv = slot_smi_val(slot); \ + if (_bv < INT_MIN || _bv > INT_MAX) { \ + rt_error(EK_VALUE, g_vm.current_line, \ + "slice bound %lld is out of range", \ + (long long)_bv); \ + bound_err = 1; \ + } else { \ + (outvar) = (int)_bv; \ + } \ } else { \ /* #1637: an immediate bool (or any other non-number \ * slot) is not a bound -- never the default one. */ \ @@ -6345,8 +6388,20 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.sp -= 3; double key_d; - if (slot_is_num(key_s)) { - key_d = SLOT_NUM_RAW(key_s); + if (slot_is_f64(key_s)) { + key_d = SLOT_F64_RAW(key_s); + } else if (slot_is_smi(key_s)) { + /* #1758: an int key is its value, when an int (the C type) holds + * it; the double is then exact and the index rule below takes it. */ + int64_t kv = slot_smi_val(key_s); + if (kv < INT_MIN || kv > INT_MAX) { + slot_decref(arg_s); slot_decref(key_s); slot_decref(table_s); + rt_error(EK_VALUE, current_line, "dispatch key %lld is out of range", + (long long)kv); + vm_push_slot(slot_null()); + DISPATCH(); + } + key_d = (double)kv; } else if (slot_is_ptr(key_s) && slot_as_ptr(key_s) && slot_as_ptr(key_s)->type == VAL_NUM) { key_d = VAL_NUM_RAW(slot_as_ptr(key_s)); @@ -6493,10 +6548,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (g_vm.frame_count <= base_frame) { EigsSlot result_s = g_vm.stack[--g_vm.sp]; eigs_view_check(&fn_view); - if (slot_is_num(result_s)) return make_num(SLOT_NUM_RAW(result_s)); - if (slot_is_null(result_s)) return make_null(); - if (slot_is_bool(result_s)) return make_bool(slot_as_bool(result_s)); - return slot_as_ptr(result_s); + /* Transfer the slot's owned ref into a Value*: the one conversion, + * with its #1758 int arm (it was spelled out at four sites). */ + return slot_bridge_unwrap(result_s); } frame = &g_vm.frames[g_vm.frame_count - 1]; ip = frame->ip; diff --git a/tests/sections/0fb-bool-type.sh b/tests/sections/0fb-bool-type.sh index 265604b7e..caf0bed2b 100644 --- a/tests/sections/0fb-bool-type.sh +++ b/tests/sections/0fb-bool-type.sh @@ -36,7 +36,7 @@ else fi unset BOOL_JIT_OUT BOOL_JIT_RC # The class gate (#1637 round 4): the number members are renamed, so a raw -# read is a VAL_NUM_RAW / SLOT_NUM_RAW token; every token sits in a reviewed +# read is a VAL_NUM_RAW / SLOT_F64_RAW token; every token sits in a reviewed # function with its exact count, and every builtin call passes the bool gate # (tools/num_read_check.sh). TOTAL=$((TOTAL + 1)) diff --git a/tests/test_container_slots.c b/tests/test_container_slots.c index b6404630f..b52b2abbd 100644 --- a/tests/test_container_slots.c +++ b/tests/test_container_slots.c @@ -25,7 +25,7 @@ int main(int argc, char **argv) { static EigsView escaped; Value *arg = make_list(1); list_append_num(arg, 1.0); - vm_borrow_compensate(arg, slot_view(slot_from_num(1665.0), &escaped), 1, NULL, NULL); + vm_borrow_compensate(arg, slot_view(slot_from_f64(1665.0), &escaped), 1, NULL, NULL); return 99; } Value *list = make_list(8); @@ -40,7 +40,7 @@ int main(int argc, char **argv) { /* Storage encodings: numbers immediate, null/bool singleton bits, refs heap. */ EigsSlot *raw = list_values_storage(list); - CHECK(slot_is_num(raw[0]) && SLOT_NUM_RAW(raw[0]) == 3.0); + CHECK(slot_is_f64(raw[0]) && SLOT_F64_RAW(raw[0]) == 3.0); CHECK(slot_is_heap(raw[1]) && slot_is_heap(raw[2])); CHECK(raw[3].u == SLOT_NULL_BITS && raw[4].u == SLOT_TRUE_BITS); CHECK(str->refcount == 1); /* one container ref; a list may also be GC-buffered */ @@ -70,7 +70,7 @@ int main(int argc, char **argv) { CHECK(eigs_slot_num(list_slot(list, 0), "test") == 4.0); /* A boxed number or a singleton stored through a heap slot is re-encoded. */ list_set_slot_owned(list, 2, slot_from_heap(make_num(5.0))); - CHECK(slot_is_num(list_values_storage(list)[2])); + CHECK(slot_is_f64(list_values_storage(list)[2])); list_set_owned(list, 3, make_bool(0)); CHECK(list_values_storage(list)[3].u == SLOT_FALSE_BITS); /* The NaN guard: the default x86 NaN must never be stored as null bits. */ @@ -79,7 +79,7 @@ int main(int argc, char **argv) { g_strict = 0; list_set_num(list, 4, -__builtin_nan("")); g_strict = strict; - CHECK(slot_is_num(list_values_storage(list)[4])); + CHECK(slot_is_f64(list_values_storage(list)[4])); } EigsSlot taken = list_take_slot(list, 0); CHECK(eigs_slot_num(taken, "test") == 4.0); @@ -93,7 +93,7 @@ int main(int argc, char **argv) { /* Zero bits are 0.0: a calloc'd slot array reads as numbers. */ Value *zeros = make_list(4); - CHECK(slot_is_num(list_values_storage(zeros)[0]) && zeros->data.list.count == 0); + CHECK(slot_is_f64(list_values_storage(zeros)[0]) && zeros->data.list.count == 0); Value *dict = make_dict(4); dict_set_owned(dict, "n", make_num(2)); @@ -104,7 +104,7 @@ int main(int argc, char **argv) { int ni = env_hash_find_dict(dict, "n", env_hash_name("n")); int si = env_hash_find_dict(dict, "s", env_hash_name("s")); CHECK(dict_value_type(dict, ni) == VAL_NUM && dict_value_get_ref(dict, ni) == NULL); - CHECK(slot_is_num(dict_values_storage(dict)[ni])); + CHECK(slot_is_f64(dict_values_storage(dict)[ni])); CHECK(eigs_slot_num(dict_value_slot(dict, ni), "test") == 2.0); { EIGS_VIEW(v); CHECK(eigs_num_arg(dict_value_get_view(dict, ni, &v), "test") == 2.0); } { EIGS_VIEW(v); Value *zv = dict_get_view(dict, "z", &v); diff --git a/tests/test_error_line_fallback.c b/tests/test_error_line_fallback.c index 6ce103ccf..48124e83c 100644 --- a/tests/test_error_line_fallback.c +++ b/tests/test_error_line_fallback.c @@ -150,22 +150,22 @@ int main(void) { static const char *const NM = "errline_1434"; EigsSlot sl, out; g_has_error = 0; /* a pending error halts the callback before it runs */ - g_trace_current_line = 70; SLOT_NUM_RAW(sl) = 1.0; trace_assign(NM, sl); + g_trace_current_line = 70; SLOT_F64_RAW(sl) = 1.0; trace_assign(NM, sl); g_trace_current_line = 80; r = builtin_sort_by(args_good); check(!g_has_error && r && r->type == VAL_LIST && r->data.list.count == 6001, "#1434 the history row's sort_by ran its callbacks"); if (r) val_decref(r); - SLOT_NUM_RAW(sl) = 2.0; trace_assign(NM, sl); + SLOT_F64_RAW(sl) = 2.0; trace_assign(NM, sl); trace_line(95); /* a stop right after the store, for [0b]'s `--step` query */ - check(trace_query_at(0, NM, 75, &out) && SLOT_NUM_RAW(out) == 1.0 && - trace_query_at(0, NM, 85, &out) && SLOT_NUM_RAW(out) == 2.0, + check(trace_query_at(0, NM, 75, &out) && SLOT_F64_RAW(out) == 1.0 && + trace_query_at(0, NM, 85, &out) && SLOT_F64_RAW(out) == 2.0, "#1434 a store after the callbacks is filed under the call's stamp"); /* The line live history filed the second store under, for [0b] to compare * with the tape stepper's `t` row over the same run's EIGS_TRACE tape. */ int filed = 0; for (int ln = 1; ln <= 100 && !filed; ln++) - if (trace_query_at(0, NM, ln, &out) && SLOT_NUM_RAW(out) == 2.0) filed = ln; + if (trace_query_at(0, NM, ln, &out) && SLOT_F64_RAW(out) == 2.0) filed = ln; printf("LIVE: %s=2 line %d\n", NM, filed); g_has_error = 0; diff --git a/tests/test_loop_counter_sequential.c b/tests/test_loop_counter_sequential.c index 169c975a1..f2467801b 100644 --- a/tests/test_loop_counter_sequential.c +++ b/tests/test_loop_counter_sequential.c @@ -40,9 +40,9 @@ static void step(Env *env, const char *label, int stall, * so sequential reads do not defeat the ordinary warm-cache path. * This getter returns a borrowed slot: do not decrement its ownership. */ EigsSlot value = env_get_hashed_slot(env, counter, 0, &found); - int numeric = slot_is_num(value) || + int numeric = slot_is_f64(value) || (slot_is_ptr(value) && slot_as_ptr(value)->type == VAL_NUM); - double actual = slot_is_num(value) ? SLOT_NUM_RAW(value) : + double actual = slot_is_f64(value) ? SLOT_F64_RAW(value) : (numeric ? VAL_NUM_RAW(slot_as_ptr(value)) : -1); int assignments = env_get_assign_count(env, counter, 0); int ok = rc == 0 && !g_has_error && found && numeric && diff --git a/tests/test_trace_history_boundary.c b/tests/test_trace_history_boundary.c index 62a154fe9..7cf5424e0 100644 --- a/tests/test_trace_history_boundary.c +++ b/tests/test_trace_history_boundary.c @@ -30,7 +30,7 @@ static void check(int ok, const char *name) { if (ok) passed++; else failed++; } static int number(EigsSlot value, double want) { - return slot_is_num(value) && SLOT_NUM_RAW(value) == want; + return slot_is_f64(value) && SLOT_F64_RAW(value) == want; } static int host_values(const PrevEntry *e) { return e->has_current && number(e->current, 22) && @@ -86,10 +86,10 @@ int main(void) { /* No history table exists yet. All four public assignment routes must * return before metadata or retention calls when the branch is active. */ g_sandbox_active = 1; - trace_assign(fresh, slot_from_num(1)); - trace_assign_filtered(fresh, slot_from_num(2)); - trace_assign_at_line(fresh, slot_from_num(3), 10); - trace_assign_filtered_at_line(fresh, slot_from_num(4), 20); + trace_assign(fresh, slot_from_f64(1)); + trace_assign_filtered(fresh, slot_from_f64(2)); + trace_assign_at_line(fresh, slot_from_f64(3), 10); + trace_assign_filtered_at_line(fresh, slot_from_f64(4), 20); trace_record_obs(fresh, .5, .25, .125); g_sandbox_active = 0; check(!g_prev_tab && g_prev_count == 0 && g_prev_cap == 0, @@ -99,13 +99,13 @@ int main(void) { /* Trusted unarmed producers still record; the ordinary filtered twin * still narrows. End this small control table before the host scenario. */ - trace_assign_at_line(fresh, slot_from_num(11), 10); + trace_assign_at_line(fresh, slot_from_f64(11), 10); EigsSlot direct = slot_null(); int direct_found = trace_query_at(0, fresh, 10, &direct); check(direct_found && number(direct, 11), "trusted unarmed producer records outside boundary"); if (direct_found) slot_decref(direct); - trace_assign_filtered_at_line(unarmed, slot_from_num(22), 20); + trace_assign_filtered_at_line(unarmed, slot_from_f64(22), 20); EigsSlot filtered = slot_null(); int filtered_found = trace_query_at(0, unarmed, 20, &filtered); check(!filtered_found, "ordinary filtered producer still omits unarmed values"); @@ -113,9 +113,9 @@ int main(void) { trace_thread_release(); trace_arm_occurrences_name(host); - trace_assign_at_line(host, slot_from_num(11), 10); + trace_assign_at_line(host, slot_from_f64(11), 10); trace_record_obs(host, .25, .125, .0625); - trace_assign_filtered_at_line(host, slot_from_num(22), 20); + trace_assign_filtered_at_line(host, slot_from_f64(22), 20); trace_record_obs(host, .5, .25, .125); check(g_prev_tab && g_prev_count == 1, "host producer creates one entry"); if (!g_prev_tab) goto done; @@ -135,8 +135,8 @@ int main(void) { PrevEntry *table = g_prev_tab; unsigned retained = retain_calls, incremented = incref_calls; g_sandbox_active = 1; - trace_assign(host, slot_from_num(33)); - trace_assign_filtered_at_line(host, slot_from_num(44), 30); + trace_assign(host, slot_from_f64(33)); + trace_assign_filtered_at_line(host, slot_from_f64(44), 30); trace_record_obs(host, 9, 8, 7); g_sandbox_active = 0; check(g_prev_tab == table && g_prev_count == count && g_prev_cap == capacity, @@ -154,10 +154,10 @@ int main(void) { * not override the history boundary. The same fixed name remains live. */ trace_set_sink(capture, &tape); g_sandbox_active = 1; - trace_assign(fresh, slot_from_num(5)); - trace_assign_filtered(fresh, slot_from_num(6)); - trace_assign_at_line(fresh, slot_from_num(7), 30); - trace_assign_filtered_at_line(fresh, slot_from_num(8), 40); + trace_assign(fresh, slot_from_f64(5)); + trace_assign_filtered(fresh, slot_from_f64(6)); + trace_assign_at_line(fresh, slot_from_f64(7), 30); + trace_assign_filtered_at_line(fresh, slot_from_f64(8), 40); trace_record_obs(host, 9, 8, 7); g_sandbox_active = 0; check(!tape.overflow && tape.assignments == 4 && @@ -174,7 +174,7 @@ int main(void) { check(host_observers(e) && host_occ_observers(e), "wildcard recording preserves both host observer snapshots"); - trace_assign_at_line(host, slot_from_num(33), 30); + trace_assign_at_line(host, slot_from_f64(33), 30); trace_record_obs(host, .75, .5, .25); check(number(e->current, 33) && number(e->prev, 22), "host producer resumes after boundary ends"); @@ -188,7 +188,7 @@ int main(void) { check(e->occ_total == 3 && e->occ_count == 3 && e->occ[2].obs_valid && e->occ[2].entropy == .75 && e->occ[2].dH == .5, "host occurrence observer recording resumes"); - trace_assign_tape_only(fresh, slot_from_num(9)); + trace_assign_tape_only(fresh, slot_from_f64(9)); check(tape.assignments == 6 && strstr(tape.bytes, "A 0 boundary_fresh=9\n") && g_prev_count == count, "explicit tape-only producer remains tape-only outside boundary"); diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 3dffd0a63..013776684 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -1,40 +1,40 @@ # tools/num_read_allowlist.txt -- every raw number token, reviewed (#1637 round 4). # file|function|count|reason. tools/num_read_check.sh counts VAL_NUM_RAW / -# SLOT_NUM_RAW / VAL_NUM_OFFSET tokens per function and fails when a count +# SLOT_F64_RAW / VAL_NUM_OFFSET tokens per function and fails when a count # differs (a new raw read, however it is spelled across lines, changes the # count), when a function with raw tokens is missing here, or a row is stale. # Builtins never belong here: they read through eigs_num_arg / eigs_list_num / # eigs_opt_num / eigs_elem_num, which raise on a bool. builtins_tensor.c|builtin_tensor_matmul|1|writes the NaN-boxed null sentinel into a result buffer cell (EIGS_STRICT=0 path); a write, no Value is read -container.h|dict_value_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_num test (#1665 arm D) -container.h|dict_value_get_return|1|builtin-return read boxes an immediate only after slot_is_num +container.h|dict_value_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) +container.h|dict_value_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 container.h|eigs_container_slot|1|Value-to-slot encoder reads a box only after type == VAL_NUM, then num_guards it -container.h|eigs_slot_store_borrow|1|storage normaliser re-guards an immediate only after slot_is_num (#1665 arm D B10) -container.h|eigs_slot_store_owned|1|storage normaliser re-guards an immediate only after slot_is_num (#1665 arm D B10) -container.h|eigs_slot_box|1|borrowed slot write boxes a double only after slot_is_num -container.h|eigs_slot_elem_num|1|element numeric accessor reads only after slot_is_num -container.h|eigs_slot_num|1|required numeric accessor reads only after slot_is_num -container.h|eigs_slot_opt_num|1|optional numeric accessor reads only after slot_is_num -container.h|list_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_num test (#1665 arm D) -container.h|list_get_return|1|builtin-return read boxes an immediate only after slot_is_num +container.h|eigs_slot_store_borrow|1|storage normaliser re-guards an immediate only after slot_is_f64 (#1665 arm D B10) +container.h|eigs_slot_store_owned|1|storage normaliser re-guards an immediate only after slot_is_f64 (#1665 arm D B10) +container.h|eigs_slot_box|1|borrowed slot write boxes a double only after slot_is_f64 +container.h|eigs_slot_elem_num|1|element numeric accessor reads only after slot_is_f64 +container.h|eigs_slot_num|1|required numeric accessor reads only after slot_is_f64 +container.h|eigs_slot_opt_num|1|optional numeric accessor reads only after slot_is_f64 +container.h|list_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) +container.h|list_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 container.h|slot_view|2|numeric view copies a proven immediate into caller storage chunk.c|chunk_disassemble|1|debug disassembly prints a constant behind its own type == VAL_NUM test chunk.c|const_equal|2|constant-pool dedup compares two constants after testing both are VAL_NUM chunk.c|const_hash_value|1|constant-pool hash of a constant inside its type == VAL_NUM branch eigenscript.c|chan_clone_rec|1|channel deep-copy, switch case VAL_NUM eigenscript.c|compute_entropy_impl|1|observer entropy, switch case VAL_NUM -eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_num +eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_f64 eigenscript.c|eigs_num_arg_slow|1|checking accessor itself: reads only after type == VAL_NUM, raises otherwise eigenscript.c|is_truthy|1|truthiness, switch case VAL_NUM (a bool has its own case) eigenscript.c|make_num|1|constructor: writes the number of a Value it just typed VAL_NUM eigenscript.c|make_num_permanent|1|constructor: writes the number of a Value it just typed VAL_NUM -eigenscript.c|module_ns_project|1|mirror refresh: reads the binding slot after slot_is_num and stores it over a numeric mirror slot -eigenscript.c|observer_entropy_now|1|observer entropy of a slot after slot_is_num +eigenscript.c|module_ns_project|1|mirror refresh: reads the binding slot after slot_is_f64 and stores it over a numeric mirror slot +eigenscript.c|observer_entropy_now|1|observer entropy of a slot after slot_is_f64 eigenscript.c|observer_slot_from_trajectory|6|trajectory snapshot fields each read right after its own type != VAL_NUM refusal eigenscript.c|observer_slot_sample_gated|1|observer sample after newval->type == VAL_NUM eigenscript.c|observer_slot_update|1|observer update after newval->type == VAL_NUM eigenscript.c|slot_from_value|1|NaN-boxing boundary, inside its VAL_NUM branch -eigenscript.c|slot_to_value|1|NaN-boxing boundary after slot_is_num +eigenscript.c|slot_to_value|1|NaN-boxing boundary after slot_is_f64 eigenscript.c|values_equal_impl|2|equality, switch case VAL_NUM after the bool/num pair raised eigenscript.c|value_to_string|1|printing, switch case VAL_NUM eigenscript.h|#define VAL_NUM_OFFSET|1|the raw member offset definition (JIT) @@ -51,29 +51,28 @@ jit_smoke.c|run_exit_cases|3|JIT smoke test program (stubbed helpers over slots jit_smoke.c|run_index_bail_cases|2|JIT smoke test program (stubbed helpers over slots it built as numbers) jit_smoke.c|run_reader_bail_cases|8|JIT smoke test program (stubbed helpers over slots it built as numbers) jit_smoke.c|run_store_cases|4|JIT smoke test program (stubbed helpers over slots it built as numbers) -trace.c|write_slot|1|tape writer after slot_is_num +trace.c|write_slot|1|tape writer after slot_is_f64 trace.c|write_value_ptr|1|tape writer, switch case VAL_NUM trace.c|write_value_ptr_full|1|tape writer, switch case VAL_NUM -value_slot.h|#define SLOT_NUM_RAW|1|the raw slot read definition -value_slot.h|slot_from_num|1|constructor: writes a number into a fresh slot -value_slot.h|slot_truthy_immediate|1|truthiness after slot_is_num +value_slot.h|#define SLOT_F64_RAW|1|the raw slot read definition (#1758: was SLOT_NUM_RAW) +value_slot.h|slot_f64_value|2|float reader (#1758: was vm.c slot_as_double): an immediate after slot_is_f64, a box after type == VAL_NUM; 0 for an int +value_slot.h|slot_from_f64|1|constructor: writes a double into a fresh slot (#1758: was slot_from_num) +value_slot.h|slot_truthy_immediate|1|truthiness after slot_is_f64 vm.c|#define ARITH_FAST|2|arithmetic fast path after both operands tested VAL_NUM; NUM_REUSE writes -vm.c|#define INT_BINOP_R|2|integer op fast path after both slots slot_is_num +vm.c|#define INT_BINOP_R|2|integer op fast path after both slots slot_is_f64 vm.c|#define NUM_BINOP|6|arithmetic after a->type == VAL_NUM && b->type == VAL_NUM; NUM_REUSE writes -vm.c|jit_helper_dot_set|1|JIT helper: number store after slot_is_num -vm.c|jit_helper_index_get|9|JIT helper: index read after slot_is_num / VAL_NUM tests on index and element -vm.c|jit_helper_index_set|10|JIT helper: index store after slot_is_num / VAL_NUM tests on index and value +vm.c|jit_helper_dot_set|1|JIT helper: number store after slot_is_f64 +vm.c|jit_helper_index_get|9|JIT helper: index read after slot_is_f64 / VAL_NUM tests on index and element +vm.c|jit_helper_index_set|10|JIT helper: index store after slot_is_f64 / VAL_NUM tests on index and value vm.c|jit_helper_iter_next|1|JIT helper: loop state list [iterable, idx, snap] built by the VM, each read behind a VAL_NUM test -vm.c|jit_helper_local_dot_set|1|JIT helper: number store after slot_is_num -vm.c|jit_helper_observe_assign_local|2|JIT helper: observer update after slot_is_num -vm.c|jit_helper_observe_name_post|2|JIT helper: observer update after slot_is_num -vm.c|loop_iter_store|1|writes the loop counter slot after slot_is_num -vm.c|obs_dump_scope|1|SIGUSR1 observer dump after slot_is_num -vm.c|obs_dump_value|2|SIGUSR1 observer dump after slot_is_num / case VAL_NUM -vm.c|slot_as_double|2|VM numeric operand read: returns 0 (not a number) unless slot_is_num or VAL_NUM -vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_num -vm.c|slot_truthy|1|truthiness after slot_is_num +vm.c|jit_helper_local_dot_set|1|JIT helper: number store after slot_is_f64 +vm.c|loop_iter_store|1|writes the loop counter slot after slot_is_f64 +vm.c|obs_dump_scope|1|SIGUSR1 observer dump after slot_is_f64 +vm.c|obs_dump_value|2|SIGUSR1 observer dump after slot_is_f64 / case VAL_NUM +vm.c|obs_slot_num|1|observer numeric channel (#1758): reads an immediate after slot_is_f64; an int converts exactly +vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 +vm.c|slot_truthy|1|truthiness after slot_is_f64 vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_NUM (chunk_scan_leaf_accessor) and values behind VAL_NUM tests -vm.c|vm_run_ex|57|the interpreter loop: every opcode reads numbers behind slot_is_num / type == VAL_NUM dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built -vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_num -vm.c|vm_store_local_slot|2|in-place local number store after slot_is_num +vm.c|vm_run_ex|49|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_NUM dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built +vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 +vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 diff --git a/tools/num_read_check.sh b/tools/num_read_check.sh index b3c414778..23b85189a 100644 --- a/tools/num_read_check.sh +++ b/tools/num_read_check.sh @@ -7,7 +7,7 @@ # two ways: # - the checking accessors eigs_num_arg / eigs_list_num / eigs_opt_num, # which raise a type error on a bool or any other non-number; -# - the raw macros VAL_NUM_RAW(v) / SLOT_NUM_RAW(s) (and VAL_NUM_OFFSET for +# - the raw macros VAL_NUM_RAW(v) / SLOT_F64_RAW(s) (and VAL_NUM_OFFSET for # JIT-emitted loads), for a value whose type is already proven. # This gate enumerates every raw token in src/*.c and src/*.h. It attributes # each one to its enclosing function, or to its #define for a macro. Then it @@ -56,12 +56,12 @@ for f in "$SRC_DIR"/*.c "$SRC_DIR"/*.h; do { linemac = inmac } { s = line - while (match(s, /(VAL_NUM_RAW|SLOT_NUM_RAW)[ \t]*\(|VAL_NUM_OFFSET/)) { + while (match(s, /(VAL_NUM_RAW|SLOT_F64_RAW)[ \t]*\(|VAL_NUM_OFFSET/)) { tok = substr(s, RSTART, RLENGTH); sub(/[ \t]*\($/, "", tok) printf "%s|%s|%s|%d\n", FILE, (scope == "" ? "" : scope), tok, NR s = substr(s, RSTART + RLENGTH) } - if (line ~ /data\.num_|[A-Za-z0-9_)\]]\.d_([^A-Za-z0-9_]|$)/ && scope !~ /^#define (VAL_NUM_RAW|SLOT_NUM_RAW|VAL_NUM_OFFSET)$/) + if (line ~ /data\.num_|[A-Za-z0-9_)\]]\.d_([^A-Za-z0-9_]|$)/ && scope !~ /^#define (VAL_NUM_RAW|SLOT_F64_RAW|VAL_NUM_OFFSET)$/) printf "%s:%d: %s\n", FILE, NR, $0 >> BYPASS if (line ~ /->data\.builtin[ \t]*\(/) printf "%s:%d: ungated builtin call: %s\n", FILE, NR, $0 >> BYPASS incont = ($0 ~ /\\$/) diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index 7ef6cf470..759e2a45a 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -56,15 +56,17 @@ VOCAB = { # (a) type tests and type derivations 'VAL_NUM': 'TAG', # position decides: TEST/CASE/TAGSET/YIELD/EMIT - 'slot_is_num': 'TEST', - 'slot_is_numeric': 'TEST', + 'slot_is_f64': 'TEST', # R1.1: was slot_is_num (slot_is_numeric deleted) + 'slot_is_smi': 'TEST', # R1.1: the SMI tag test 'NUM_REUSE': 'TEST', 'AST_NUM': 'TAG', # (b) payload reads 'VAL_NUM_RAW': 'RAW', # an lvalue: `VAL_NUM_RAW(v) = x` is a WRITE - 'SLOT_NUM_RAW': 'RAW', + 'SLOT_F64_RAW': 'RAW', # R1.1: was SLOT_NUM_RAW + 'slot_smi_val': 'RAW', # R1.1: an SMI's int (no int Value exists before R1.3) 'VAL_NUM_OFFSET': 'RAW', - 'slot_as_double': 'READ', + 'slot_f64_value': 'READ', # R1.1: replaces vm.c's slot_as_double (floats only) + 'slot_int_value': 'READ', # R1.1: an int's value (SMI; R1.2a adds the VAL_INT box) 'eigs_num_arg': 'READ', 'eigs_num_arg_slow': 'READ', 'eigs_list_num': 'READ', @@ -85,7 +87,8 @@ # (c) producers 'make_num': 'PRODUCE', 'make_num_permanent': 'PRODUCE', - 'slot_from_num': 'PRODUCE', + 'slot_from_f64': 'PRODUCE', # R1.1: was slot_from_num + 'slot_from_int': 'PRODUCE', # R1.1: the one int writer (no runtime caller before R1.3) 'list_set_num': 'PRODUCE', 'list_append_num': 'PRODUCE', 'dict_value_set_num': 'PRODUCE', @@ -143,6 +146,7 @@ 'compute_entropy_impl': 'observer: returns an entropy, not the number; its payload read is the site', 'ent_child_slot': 'observer: returns a child entropy, not the number; its payload read is the site', 'observer_entropy_now': 'observer: writes an entropy, not the number; its payload read is the site', + 'obs_slot_num': 'observer: the numeric channel of a slot (R1.1); its payload read is the site', 'numerical_loss': 'tensor: reads the loss callback result once; that read is the site', 'tensor_flatten_recursive': 'tensor: bulk element flattener into a double array; the per-element read is the site', 'tensor_to_flat': 'tensor: bulk element flattener into a double array; the per-element read is the site', @@ -182,7 +186,7 @@ # Raw union members: the Value's double (`num_`) and the slot's (`d_`). Only # the accessor macros may name them; anywhere else is a bypass. RAW_MEMBER = re.compile(r'(?:\.|->)(d_|num_)\b') -RAW_MEMBER_HOMES = {'#define VAL_NUM_RAW', '#define SLOT_NUM_RAW', '#define VAL_NUM_OFFSET'} +RAW_MEMBER_HOMES = {'#define VAL_NUM_RAW', '#define SLOT_F64_RAW', '#define VAL_NUM_OFFSET'} C_KEYWORDS = {'if', 'while', 'for', 'switch', 'return', 'sizeof', 'do', 'else', 'case', 'defined', '__attribute__', '__typeof__', '_Generic'} @@ -353,7 +357,7 @@ def val_num_kind(line, start, end, token): def raw_kind(line, end): - """VAL_NUM_RAW(...)/SLOT_NUM_RAW(...) followed by a plain `=` is a write.""" + """VAL_NUM_RAW(...)/SLOT_F64_RAW(...) followed by a plain `=` is a write.""" depth, i = 0, end while i < len(line): ch = line[i] @@ -385,7 +389,7 @@ def scan_file(path, rel): kind = VOCAB[tok] if kind == 'TAG': kind = val_num_kind(line, m.start(), m.end(), tok) - elif tok in ('VAL_NUM_RAW', 'SLOT_NUM_RAW'): + elif tok in ('VAL_NUM_RAW', 'SLOT_F64_RAW'): kind = raw_kind(line, m.end()) sites.append((rel, ln, scope[ln], tok, kind)) if JIT_FILES.match(rel): @@ -415,8 +419,8 @@ def classify(site): # ---- derived accessor check ---------------------------------------------- -READ_IN_BODY = re.compile(r'\b(VAL_NUM_RAW|SLOT_NUM_RAW|eigs_num_arg|eigs_list_num|' - r'eigs_slot_num|list_get_num|dict_value_get_num|slot_as_double)\b|' +READ_IN_BODY = re.compile(r'\b(VAL_NUM_RAW|SLOT_F64_RAW|eigs_num_arg|eigs_list_num|' + r'eigs_slot_num|list_get_num|dict_value_get_num|slot_f64_value)\b|' r'(?:\.|->)(?:d_|num_)\b') @@ -580,18 +584,24 @@ def executor_arms(stripped_by_file, scope_by_file): # ---- slot classifiers (R1.1's worklist) ------------------------------------ # Every function (or dispatcher arm) that tests, dereferences or types an -# EigsSlot. D1 holds a number test, so the rename forces it; D2 dereferences -# with no number test; D3 tests other tags or bits; T only reads slot_type. -# Every D2 and D3 entry needs a reviewed disposition in the design doc. -SLOT_TEST = {'slot_is_num', 'slot_is_numeric', 'slot_as_double'} +# EigsSlot. D1 holds a number test (R1.1 renamed or deleted every one, so the +# compiler stopped at each); D2 dereferences with no number test; D3 tests +# other tags or bits; T only reads slot_type. From R1.1 on, every D1, D2 and +# D3 entry needs a reviewed disposition in the design doc: what an int (an +# SMI) does there. +SLOT_TEST = {'slot_is_f64', 'slot_is_smi', 'slot_f64_value', 'slot_int_value', 'slot_smi_val'} SLOT_OTHER = {'slot_is_null', 'slot_is_bool', 'slot_is_heap', 'slot_is_ptr'} SLOT_DEREF = {'slot_as_ptr', 'slot_as_heap', 'eigs_slot_ref'} SLOT_TYPE = {'slot_type', 'list_elem_type', 'dict_value_type'} -SLOT_BITS = {'SLOT_QNAN_MASK', 'SLOT_TAG_MASK', 'SLOT_PAYLOAD_MASK', 'TAG_HEAP', 'TAG_BOOL', +SLOT_BITS = {'SLOT_QNAN_MASK', 'SLOT_TAG_MASK', 'SLOT_PAYLOAD_MASK', 'TAG_HEAP', 'TAG_BOOL', 'TAG_SMI', + 'SLOT_SMI_MIN', 'SLOT_SMI_MAX', 'SLOT_SMI_SIGN', 'TAG_SENTINEL', 'SLOT_NULL_BITS', 'SLOT_TRUE_BITS', 'SLOT_FALSE_BITS'} SLOT_RE = re.compile(r'\b(' + '|'.join(sorted(SLOT_TEST | SLOT_OTHER | SLOT_DEREF | SLOT_TYPE | SLOT_BITS, key=len, reverse=True)) + r')\b') -DISPOSITIONS = {'guarded', 'smi-arm', 'refuse', 'not-a-classifier'} +# `unwired` (R1.1): aborts on an SMI through eigs_int_unwired, whose arm needs +# the int Value kind or tape v7; R1.3 deletes eigs_int_unwired, so each one +# stops compiling in the commit that makes ints reachable. +DISPOSITIONS = {'guarded', 'smi-arm', 'refuse', 'unwired', 'not-a-classifier'} def slot_classifiers(stripped_by_file, scope_by_file): @@ -616,6 +626,34 @@ def slot_classifiers(stripped_by_file, scope_by_file): return out +def slot_population(slots, sigs_by_file): + """The C slot test's population (design 2.5): every D1/D2/D3 FUNCTION + entry whose first parameter is an EigsSlot by value. #define entries and + dispatcher arms take no slot argument. tests/phase2/slot_layer.sh + compares this list with the entries the test examined, both ways.""" + out, bad = [], [] + for (rel, k), (cls, c) in sorted(slots.items()): + if cls not in ('D1', 'D2', 'D3') or k.startswith('#define') or '/' in k: + continue + sig = sigs_by_file[rel].get(k) + if not sig or k not in sig: + bad.append('%s:%s has no signature' % (rel, k)) + continue + params = sig[sig.rindex(k) + len(k):].strip() + if not params.startswith('('): + bad.append('%s:%s: unparsed signature %r' % (rel, k, sig.strip()[:60])) + continue + first = re.split(r'[,)]', params[1:], 1)[0].strip() + if re.match(r'^(const\s+)?EigsSlot\s+[A-Za-z_]\w*$', first): + out.append('%s:%s' % (rel, k)) + for line in out: + print(line) + for b in bad: + print('slot-population: FAIL: ' + b) + print('slot-population: entries=%d' % len(out)) + return 1 if bad or not out else 0 + + def read_marked_table(doc, tag, row_re): """Rows between and ; an unparsed line inside the markers is refused, never skipped.""" @@ -653,8 +691,8 @@ def read_marked_table(doc, tag, row_re): Q7_CLASSES = ['geometry', 'bounded', 'magnitude'] # A LOSS row claims the body computes through a double; it must have one. DOUBLE_PATH = {'eigs_num_arg', 'eigs_list_num', 'eigs_slot_num', 'eigs_opt_num', 'eigs_slot_opt_num', - 'eigs_slot_elem_num', 'eigs_elem_num', 'buffer_read_num', 'make_num', 'slot_as_double', - 'VAL_NUM_RAW', 'SLOT_NUM_RAW', 'strtod', 'atof', 'num_guard', 'list_set_num'} + 'eigs_slot_elem_num', 'eigs_elem_num', 'buffer_read_num', 'make_num', 'slot_f64_value', + 'VAL_NUM_RAW', 'SLOT_F64_RAW', 'strtod', 'atof', 'num_guard', 'list_set_num'} def read_table(doc): @@ -703,6 +741,8 @@ def main(): ap.add_argument('--out', default=os.path.join(ROOT, 'docs/design/phase2-inventory.txt')) ap.add_argument('--no-write', action='store_true') ap.add_argument('--sites', action='store_true', help='print every site') + ap.add_argument('--slot-population', action='store_true', + help='print the C slot test population (design 2.5) and exit') args = ap.parse_args() files = sorted(glob.glob(os.path.join(args.src, '*.c')) + glob.glob(os.path.join(args.src, '*.h'))) @@ -773,12 +813,12 @@ def main(): exec_bad += ['dispatcher %s (%s) attributed no opcode arm' % (f, r) for f, r in sorted(ROLE_OF.items()) if r not in found] - # slot classifiers: every D2/D3 entry has a reviewed disposition row + # slot classifiers: every D1/D2/D3 entry has a reviewed disposition row slots = slot_classifiers(stripped_by_file, scope_by_file) slot_cls = {} for key, (cls, c) in slots.items(): slot_cls[cls] = slot_cls.get(cls, 0) + 1 - need = {'%s:%s' % k for k, (cls, c) in slots.items() if cls in ('D2', 'D3')} + need = {'%s:%s' % k for k, (cls, c) in slots.items() if cls in ('D1', 'D2', 'D3')} srows, sbad = read_marked_table(args.doc, 'slot-table', SLOT_ROW) srows = srows or {} for name, (ln, disp) in srows.items(): @@ -789,6 +829,9 @@ def main(): if not any(slot_cls.get(k) for k in ('D1', 'D2', 'D3')): sbad.append('slot classifiers: examined=0 (no D1/D2/D3 entry found)') + if args.slot_population: + return slot_population(slots, sigs_by_file) + # ---- report ---- cats = 'abcdefghij' per_cat = {c: 0 for c in cats} @@ -848,7 +891,7 @@ def main(): for key in sorted(slots, key=lambda k: (slots[k][0], k)): cls, c = slots[key] if cls in ('D1', 'D2', 'D3'): - disp = 'forced' if cls == 'D1' else srows.get('%s:%s' % key, (0, '-'))[1] + disp = srows.get('%s:%s' % key, (0, '-'))[1] out.append('%s %-42s %-16s %s' % (cls, '%s:%s' % key, disp, ' '.join('%s=%d' % kv for kv in sorted(c.items())))) out.append('') @@ -899,7 +942,7 @@ def main(): for n in slot_missing: fail.append('slot classifier `%s` has no disposition row' % n) for n in slot_stale: - fail.append('disposition row `%s` names no D2/D3 slot classifier' % n) + fail.append('disposition row `%s` names no D1/D2/D3 slot classifier' % n) for f_ in fail: print('FAIL: ' + f_) print('builtins: registered=%d numeric=%d classified=%d unclassified=%d stale=%d' % ( From 19be0b59ac84e41f9023ad42c83d25220357621f Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 17:55:02 -0500 Subject: [PATCH 005/188] phase2 R1.1: the C slot test, its suite section and plant 1 (#1758) tests/phase2/slot_layer.c (design 2.5) includes the single-file amalgamation, so the static slot classifiers are reachable, and drives them with hand-built SMI slots (the literal tag, never slot_from_int): - Part A: every entry of `tools/phase2_inventory.py --slot-population` (every slot classifier whose first parameter is an EigsSlot, 33 today) with the SMI boundary values 0, 1, -1, 2^47-1, -2^47. An entry returns the int's answer or aborts through a named refusal; an abort runs in a forked child and its FATAL line must name the expected reader. - Part B: the predicates and the deciding readers against a double, the canonical NaN, -0.0, null, both bools, an SMI, a heap pointer, the three reserved tags and the sentinel. - Part C, plant 1's named check: slot_from_int over the boundary values must give the SMI bits (inside the range) or refuse (outside it, until R1.3). tests/phase2/slot_layer.sh builds it (make phase2-slot-test; release CFLAGS plus -DEIGS_SLOT_CHECKED, or ASan) and compares the entries it examined with the derived population both ways. Suite section [0fk] runs it in the variant the suite binary is. tools/phase2_plants.sh (design 9.3) holds the plants that have landed: plant 1 (slot_from_int tags an int that fits as a heap pointer), killed by its named check and shown transverse (the same plant with that one assertion deleted passes). Results on this tree: - bash tests/phase2/slot_layer.sh release: slot-layer-test: examined=33 smi_values=5 calls=165 tag_rows=156 from_int_rows=11 failures=0 slot-layer-population: derived=33 examined=33 entries=33 missing=0 extra=0 test_rc=0 slot-layer: PASS - the ASan/UBSan build (make PHASE2_SLOT_VARIANT=asan phase2-slot-test, run with ASAN_OPTIONS=detect_leaks=1): the same four lines, rc 0, no sanitizer report. - suite section [0fk] in the full release suite: the same lines, PASS (297 s on the 4 GB box, most of it the -O2 compile of the amalgamation). - bash tools/phase2_plants.sh: red: slot-layer-test: FAIL slot_from_int(0): bits 0xfffb000000000000 (tag 0xfffb), want the SMI 0xfffa000000000000 plant 1: KILLED transverse=TRANSVERSE plants=1 killed=1 survived=0 broken=0 transverse=1 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 16 + tests/phase2/slot_layer.c | 375 ++++++++++++++++++++++++ tests/phase2/slot_layer.sh | 60 ++++ tests/sections/0fk-phase2-slot-layer.sh | 22 ++ tools/phase2_plants.sh | 113 +++++++ 5 files changed, 586 insertions(+) create mode 100644 tests/phase2/slot_layer.c create mode 100755 tests/phase2/slot_layer.sh create mode 100644 tests/sections/0fk-phase2-slot-layer.sh create mode 100755 tools/phase2_plants.sh diff --git a/Makefile b/Makefile index 826f5a56f..9001dca92 100644 --- a/Makefile +++ b/Makefile @@ -231,6 +231,22 @@ build/$(SLOT_TEST_VARIANT)/test_container_slots: tests/test_container_slots.c $( container-slot-test: build/$(SLOT_TEST_VARIANT)/test_container_slots @echo "Container slot API test built: $<" +# #1758 R1.1: the C slot test (docs/design/phase2-numbers.md 2.5). It includes +# the single-file amalgamation so the static slot classifiers are reachable; +# tests/phase2/slot_layer.sh runs it and compares the entries it examined with +# the population tools/phase2_inventory.py derives. The release flavour turns +# on slot_as_ptr's refusal with -DEIGS_SLOT_CHECKED; ASan turns it on itself. +PHASE2_SLOT_VARIANT ?= release +PHASE2_SLOT_FLAGS_release := $(CFLAGS) -g -DEIGS_SLOT_CHECKED +PHASE2_SLOT_FLAGS_asan := $(ASAN_FLAGS) +build/phase2/eigenscript_all.c: $(filter-out $(CLI_ONLY),$(SOURCES)) $(wildcard $(SRC_DIR)/*.h) tools/amalgamate.sh Makefile + bash tools/amalgamate.sh build/phase2 +build/phase2/slot_layer_%: tests/phase2/slot_layer.c build/phase2/eigenscript_all.c tools/werror_flags.txt + $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread +.PHONY: phase2-slot-test +phase2-slot-test: build/phase2/slot_layer_$(PHASE2_SLOT_VARIANT) + @echo "phase2 slot test built: $<" + # Focused lifetime regression for sandbox descriptor interns (#964). Link the # public embedding/runtime surface without CLI-only translation units so the # C test can inspect the internal thread-local intern accounting directly. diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c new file mode 100644 index 000000000..c56dd2966 --- /dev/null +++ b/tests/phase2/slot_layer.c @@ -0,0 +1,375 @@ +/* tests/phase2/slot_layer.c -- #1758 R1.1, the C slot test (design 2.5). + * + * Nothing in the runtime produces an SMI before R1.3, so no program can show + * what a slot reader does with one. This test builds SMI slots BY HAND (the + * literal tag 0xFFFA, never slot_from_int) and drives every slot classifier + * whose first parameter is an EigsSlot -- the population + * `tools/phase2_inventory.py --slot-population` derives -- with the SMI + * boundary values. It includes the single-file amalgamation + * (tools/amalgamate.sh) so the static classifiers are reachable. + * + * Parts: + * A every population entry x every SMI boundary value. An entry either + * RETURNS the int's answer (its truthiness, type name, double, digits, + * the slot unchanged), or ABORTS through a named refusal: the permanent + * ones (eigs_slot_refuse) and the R1.1 placeholders whose int arm needs + * the int Value kind (eigs_int_unwired, deleted in R1.3). An abort runs + * in a forked child, and its FATAL line must name the expected reader. + * B the tag matrix: the predicates and the deciding readers against a + * double, the canonical NaN, -0.0, null, both bools, an SMI, a heap + * pointer, the reserved tags and the sentinel. + * C slot_from_int, the one int writer (plant 1's named check, design 9.3): + * inside [-2^47, 2^47) the tag is 0xFFFA and the int reads back exactly; + * outside, R1.1 refuses (the VAL_INT box lands in R1.3). + * + * Output: one `ENTRY : ...` line per Part A entry (the runner + * compares that set with the derived population, both ways), `FAIL` lines, + * and a final `slot-layer-test: examined=N ... failures=F` line, then its verdict. + * Exit 0 only for failures == 0 with every part non-empty. */ +#include "eigenscript_all.c" + +#include +#include +#include + +#ifndef EIGS_SLOT_CHECKS +#error "build with -DEIGS_SLOT_CHECKED (or ASan): slot_as_ptr's refusal is under test" +#endif + +static int failures; + +/* The test's own encoding, independent of value_slot.h's writers. */ +#define T_SMI_TAG 0xFFFA000000000000ULL +#define T_PAYLOAD 0x0000FFFFFFFFFFFFULL +static EigsSlot bits(uint64_t u) { EigsSlot s; s.u = u; return s; } +static EigsSlot smi(int64_t v) { return bits(T_SMI_TAG | ((uint64_t)v & T_PAYLOAD)); } +static double f64_of(uint64_t u) { double d; memcpy(&d, &u, sizeof d); return d; } + +static const int64_t SMI_VALUES[] = { + 0, 1, -1, (INT64_C(1) << 47) - 1, -(INT64_C(1) << 47), +}; +#define N_SMI ((int)(sizeof SMI_VALUES / sizeof SMI_VALUES[0])) + +#define FAILF(...) do { printf("slot-layer-test: FAIL "); printf(__VA_ARGS__); printf("\n"); \ + failures++; } while (0) + +/* Run fn(s) in a child; it must die by SIGABRT with a FATAL line naming + * `who`. Returns 1 when it did. */ +static int aborts_naming(void (*fn)(EigsSlot), EigsSlot s, const char *who, const char *what) { + int p[2]; + if (pipe(p) != 0) { FAILF("%s: pipe", what); return 0; } + fflush(stdout); fflush(stderr); + pid_t pid = fork(); + if (pid < 0) { FAILF("%s: fork", what); return 0; } + if (pid == 0) { + close(p[0]); + dup2(p[1], 2); + fn(s); + _exit(0); /* returned: the refusal did not fire */ + } + close(p[1]); + char buf[1024]; + size_t n = 0; + ssize_t r; + while (n < sizeof buf - 1 && (r = read(p[0], buf + n, sizeof buf - 1 - n)) > 0) n += (size_t)r; + buf[n] = 0; + close(p[0]); + int st = 0; + waitpid(pid, &st, 0); + char want[160]; + snprintf(want, sizeof want, "EigenScript FATAL: %s:", who); + if (WIFSIGNALED(st) && WTERMSIG(st) == SIGABRT && strstr(buf, want)) return 1; + char *nl = strchr(buf, '\n'); + if (nl) *nl = 0; + FAILF("%s(0x%016llx): want an abort naming %s; got %s %d, stderr \"%s\"", what, + (unsigned long long)s.u, who, WIFSIGNALED(st) ? "signal" : "exit", + WIFSIGNALED(st) ? WTERMSIG(st) : WEXITSTATUS(st), buf); + return 0; +} + +/* ---- Part A: RETURN checks (0 = ok) ------------------------------------ */ + +static int r_eigs_slot_elem_num(int64_t v) { return eigs_slot_elem_num(smi(v), "slot_layer") != (double)v; } +static int r_eigs_slot_num(int64_t v) { return eigs_slot_num(smi(v), "slot_layer") != (double)v; } +static int r_eigs_slot_opt_num(int64_t v) { + double d = -7.25; + return eigs_slot_opt_num(smi(v), &d, "slot_layer") != 1 || d != (double)v; +} +static int r_eigs_slot_store_borrow(int64_t v) { return eigs_slot_store_borrow(smi(v)).u != smi(v).u; } +static int r_eigs_slot_store_owned(int64_t v) { return eigs_slot_store_owned(smi(v)).u != smi(v).u; } +static int r_ent_child_slot(int64_t v) { + return ent_child_slot(smi(v)) != ent_child_slot(slot_from_f64((double)v)); +} +static int r_store_json_encode_slot(int64_t v) { + strbuf sb; + strbuf_init(&sb); + store_json_encode_slot(smi(v), &sb); + char want[32]; + snprintf(want, sizeof want, "%lld", (long long)v); + int bad = !sb.data || strcmp(sb.data, want) != 0; + strbuf_free(&sb); + return bad; +} +static int r_slot_f64_value(int64_t v) { double d = -7.25; return slot_f64_value(smi(v), &d) != 0 || d != -7.25; } +static int r_slot_int_value(int64_t v) { int64_t i = 7; return slot_int_value(smi(v), &i) != 1 || i != v; } +static int r_slot_is_f64(int64_t v) { return slot_is_f64(smi(v)) != 0; } +static int r_slot_is_smi(int64_t v) { return slot_is_smi(smi(v)) != 1; } +static int r_slot_smi_val(int64_t v) { return slot_smi_val(smi(v)) != v; } +static int r_slot_truthy_immediate(int64_t v) { + int decided = -1; + int t = slot_truthy_immediate(smi(v), &decided); + return decided != 1 || t != (v != 0); +} +static int r_obs_dump_value(int64_t v) { + char buf[160], want[32]; + obs_dump_value(smi(v), buf, sizeof buf); + snprintf(want, sizeof want, "%lld", (long long)v); + return strcmp(buf, want) != 0; +} +static int r_obs_slot_num(int64_t v) { double d = -7.25; return obs_slot_num(smi(v), &d) != 1 || d != (double)v; } +static int r_slot_truthy(int64_t v) { return slot_truthy(smi(v)) != (v != 0); } +static int r_slot_type_name(int64_t v) { return strcmp(slot_type_name(smi(v)), "num") != 0; } +static int r_slot_decref(int64_t v) { slot_decref(smi(v)); return 0; } /* no refcount: no-op */ +static int r_slot_incref(int64_t v) { slot_incref(smi(v)); return 0; } +static int r_slot_is_bool(int64_t v) { return slot_is_bool(smi(v)) != 0; } +static int r_slot_is_heap(int64_t v) { return slot_is_heap(smi(v)) != 0; } +static int r_slot_is_null(int64_t v) { return slot_is_null(smi(v)) != 0; } +static int r_slot_is_ptr(int64_t v) { return slot_is_ptr(smi(v)) != 0; } + +/* ---- Part A: ABORT calls ------------------------------------------------ */ + +static void a_eigs_slot_box(EigsSlot s) { (void)eigs_slot_box(s); } +static void a_slot_type(EigsSlot s) { (void)slot_type(s); } +static void a_slot_view(EigsSlot s) { EIGS_VIEW_NOCHECK(view); (void)slot_view(s, &view); } +static void a_slot_to_value(EigsSlot s) { (void)slot_to_value(s); } +static void a_write_slot(EigsSlot s) { write_slot(s); } +static void a_obs_slot_observable(EigsSlot s) { (void)obs_slot_observable(s); } +static void a_slot_bridge_unwrap(EigsSlot s) { (void)slot_bridge_unwrap(s); } +static void a_eigs_slot_ref(EigsSlot s) { (void)eigs_slot_ref(s); } +static void a_slot_as_ptr(EigsSlot s) { (void)slot_as_ptr(s); } +static void a_obs_slot_value(EigsSlot s) { (void)obs_slot_value(s); } + +typedef struct { + const char *name; /* the inventory's file:function */ + int (*ret)(int64_t); /* returns the int's answer, or */ + void (*abort_call)(EigsSlot); /* aborts ... */ + const char *aborts; /* ... naming this reader */ + const char *why; +} Entry; + +static const Entry ENTRIES[] = { + {"container.h:eigs_slot_elem_num", r_eigs_slot_elem_num, 0, 0, "bridge: the int's double"}, + {"container.h:eigs_slot_num", r_eigs_slot_num, 0, 0, "bridge: the int's double"}, + {"container.h:eigs_slot_opt_num", r_eigs_slot_opt_num, 0, 0, "bridge: present, the int's double"}, + {"container.h:eigs_slot_store_borrow", r_eigs_slot_store_borrow, 0, 0, "canonical storage: unchanged"}, + {"container.h:eigs_slot_store_owned", r_eigs_slot_store_owned, 0, 0, "canonical storage: unchanged"}, + {"eigenscript.c:ent_child_slot", r_ent_child_slot, 0, 0, "the entropy of its double"}, + {"ext_store.c:store_json_encode_slot", r_store_json_encode_slot, 0, 0, "exact digits"}, + {"value_slot.h:slot_f64_value", r_slot_f64_value, 0, 0, "not a float: 0, out untouched"}, + {"value_slot.h:slot_int_value", r_slot_int_value, 0, 0, "the int"}, + {"value_slot.h:slot_is_f64", r_slot_is_f64, 0, 0, "0"}, + {"value_slot.h:slot_is_smi", r_slot_is_smi, 0, 0, "1"}, + {"value_slot.h:slot_smi_val", r_slot_smi_val, 0, 0, "the int, sign-extended"}, + {"value_slot.h:slot_truthy_immediate", r_slot_truthy_immediate, 0, 0, "decided: not 0"}, + {"vm.c:obs_dump_value", r_obs_dump_value, 0, 0, "exact digits"}, + {"vm.c:obs_slot_num", r_obs_slot_num, 0, 0, "the numeric channel: the int's double"}, + {"vm.c:slot_truthy", r_slot_truthy, 0, 0, "not 0"}, + {"vm.c:slot_type_name", r_slot_type_name, 0, 0, "\"num\""}, + {"value_slot.h:slot_decref", r_slot_decref, 0, 0, "no refcount"}, + {"value_slot.h:slot_incref", r_slot_incref, 0, 0, "no refcount"}, + {"value_slot.h:slot_is_bool", r_slot_is_bool, 0, 0, "0"}, + {"value_slot.h:slot_is_heap", r_slot_is_heap, 0, 0, "0"}, + {"value_slot.h:slot_is_null", r_slot_is_null, 0, 0, "0"}, + {"value_slot.h:slot_is_ptr", r_slot_is_ptr, 0, 0, "0"}, + {"container.h:eigs_slot_box", 0, a_eigs_slot_box, "slot_to_value", "unwired: an int Value (R1.3)"}, + {"container.h:slot_type", 0, a_slot_type, "slot_type", "unwired: the int ValType (R1.2a)"}, + {"container.h:slot_view", 0, a_slot_view, "slot_view", "unwired: a VAL_INT facade (R1.2a)"}, + {"eigenscript.c:slot_to_value", 0, a_slot_to_value, "slot_to_value", "unwired: make_int (R1.3)"}, + {"trace.c:write_slot", 0, a_write_slot, "write_slot", "unwired: tape v7 (R1.3)"}, + {"vm.c:obs_slot_observable", 0, a_obs_slot_observable, "obs_slot_observable", "refuse"}, + {"vm.c:slot_bridge_unwrap", 0, a_slot_bridge_unwrap, "slot_to_value", "routes to the one SMI boxer"}, + {"container.h:eigs_slot_ref", 0, a_eigs_slot_ref, "eigs_slot_ref", "refuse"}, + {"value_slot.h:slot_as_ptr", 0, a_slot_as_ptr, "slot_as_ptr", "refuse (checked builds)"}, + {"vm.c:obs_slot_value", 0, a_obs_slot_value, "slot_as_ptr", "precondition: pointer or bool only"}, +}; +#define N_ENTRIES ((int)(sizeof ENTRIES / sizeof ENTRIES[0])) + +static int part_a(void) { + int calls = 0; + for (int i = 0; i < N_ENTRIES; i++) { + const Entry *e = &ENTRIES[i]; + int bad = 0; + for (int k = 0; k < N_SMI; k++) { + int64_t v = SMI_VALUES[k]; + calls++; + if (e->ret) { + if (e->ret(v)) { FAILF("%s(SMI %lld): want %s", e->name, (long long)v, e->why); bad++; } + } else if (!aborts_naming(e->abort_call, smi(v), e->aborts, e->name)) { + bad++; + } + } + printf("ENTRY %s %s values=%d %s\n", e->name, + e->ret ? "returns" : e->aborts, N_SMI, bad ? "FAIL" : "ok"); + } + return calls; +} + +/* ---- Part B: the tag matrix ---------------------------------------------- */ + +typedef struct { const char *name; uint64_t u; } Kind; + +static void b_type_name(EigsSlot s) { (void)slot_type_name(s); } +static void b_truthy(EigsSlot s) { (void)slot_truthy(s); } + +static int part_b(void) { + Value *str = make_str("x"); + Kind kinds[] = { + {"f64 1.5", 0x3FF8000000000000ULL}, + {"f64 canonical NaN", 0x7FF8000000000000ULL}, + {"f64 -0.0", 0x8000000000000000ULL}, + {"null", 0xFFF8000000000000ULL}, + {"false", 0xFFF9000000000000ULL}, + {"true", 0xFFF9000000000001ULL}, + {"SMI 5", T_SMI_TAG | 5}, + {"heap str", 0}, + {"reserved 0xFFFC", 0xFFFC000000000000ULL}, + {"reserved 0xFFFD", 0xFFFD000000000000ULL}, + {"reserved 0xFFFE", 0xFFFE000000000000ULL}, + {"sentinel 0xFFFF", 0xFFFF000000000000ULL}, + }; + int nk = (int)(sizeof kinds / sizeof kinds[0]); + kinds[7].u = slot_from_heap(str).u; + /* expected predicate answers, columns: f64 smi null bool heap ptr */ + static const int want_pred[][6] = { + {1,0,0,0,0,0}, {1,0,0,0,0,0}, {1,0,0,0,0,0}, {0,0,1,0,0,0}, {0,0,0,1,0,0}, + {0,0,0,1,0,0}, {0,1,0,0,0,0}, {0,0,0,0,1,1}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, + {0,0,0,0,0,0}, {0,0,0,0,0,0}, + }; + static const char *want_type[] = { + "num", "num", "num", "none", "bool", "bool", "num", "str", 0, 0, 0, 0, + }; + static const int want_truthy[] = { 1, 1, 0, 0, 0, 1, 1, 1, -1, -1, -1, -1 }; + static const int want_f64[] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int rows = 0; + for (int i = 0; i < nk; i++) { + EigsSlot s = bits(kinds[i].u); + int got[6] = { slot_is_f64(s), slot_is_smi(s), slot_is_null(s), slot_is_bool(s), + slot_is_heap(s), slot_is_ptr(s) }; + static const char *pn[6] = {"slot_is_f64", "slot_is_smi", "slot_is_null", + "slot_is_bool", "slot_is_heap", "slot_is_ptr"}; + for (int j = 0; j < 6; j++, rows++) + if (got[j] != want_pred[i][j]) + FAILF("%s(%s) = %d, want %d", pn[j], kinds[i].name, got[j], want_pred[i][j]); + rows++; + if (want_type[i]) { + const char *t = slot_type_name(s); + if (strcmp(t, want_type[i]) != 0) + FAILF("slot_type_name(%s) = %s, want %s", kinds[i].name, t, want_type[i]); + } else { + (void)aborts_naming(b_type_name, s, "slot_type_name", "slot_type_name"); + } + rows++; + if (want_truthy[i] >= 0) { + int t = slot_truthy(s); + if (t != want_truthy[i]) + FAILF("slot_truthy(%s) = %d, want %d", kinds[i].name, t, want_truthy[i]); + } else { + (void)aborts_naming(b_truthy, s, "slot_truthy", "slot_truthy"); + } + rows++; + double d = -7.25; + int f = slot_f64_value(s, &d); + if (f != want_f64[i] || (f && memcmp(&d, &kinds[i].u, sizeof d) != 0)) + FAILF("slot_f64_value(%s) = %d, want %d with the same bits", kinds[i].name, f, want_f64[i]); + rows++; + int64_t iv = 0; + int isint = slot_int_value(s, &iv); + if (isint != (i == 6) || (isint && iv != 5)) + FAILF("slot_int_value(%s) = %d (%lld)", kinds[i].name, isint, (long long)iv); + /* the readers that must refuse every non-pointer, non-null, non-bool */ + rows++; + if (want_pred[i][3] || want_pred[i][2] || want_pred[i][4]) { + Value *r = eigs_slot_ref(s); + Value *want = want_pred[i][4] ? str : want_pred[i][2] ? make_null() : make_bool(i == 5); + if (r != want) FAILF("eigs_slot_ref(%s) is not its Value", kinds[i].name); + } else { + (void)aborts_naming(a_eigs_slot_ref, s, "eigs_slot_ref", "eigs_slot_ref"); + } + rows++; + if (want_pred[i][1]) { + (void)aborts_naming(a_slot_to_value, s, "slot_to_value", "slot_to_value"); + } else if (want_pred[i][0] || want_pred[i][2] || want_pred[i][3] || want_pred[i][4]) { + Value *v = slot_to_value(s); + /* make_num guards: a NaN reads back 0.0 (non-strict, set in main) */ + double wd = want_pred[i][0] ? num_guard(f64_of(kinds[i].u)) : 0.0; + int ok = want_pred[i][0] ? (v->type == VAL_NUM && memcmp(&VAL_NUM_RAW(v), &wd, 8) == 0) + : want_pred[i][2] ? v->type == VAL_NULL + : want_pred[i][3] ? (v->type == VAL_BOOL && v->data.boolean == (i == 5)) + : v == str; + if (!ok) FAILF("slot_to_value(%s) is not its Value", kinds[i].name); + val_decref(v); + } else { + (void)aborts_naming(a_slot_to_value, s, "slot_to_value", "slot_to_value"); + } + rows++; + if (want_pred[i][1] || (!want_pred[i][0] && !want_pred[i][2] && !want_pred[i][3] && !want_pred[i][4])) { + (void)aborts_naming(a_obs_slot_observable, s, "obs_slot_observable", "obs_slot_observable"); + } else { + int o = obs_slot_observable(s); + int wo = want_pred[i][3] || want_pred[i][4]; + if (o != wo) FAILF("obs_slot_observable(%s) = %d, want %d", kinds[i].name, o, wo); + } + } + val_decref(str); + return rows; +} + +/* ---- Part C: slot_from_int (plant 1's named check) ----------------------- */ + +static int64_t g_from_int_arg; +static void c_from_int(EigsSlot s) { (void)s; (void)slot_from_int(g_from_int_arg); } + +static int part_c(void) { + static const int64_t inside[] = { + 0, 1, -1, 12345, -12345, (INT64_C(1) << 47) - 1, -(INT64_C(1) << 47), + }; + static const int64_t outside[] = { + INT64_C(1) << 47, -(INT64_C(1) << 47) - 1, INT64_MAX, INT64_MIN, + }; + int rows = 0; + for (size_t k = 0; k < sizeof inside / sizeof inside[0]; k++, rows++) { + int64_t v = inside[k]; + EigsSlot s = slot_from_int(v); + /* plant 1's named check: an int that fits is stored as an SMI */ + if (s.u != smi(v).u) + FAILF("slot_from_int(%lld): bits 0x%016llx (tag 0x%04llx), want the SMI 0x%016llx", + (long long)v, (unsigned long long)s.u, (unsigned long long)(s.u >> 48), + (unsigned long long)smi(v).u); + if (slot_smi_val(smi(v)) != v) + FAILF("slot_smi_val(SMI %lld) = %lld", (long long)v, (long long)slot_smi_val(smi(v))); + } + for (size_t k = 0; k < sizeof outside / sizeof outside[0]; k++, rows++) { + g_from_int_arg = outside[k]; + char what[64]; + snprintf(what, sizeof what, "slot_from_int(%lld)", (long long)outside[k]); + (void)aborts_naming(c_from_int, slot_null(), "slot_from_int", what); + } + return rows; +} + +int main(void) { + EigsState *st = eigs_open(); + if (!st) { printf("slot-layer-test: FAIL eigs_open\n"); return 1; } + /* Part B reads the canonical NaN back through make_num, whose guard + * raises under strict mode; the test pins the soft read instead. */ + eigs_state_set_strict(st, 0); + int calls = part_a(); + int tag_rows = part_b(); + int from_int_rows = part_c(); + printf("slot-layer-test: examined=%d smi_values=%d calls=%d tag_rows=%d from_int_rows=%d failures=%d\n", + N_ENTRIES, N_SMI, calls, tag_rows, from_int_rows, failures); + eigs_close(st); + int ok = failures == 0 && N_ENTRIES > 0 && calls > 0 && tag_rows > 0 && from_int_rows > 0; + printf("slot-layer-test: %s\n", ok ? "PASS" : "FAIL"); + return ok ? 0 : 1; +} diff --git a/tests/phase2/slot_layer.sh b/tests/phase2/slot_layer.sh new file mode 100755 index 000000000..d0967a6dd --- /dev/null +++ b/tests/phase2/slot_layer.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# tests/phase2/slot_layer.sh [release|asan] -- #1758 R1.1: the C slot test +# (docs/design/phase2-numbers.md 2.5), with its population checked. +# +# 1. Derive the population: `tools/phase2_inventory.py --slot-population` +# lists every slot classifier whose first parameter is an EigsSlot. +# 2. Build tests/phase2/slot_layer.c against the amalgamation +# (make phase2-slot-test) and run it. +# 3. The set of `ENTRY` lines it printed must equal the derived population, +# both ways, and its examined count must equal the population's size, +# which must be above zero. The test's own verdict must be PASS. +# Prints the test's whole output, then `slot-layer-population: ...` and a +# final `slot-layer: PASS|FAIL` line. Exit 0 only for PASS. +set -u +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +VARIANT="${1:-release}" +case "$VARIANT" in release|asan) ;; *) echo "slot-layer: FAIL: unknown variant $VARIANT"; exit 2 ;; esac +TMP=$(mktemp -d "${TMPDIR:-/tmp}/eigs-slot-layer.XXXXXX") || { echo "slot-layer: FAIL: mktemp"; exit 2; } +trap 'rm -rf "$TMP"' EXIT +fail() { echo "slot-layer: FAIL: $*"; exit 1; } + +command -v python3 >/dev/null 2>&1 || fail "python3 is required (the population and the amalgamation need it)" +python3 "$ROOT/tools/phase2_inventory.py" --no-write --slot-population > "$TMP/pop.txt" 2>&1 +prc=$? +if [ "$prc" -ne 0 ]; then + sed 's/^/ inventory: /' "$TMP/pop.txt" + fail "the population scan exited $prc" +fi +grep -v "^slot-population:" "$TMP/pop.txt" | LC_ALL=C sort > "$TMP/want" +n_want=$(grep -c . "$TMP/want") +[ "$n_want" -gt 0 ] || fail "the population scan listed no entry (grep -c gave $n_want)" + +make -s -C "$ROOT" PHASE2_SLOT_VARIANT="$VARIANT" phase2-slot-test > "$TMP/build.txt" 2>&1 +brc=$? +if [ "$brc" -ne 0 ]; then + sed 's/^/ build: /' "$TMP/build.txt" + fail "make phase2-slot-test exited $brc" +fi +BIN="$ROOT/build/phase2/slot_layer_$VARIANT" +[ -x "$BIN" ] || fail "no binary at $BIN after the build" + +"$BIN" > "$TMP/out.txt" 2>&1 +trc=$? +cat "$TMP/out.txt" +awk '$1 == "ENTRY" { print $2 }' "$TMP/out.txt" | LC_ALL=C sort > "$TMP/got" +n_got=$(grep -c . "$TMP/got") +examined=$(awk '/^slot-layer-test: examined=/ { sub(/^slot-layer-test: examined=/, ""); sub(/ .*/, ""); print }' "$TMP/out.txt") +LC_ALL=C comm -23 "$TMP/want" "$TMP/got" > "$TMP/missing" +LC_ALL=C comm -13 "$TMP/want" "$TMP/got" > "$TMP/extra" +n_missing=$(grep -c . "$TMP/missing") +n_extra=$(grep -c . "$TMP/extra") +sed 's/^/ MISSING (a slot classifier the test never called): /' "$TMP/missing" +sed 's/^/ EXTRA (a test entry that is not a derived slot classifier): /' "$TMP/extra" +echo "slot-layer-population: derived=$n_want examined=${examined:-none} entries=$n_got missing=$n_missing extra=$n_extra test_rc=$trc" +[ "$trc" -eq 0 ] || fail "the test exited $trc" +grep -q '^slot-layer-test: PASS$' "$TMP/out.txt" || fail "the test printed no PASS verdict" +[ "${examined:-x}" = "$n_want" ] || fail "examined=${examined:-none} differs from the derived population ($n_want)" +[ "$n_got" -eq "$n_want" ] && [ "$n_missing" -eq 0 ] && [ "$n_extra" -eq 0 ] || + fail "the examined entries differ from the derived population" +echo "slot-layer: PASS" diff --git a/tests/sections/0fk-phase2-slot-layer.sh b/tests/sections/0fk-phase2-slot-layer.sh new file mode 100644 index 000000000..23d015aa1 --- /dev/null +++ b/tests/sections/0fk-phase2-slot-layer.sh @@ -0,0 +1,22 @@ +# #1758 R1.1: the C slot test (docs/design/phase2-numbers.md 2.5). Nothing +# produces an int before R1.3, so this is the only witness of what every slot +# classifier does with one; tests/phase2/slot_layer.sh also checks that it +# examined exactly the population tools/phase2_inventory.py derives. +echo "[0fk] Phase 2 slot layer: every slot classifier against an SMI (#1758)" +TOTAL=$((TOTAL + 1)) +slot_variant=release +if [ -e ../build/asan/eigenscript ] && [ ./eigenscript -ef ../build/asan/eigenscript ]; then + slot_variant=asan +fi +slot_rc=0 +bash ../tests/phase2/slot_layer.sh "$slot_variant" > /tmp/eigs-slot-layer.$$ 2>&1 || slot_rc=$? +slot_last=$(tail -1 /tmp/eigs-slot-layer.$$) +if [ "$slot_rc" -eq 0 ] && [ "$slot_last" = "slot-layer: PASS" ]; then + PASS=$((PASS + 1)) + grep '^slot-layer' /tmp/eigs-slot-layer.$$ | sed 's/^/ /' +else + FAIL=$((FAIL + 1)); echo " FAIL: slot layer ($slot_variant) rc=$slot_rc" + sed 's/^/ | /' /tmp/eigs-slot-layer.$$ +fi +rm -f /tmp/eigs-slot-layer.$$ +echo "" diff --git a/tools/phase2_plants.sh b/tools/phase2_plants.sh new file mode 100755 index 000000000..33d7adc25 --- /dev/null +++ b/tools/phase2_plants.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +# tools/phase2_plants.sh [--ref REF] -- #1758: Phase 2's planted faults +# (docs/design/phase2-numbers.md 9.3). Each plant: +# 1. `git archive REF` (default HEAD) into a scratch tree with no .git; +# 2. applies one replacement, refusing unless the original text occurs +# exactly once before and the planted text after (else BROKEN); +# 3. builds what its named check needs (plain make, one at a time); +# 4. runs the named check and requires the check's OWN failure line naming +# the row (keyed on the message, not on a nonzero exit) -> KILLED. +# Then, once per plant, the transverse run (9.3, "deleting its named check's +# assertion must let the plant through"): the same planted tree with the +# check's assertion removed must NOT print that line -> the plant survives +# exactly the deletion of the assertion that names it. +# +# Plants land with their named checks: plant 1 with R1.1 (the C slot test); +# 2-7 name MAP rows that land in R1.3-R2.2 and join this table then. +# Prints one line per plant and `plants=N killed=N survived=0 broken=0 +# transverse=N`; exit 0 only for exactly that, with N > 0. About 7 minutes +# per plant on the 4 GB box (two compiles of the amalgamated slot test). +set -u +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +REF=HEAD +while [ $# -gt 0 ]; do + case "$1" in + --ref) REF="$2"; shift 2 ;; + *) echo "phase2-plants: FAIL: unknown argument $1"; exit 2 ;; + esac +done +TMO="" +if command -v timeout >/dev/null 2>&1; then TMO="timeout 1500" +elif command -v gtimeout >/dev/null 2>&1; then TMO="gtimeout 1500"; fi +WORK=$(mktemp -d "${TMPDIR:-/tmp}/eigs-phase2-plants.XXXXXX") || { echo "phase2-plants: FAIL: mktemp"; exit 2; } +VERDICT_DONE=0 +# A run that ends without its verdict line is a FAIL, named with the command +# it was running (the #988 rule). +trap 'rc=$?; [ "$VERDICT_DONE" = 1 ] || echo "phase2-plants: FAIL: exited ($rc) before a verdict, at: $BASH_COMMAND"; rm -rf "$WORK"' EXIT + +# replace FILE OLD NEW: exactly one OLD before, NEW present after. +replace() { + python3 - "$1" "$2" "$3" <<'PY' +import sys +path, old, new = sys.argv[1], sys.argv[2], sys.argv[3] +text = open(path, encoding='utf-8').read() +n = text.count(old) +if n != 1: + print('replace: %s: the original occurs %d times, want exactly 1' % (path, n)) + sys.exit(1) +text = text.replace(old, new) +if new not in text: + print('replace: %s: the planted text is absent after the replacement' % path) + sys.exit(1) +open(path, 'w', encoding='utf-8').write(text) +PY +} + +plants=0; killed=0; survived=0; broken=0; transverse=0 + +# run_plant ID FILE OLD NEW CHECK_FILE CHECK_OLD CHECK_NEW FAIL_RE CHECK_CMD... +run_plant() { + local id="$1" file="$2" old="$3" new="$4" cfile="$5" cold="$6" cnew="$7" re="$8" + shift 8 + plants=$((plants + 1)) + local verdict="" trans="" + for mode in plant transverse; do + local dir="$WORK/$id-$mode" + mkdir -p "$dir" + if ! git -C "$ROOT" archive "$REF" | tar -x -C "$dir"; then verdict=BROKEN; echo " $id: archive of $REF failed"; break; fi + if ! replace "$dir/$file" "$old" "$new"; then verdict=BROKEN; break; fi + if [ "$mode" = transverse ] && ! replace "$dir/$cfile" "$cold" "$cnew"; then trans=BROKEN; break; fi + local log="$WORK/$id-$mode.log" + (cd "$dir" && $TMO "$@") > "$log" 2>&1 + local rc=$? + if [ "$mode" = plant ]; then + if grep -Eq "$re" "$log"; then verdict=KILLED + elif [ "$rc" -eq 124 ] || grep -q 'build: \|make phase2-slot-test exited' "$log"; then + verdict=BROKEN; echo " $id: the check did not run (rc=$rc):"; tail -20 "$log" | sed 's/^/ | /' + else verdict=SURVIVED; echo " $id: no failure line matching /$re/ (rc=$rc):"; tail -20 "$log" | sed 's/^/ | /'; fi + grep -E "$re" "$log" | head -3 | sed 's/^/ red: /' + [ "$verdict" = KILLED ] || break + else + if grep -Eq "$re" "$log"; then trans=NOT-TRANSVERSE; echo " $id: the line still fired with its assertion deleted" + elif [ "$rc" -eq 124 ]; then trans=BROKEN + else trans=TRANSVERSE; fi + tail -2 "$log" | sed 's/^/ assertion deleted: /' + fi + done + case "$verdict" in + KILLED) killed=$((killed + 1)) ;; + SURVIVED) survived=$((survived + 1)) ;; + *) broken=$((broken + 1)); verdict=BROKEN ;; + esac + [ "$trans" = TRANSVERSE ] && transverse=$((transverse + 1)) + echo "plant $id: $verdict transverse=${trans:-not-run}" +} + +# Plant 1 (9.3): an int that fits inline stored boxed. slot_from_int, the one +# int writer, skips the small-int rule and tags the int as a heap pointer. +# Named check: the C slot test's slot_from_int rows (Part C). +run_plant 1 src/value_slot.h \ + 'EigsSlot s; s.u = TAG_SMI | ((uint64_t)i & SLOT_PAYLOAD_MASK); return s;' \ + 'EigsSlot s; s.u = TAG_HEAP | ((uint64_t)i & SLOT_PAYLOAD_MASK); return s;' \ + tests/phase2/slot_layer.c \ + ' if (s.u != smi(v).u)' \ + ' if (0)' \ + '^slot-layer-test: FAIL slot_from_int\(0\): bits 0x' \ + bash tests/phase2/slot_layer.sh release + +echo "plants=$plants killed=$killed survived=$survived broken=$broken transverse=$transverse" +VERDICT_DONE=1 +if [ "$plants" -gt 0 ] && [ "$killed" -eq "$plants" ] && [ "$transverse" -eq "$plants" ]; then + echo "phase2-plants: PASS"; exit 0 +fi +echo "phase2-plants: FAIL"; exit 1 From 9ce8e0bda023e91f25748101b287f7b271bbb545 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 17:55:02 -0500 Subject: [PATCH 006/188] phase2 R1.1: tools/phase2_check.sh with --through, the int-source check and its calibration (#1758) tools/phase2_check.sh (design 9.2; the work is in tools/phase2_check.py): - the MAP's rows, controls and gates; `--through Rk` selects what has landed by Rk (R1.1 < R1.2 < ... < R2.6 < R3), and a mechanical round (R1.1, R1.2, R2.1) runs its gates instead of failing on zero rows: the token gate (the tokens a landed round deleted occur in no code line), the int-source check (before R1.3 nothing outside the canonicalizing writers calls slot_from_int or make_int, and make_int does not exist), the C slot test, and the corpus differential against --baseline; - four tiers (off, default, osr, trace = the leaf differential), the verdicts tag_fail / branch_pass / vacuous / TIMEOUT / SIGNAL, and the tier witnesses exactly as design 9.1 defines them, the osr rule being oadv == len (the return sentinel); - plan checks: every item has a row, every numeric JIT-emitter and leaf arm is exercised by an L/F/O row of its role, every round has rows or gates. tools/phase2_corpus_diff.sh: the behaviour differential of a mechanical round. A file whose baseline disagrees with itself is adjudicated by replaying the baseline's tape on both binaries. Calibration, `phase2_check.sh --calibrate --build-plants ` on tests/phase2/calib/ (each fixture ends in `5.5 & 1`, which raises on the branch and truncates on the tag): calibration: cases=27 as-expected=27 unexpected=0 including: honest rows tag_fail=7 branch_pass=7 in every tier with 6/6 witnesses holding (osr fill oadv=123 len=123 oent=37; osr-stop g oent=33 oadv=20, ADD); the tag passed as both binaries -> branch_pass=0; a corrupted .out, an empty rows directory, a MAP id with no file and a file with no MAP id each fail by name; each witness kind's negative plant (and the fn row called 10 times) -> vacuous=1, named; a build whose leaf scanner returns early -> vacuous; a build whose leaf MUL adds 1 -> the trace tier alone passes; the int-source plant (slot_from_int(count) in trace.c) fails naming its caller; a reintroduced slot_is_num fails the token gate. bash tools/phase2_check.sh --through R1.1 --baseline
: tier=default examined=0 rows tag_fail=0 branch_pass=0 vacuous=0 (all four tiers alike) controls=0 both_pass=0 witnessed=0 mapped=0 gates=0 through=R1.1 tokens: rounds<=R1.1 tokens=5 files=89 hits=0 int-source: files=64 slot_from_int_defs=1 make_int_defs=0 calls=0 outside_writers=0 slot-layer: PASS corpus-diff: examined=441 same=433 same_under_replay=6 nondet=2 diff=0 new=14 deleted=0 crash_both=0 timeout_both=1 phase2-check: PASS Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 40 + tests/phase2/calib/MAP.md | 67 ++ .../calib/cal.fn-keep-10calls-plant.eigs | 20 + .../calib/cal.fn-keep-10calls-plant.out | 2 + tests/phase2/calib/cal.fn-keep-plant.eigs | 21 + tests/phase2/calib/cal.fn-keep-plant.out | 2 + tests/phase2/calib/cal.fn-keep.eigs | 20 + tests/phase2/calib/cal.fn-keep.out | 2 + tests/phase2/calib/cal.fnstop-cat-plant.eigs | 20 + tests/phase2/calib/cal.fnstop-cat-plant.out | 2 + tests/phase2/calib/cal.fnstop-cat.eigs | 20 + tests/phase2/calib/cal.fnstop-cat.out | 2 + tests/phase2/calib/cal.leaf-sq-plant.eigs | 15 + tests/phase2/calib/cal.leaf-sq-plant.out | 2 + tests/phase2/calib/cal.leaf-sq.eigs | 14 + tests/phase2/calib/cal.leaf-sq.out | 2 + tests/phase2/calib/cal.leafgen-nth-plant.eigs | 14 + tests/phase2/calib/cal.leafgen-nth-plant.out | 2 + tests/phase2/calib/cal.leafgen-nth.eigs | 14 + tests/phase2/calib/cal.leafgen-nth.out | 2 + tests/phase2/calib/cal.osr-fill-plant.eigs | 22 + tests/phase2/calib/cal.osr-fill-plant.out | 2 + tests/phase2/calib/cal.osr-fill.eigs | 20 + tests/phase2/calib/cal.osr-fill.out | 2 + tests/phase2/calib/cal.osrstop-g-plant.eigs | 20 + tests/phase2/calib/cal.osrstop-g-plant.out | 2 + tests/phase2/calib/cal.osrstop-g.eigs | 20 + tests/phase2/calib/cal.osrstop-g.out | 2 + tests/phase2/calib/cal.verdict.eigs | 11 + tests/phase2/calib/cal.verdict.out | 1 + tools/phase2_check.py | 765 ++++++++++++++++++ tools/phase2_check.sh | 8 + tools/phase2_corpus_diff.sh | 146 ++++ 33 files changed, 1304 insertions(+) create mode 100644 tests/phase2/calib/MAP.md create mode 100644 tests/phase2/calib/cal.fn-keep-10calls-plant.eigs create mode 100644 tests/phase2/calib/cal.fn-keep-10calls-plant.out create mode 100644 tests/phase2/calib/cal.fn-keep-plant.eigs create mode 100644 tests/phase2/calib/cal.fn-keep-plant.out create mode 100644 tests/phase2/calib/cal.fn-keep.eigs create mode 100644 tests/phase2/calib/cal.fn-keep.out create mode 100644 tests/phase2/calib/cal.fnstop-cat-plant.eigs create mode 100644 tests/phase2/calib/cal.fnstop-cat-plant.out create mode 100644 tests/phase2/calib/cal.fnstop-cat.eigs create mode 100644 tests/phase2/calib/cal.fnstop-cat.out create mode 100644 tests/phase2/calib/cal.leaf-sq-plant.eigs create mode 100644 tests/phase2/calib/cal.leaf-sq-plant.out create mode 100644 tests/phase2/calib/cal.leaf-sq.eigs create mode 100644 tests/phase2/calib/cal.leaf-sq.out create mode 100644 tests/phase2/calib/cal.leafgen-nth-plant.eigs create mode 100644 tests/phase2/calib/cal.leafgen-nth-plant.out create mode 100644 tests/phase2/calib/cal.leafgen-nth.eigs create mode 100644 tests/phase2/calib/cal.leafgen-nth.out create mode 100644 tests/phase2/calib/cal.osr-fill-plant.eigs create mode 100644 tests/phase2/calib/cal.osr-fill-plant.out create mode 100644 tests/phase2/calib/cal.osr-fill.eigs create mode 100644 tests/phase2/calib/cal.osr-fill.out create mode 100644 tests/phase2/calib/cal.osrstop-g-plant.eigs create mode 100644 tests/phase2/calib/cal.osrstop-g-plant.out create mode 100644 tests/phase2/calib/cal.osrstop-g.eigs create mode 100644 tests/phase2/calib/cal.osrstop-g.out create mode 100644 tests/phase2/calib/cal.verdict.eigs create mode 100644 tests/phase2/calib/cal.verdict.out create mode 100755 tools/phase2_check.py create mode 100755 tools/phase2_check.sh create mode 100755 tools/phase2_corpus_diff.sh diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 7071aa28b..1456cfaf3 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2187,6 +2187,39 @@ fails if a round named here has neither rows nor its mechanical gates.) mechanical gates, `mapped=0`; and with the int-source check planted (a production `slot_from_int(count)` call): exit 1. +**As built in R1.1** (`tools/phase2_check.sh`, a wrapper over +`tools/phase2_check.py`, whose docstring is the reference): +- **Controls land with R1.3**, the first round with rows of its own. Under a + mechanical `--through` they are not required: their witnesses are about + ints (`ctl.N1.fn-int-truthiness` expects the int call to bail), which + cannot hold before an int exists. +- **The leaf witness is read in the default and `osr` tiers.** With + `EIGS_JIT_OFF=1` the hot table counts no call at all (probed on the R1.1 + binary: a function called 60 times has no row), so the `off` tier cannot + witness either way. +- **The token gate** checks, in every mode, that each token a landed round + deleted (2.7) occurs in no code line of `src/` or `tests/` C files. +- **The corpus differential** is `tools/phase2_corpus_diff.sh + `: both binaries run every `.eigs` under the branch tree's + `tests/` from the branch tree's `src/` (the suite's cwd), so the file and + whatever it loads by a relative path are the same bytes for both; only + the binary and its stdlib differ. A file only the branch has (a new + fixture) is counted as `new`; one only the baseline has is a DELETED + failure. A file whose baseline disagrees with itself (randomness, timing) + is replayed: the baseline records a tape, replays it twice, and the branch + replays it once; the branch must match (`same_under_replay`), or it is a + DIFF. Only files whose replays disagree with each other stay NONDET. +- **The calibration** is `phase2_check.sh --calibrate [--build-plants] + `, on the fixtures in `tests/phase2/calib/`: each ends in a line + that fails on the tag (#1740: `5.5 & 1` raises `value` on the branch and + truncates on v0.46.0), so an honest fixture has tag_fail == branch_pass. + `--through R1.2` cannot pass on the R1.1 tree (its token gate would find + `VAL_NUM`, correctly), so the R1.1 run of that item is `--through R1.1`; + the int-source plant runs against a planted copy of `src/`. Cases the + design did not list were added for the plan-level checks (an item with no + row, an arm no row exercises, a round with neither rows nor gates) and + for the token gate (a reintroduced `slot_is_num`). + ### 9.3 `tools/phase2_plants.sh` (round 1 builds it; detached, about 7 release builds) Each plant: @@ -2219,6 +2252,13 @@ The tier-witness and leaf-differential plants (§9.2's calibration) belong to `phase2_check.sh`'s own calibration, not to this list: they test the instrument, not the semantics. +As built in R1.1, the tool holds the plants whose named checks exist: plant +1 (`slot_from_int` tags an int that fits as a heap pointer; its named line +is `slot-layer-test: FAIL slot_from_int(0): bits ...`). Plants 2-7 join the +table in the commits that land their rows, and its output then reads +`plants=7`. Its transverse run deletes exactly the named assertion +(`if (s.u != smi(v).u)` becomes `if (0)`) and requires the plant to pass. + ### 9.4 The per-builtin behaviour table (R1.6's gate; replaces the int-fuzz class check) Round 2 planned an int-fuzz gate asserting "the result is an int for int diff --git a/tests/phase2/calib/MAP.md b/tests/phase2/calib/MAP.md new file mode 100644 index 000000000..a426e9e2f --- /dev/null +++ b/tests/phase2/calib/MAP.md @@ -0,0 +1,67 @@ +# tests/phase2/calib/MAP.md: phase2_check.sh --calibrate fixtures (design 9.2) + +Every row ends in a line that fails on the v0.46.0 tag (#1740: `5.5 & 1` +raises `value` on the branch, the tag truncates), so an honest row has +tag_fail == branch_pass. `-plant` rows are the negative witness plants of +design 9.1: the claimed op does not run as claimed, so each must be VACUOUS. + +### N1 +- `cal.verdict` [R1.3] a straight-line row: #1740 raises `value` on a fractional bitwise operand, the tag truncates + -> see cal.verdict.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) +- `cal.fn-keep` [R1.3] keep runs natively to its return on its 60th call + -> see cal.fn-keep.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: F witness: fn keep ops: SET_LOCAL +- `cal.fn-keep-plant` [R1.3] plant: an unsupported op (LIST) ahead of the claimed one + -> see cal.fn-keep-plant.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: F witness: fn keep ops: SET_LOCAL +- `cal.fn-keep-10calls-plant` [R1.3] plant: 10 calls instead of 60, so the JIT never compiles keep + -> see cal.fn-keep-10calls-plant.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: F witness: fn keep ops: SET_LOCAL + +### N3 +- `cal.leaf-sq` [R1.3] the leaf computes sq: no entries normally, 1 under trace + -> see cal.leaf-sq.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: L witness: leaf sq ops: MUL +- `cal.leaf-sq-plant` [R1.3] plant: two statements, not leaf-eligible + -> see cal.leaf-sq-plant.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: L witness: leaf sq ops: MUL +- `cal.fnstop-cat` [R1.3] the ADD guard bails on two strings + -> see cal.fnstop-cat.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: F witness: fn-stop cat ADD ops: ADD +- `cal.fnstop-cat-plant` [R1.3] plant: two floats, so ADD runs natively to the return + -> see cal.fnstop-cat-plant.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: F witness: fn-stop cat ADD ops: ADD +- `cal.osrstop-g` [R1.3] every OSR entry hands back at the string ADD + -> see cal.osrstop-g.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: O witness: osr-stop g ADD ops: ADD +- `cal.osrstop-g-plant` [R1.3] plant: a float ADD, which runs natively to the sentinel + -> see cal.osrstop-g-plant.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: O witness: osr-stop g ADD ops: ADD + +### N5 +- `cal.leafgen-nth` [R1.3] the leaf INDEX_GET bails on a string, the generic call indexes + -> see cal.leafgen-nth.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: L witness: leaf-gen nth ops: INDEX_GET +- `cal.leafgen-nth-plant` [R1.3] plant: a list, which the leaf computes itself + -> see cal.leafgen-nth-plant.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: L witness: leaf-gen nth ops: INDEX_GET +- `cal.osr-fill` [R1.3] the OSR thunk runs the body natively to the return sentinel + -> see cal.osr-fill.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: O witness: osr fill ops: INDEX_SET +- `cal.osr-fill-plant` [R1.3] plant: a string concat ahead of the claimed op, so INDEX_SET never runs natively + -> see cal.osr-fill-plant.out + tag: the last line prints 1 (read: v0.46.0 truncates a bitwise operand) + shape: O witness: osr fill ops: INDEX_SET diff --git a/tests/phase2/calib/cal.fn-keep-10calls-plant.eigs b/tests/phase2/calib/cal.fn-keep-10calls-plant.eigs new file mode 100644 index 000000000..f92c03f74 --- /dev/null +++ b/tests/phase2/calib/cal.fn-keep-10calls-plant.eigs @@ -0,0 +1,20 @@ +# ROW: cal.fn-keep-10calls-plant +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn keep +# OPS: SET_LOCAL +# plant: 10 calls instead of 60, so the JIT never compiles keep +define keep(q) as: + t is q + return t +k is 0 +r is 0 +loop while k < 10: + r is keep of 2.5 + k is k + 1 +print of r +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.fn-keep-10calls-plant.out b/tests/phase2/calib/cal.fn-keep-10calls-plant.out new file mode 100644 index 000000000..f972948d1 --- /dev/null +++ b/tests/phase2/calib/cal.fn-keep-10calls-plant.out @@ -0,0 +1,2 @@ +2.5 +value diff --git a/tests/phase2/calib/cal.fn-keep-plant.eigs b/tests/phase2/calib/cal.fn-keep-plant.eigs new file mode 100644 index 000000000..642f97213 --- /dev/null +++ b/tests/phase2/calib/cal.fn-keep-plant.eigs @@ -0,0 +1,21 @@ +# ROW: cal.fn-keep-plant +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn keep +# OPS: SET_LOCAL +# plant: an unsupported op (LIST) ahead of the claimed one +define keep(q) as: + zz is [q] + t is q + return t +k is 0 +r is 0 +loop while k < 60: + r is keep of 2.5 + k is k + 1 +print of r +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.fn-keep-plant.out b/tests/phase2/calib/cal.fn-keep-plant.out new file mode 100644 index 000000000..f972948d1 --- /dev/null +++ b/tests/phase2/calib/cal.fn-keep-plant.out @@ -0,0 +1,2 @@ +2.5 +value diff --git a/tests/phase2/calib/cal.fn-keep.eigs b/tests/phase2/calib/cal.fn-keep.eigs new file mode 100644 index 000000000..15c2579e3 --- /dev/null +++ b/tests/phase2/calib/cal.fn-keep.eigs @@ -0,0 +1,20 @@ +# ROW: cal.fn-keep +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn keep +# OPS: SET_LOCAL +# keep runs natively to its return on its 60th call +define keep(q) as: + t is q + return t +k is 0 +r is 0 +loop while k < 60: + r is keep of 2.5 + k is k + 1 +print of r +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.fn-keep.out b/tests/phase2/calib/cal.fn-keep.out new file mode 100644 index 000000000..f972948d1 --- /dev/null +++ b/tests/phase2/calib/cal.fn-keep.out @@ -0,0 +1,2 @@ +2.5 +value diff --git a/tests/phase2/calib/cal.fnstop-cat-plant.eigs b/tests/phase2/calib/cal.fnstop-cat-plant.eigs new file mode 100644 index 000000000..ee7f53551 --- /dev/null +++ b/tests/phase2/calib/cal.fnstop-cat-plant.eigs @@ -0,0 +1,20 @@ +# ROW: cal.fnstop-cat-plant +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop cat ADD +# OPS: ADD +# plant: two floats, so ADD runs natively to the return +define cat(a, b) as: + t is a + b + return t +k is 0 +r is 0 +loop while k < 60: + r is cat of [1.5, 2.5] + k is k + 1 +print of r +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.fnstop-cat-plant.out b/tests/phase2/calib/cal.fnstop-cat-plant.out new file mode 100644 index 000000000..4022b19ee --- /dev/null +++ b/tests/phase2/calib/cal.fnstop-cat-plant.out @@ -0,0 +1,2 @@ +4 +value diff --git a/tests/phase2/calib/cal.fnstop-cat.eigs b/tests/phase2/calib/cal.fnstop-cat.eigs new file mode 100644 index 000000000..61b9574b0 --- /dev/null +++ b/tests/phase2/calib/cal.fnstop-cat.eigs @@ -0,0 +1,20 @@ +# ROW: cal.fnstop-cat +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop cat ADD +# OPS: ADD +# the ADD guard bails on two strings +define cat(a, b) as: + t is a + b + return t +k is 0 +r is 0 +loop while k < 60: + r is cat of ["x", "y"] + k is k + 1 +print of r +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.fnstop-cat.out b/tests/phase2/calib/cal.fnstop-cat.out new file mode 100644 index 000000000..3fcbc97f9 --- /dev/null +++ b/tests/phase2/calib/cal.fnstop-cat.out @@ -0,0 +1,2 @@ +xy +value diff --git a/tests/phase2/calib/cal.leaf-sq-plant.eigs b/tests/phase2/calib/cal.leaf-sq-plant.eigs new file mode 100644 index 000000000..9b0b138ba --- /dev/null +++ b/tests/phase2/calib/cal.leaf-sq-plant.eigs @@ -0,0 +1,15 @@ +# ROW: cal.leaf-sq-plant +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf sq +# OPS: MUL +# plant: two statements, not leaf-eligible +define sq(x) as: + y is x * x + return y +print of (sq of 1.5) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.leaf-sq-plant.out b/tests/phase2/calib/cal.leaf-sq-plant.out new file mode 100644 index 000000000..24e0d191c --- /dev/null +++ b/tests/phase2/calib/cal.leaf-sq-plant.out @@ -0,0 +1,2 @@ +2.25 +value diff --git a/tests/phase2/calib/cal.leaf-sq.eigs b/tests/phase2/calib/cal.leaf-sq.eigs new file mode 100644 index 000000000..f62879539 --- /dev/null +++ b/tests/phase2/calib/cal.leaf-sq.eigs @@ -0,0 +1,14 @@ +# ROW: cal.leaf-sq +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf sq +# OPS: MUL +# the leaf computes sq: no entries normally, 1 under trace +define sq(x) as: + return x * x +print of (sq of 1.5) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.leaf-sq.out b/tests/phase2/calib/cal.leaf-sq.out new file mode 100644 index 000000000..24e0d191c --- /dev/null +++ b/tests/phase2/calib/cal.leaf-sq.out @@ -0,0 +1,2 @@ +2.25 +value diff --git a/tests/phase2/calib/cal.leafgen-nth-plant.eigs b/tests/phase2/calib/cal.leafgen-nth-plant.eigs new file mode 100644 index 000000000..3fbdcba52 --- /dev/null +++ b/tests/phase2/calib/cal.leafgen-nth-plant.eigs @@ -0,0 +1,14 @@ +# ROW: cal.leafgen-nth-plant +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf-gen nth +# OPS: INDEX_GET +# plant: a list, which the leaf computes itself +define nth(xs, i) as: + return xs[i] +print of (nth of [[10, 20], 0.0]) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.leafgen-nth-plant.out b/tests/phase2/calib/cal.leafgen-nth-plant.out new file mode 100644 index 000000000..776f504dc --- /dev/null +++ b/tests/phase2/calib/cal.leafgen-nth-plant.out @@ -0,0 +1,2 @@ +10 +value diff --git a/tests/phase2/calib/cal.leafgen-nth.eigs b/tests/phase2/calib/cal.leafgen-nth.eigs new file mode 100644 index 000000000..924109996 --- /dev/null +++ b/tests/phase2/calib/cal.leafgen-nth.eigs @@ -0,0 +1,14 @@ +# ROW: cal.leafgen-nth +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf-gen nth +# OPS: INDEX_GET +# the leaf INDEX_GET bails on a string, the generic call indexes +define nth(xs, i) as: + return xs[i] +print of (nth of ["abc", 0.0]) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.leafgen-nth.out b/tests/phase2/calib/cal.leafgen-nth.out new file mode 100644 index 000000000..89f2f84b9 --- /dev/null +++ b/tests/phase2/calib/cal.leafgen-nth.out @@ -0,0 +1,2 @@ +a +value diff --git a/tests/phase2/calib/cal.osr-fill-plant.eigs b/tests/phase2/calib/cal.osr-fill-plant.eigs new file mode 100644 index 000000000..56edba6db --- /dev/null +++ b/tests/phase2/calib/cal.osr-fill-plant.eigs @@ -0,0 +1,22 @@ +# ROW: cal.osr-fill-plant +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr fill +# OPS: INDEX_SET +# plant: a string concat ahead of the claimed op, so INDEX_SET never runs natively +define fill(big, n) as: + xs is [0, 0, 0, 0] + s is "" + i is 0.0 + loop while true: + s is s + "a" + xs[i] is big + i is i + 1.0 + if i >= n: + return xs +print of (fill of [9007199254740993, 4.0]) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.osr-fill-plant.out b/tests/phase2/calib/cal.osr-fill-plant.out new file mode 100644 index 000000000..4600611f9 --- /dev/null +++ b/tests/phase2/calib/cal.osr-fill-plant.out @@ -0,0 +1,2 @@ +[9007199254740992, 9007199254740992, 9007199254740992, 9007199254740992] +value diff --git a/tests/phase2/calib/cal.osr-fill.eigs b/tests/phase2/calib/cal.osr-fill.eigs new file mode 100644 index 000000000..4435ed2a1 --- /dev/null +++ b/tests/phase2/calib/cal.osr-fill.eigs @@ -0,0 +1,20 @@ +# ROW: cal.osr-fill +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr fill +# OPS: INDEX_SET +# the OSR thunk runs the body natively to the return sentinel +define fill(big, n) as: + xs is [0, 0, 0, 0] + i is 0.0 + loop while true: + xs[i] is big + i is i + 1.0 + if i >= n: + return xs +print of (fill of [9007199254740993, 4.0]) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.osr-fill.out b/tests/phase2/calib/cal.osr-fill.out new file mode 100644 index 000000000..4600611f9 --- /dev/null +++ b/tests/phase2/calib/cal.osr-fill.out @@ -0,0 +1,2 @@ +[9007199254740992, 9007199254740992, 9007199254740992, 9007199254740992] +value diff --git a/tests/phase2/calib/cal.osrstop-g-plant.eigs b/tests/phase2/calib/cal.osrstop-g-plant.eigs new file mode 100644 index 000000000..c87994621 --- /dev/null +++ b/tests/phase2/calib/cal.osrstop-g-plant.eigs @@ -0,0 +1,20 @@ +# ROW: cal.osrstop-g-plant +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr-stop g ADD +# OPS: ADD +# plant: a float ADD, which runs natively to the sentinel +define g(n) as: + s is 0.5 + i is 0.0 + loop while true: + s is s + 1.5 + i is i + 1.0 + if i >= n: + return s +print of (g of 4.0) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.osrstop-g-plant.out b/tests/phase2/calib/cal.osrstop-g-plant.out new file mode 100644 index 000000000..c70647f99 --- /dev/null +++ b/tests/phase2/calib/cal.osrstop-g-plant.out @@ -0,0 +1,2 @@ +6.5 +value diff --git a/tests/phase2/calib/cal.osrstop-g.eigs b/tests/phase2/calib/cal.osrstop-g.eigs new file mode 100644 index 000000000..85d066fa3 --- /dev/null +++ b/tests/phase2/calib/cal.osrstop-g.eigs @@ -0,0 +1,20 @@ +# ROW: cal.osrstop-g +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr-stop g ADD +# OPS: ADD +# every OSR entry hands back at the string ADD +define g(n) as: + s is "" + i is 0.0 + loop while true: + s is s + "a" + i is i + 1.0 + if i >= n: + return s +print of (g of 4.0) +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.osrstop-g.out b/tests/phase2/calib/cal.osrstop-g.out new file mode 100644 index 000000000..0b351f4d9 --- /dev/null +++ b/tests/phase2/calib/cal.osrstop-g.out @@ -0,0 +1,2 @@ +aaaa +value diff --git a/tests/phase2/calib/cal.verdict.eigs b/tests/phase2/calib/cal.verdict.eigs new file mode 100644 index 000000000..1bf548c06 --- /dev/null +++ b/tests/phase2/calib/cal.verdict.eigs @@ -0,0 +1,11 @@ +# ROW: cal.verdict +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# a straight-line row: #1740 raises `value` on a fractional bitwise operand, the tag truncates +try: + print of (5.5 & 1) +catch e: + print of e.kind diff --git a/tests/phase2/calib/cal.verdict.out b/tests/phase2/calib/cal.verdict.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/calib/cal.verdict.out @@ -0,0 +1 @@ +value diff --git a/tools/phase2_check.py b/tools/phase2_check.py new file mode 100755 index 000000000..4c434056c --- /dev/null +++ b/tools/phase2_check.py @@ -0,0 +1,765 @@ +#!/usr/bin/env python3 +"""tools/phase2_check.py -- #1758 Phase 2's row checker (design 9.2). Run it +through tools/phase2_check.sh; `--help` lists the options. + +ROWS. tests/phase2/MAP.md maps the #1758 items to rows; a row is +tests/phase2/rows/.eigs (or .sh, run as `bash .sh `) with +its exact branch stdout in .out and a header (`# ROW:`, `# ITEMS:`, +`# EXPECT-RC:`, `# SHAPE:`, `# WITNESS:`, `# OPS:`, optional `# TIERS:`). +Controls (ctl.*) live in tests/phase2/controls/ and must pass on BOTH +binaries. `--through Rk` selects the rows whose [Rn] has landed by Rk. + +TIERS. off (EIGS_JIT_OFF=1), default, osr (EIGS_JIT_OSR_THRESHOLD=1) and +trace (EIGS_TRACE, default JIT: the leaf evaluator is off there, so this +tier is the leaf differential). Every run: 30 s bound, stdin /dev/null, a +fresh scratch cwd, every inherited EIGS_* variable removed. + +VERDICTS per row and tier: branch PASS = rc equals EXPECT-RC and stdout +equals the .out; tag FAIL = not that; VACUOUS = the branch passed but the +row's tier witness (design 9.1) does not hold. rc 124 is TIMEOUT and rc >= +128 SIGNAL: a FAIL on the branch, counted apart on the tag. + +WITNESSES (read on the branch, from EIGS_JIT_HOT / STATS / STOPS and +EIGS_DUMP_BC; nothing in production changes so a witness can see it): + leaf F... JIT-on normal runs (default, osr) count no entry for F, and + the trace run counts K >= 1: the leaf computed every call. + (With EIGS_JIT_OFF the hot table counts no calls at all, so + the off tier cannot witness.) + leaf-gen F... the default run and the trace run count the same K >= 1. + fn F default and osr runs: `jit yes`, `adv RET`, compiled >= 1. + fn-stop F OP default run: `jit yes`, the op at offset `adv` is OP. + osr C osr run: `osr yes` and oadv == len (the return sentinel). + osr-stop C OP osr run: `osr yes`, oadv != len, the op at oent+oadv is OP. +A -stop whose op is the chunk's compile stop must also be named by +EIGS_JIT_STOPS. + +MECHANICAL ROUNDS (R1.1, R1.2, R2.1) have no rows of their own; --through +one of them runs its gates instead: the token gate (every token a landed +round deleted is absent from code), the int-source check (before R1.3 no +runtime code calls slot_from_int or make_int outside the canonicalizing +writers; make_int does not exist), the C slot test, and the corpus +differential against --baseline (the binary from before the round). + +Exit 0 iff the population checks pass, every tier has examined == tag_fail +== branch_pass > 0 (or the round is mechanical and every gate passed), +vacuous == 0, and every landed control passes on both binaries. +`--calibrate` runs the design's calibration list (9.2) on fixtures in +tests/phase2/calib/ and prints `calibration: cases=N as-expected=N`. +""" +import argparse +import os +import re +import shutil +import subprocess +import sys +import tempfile + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, os.path.join(ROOT, 'tools')) +import phase2_inventory as inv # noqa: E402 (strip_c: one C-comment grammar) + +ROUNDS = ['R1.1', 'R1.2', 'R1.3', 'R1.4', 'R1.5', 'R1.6', 'R1.7', 'R1.8', + 'R2.1', 'R2.2', 'R2.3', 'R2.4', 'R2.5', 'R2.6', 'R3'] +MECHANICAL = { + 'R1.1': ('tokens', 'int-source', 'slot-test', 'corpus-diff'), + 'R1.2': ('tokens', 'int-source', 'slot-test', 'corpus-diff'), + 'R2.1': ('tokens', 'slot-test', 'corpus-diff'), +} +ITEMS = ['N%d' % i for i in range(1, 15)] + ['N4b', 'A', 'B', 'T1', 'O1', 'O2', 'O3', 'O4'] +# design 2.7: the tokens each round deletes. A later round adds its list here +# in the commit that deletes them (R1.6's bridge, 21 tokens, with R1.6). +DELETED_TOKENS = { + 'R1.1': ['slot_is_num', 'slot_is_numeric', 'SLOT_NUM_RAW', 'slot_from_num', 'slot_as_double'], + 'R1.3': ['eigs_int_unwired'], + 'R2.2': ['num_guard', 'num_guard_named', 'EIGS_NUM_MAX'], +} +# design 2.1: the canonicalizing writers, the only runtime callers of an int +# writer allowed before R1.3 (they convert an existing VAL_INT). +INT_SOURCE_ALLOWED = {'eigs_container_slot', 'eigs_slot_adopt', 'eigs_slot_store_owned', + 'eigs_slot_store_borrow', 'slot_from_value'} +WITNESS_KINDS = {'none', 'leaf', 'leaf-gen', 'fn', 'fn-stop', 'osr', 'osr-stop'} +TIERS = ['off', 'default', 'osr', 'trace'] +HOT_HDR = re.compile(r'^chunk\s+exec\s+jit\s+pct\s+adv\s+len\s+nat%\s+bked\s+osr\s+oadv\s+oent\s+stop$') + + +def rindex(r): + return ROUNDS.index(r) + + +# ---- the MAP --------------------------------------------------------------- +ROW_LINE = re.compile(r'^- `([^`]+)` (?:\[([^\]]+)\]|\((control)\))') +SHAPE_LINE = re.compile(r'^\s+shape:\s*([LFO])\s+witness:\s*(.*?)\s+ops:\s*(.*?)\s*$') + + +def parse_witness(text): + text = re.sub(r'\([^)]*\)', ' ', text).split() + if not text: + return None + kind = text[0] + if kind.endswith('-stop'): + return {'kind': kind, 'chunks': text[1:-1], 'op': text[-1] if len(text) > 2 else None} + return {'kind': kind, 'chunks': text[1:], 'op': None} + + +def parse_map(path): + rows, bad, item = [], [], None + lines = open(path, encoding='utf-8').read().split('\n') + for n, line in enumerate(lines, 1): + m = re.match(r'^### (\S+)\s*$', line) + if m: + item = m.group(1) + continue + m = ROW_LINE.match(line) + if not m: + continue + rid, rnd, ctl = m.group(1), m.group(2), m.group(3) + row = {'id': rid, 'item': item, 'line': n, 'shape': 'S', 'sketch': line[m.end():], + 'witness': {'kind': 'none', 'chunks': [], 'op': None}, 'ops': []} + if rid.startswith('ctl.') != bool(ctl): + bad.append('MAP:%d: `%s`: a control must be marked (control), and only a control' % (n, rid)) + row['kind'] = 'control' if ctl else 'gate' if rid.startswith('gate.') else 'row' + if rnd: + parts = rnd.split('/') + if any(p not in ROUNDS for p in parts): + bad.append('MAP:%d: `%s` names an unknown round [%s]' % (n, rid, rnd)) + continue + row['round'] = max(parts, key=rindex) + else: + row['round'] = None + for follow in lines[n:n + 4]: + if follow.startswith('- ') or follow.startswith('#'): + break + ms = SHAPE_LINE.match(follow) + if ms: + row['shape'] = ms.group(1) + w = parse_witness(ms.group(2)) + if not w or w['kind'] not in WITNESS_KINDS: + bad.append('MAP:%d: `%s` has an unknown witness %r' % (n, rid, ms.group(2))) + else: + row['witness'] = w + row['ops'] = ms.group(3).split() + rows.append(row) + return rows, bad + + +def header(path): + h = {} + for line in open(path, encoding='utf-8'): + m = re.match(r'^#\s*([A-Z-]+):\s*(.*?)\s*$', line) + if not m: + if line.strip() and not line.startswith('#'): + break + continue + h[m.group(1)] = m.group(2) + return h + + +def row_file(d, rid): + for ext in ('.eigs', '.sh'): + p = os.path.join(d, rid + ext) + if os.path.exists(p): + return p + return None + + +# ---- running --------------------------------------------------------------- +def run(binary, path, env_extra, scratch): + env = {k: v for k, v in os.environ.items() if not k.startswith('EIGS_')} + env.update(env_extra) + cwd = tempfile.mkdtemp(dir=scratch) + if 'EIGS_TRACE' in env and env['EIGS_TRACE'] == '@': + env['EIGS_TRACE'] = os.path.join(cwd, 't.tape') + cmd = (['bash', path, binary] if path.endswith('.sh') else [binary, path]) + tmo = shutil.which('timeout') or shutil.which('gtimeout') + if tmo: + cmd = [tmo, '30'] + cmd + try: + p = subprocess.run(cmd, cwd=cwd, env=env, stdin=subprocess.DEVNULL, + capture_output=True, timeout=60) + return p.returncode, p.stdout.decode('utf-8', 'replace'), p.stderr.decode('utf-8', 'replace') + except subprocess.TimeoutExpired: + return 124, '', 'phase2-check: the 60 s backstop fired' + finally: + shutil.rmtree(cwd, ignore_errors=True) + + +TIER_ENV = {'off': {'EIGS_JIT_OFF': '1'}, 'default': {}, 'osr': {'EIGS_JIT_OSR_THRESHOLD': '1'}, + 'trace': {'EIGS_TRACE': '@'}} + + +def hot_rows(err): + lines = err.split('\n') + try: + i = next(k for k, l in enumerate(lines) if HOT_HDR.match(l.strip())) + except StopIteration: + return None + rows = {} + for l in lines[i + 1:]: + w = l.split() + if len(w) != 12 or not w[1].isdigit(): + break + rows[w[0]] = dict(exec=int(w[1]), jit=w[2], adv=w[4], len=int(w[5]), osr=w[8], + oadv=int(w[9]), oent=int(w[10]), stop=w[11]) + return rows + + +def compiled(err): + m = re.search(r'\[jit\] scanned=\d+ compiled=(\d+)', err) + return int(m.group(1)) if m else -1 + + +def bytecode(text, chunk): + ops, cur = {}, None + for l in text.split('\n'): + m = re.match(r'^=== (\S+) \((\S+?), (\d+) bytes', l) + if m: + cur = m.group(2) + continue + m = re.match(r'^(\d{4}) \[L\d+\] (\S+)', l) + if m and cur == chunk: + ops[int(m.group(1))] = m.group(2) + return ops + + +def witness(binary, path, w, scratch): + """(holds, evidence). Instrument failures (no hot table) do not hold.""" + kind, chunks, op = w['kind'], w['chunks'], w['op'] + diag = {'EIGS_JIT_HOT': '1', 'EIGS_JIT_STATS': '1', 'EIGS_JIT_STOPS': '1'} + ev = [] + if kind in ('leaf', 'leaf-gen'): + _, _, terr = run(binary, path, dict(diag, EIGS_TRACE='@'), scratch) + thot = hot_rows(terr) + if thot is None: + return False, 'no EIGS_JIT_HOT table in the trace run' + ok = True + for tier in ('default', 'osr'): + _, _, err = run(binary, path, dict(TIER_ENV[tier], **diag), scratch) + hot = hot_rows(err) + if hot is None: + return False, 'no EIGS_JIT_HOT table (%s)' % tier + for c in chunks: + kn, kt = hot.get(c, {}).get('exec', 0), thot.get(c, {}).get('exec', 0) + ev.append('%s %s=%d trace=%d' % (c, tier, kn, kt)) + if kt < 1 or (kind == 'leaf' and kn != 0) or (kind == 'leaf-gen' and kn != kt): + ok = False + if kind == 'leaf-gen': + break # the generic path is the same in both JIT tiers + return ok and bool(chunks), '; '.join(ev) + tiers = ('default', 'osr') if kind == 'fn' else ('default',) if kind == 'fn-stop' else ('osr',) + c = chunks[0] if chunks else None + ok = bool(c) + for tier in tiers: + env = dict(TIER_ENV[tier], **diag) + _, _, err = run(binary, path, env, scratch) + hot = hot_rows(err) + r = (hot or {}).get(c) + if r is None: + return False, '%s: no EIGS_JIT_HOT row for %s' % (tier, c) + ev.append('%s %s jit=%s adv=%s len=%d osr=%s oadv=%d oent=%d stop=%s compiled=%d' % ( + tier, c, r['jit'], r['adv'], r['len'], r['osr'], r['oadv'], r['oent'], r['stop'], + compiled(err))) + if compiled(err) < 1: + ok = False + if kind == 'fn': + ok = ok and r['jit'] == 'yes' and r['adv'] == 'RET' + elif kind == 'osr': + ok = ok and r['osr'] == 'yes' and r['oadv'] == r['len'] + else: + _, dout, derr = run(binary, path, dict(TIER_ENV[tier], EIGS_DUMP_BC='1'), scratch) + ops = bytecode(dout + '\n' + derr, c) + if kind == 'fn-stop': + at = None if r['adv'] in ('RET', '?') else int(r['adv']) + ok = ok and r['jit'] == 'yes' and at is not None and ops.get(at) == op + else: + at = r['oent'] + r['oadv'] + ok = ok and r['osr'] == 'yes' and r['oadv'] != r['len'] and ops.get(at) == op + ev.append('op_at_stop=%s' % (ops.get(at) if at is not None else 'RET')) + if ok and r['stop'] == op and not re.search(r'\b%s\b' % re.escape(op), err.split( + '=== Hot chunks')[0]): + ok = False + ev.append('compile stop %s not named by EIGS_JIT_STOPS' % op) + return ok, '; '.join(ev) + + +# ---- the row check ----------------------------------------------------------- +def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): + """Runs the landed rows and controls; returns (ok, counters).""" + landed = [r for r in map_rows if r['kind'] == 'row' and r['round'] and + rindex(r['round']) <= rindex(through)] + controls = [r for r in map_rows if r['kind'] == 'control'] + gates = [r for r in map_rows if r['kind'] == 'gate' and r['round'] and + rindex(r['round']) <= rindex(through)] + bad = [] + ids = {r['id'] for r in map_rows} + files = sorted(f for f in (os.listdir(rows_dir) if os.path.isdir(rows_dir) else []) + if f.endswith(('.eigs', '.sh'))) + for f in files: + stem = f.rsplit('.', 1)[0] + if stem not in ids: + bad.append('row file %s has no MAP id' % f) + # controls land with the first round that has rows of its own (R1.3) + want_controls = any(rindex(r['round']) <= rindex(through) for r in map_rows + if r['kind'] == 'row' and r['round']) + ctl_files = sorted(f for f in (os.listdir(ctl_dir) if os.path.isdir(ctl_dir) else []) + if f.endswith(('.eigs', '.sh'))) + for f in ctl_files: + if f.rsplit('.', 1)[0] not in ids: + bad.append('control file %s has no MAP id' % f) + todo = [] + for r in landed + (controls if want_controls else []): + d = ctl_dir if r['kind'] == 'control' else rows_dir + p = row_file(d, r['id']) + if not p: + bad.append('MAP id %s [%s] has no file in %s' % (r['id'], r['round'] or 'control', d)) + continue + h = header(p) + if h.get('ROW') != r['id']: + bad.append('%s: header ROW %r is not its id' % (p, h.get('ROW'))) + if h.get('SHAPE', 'S') != r['shape']: + bad.append('%s: SHAPE %s, the MAP says %s' % (p, h.get('SHAPE'), r['shape'])) + hw = parse_witness(h.get('WITNESS', 'none')) or {} + if (hw.get('kind'), hw.get('chunks'), hw.get('op')) != ( + r['witness']['kind'], r['witness']['chunks'], r['witness']['op']): + bad.append('%s: WITNESS %r differs from the MAP' % (p, h.get('WITNESS'))) + if not os.path.exists(p.rsplit('.', 1)[0] + '.out'): + bad.append('%s: no .out' % p) + continue + todo.append((r, p, h)) + for g in gates: + # a gate names a check the Done-when runs on its own: its file or + # make target must exist (it is listed, never run or counted here) + named = [t for t in re.findall(r'`([^`]+)`', g['sketch']) + if t.startswith('make ') or ('/' in t and ' ' not in t)] + for t in named: + found = (subprocess.run(['make', '-n', '-C', ROOT] + t.split()[1:], capture_output=True + ).returncode == 0 if t.startswith('make ') + else os.path.exists(os.path.join(ROOT, t))) + if not found: + bad.append('gate %s names %r, which does not exist' % (g['id'], t)) + if not named: + bad.append('gate %s names no file or make target' % g['id']) + cnt = {t: dict(examined=0, tag_fail=0, branch_pass=0, vacuous=0, tag_timeout=0, tag_signal=0) + for t in TIERS} + ctl_n = ctl_both = witnessed = 0 + for r, p, h in todo: + want = open(p.rsplit('.', 1)[0] + '.out', encoding='utf-8').read() + want_rc = int(h.get('EXPECT-RC', '0')) + tiers = h.get('TIERS', ' '.join(TIERS)).split() + is_ctl = r['kind'] == 'control' + passes = {} + for t in tiers: + res = {} + for who, b in (('tag', tag), ('branch', branch)): + rc, so, se = run(b, p, TIER_ENV[t], scratch) + res[who] = (rc == want_rc and so == want, rc) + passes[t] = res + if is_ctl: + continue + c = cnt[t] + c['examined'] += 1 + ok_tag, rc_tag = res['tag'] + ok_br, rc_br = res['branch'] + if not ok_tag: + c['tag_fail'] += 1 + c['tag_timeout'] += rc_tag == 124 + c['tag_signal'] += rc_tag >= 128 + if ok_br: + c['branch_pass'] += 1 + else: + out(' BRANCH-FAIL %s tier=%s rc=%d%s' % (r['id'], t, rc_br, + ' TIMEOUT' if rc_br == 124 else ' SIGNAL' if rc_br >= 128 else '')) + if ok_tag: + out(' TAG-PASS %s tier=%s: the row does not fail on the tag' % (r['id'], t)) + if is_ctl: + ctl_n += 1 + if all(v[0] for res in passes.values() for v in res.values()): + ctl_both += 1 + else: + out(' CONTROL-FAIL %s: %s' % (r['id'], passes)) + continue + if r['witness']['kind'] != 'none' and all(passes[t]['branch'][0] for t in tiers): + holds, ev = witness(branch, p, r['witness'], scratch) + if holds: + witnessed += 1 + out(' WITNESS %s %s holds [%s]' % (r['id'], r['witness']['kind'], ev)) + else: + for t in tiers: + cnt[t]['vacuous'] += 1 + out(' VACUOUS %s %s [%s]' % (r['id'], r['witness']['kind'], ev)) + for b in bad: + out(' POPULATION: ' + b) + for t in TIERS: + c = cnt[t] + out('tier=%s examined=%d rows tag_fail=%d branch_pass=%d vacuous=%d tag_timeout=%d tag_signal=%d' + % (t, c['examined'], c['tag_fail'], c['branch_pass'], c['vacuous'], c['tag_timeout'], + c['tag_signal'])) + out('controls=%d both_pass=%d witnessed=%d mapped=%d gates=%d through=%s' % ( + ctl_n, ctl_both, witnessed, len(landed), len(gates), through)) + rows_ok = all(c['examined'] == c['tag_fail'] == c['branch_pass'] > 0 and c['vacuous'] == 0 + for c in cnt.values()) + return (not bad, rows_ok, ctl_n == ctl_both, len(landed), cnt, witnessed) + + +# ---- mechanical gates ---------------------------------------------------------- +def code_text(path): + return inv.strip_c(open(path, encoding='utf-8', errors='replace').read()) + + +def c_files(root, dirs=('src',), recurse_tests=True): + out = [] + for d in dirs: + out += [os.path.join(root, d, f) for f in sorted(os.listdir(os.path.join(root, d))) + if f.endswith(('.c', '.h'))] + if recurse_tests: + for base, _, fs in os.walk(os.path.join(root, 'tests')): + out += [os.path.join(base, f) for f in sorted(fs) if f.endswith(('.c', '.h'))] + return out + + +def token_gate(root, through, out): + toks = [t for r, ts in DELETED_TOKENS.items() if rindex(r) <= rindex(through) for t in ts] + files = c_files(root) + hits = [] + for p in files: + text = code_text(p) + for t in toks: + for m in re.finditer(r'\b%s\b' % re.escape(t), text): + hits.append('%s:%d %s' % (os.path.relpath(p, root), text.count('\n', 0, m.start()) + 1, t)) + for h in hits: + out(' TOKEN %s (deleted by a landed round, still in code)' % h) + out('tokens: rounds<=%s tokens=%d files=%d hits=%d' % (through, len(toks), len(files), len(hits))) + return bool(files) and bool(toks) and not hits + + +def int_source(src, out): + """Before R1.3: runtime calls of slot_from_int / make_int only inside the + canonicalizing writers; make_int is not defined; slot_from_int is defined + exactly once.""" + files = sorted(os.path.join(src, f) for f in os.listdir(src) if f.endswith(('.c', '.h'))) + defs = {'slot_from_int': 0, 'make_int': 0} + calls, bad = [], [] + for p in files: + text = code_text(p) + scope = inv.scopes_for(text, os.path.basename(p)) + for ln, line in enumerate(text.split('\n'), 1): + for m in re.finditer(r'\b(slot_from_int|make_int)\s*\(', line): + fn = scope[ln].split('/')[0] + name = m.group(1) + if fn == '' or fn == name: + defs[name] += 1 # a definition or a prototype + continue + calls.append((os.path.basename(p), ln, fn, name)) + if fn not in INT_SOURCE_ALLOWED: + bad.append('%s:%d: %s calls %s' % (os.path.basename(p), ln, fn, name)) + for b in bad: + out(' INT-SOURCE %s: no int may be produced before R1.3' % b) + if defs['make_int']: + out(' INT-SOURCE make_int is defined before R1.3') + if defs['slot_from_int'] != 1: + out(' INT-SOURCE slot_from_int is defined %d times, want 1 (did the scan find it?)' + % defs['slot_from_int']) + out('int-source: files=%d slot_from_int_defs=%d make_int_defs=%d calls=%d outside_writers=%d' % ( + len(files), defs['slot_from_int'], defs['make_int'], len(calls), len(bad))) + return bool(files) and not bad and not defs['make_int'] and defs['slot_from_int'] == 1 + + +def tool(cmd, out, tail_re): + p = subprocess.run(cmd, cwd=ROOT, stdin=subprocess.DEVNULL, capture_output=True) + text = (p.stdout + p.stderr).decode('utf-8', 'replace') + for l in text.split('\n'): + if re.match(tail_re, l): + out(' ' + l) + return p.returncode == 0, text + + +def mechanical(through, baseline, branch, out): + res = {} + for g in MECHANICAL[through]: + if g == 'tokens': + res[g] = token_gate(ROOT, through, out) + elif g == 'int-source': + res[g] = int_source(os.path.join(ROOT, 'src'), out) + elif g == 'slot-test': + res[g], _ = tool(['bash', 'tests/phase2/slot_layer.sh', 'release'], out, + r'^(slot-layer|slot-layer-population|slot-layer-test: (examined|FAIL))') + elif g == 'corpus-diff': + if not baseline: + out(' corpus-diff: a mechanical round needs --baseline ') + res[g] = False + else: + res[g], _ = tool(['bash', 'tools/phase2_corpus_diff.sh', baseline, branch], out, + r'^(corpus-diff: (baseline|branch|examined|PASS|FAIL)|DIFF|DELETED|NEW|NONDET|BOTH-)') + out('mechanical %s: %s' % (g, 'PASS' if res[g] else 'FAIL')) + return all(res.values()) and bool(res) + + +# ---- the plan-level checks ------------------------------------------------------- +def plan_checks(map_rows, bad, out): + for item in ITEMS: + if not any(r['item'] == item for r in map_rows if r['kind'] != 'control'): + bad.append('item %s has no row in the MAP' % item) + arms, lines, inside = {}, open(os.path.join(ROOT, 'docs/design/phase2-inventory.txt')).read( + ).split('\n'), False + for l in lines: + if l.startswith('## Numeric arms'): + inside = True + continue + if inside and (l.startswith('## ') or not l.strip()): + break + if inside: + w = l.split() + arms['%s %s' % (w[0], w[1])] = set(w[2:]) + # a leaf arm is exercised by a leaf (L) row, an emitter arm by an F or O row + shaped = [r for r in map_rows if r['shape'] in ('L', 'F', 'O')] + ops = {'leaf_exec': {('OP_' + o) for r in shaped if r['shape'] == 'L' for o in r['ops']}, + 'jit_emit': {('OP_' + o) for r in shaped if r['shape'] != 'L' for o in r['ops']}} + covered = [a for a, chain in arms.items() if chain & ops.get(a.split()[0], set())] + for a in sorted(set(arms) - set(covered)): + bad.append('numeric arm %s is exercised by no L/F/O row ops' % a) + rounds = {r['round'] for r in map_rows if r['round']} + for rd in ROUNDS: + if rd not in rounds and rd not in MECHANICAL: + bad.append('round %s has neither rows nor mechanical gates' % rd) + out('rounds: ' + ' '.join('%s=%d%s' % (rd, sum(r['round'] == rd for r in map_rows if r['kind'] == 'row'), + '+mechanical' if rd in MECHANICAL else + '+gates' if any(r['round'] == rd for r in map_rows + if r['kind'] == 'gate') else '') + for rd in ROUNDS)) + out('plan: items=%d rows=%d shaped=%d arms=%d covered=%d' % ( + len(ITEMS), sum(r['kind'] == 'row' for r in map_rows), len(shaped), len(arms), len(covered))) + if not arms: + bad.append('the inventory lists no numeric arm (scan found nothing)') + return len(arms) + + +def banner(tag, branch, out): + for who, b in (('tag', tag), ('branch', branch)): + v = subprocess.run([b, '--version'], capture_output=True).stdout.decode().strip() + h = subprocess.run(['sha256sum', b], capture_output=True).stdout.decode().split()[:1] + out('%s: %s (%s) sha256 %s' % (who, b, v, (h or ['?'])[0][:16])) + + +def main_check(args, out): + banner(args.tag, args.branch, out) + map_rows, bad = parse_map(args.map) + if not map_rows: + bad.append('the MAP lists no row') + plan_checks(map_rows, bad, out) + for b in bad: + out(' PLAN: ' + b) + with tempfile.TemporaryDirectory(prefix='eigs-p2-') as scratch: + pop_ok, rows_ok, ctl_ok, landed, cnt, _ = check( + map_rows, args.rows, args.controls, args.tag, args.branch, args.through, scratch, out) + mech_ok = None + if args.through in MECHANICAL: + mech_ok = mechanical(args.through, args.baseline, args.branch, out) + if landed == 0: + if mech_ok is None: + out(' ZERO-ROWS: %s has no landed row and no mechanical gates' % args.through) + verdict = bool(mech_ok) and pop_ok and not bad and ctl_ok + else: + verdict = rows_ok and pop_ok and not bad and ctl_ok and mech_ok is not False + out('phase2-check: %s' % ('PASS' if verdict else 'FAIL')) + return 0 if verdict else 1 + + +# ---- calibration (design 9.2, one-time) ------------------------------------------- +def calibrate(args, out): + cal = os.path.join(ROOT, 'tests/phase2/calib') + map_rows, bad = parse_map(os.path.join(cal, 'MAP.md')) + results = [] + + def case(name, got, want): + ok = got == want + results.append(ok) + out('CAL %-58s want %-28s got %-28s %s' % (name, want, got, 'ok' if ok else 'UNEXPECTED')) + + def quiet(_): + pass + + def sub(rows, ids, mutate=None, tag=None, branch=None, log=quiet): + with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: + rd = os.path.join(d, 'rows') + os.mkdir(rd) + for r in rows: + if r['id'] in ids: + for ext in ('.eigs', '.out'): + shutil.copy(os.path.join(cal, r['id'] + ext), rd) + if mutate: + mutate(rd) + sel = [r for r in rows if r['id'] in ids] + lines = [] + res = check(sel, rd, os.path.join(d, 'none'), tag or args.tag, branch or args.branch, + 'R1.3', os.path.join(d), lambda s: (lines.append(s), log(s))) + return res, lines + + honest = [r['id'] for r in map_rows if not r['id'].endswith('-plant')] + out('calibration fixtures: %d rows (%d honest) in %s' % (len(map_rows), len(honest), cal)) + case('fixture MAP parses', not bad and len(map_rows) > 0, True) + (pop, rows_ok, _, n, cnt, wit), _ = sub(map_rows, honest, log=out) + case('honest rows: every tier tag_fail == branch_pass == examined', rows_ok, True) + case('honest rows: every witness holds', wit, sum(r['witness']['kind'] != 'none' + for r in map_rows if r['id'] in honest)) + (pop, rows_ok, _, n, cnt, _), _ = sub(map_rows, honest, tag=args.branch) + case('the branch passed as the tag too: branch_pass=0?', cnt['default']['tag_fail'], 0) + case('... and the check fails', rows_ok, False) + (pop, rows_ok, _, n, cnt, _), _ = sub(map_rows, honest, branch=args.tag) + case('the tag passed as the branch: branch_pass', cnt['default']['branch_pass'], 0) + victim = honest[0] + + def corrupt(rd): + with open(os.path.join(rd, victim + '.out'), 'a') as f: + f.write('corrupted\n') + (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, mutate=corrupt) + case('a corrupted .out fails, naming the row', (rows_ok, any( + ('BRANCH-FAIL %s ' % victim) in l for l in lines)), (False, True)) + (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, []) + case('an empty rows directory: examined=0 fails', (rows_ok, cnt['default']['examined']), (False, 0)) + + def drop(rd): + os.remove(os.path.join(rd, victim + '.eigs')) + (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, mutate=drop) + case('a MAP id with no file fails', (pop, any('has no file' in l for l in lines)), (False, True)) + + def stray(rd): + shutil.copy(os.path.join(rd, victim + '.eigs'), os.path.join(rd, 'stray.row.eigs')) + (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, mutate=stray) + case('a file with no MAP id fails', (pop, any('stray.row.eigs has no MAP id' in l for l in lines)), + (False, True)) + for r in map_rows: + if r['id'].endswith('-plant'): + (pop, rows_ok, _, n, cnt, wit), lines = sub(map_rows, [r['id']]) + case('plant %s: vacuous, named' % r['id'], (cnt['default']['vacuous'], any( + ('VACUOUS %s ' % r['id']) in l for l in lines)), (1, True)) + # the plan-level checks against a mutated copy of the real MAP + real, rbad = parse_map(os.path.join(ROOT, 'tests/phase2/MAP.md')) + lines = [] + plan_checks(real, list(rbad), lines.append) + pb = [] + plan_checks(real, pb, quiet) + case('plan checks on the real MAP pass', (rbad, pb), ([], [])) + pb = [] + plan_checks([r for r in real if r['item'] != 'N4b'], pb, quiet) + case('a MAP with no N4b row fails, naming N4b', any('item N4b' in b for b in pb), True) + pb = [] + n_arms = plan_checks([dict(r, ops=[]) for r in real], pb, quiet) + case('a MAP whose rows exercise no arm fails per arm (%d arms)' % n_arms, + sum('numeric arm' in b for b in pb) == n_arms > 0, True) + pb = [] + plan_checks([r for r in real if r['round'] != 'R2.3'], pb, quiet) + case('a round with neither rows nor gates fails', any('round R2.3' in b for b in pb), True) + # the int-source check against a planted production call + with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: + shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src')) + p = os.path.join(d, 'src', 'trace.c') + text = open(p).read() + anchor = ' *out = slot_from_f64((double)count);' + n_anchor = text.count(anchor) + open(p, 'w').write(text.replace(anchor, ' *out = slot_from_int(count);')) + lines = [] + ok = int_source(os.path.join(d, 'src'), lines.append) + case('int-source plant (slot_from_int(count) in trace.c) applied once', n_anchor, 1) + case('int-source plant: the check fails, naming the caller', (ok, any( + 'trace.c' in l and 'calls slot_from_int' in l for l in lines)), (False, True)) + lines = [] + case('int-source on the real tree passes', int_source(os.path.join(ROOT, 'src'), lines.append), True) + # the token gate against a reintroduced deleted token + with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: + os.mkdir(os.path.join(d, 'src')) + os.mkdir(os.path.join(d, 'tests')) + for f in os.listdir(os.path.join(ROOT, 'src')): + if f.endswith(('.c', '.h')): + shutil.copy(os.path.join(ROOT, 'src', f), os.path.join(d, 'src')) + with open(os.path.join(d, 'src', 'vm.c'), 'a') as f: + f.write('\nstatic int stray_reader(EigsSlot s) { return slot_is_num(s); }\n') + lines = [] + case('token plant (slot_is_num reintroduced): the gate fails', + (token_gate(d, 'R1.1', lines.append), any('slot_is_num' in l for l in lines)), (False, True)) + if args.build_plants: + args.planted_leaf_scan, args.planted_leaf_mul = build_leaf_plants(out) + for label, flag, b in (('leaf-scanner-early-return', '--planted-leaf-scan', args.planted_leaf_scan), + ('leaf-mul-plus-one', '--planted-leaf-mul', args.planted_leaf_mul)): + if not b: + out('CAL %-58s NOT RUN (no %s binary; --build-plants builds it)' % (label, flag)) + results.append(False) + continue + leaf = [r['id'] for r in map_rows if r['witness']['kind'] == 'leaf' and r['id'] in honest] + (pop, rows_ok, _, n, cnt, wit), lines = sub(map_rows, leaf, branch=b) + if label == 'leaf-scanner-early-return': + case('leaf row vs a scratch build whose leaf scanner returns early', + (cnt['default']['vacuous'] > 0, rows_ok), (True, False)) + else: + case('L row vs a scratch build whose leaf MUL adds 1: trace differs', + (cnt['trace']['branch_pass'], cnt['default']['branch_pass'] > 0, rows_ok), (len(leaf), False, False)) + n_ok = sum(results) + out('calibration: cases=%d as-expected=%d unexpected=%d' % (len(results), n_ok, len(results) - n_ok)) + return 0 if results and n_ok == len(results) else 1 + + +LEAF_PLANTS = ( + # (file, original, planted): the two scratch builds of design 9.2 + ('src/chunk.c', ' c->leaf_accessor = 0;\n if (c->param_count > LEAF_ACCESSOR_MAX_DEPTH) return;', + ' c->leaf_accessor = 0;\n return; /* PLANT: the leaf scanner never admits a chunk */\n' + ' if (c->param_count > LEAF_ACCESSOR_MAX_DEPTH) return;'), + ('src/vm.c', ' r = a * b;\n', ' r = a * b + 1; /* PLANT */\n'), +) +_PLANT_DIR = [] + + +def build_leaf_plants(out): + """git archive HEAD twice into scratch trees (no .git), apply one plant to + each (exactly once before, present after), build each with plain make.""" + paths = [] + for f, old, new in LEAF_PLANTS: + d = tempfile.mkdtemp(prefix='eigs-p2leaf-') + _PLANT_DIR.append(d) + subprocess.run('git -C %s archive HEAD | tar -x -C %s' % (ROOT, d), shell=True, check=True) + p = os.path.join(d, f) + text = open(p).read() + if text.count(old) != 1: + out(' PLANT %s: the original occurs %d times, want 1 (BROKEN)' % (f, text.count(old))) + paths.append(None) + continue + open(p, 'w').write(text.replace(old, new)) + r = subprocess.run(['make'], cwd=d, capture_output=True) + b = os.path.join(d, 'src', 'eigenscript') + ok = r.returncode == 0 and os.access(b, os.X_OK) + out(' PLANT %s built in %s: %s' % (f, d, 'ok' if ok else 'BROKEN (make rc=%d)' % r.returncode)) + paths.append(b if ok else None) + return paths + + +def main(): + ap = argparse.ArgumentParser(prog='tools/phase2_check.sh') + ap.add_argument('tag', help='the v0.46.0 tag binary') + ap.add_argument('branch', help='the branch binary') + ap.add_argument('--through', default=ROUNDS[-1], choices=ROUNDS) + ap.add_argument('--baseline', help='the binary from before a mechanical round (corpus differential)') + ap.add_argument('--map', default=os.path.join(ROOT, 'tests/phase2/MAP.md')) + ap.add_argument('--rows', default=os.path.join(ROOT, 'tests/phase2/rows')) + ap.add_argument('--controls', default=os.path.join(ROOT, 'tests/phase2/controls')) + ap.add_argument('--calibrate', action='store_true') + ap.add_argument('--planted-leaf-scan', help='calibration: a build whose leaf scanner returns early') + ap.add_argument('--planted-leaf-mul', help='calibration: a build whose leaf MUL computes a*b+1') + ap.add_argument('--build-plants', action='store_true', + help='calibration: build both planted binaries from HEAD (two release builds)') + args = ap.parse_args() + for b in (args.tag, args.branch, args.baseline, args.planted_leaf_scan, args.planted_leaf_mul): + if b and not os.access(b, os.X_OK): + print('phase2-check: FAIL: %s is not an executable' % b) + return 2 + args.tag, args.branch = os.path.abspath(args.tag), os.path.abspath(args.branch) + + def out(s): + print(s, flush=True) + if args.calibrate: + try: + return calibrate(args, out) + finally: + for d in _PLANT_DIR: + shutil.rmtree(d, ignore_errors=True) + return main_check(args, out) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/phase2_check.sh b/tools/phase2_check.sh new file mode 100755 index 000000000..ade46f62e --- /dev/null +++ b/tools/phase2_check.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# tools/phase2_check.sh [--through Rk] [--baseline BIN] [--calibrate] +# #1758 Phase 2's row checker (docs/design/phase2-numbers.md 9.2): the MAP's +# landed rows on the v0.46.0 tag and the branch in four tiers, their tier +# witnesses, and a mechanical round's gates. The work is in +# tools/phase2_check.py, whose docstring is the reference. +command -v python3 >/dev/null 2>&1 || { echo "phase2-check: FAIL: python3 is required"; exit 2; } +exec python3 "$(dirname "$0")/phase2_check.py" "$@" diff --git a/tools/phase2_corpus_diff.sh b/tools/phase2_corpus_diff.sh new file mode 100755 index 000000000..97857e00d --- /dev/null +++ b/tools/phase2_corpus_diff.sh @@ -0,0 +1,146 @@ +#!/usr/bin/env bash +# tools/phase2_corpus_diff.sh -- #1758: the +# behaviour differential of a mechanical round (docs/design/phase2-numbers.md +# 8, R1.1 and R1.2): "unchanged" is measured, not inferred from a green suite. +# +# Every .eigs file under the BRANCH tree's tests/ runs once with each binary, +# both from the branch tree's src/ (the suite's cwd) as `../tests/`, so +# a file and everything it loads by a relative path are the same bytes for +# both; only the binary and the stdlib next to it differ. stdin /dev/null, +# a 60 s bound, under +# `env -u XAUTHORITY DISPLAY=:99` and a 2 GiB address-space limit. stdout, +# stderr and the exit code must all be byte-identical after one +# normalisation: each tree's absolute root is replaced by ``, so a test +# that prints its own path compares equal. +# +# A file whose outputs differ is re-run: the baseline a second time (if it +# disagrees with itself the file is NONDET -- timing, randomness, scheduling), +# then the branch a second time (if it now agrees, the branch side is NONDET +# too). Only a difference that both re-runs keep is a DIFF row. +# A NONDET file is then adjudicated on a tape (docs/TRACE.md: a tape recorded +# by one binary replays on another): the baseline records it once, and the +# baseline replays it twice and the branch once. Two baseline replays that +# agree make the tape an oracle; the branch's replay must then match it +# (`same-under-replay`) or it is a DIFF. Replays that disagree with each +# other (threads, subprocesses: the documented boundary) stay NONDET. +# A crash or timeout both binaries agree on is named in its own counter, +# never silently "same". +# +# A file only the branch tree has (a new fixture) is counted as `new`; a +# file only the baseline tree has is a DELETED row, a failure: a deleted test +# would hide a behaviour change. +# Prints `.. / s` per file as it goes, a +# DIFF/DELETED row per failure, the NONDET and crash lists, and +# `corpus-diff: examined=N same=S same_under_replay=R nondet=K diff=D new=W +# deleted=X crash_both=C timeout_both=T`. Exit 0 only for diff=0 deleted=0 +# and examined equal to the number of files listed (> 0). +set -u +[ $# -eq 2 ] || { echo "usage: tools/phase2_corpus_diff.sh "; exit 2; } +abspath() { (cd "$(dirname "$1")" && printf '%s/%s\n' "$(pwd -P)" "$(basename "$1")"); } +BASE_BIN=$(abspath "$1") || exit 2 +BR_BIN=$(abspath "$2") || exit 2 +BASE_ROOT=$(cd "$(dirname "$BASE_BIN")/.." && pwd -P) +BR_ROOT=$(cd "$(dirname "$BR_BIN")/.." && pwd -P) +for b in "$BASE_BIN" "$BR_BIN"; do [ -x "$b" ] || { echo "corpus-diff: FAIL: $b is not executable"; exit 2; }; done +command -v timeout >/dev/null 2>&1 || { echo "corpus-diff: FAIL: needs coreutils timeout (local tool)"; exit 2; } +TMP=$(mktemp -d "${TMPDIR:-/tmp}/eigs-corpus-diff.XXXXXX") || exit 2 +DONE=0 +trap 'rc=$?; [ "$DONE" = 1 ] || echo "corpus-diff: FAIL: exited ($rc) before a verdict, at: $BASH_COMMAND"; rm -rf "$TMP"' EXIT + +(cd "$BR_ROOT" && find tests -name '*.eigs' -type f | LC_ALL=C sort) > "$TMP/files" +listed=$(grep -c . "$TMP/files") +[ "$listed" -gt 0 ] || { echo "corpus-diff: FAIL: no .eigs file under $BR_ROOT/tests"; exit 1; } +echo "corpus-diff: baseline $BASE_BIN ($("$BASE_BIN" --version 2>&1 | head -1)) sha256 $(sha256sum "$BASE_BIN" | cut -c1-16)" +echo "corpus-diff: branch $BR_BIN ($("$BR_BIN" --version 2>&1 | head -1)) sha256 $(sha256sum "$BR_BIN" | cut -c1-16)" +echo "corpus-diff: files=$listed" + +# run BIN ROOT REL OUT [VAR=value] -> OUT.out OUT.err OUT.rc (ROOT is the +# binary's own tree, which only its stdlib comes from), root paths +# normalised +run() { + local bin="$1" root="$2" rel="$3" out="$4" extra="${5:-PHASE2_DIFF=1}" rc + ( + cd "$BR_ROOT/src" || exit 99 + ulimit -v 2097152 + exec env -u XAUTHORITY DISPLAY=:99 "$extra" timeout 60 "$bin" "../$rel" + ) < /dev/null > "$out.rawout" 2> "$out.rawerr" + rc=$? + echo "$rc" > "$out.rc" + sed "s|$BASE_ROOT||g; s|$BR_ROOT||g" "$out.rawout" > "$out.out" + sed "s|$BASE_ROOT||g; s|$BR_ROOT||g" "$out.rawerr" > "$out.err" +} +same() { cmp -s "$1.out" "$2.out" && cmp -s "$1.err" "$2.err" && cmp -s "$1.rc" "$2.rc"; } + +examined=0; nsame=0; nreplay=0; nondet=0; ndiff=0; new=0; crash_both=0; timeout_both=0 +: > "$TMP/new" +(cd "$BASE_ROOT" && find tests -name '*.eigs' -type f | LC_ALL=C sort) > "$TMP/basefiles" +LC_ALL=C comm -23 "$TMP/basefiles" "$TMP/files" > "$TMP/deleted" +deleted=$(grep -c . "$TMP/deleted") +sed 's/^/DELETED (in the baseline tree, not the branch): /' "$TMP/deleted" +# replay_adjudicate REL: 0 same under replay, 1 a DIFF, 2 still NONDET +replay_adjudicate() { + local rel="$1" + rm -f "$TMP/tape" + run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/t0" "EIGS_TRACE=$TMP/tape" + [ -s "$TMP/tape" ] || return 2 + run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/p1" "EIGS_REPLAY=$TMP/tape" + run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/p2" "EIGS_REPLAY=$TMP/tape" + same "$TMP/p1" "$TMP/p2" || return 2 + [ "$(cat "$TMP/p1.rc")" -lt 124 ] || return 2 + run "$BR_BIN" "$BR_ROOT" "$rel" "$TMP/q1" "EIGS_REPLAY=$TMP/tape" + same "$TMP/p1" "$TMP/q1" && return 0 + return 1 +} +: > "$TMP/nondet"; : > "$TMP/crash" +while IFS= read -r rel; do + examined=$((examined + 1)) + t0=$(date +%s) + [ -f "$BASE_ROOT/$rel" ] || { new=$((new + 1)); echo "$rel" >> "$TMP/new"; } + run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/b1" + run "$BR_BIN" "$BR_ROOT" "$rel" "$TMP/r1" + if same "$TMP/b1" "$TMP/r1"; then + nsame=$((nsame + 1)) + rc=$(cat "$TMP/b1.rc") + if [ "$rc" -eq 124 ]; then timeout_both=$((timeout_both + 1)); echo "$rel rc=124" >> "$TMP/crash" + elif [ "$rc" -ge 128 ]; then crash_both=$((crash_both + 1)); echo "$rel rc=$rc" >> "$TMP/crash"; fi + echo ".. $examined/$listed $rel same rc=$rc $(( $(date +%s) - t0 ))s" + continue + fi + run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/b2" + if ! same "$TMP/b1" "$TMP/b2"; then + replay_adjudicate "$rel"; ra=$? + if [ "$ra" -eq 0 ]; then + nreplay=$((nreplay + 1)) + echo ".. $examined/$listed $rel same-under-replay $(( $(date +%s) - t0 ))s"; continue + elif [ "$ra" -eq 1 ]; then + ndiff=$((ndiff + 1)) + echo ".. $examined/$listed $rel DIFF-under-replay $(( $(date +%s) - t0 ))s" + echo "DIFF $rel: replaying the baseline's tape, rc baseline=$(cat "$TMP/p1.rc") branch=$(cat "$TMP/q1.rc")" + diff "$TMP/p1.out" "$TMP/q1.out" | head -8 | sed 's/^/ stdout: /' + diff "$TMP/p1.err" "$TMP/q1.err" | head -8 | sed 's/^/ stderr: /' + continue + fi + nondet=$((nondet + 1)); echo "$rel (the baseline disagrees with itself, and its replays too)" >> "$TMP/nondet" + echo ".. $examined/$listed $rel nondet $(( $(date +%s) - t0 ))s"; continue + fi + run "$BR_BIN" "$BR_ROOT" "$rel" "$TMP/r2" + if same "$TMP/b1" "$TMP/r2"; then + nondet=$((nondet + 1)); echo "$rel (the branch disagreed once, then agreed)" >> "$TMP/nondet" + echo ".. $examined/$listed $rel nondet $(( $(date +%s) - t0 ))s"; continue + fi + ndiff=$((ndiff + 1)) + echo ".. $examined/$listed $rel DIFF $(( $(date +%s) - t0 ))s" + echo "DIFF $rel: rc baseline=$(cat "$TMP/b1.rc") branch=$(cat "$TMP/r2.rc")" + diff "$TMP/b1.out" "$TMP/r2.out" | head -8 | sed 's/^/ stdout: /' + diff "$TMP/b1.err" "$TMP/r2.err" | head -8 | sed 's/^/ stderr: /' +done < "$TMP/files" + +sed 's/^/NEW (only the branch tree has it) /' "$TMP/new" +sed 's/^/NONDET /' "$TMP/nondet" +sed 's/^/BOTH-CRASH-OR-TIMEOUT /' "$TMP/crash" +echo "corpus-diff: examined=$examined same=$nsame same_under_replay=$nreplay nondet=$nondet diff=$ndiff new=$new deleted=$deleted crash_both=$crash_both timeout_both=$timeout_both" +DONE=1 +if [ "$examined" -eq "$listed" ] && [ "$examined" -gt 0 ] && [ "$ndiff" -eq 0 ] && [ "$deleted" -eq 0 ]; then + echo "corpus-diff: PASS"; exit 0 +fi +echo "corpus-diff: FAIL"; exit 1 From e84bb2fd38963f0eaf8dc8f06f3ece7fc9020cf5 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 21:48:34 -0500 Subject: [PATCH 007/188] phase2 R1.1 fix: the four type-error arms refuse an int; the smi-trap build; #1775's warnings (#1758) The R1.1 critic found that NUM_CMP, INT_BINOP_R, NEG and BNOT met an SMI with the type error naming `num`, which a `try` turned into a wrong value (`r is xs[0] < 6` with an SMI 5 gave false). Each now refuses through eigs_int_unwired, so R1.3, which deletes that token, cannot compile until each has its int arm. All four are tied to R1.3, bitwise included: R1.3's int literals reach `&` at once (tests/bench_dmg_shape.eigs:21), and design section 8 gives bitwise exact int64 operands at R1.3. The design's rows for the four arms change from guarded to unwired. The dynamic half of the int-source check: built with -DEIGS_SMI_TRAP (`make smi-trap`), every slot predicate and accessor aborts on an SMI and slot_from_int aborts on any call, so a producer that writes the tag bits itself dies at its first reader. #1775: builtin_tensor_gather ends in an explicit return, and the bitwise, compare, equality and index locals are initialised where they are declared. The amalgamation compiles with no warning at -O0 and -O1 (it had 1 and 7 on main 0740af03). The slot test now builds at -O0 with -Wall -Wextra (ASan's flavour at -O1), and its runner fails on any build warning. tools/phase2_inventory.py passes re.split's maxsplit by keyword: the positional form is a DeprecationWarning on Python 3.13. Closes #1775 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 26 +++++- changes/fixed/1775-amalgamation-warnings.md | 1 + docs/design/phase2-numbers.md | 99 ++++++++++++++++++--- src/builtins_tensor.c | 2 + src/eigenscript.c | 5 +- src/value_slot.h | 39 ++++++-- src/vm.c | 45 +++++++--- tools/phase2_inventory.py | 2 +- 8 files changed, 180 insertions(+), 39 deletions(-) create mode 100644 changes/fixed/1775-amalgamation-warnings.md diff --git a/Makefile b/Makefile index 9001dca92..ace37056e 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ define AUX_REFRESH done endef -.PHONY: db-params-test all build server server-db full http net gfx zlib lib amalgamation tsan test test-changed precheck sandbox-intern-test install install-gfx clean coverage coverage-clean fuzz fuzz-run lsp lsp-asan dap jit-smoke embed-smoke embed-smoke-asan embed-smoke-asan-server embed-smoke-gfx embed-concurrent asan asan-server valgrind pgo poison freestanding-check freestanding-libc-diff asan-http asan-gfx tsan-server tsan-http nativefn-test arming-mt-test embed-roads print-% sigpipe-contract-test sigpipe-partial-test ui-sdl-input-gfx pool-off asan-pool-off pool-off-num pool-off-callenv jit-checked +.PHONY: db-params-test all build server server-db full http net gfx zlib lib amalgamation tsan test test-changed precheck sandbox-intern-test install install-gfx clean coverage coverage-clean fuzz fuzz-run lsp lsp-asan dap jit-smoke embed-smoke embed-smoke-asan embed-smoke-asan-server embed-smoke-gfx embed-concurrent asan asan-server valgrind pgo poison freestanding-check freestanding-libc-diff asan-http asan-gfx tsan-server tsan-http nativefn-test arming-mt-test embed-roads print-% sigpipe-contract-test sigpipe-partial-test ui-sdl-input-gfx pool-off asan-pool-off pool-off-num pool-off-callenv jit-checked smi-trap # ---- Per-variant objdir engine (#740) ------------------------------------- # The engine's rules are defined before `all`, so pin the default goal. @@ -183,7 +183,16 @@ SRC_V_jit-checked := $(HOSTED_SOURCES) FLAGS_jit-checked := $(CFLAGS) $(DEFS_OFF) -DEIGENSCRIPT_EXT_GFX=1 -DEIGS_JIT_CHECKED $(VERDEF) LIBS_jit-checked := $(LDFLAGS) -ldl -VARIANTS := release server server-db zlib asan asan-server tsan tsan-server valgrind poison pool-off asan-pool-off pool-off-num pool-off-callenv jit-checked +# #1758 R1.1: the dynamic half of the int-source check. Every slot classifier +# aborts when it reads an SMI and slot_from_int aborts on any call +# (value_slot.h EIGS_SMI_TRAP); slot_as_ptr checks its tag too. Until R1.3 no +# program may make an int, so this build must run the corpus exactly as +# release does: tools/phase2_check.sh --through R1.1 --smi-trap . +SRC_V_smi-trap := $(HOSTED_SOURCES) +FLAGS_smi-trap := $(CFLAGS) $(DEFS_OFF) -DEIGENSCRIPT_EXT_GFX=1 -DEIGS_SMI_TRAP -DEIGS_SLOT_CHECKED $(VERDEF) +LIBS_smi-trap := $(LDFLAGS) -ldl + +VARIANTS := release server server-db zlib asan asan-server tsan tsan-server valgrind poison pool-off asan-pool-off pool-off-num pool-off-callenv jit-checked smi-trap # Objects depend on Makefile+VERSION so a flag or version-string change # rebuilds; header edits are covered by the generated .d files. @@ -236,9 +245,12 @@ container-slot-test: build/$(SLOT_TEST_VARIANT)/test_container_slots # tests/phase2/slot_layer.sh runs it and compares the entries it examined with # the population tools/phase2_inventory.py derives. The release flavour turns # on slot_as_ptr's refusal with -DEIGS_SLOT_CHECKED; ASan turns it on itself. +# Both carry -Wall -Wextra, and the runner fails on any warning: release +# compiles the amalgamation at -O0 and ASan at -O1, the two levels #1775 +# found warnings at (and -O0 is about 41 s against -O2's 162 s). PHASE2_SLOT_VARIANT ?= release -PHASE2_SLOT_FLAGS_release := $(CFLAGS) -g -DEIGS_SLOT_CHECKED -PHASE2_SLOT_FLAGS_asan := $(ASAN_FLAGS) +PHASE2_SLOT_FLAGS_release := -Wall -Wextra $(WERROR_FLAGS) -O0 -g -DEIGS_SLOT_CHECKED +PHASE2_SLOT_FLAGS_asan := -Wall -Wextra $(ASAN_FLAGS) build/phase2/eigenscript_all.c: $(filter-out $(CLI_ONLY),$(SOURCES)) $(wildcard $(SRC_DIR)/*.h) tools/amalgamate.sh Makefile bash tools/amalgamate.sh build/phase2 build/phase2/slot_layer_%: tests/phase2/slot_layer.c build/phase2/eigenscript_all.c tools/werror_flags.txt @@ -699,6 +711,12 @@ jit-checked: build/jit-checked/eigenscript $(call RELINK,jit-checked) @echo "EigenScript $(VERSION) (jit-checked: emitted slot witnesses) built. Binary: $(BINARY)" +# #1758 R1.1 (see FLAGS_smi-trap): build it in a scratch tree, then +# tools/phase2_check.sh --through R1.1 --smi-trap /src/eigenscript ... +smi-trap: build/smi-trap/eigenscript + $(call RELINK,smi-trap) + @echo "EigenScript $(VERSION) (smi-trap: an int before #1758 R1.3 aborts) built. Binary: $(BINARY)" + # Profile-guided optimization. Builds an instrumented binary, runs the # DMG cpu_instrs workload to collect branch/edge counters, then rebuilds diff --git a/changes/fixed/1775-amalgamation-warnings.md b/changes/fixed/1775-amalgamation-warnings.md new file mode 100644 index 000000000..535276718 --- /dev/null +++ b/changes/fixed/1775-amalgamation-warnings.md @@ -0,0 +1 @@ +- The single-file amalgamation (`make amalgamation`, `build/eigenscript_all.c`) compiles without warnings at `-O0` and `-O1` with `-Wall -Wextra`, as it already did at `-O2`. `-O0` reported a missing return at the end of `builtin_tensor_gather`, and `-O1` reported seven possibly uninitialized locals in the bitwise and index paths of the VM; none was reachable, but an embedder building the two-file artifact with warnings on saw them (#1775). diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 1456cfaf3..282e3afee 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -610,6 +610,37 @@ result).** reserved tags and the sentinel against the predicates and the deciding readers) and plant 1's named check (`slot_from_int` over the boundary values). Its ABORT rows run in forked children and must name the reader. + +**As corrected in the R1.1 fix round (the R1.1 critic's FAIL).** +- **The four type-error arms are `unwired`, not `guarded`.** `NUM_CMP` + (`< > <= >=`), `INT_BINOP_R` (`& | ^ << >>`), `CASE(NEG)` and + `CASE(BNOT)` met an SMI with the type error naming `num`; inside a `try` + that error became a wrong value (`r is xs[0] < 6` with an SMI 5 gave + `false`, the float control `true`). "Handled correctly as written" was + false. Each now refuses through `eigs_int_unwired`, so R1.3, which deletes + the token, cannot compile until each has its int arm. All four are tied to + **R1.3**, bitwise included: R1.3's int literals reach `&` at once + (`tests/bench_dmg_shape.eigs:21`, `c.a is c.a & 255`), and §8 already + gives bitwise operators exact int64 operands at R1.3, with R1.5 changing + only the shift rule. +- **The tag matrix covers every entry.** Each of the 33 population entries + meets all twelve kinds (a double, the canonical NaN, -0.0, null, false, + true, an SMI, a heap pointer, the three reserved tags and the sentinel), + each kind with its expected outcome: a value, a refusal naming the reader, + or a raise. The runner requires the MATRIX set to equal the population. +- **Part D drives the operator arms through the VM.** A host builtin + (`phase2_poke`) writes an SMI into a list element, and a program then + applies each refusing operator to it, plain and inside a `try`: each must + abort naming its arm, where the float control computes the value. +- **The slot test builds at -O0** (about 41 s instead of 162 s, and well + under -O2's 602 MB peak), after the warnings #1775 listed were fixed: + `builtin_tensor_gather`'s missing return and the maybe-uninitialized + `num_to_i64_exact` and `vm_index_resolve` locals. +- **Its runner reads each tool on its own channel.** The scan and the test + each have a grammar; a line outside it, or any stderr, is a FAIL that + prints the line (the R1.1 critic: Python 3.13's DeprecationWarning on the + scan's stderr was read as two classifiers). The Python runs with `-W + error`. - **"The int's Value"** cannot be checked in R1.1: no int Value kind exists, so `slot_to_value` and the readers that route to it are ABORT rows until R1.3 turns them into RETURN rows. @@ -651,6 +682,7 @@ result).** | `jit_smoke.c:run_bool_cases` | not-a-classifier | test harness: expected bool bits (D3) | | `jit_smoke.c:run_index_bail_cases` | guarded | test harness: an exact null test of a result (D3) | | `trace.c:write_slot` | unwired | an int needs tape v7 (ints as digits, floats marked), R1.3; a v6 tape would replay it as a float. Any other tag refuses; it was written as `` (D1) | +| `value_slot.h:#define SLOT_SMI_TRAP` | refuse | the smi-trap build's check (`-DEIGS_SMI_TRAP`): every slot classifier aborts on an SMI before R1.3; nothing in other builds (D3) | | `value_slot.h:#define slot_as_heap` | refuse | alias of `slot_as_ptr` (D2) | | `value_slot.h:slot_as_ptr` | refuse | the raw dereference: R1.1 refuses a non-heap slot in ASan builds and under `-DEIGS_SLOT_CHECKED` (the C slot test) (D2) | | `value_slot.h:slot_decref` | guarded | acts only on tag `0xFFFB`; an SMI has no refcount (D3) | @@ -672,8 +704,8 @@ result).** | `value_slot.h:slot_true` | not-a-classifier | constructor (D3) | | `value_slot.h:slot_truthy_immediate` | smi-arm | an int is truthy when it is not 0, like a double (D1) | | `vm.c:#define ARITH_FAST` | guarded | an int is not a float (`slot_f64_value`): the arm's slow path pops it through `slot_bridge_unwrap`; R1.3 gives that path int arithmetic (D1) | -| `vm.c:#define INT_BINOP_R` | guarded | an int is not a float: the type error, which names it `num` (`slot_type_name`); R1.3 adds the int arm (D1) | -| `vm.c:#define NUM_CMP` | guarded | an int is not a float: the type error naming `num`; R1.3 adds N2's exact compare (D1) | +| `vm.c:#define INT_BINOP_R` | unwired | an int operand used to reach the type error naming `num`, which a `try` turned into a wrong value (the R1.1 critic). It now refuses through `eigs_int_unwired` until R1.3 gives the bitwise arms exact int64 operands (D1) | +| `vm.c:#define NUM_CMP` | unwired | an int operand used to reach the type error naming `num` (`r is xs[0] < 6` gave `false` inside a `try`). It now refuses through `eigs_int_unwired` until R1.3 adds N2's exact compare (D1) | | `vm.c:#define READ_SLICE_BOUND` | smi-arm | an int bound is its value when a C `int` holds it, else a value error (D1) | | `vm.c:jit_helper_dot_get` | guarded | a non-null field is pushed as its bits; an SMI is a valid stack slot (D3) | | `vm.c:jit_helper_dot_set` | guarded | an int value skips the immediate store: the slow path pops it through `slot_bridge_unwrap` (D1) | @@ -698,7 +730,7 @@ result).** | `vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET` | guarded | a non-pointer target bails (`return 0`); a non-null field is borrowed as its bits, an SMI included (D2) | | `vm.c:vm_local_is_null` | guarded | exact null test (D3) | | `vm.c:vm_local_lift` | guarded | a non-pointer, non-null slot goes through `slot_to_value` (compile-forced) and is boxed on purpose (D2) | -| `vm.c:vm_run_ex/CASE(BNOT)` | guarded | an int is not a float: the type error naming `num`; R1.3 adds the int arm (D1) | +| `vm.c:vm_run_ex/CASE(BNOT)` | unwired | an int used to reach the type error naming `num`. It now refuses through `eigs_int_unwired` until R1.3 gives the bitwise arms exact int64 operands (D1) | | `vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK)` | guarded | a non-pointer source takes the error path, which names the type through `slot_type_name` (D2) | | `vm.c:vm_run_ex/CASE(DISPATCH)` | smi-arm | an int key is its value when a C `int` holds it, else a value error; the result returns through `slot_bridge_unwrap` (D1) | | `vm.c:vm_run_ex/CASE(DOT_GET)` | guarded | exact null test of a field (D3) | @@ -710,7 +742,7 @@ result).** | `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET)` | guarded | exact null test of a field (D3) | | `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET)` | guarded | an int value: `vm_slot_lift` boxes it (D1) | | `vm.c:vm_run_ex/CASE(NE)` | guarded | an int is not a float: the slow path; R1.3 adds N2 (D1) | -| `vm.c:vm_run_ex/CASE(NEG)` | guarded | an int is not a float: the type error naming `num`; R1.3 adds N4b (D1) | +| `vm.c:vm_run_ex/CASE(NEG)` | unwired | an int used to reach the type error naming `num`. It now refuses through `eigs_int_unwired` until R1.3 adds N4b (D1) | | `vm.c:vm_run_ex/CASE(SLICE_GET)` | guarded | as DESTRUCTURE_UNPACK (D2) | | `vm.c:vm_slot_lift` | smi-arm | an int is boxed on purpose through `slot_to_value` (2.1; unwired until R1.3); a reserved tag refuses, where it became null (D1) | | `vm.c:vm_slot_value_opaque` | guarded | only a pointer can be a fn or builtin; an SMI answers "not opaque", which is right (D2) | @@ -852,7 +884,9 @@ catches a miss: (§8) proves nothing before R1.3 could produce an int, so nothing earlier could have exercised an unfinished arm. The R1.1 arms that could not be final (`unwired`, 2.5) are token-forced instead: R1.3 deletes - `eigs_int_unwired`. + `eigs_int_unwired`. Since the R1.1 fix round the four operator arms that + raised a type error for an SMI (`NUM_CMP`, `INT_BINOP_R`, `NEG`, `BNOT`) + are among them. - **R1.3, the tape parser.** `parse_value_p` (trace.c:2284) reads digits as an int from v7 on; the version bump refuses an older tape. Gate: the T1 rows (`T1.twice-int`, `T1.v6-refused`). @@ -1787,7 +1821,12 @@ No int VALUE exists before R1.3, and this is structural, not a promise: convert an existing `VAL_INT`, and none exists. `phase2_check.sh --through R1.2` checks this: it derives the callers of `slot_from_int` and `make_int` from the source and fails on any caller outside that list - (the int-source check); + (the int-source check). A producer can also write the tag bits without + calling the writer, so the check fails on `TAG_SMI` or the SMI bit pattern + anywhere outside its definitions in `value_slot.h`, and its dynamic half + runs the corpus on a `make smi-trap` build, where every slot classifier + aborts on an SMI and `slot_from_int` aborts on any call (the R1.1 fix + round, after the critic's plants P3-P5); - the lexer produces only float literals until R1.3, and the tape cannot carry an int until v7 (R1.3). @@ -2205,10 +2244,31 @@ fails if a round named here has neither rows nor its mechanical gates.) whatever it loads by a relative path are the same bytes for both; only the binary and its stdlib differ. A file only the branch has (a new fixture) is counted as `new`; one only the baseline has is a DELETED - failure. A file whose baseline disagrees with itself (randomness, timing) - is replayed: the baseline records a tape, replays it twice, and the branch - replays it once; the branch must match (`same_under_replay`), or it is a - DIFF. Only files whose replays disagree with each other stay NONDET. + failure. **As corrected in the R1.1 fix round** (the critic's plants B + and D passed the first version): + - each binary runs each file TWICE. A file is deterministic when the + baseline's two runs agree, and then any branch run that differs is a + DIFF: a branch that is wrong on every other run is wrong; + - randomness runs LIVE with a pinned seed. The runtime has no seed flag + or variable (an unseeded program seeds from `CLOCK_MONOTONIC ^ pid`), so + the tool builds an `LD_PRELOAD` shim that pins every self-seed (>= 2^20) + to one constant and passes a small explicit seed through, and checks the + shim first (pinned draws agree, unpinned ones differ). A random builtin + changed on the branch therefore shows wherever the corpus observes it; + `test_system.eigs` now draws `random_int` 300 times against its bounds; + - a tape is the last resort, for a file whose baseline disagrees with + itself even pinned (timing, threads): the baseline records it and + replays it twice, the branch replays it once and must match + (`same_under_replay`). Such a file's nondeterministic builtins did not + run live, so their behaviour is invisible there; the report lists every + file adjudicated that way (`REPLAYED`). Files whose replays disagree with + each other stay NONDET, also listed; + - no blanket memory cap: only files that drive the gfx, ui or audio + surface run under `ulimit -v 2097152` (listed as `CAPPED`). + `handles_full.eigs` varied only because of the old blanket cap. +- **The smi-trap gate** (`--smi-trap BIN`, R1.1 and R1.2) runs the same + differential with a `make smi-trap` build as the branch; until R1.3 it + must show no difference, because no program may make an int. - **The calibration** is `phase2_check.sh --calibrate [--build-plants] `, on the fixtures in `tests/phase2/calib/`: each ends in a line that fails on the tag (#1740: `5.5 & 1` raises `value` on the branch and @@ -2218,7 +2278,15 @@ fails if a round named here has neither rows nor its mechanical gates.) the int-source plant runs against a planted copy of `src/`. Cases the design did not list were added for the plan-level checks (an item with no row, an arm no row exercises, a round with neither rows nor gates) and - for the token gate (a reintroduced `slot_is_num`). + for the token gate (a reintroduced `slot_is_num`). The fix round added the + critic's plants: the differential's A (a deterministic file prints one + more line), B (a branch wrong on alternate runs, both phases) and D (a + build whose `random_int` answers lo+1..hi+1), each of which must make the + differential name the file DIFF; the int-source plants P1-P5, each of + which the static half must name at R1.1 (at R1.2, P4 sits inside an + allowed writer and the static half passes it); and P4 built into a + smi-trap binary, which the dynamic half must stop. A restricted run (the + calibration's file list) prints `RESTRICTED` and exits 3, never PASS. ### 9.3 `tools/phase2_plants.sh` (round 1 builds it; detached, about 7 release builds) @@ -2259,6 +2327,15 @@ table in the commits that land their rows, and its output then reads `plants=7`. Its transverse run deletes exactly the named assertion (`if (s.u != smi(v).u)` becomes `if (0)`) and requires the plant to pass. +The R1.1 fix round added three instrument plants on the slot test, each +with its own transverse run: `arm-refusal` (`NUM_CMP`'s int refusal +deleted; named line `slot-layer-test: FAIL arm lt with an int: got ...`), +`stderr-noise` (the population scan writes a line to stderr; named line +`slot-layer: FAIL: the population scan wrote to stderr`) and +`stdout-noise` (the scan prints a line outside its grammar; named line +`slot-layer: FAIL: the population scan printed lines outside its +grammar`). The tool also fails a plant whose check writes to stderr. + ### 9.4 The per-builtin behaviour table (R1.6's gate; replaces the int-fuzz class check) Round 2 planned an int-fuzz gate asserting "the result is an int for int diff --git a/src/builtins_tensor.c b/src/builtins_tensor.c index cc22315c2..b4749c0e6 100644 --- a/src/builtins_tensor.c +++ b/src/builtins_tensor.c @@ -1584,6 +1584,8 @@ Value* builtin_tensor_gather(Value *arg) { * other wrong-type case: a raise in strict mode (the default, #1361), * 0.0 under EIGS_STRICT=0. */ ARG_GUARD(1, "gather", "a tensor and an index or index vector", make_num(0.0)); + return make_null(); /* unreachable: the guard above always returns, but + * -O0 does not fold its constant test (#1775) */ } /* ==== Helper: call a user-defined EigenScript function from C ==== diff --git a/src/eigenscript.c b/src/eigenscript.c index 52b12788b..7f571a802 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -1914,9 +1914,8 @@ void eigs_slot_refuse(const char *who, EigsSlot s) { } void eigs_int_unwired(const char *who, uint64_t bits) { - fprintf(stderr, "EigenScript FATAL: %s: int 0x%016llx reached a path whose " - "int arm lands with the int Value kind (#1758 R1.3)\n", who, - (unsigned long long)bits); + fprintf(stderr, "EigenScript FATAL: %s: int 0x%016llx reached an arm whose " + "int handling lands in #1758 R1.3\n", who, (unsigned long long)bits); abort(); } diff --git a/src/value_slot.h b/src/value_slot.h index 0e0410535..23dc6135f 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -82,20 +82,38 @@ EIGS_SLOT_NORETURN void eigs_int_unwired(const char *who, uint64_t bits); # endif #endif +/* #1758 R1.1, the dynamic half of the int-source check: built with + * -DEIGS_SMI_TRAP (`make smi-trap`), every slot classifier below aborts the + * moment it reads an SMI, and slot_from_int aborts on any call. Nothing may + * make an int before R1.3, so the corpus must run on that build exactly as on + * release; a producer that writes the tag bits itself, which no scan of names + * sees, dies at its first reader. R1.3 retires the mode with eigs_int_unwired. + * In every other build SLOT_SMI_TRAP is nothing. */ +#ifdef EIGS_SMI_TRAP +#define SLOT_SMI_TRAP(s) \ + do { \ + if (__builtin_expect(((s).u & SLOT_TAG_MASK) == TAG_SMI, 0)) \ + eigs_slot_refuse("EIGS_SMI_TRAP: an int before #1758 R1.3", (s)); \ + } while (0) +#else +#define SLOT_SMI_TRAP(s) ((void)0) +#endif + /* Predicates */ -/* #1758: a double. Was slot_is_f64; renamed so that every site that meant +/* #1758: a double. Was slot_is_num; renamed so that every site that meant * "a number" had to decide what an int (SMI) does there. */ static inline int slot_is_f64(EigsSlot s) { + SLOT_SMI_TRAP(s); return (s.u & SLOT_QNAN_MASK) != SLOT_QNAN_MASK; } -static inline int slot_is_null(EigsSlot s) { return s.u == SLOT_NULL_BITS; } -static inline int slot_is_bool(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_BOOL; } -static inline int slot_is_smi(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_SMI; } -static inline int slot_is_heap(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_HEAP; } +static inline int slot_is_null(EigsSlot s) { SLOT_SMI_TRAP(s); return s.u == SLOT_NULL_BITS; } +static inline int slot_is_bool(EigsSlot s) { SLOT_SMI_TRAP(s); return (s.u & SLOT_TAG_MASK) == TAG_BOOL; } +static inline int slot_is_smi(EigsSlot s) { SLOT_SMI_TRAP(s); return (s.u & SLOT_TAG_MASK) == TAG_SMI; } +static inline int slot_is_heap(EigsSlot s) { SLOT_SMI_TRAP(s); return (s.u & SLOT_TAG_MASK) == TAG_HEAP; } /* #262 Step E: TAG_TRACKED is gone — a number is always an immediate, never a * heap-boxed observer-tracked Value. Heap is the only pointer tag. */ -static inline int slot_is_ptr(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == TAG_HEAP; } +static inline int slot_is_ptr(EigsSlot s) { SLOT_SMI_TRAP(s); return (s.u & SLOT_TAG_MASK) == TAG_HEAP; } /* Accessors (caller must check the predicate first) */ @@ -103,8 +121,9 @@ static inline int slot_is_ptr(EigsSlot s) { return (s.u & SLOT_TAG_MASK) == * proven a double (slot_is_f64). Every use sits in a function listed in * tools/num_read_allowlist.txt with its count (tools/num_read_check.sh). */ #define SLOT_F64_RAW(s) ((s).d_) -static inline int slot_as_bool(EigsSlot s) { return (int)(s.u & 1ULL); } +static inline int slot_as_bool(EigsSlot s) { SLOT_SMI_TRAP(s); return (int)(s.u & 1ULL); } static inline Value *slot_as_ptr(EigsSlot s) { + SLOT_SMI_TRAP(s); #ifdef EIGS_SLOT_CHECKS if (__builtin_expect(!slot_is_heap(s), 0)) eigs_slot_refuse("slot_as_ptr", s); #endif @@ -114,6 +133,7 @@ static inline Value *slot_as_ptr(EigsSlot s) { /* The int an SMI holds, sign-extending payload bit 47 without an * implementation-defined right shift (design 2.1). */ static inline int64_t slot_smi_val(EigsSlot s) { + SLOT_SMI_TRAP(s); return (int64_t)((s.u & SLOT_PAYLOAD_MASK) ^ SLOT_SMI_SIGN) - (int64_t)SLOT_SMI_SIGN; } @@ -126,6 +146,9 @@ static inline EigsSlot slot_from_f64(double d) { EigsSlot s; SLOT_F64_RAW( * R1.3 nothing in the runtime calls this (tools/phase2_check.sh, the * int-source check); tests/phase2/slot_layer.c drives it. */ static inline EigsSlot slot_from_int(int64_t i) { +#ifdef EIGS_SMI_TRAP + eigs_int_unwired("slot_from_int under EIGS_SMI_TRAP", (uint64_t)i); +#endif if (__builtin_expect(i < SLOT_SMI_MIN || i > SLOT_SMI_MAX, 0)) eigs_int_unwired("slot_from_int", (uint64_t)i); EigsSlot s; s.u = TAG_SMI | ((uint64_t)i & SLOT_PAYLOAD_MASK); return s; @@ -160,6 +183,7 @@ static inline EigsSlot slot_from_heap(Value *v) { * The outer `& SLOT_QNAN_MASK` branch peels off numbers in one * predicted-not-taken test with zero memory access. */ static inline void slot_incref(EigsSlot s) { + SLOT_SMI_TRAP(s); if ((s.u & SLOT_QNAN_MASK) == SLOT_QNAN_MASK) { uint64_t tag = s.u & SLOT_TAG_MASK; if (tag == TAG_HEAP) { @@ -173,6 +197,7 @@ static inline void slot_incref(EigsSlot s) { } static inline void slot_decref(EigsSlot s) { + SLOT_SMI_TRAP(s); if ((s.u & SLOT_QNAN_MASK) == SLOT_QNAN_MASK) { uint64_t tag = s.u & SLOT_TAG_MASK; if (tag == TAG_HEAP) { diff --git a/src/vm.c b/src/vm.c index a79fdac35..3da4b68f7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -879,10 +879,12 @@ static inline int slot_truthy(EigsSlot s) { /* #1758 R1.1: vm.c's slot_as_double is gone. Its readers now call * slot_f64_value (value_slot.h), which answers only for a FLOAT; each one - * decided what an int does there: the arithmetic, comparison, negation and - * bitwise arms send it to their slow path or type error, which R1.3 gives - * the int semantics (design 8); the leaf evaluator bails, so the generic - * call computes it (design 4.5). */ + * decided what an int does there: the arithmetic and equality arms send it to + * their slow path, which lifts it through slot_to_value; the ordering, + * bitwise, negation and `~` arms refuse it (eigs_int_unwired) where they used + * to raise a type error, which a `try` turned into a wrong value. R1.3 gives + * every one of them the int semantics and deletes eigs_int_unwired (design 8); + * the leaf evaluator bails, so the generic call computes it (design 4.5). */ static inline uint16_t read_u16(uint8_t *ip) { return ip[0] | (ip[1] << 8); @@ -2199,7 +2201,7 @@ void jit_helper_index_set(void) { EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { target->data.buffer.data[i] = SLOT_F64_RAW(val_s); @@ -2269,7 +2271,7 @@ int jit_helper_index_get(void) { g_vm.sp -= 2; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_LIST) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { EigsSlot r = slot_read_owned(list_slot(target, i)); @@ -3320,7 +3322,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, #define ARITH_FAST(OP, UF) do { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - double _ad, _bd; \ + double _ad = 0.0, _bd = 0.0; \ if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ double _r = num_guard(_ad OP _bd); \ if ((UF) && _r == 0.0 && _ad != 0.0 && _bd != 0.0) \ @@ -3490,7 +3492,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NAME): { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - double _ad, _bd; \ + double _ad = 0.0, _bd = 0.0; \ if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ int64_t _ai, _bi; \ if (__builtin_expect(!num_to_i64_exact(_ad, &_ai) || \ @@ -3516,6 +3518,12 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.sp--; \ DISPATCH(); \ } \ + /* #1758 R1.1: an int operand is not a type error (inside a try \ + * it would become a wrong value). The arm refuses until R1.3 \ + * gives it exact int64 operands, and deleting eigs_int_unwired \ + * there forces that. */ \ + if (slot_is_smi(_as) || slot_is_smi(_bs)) \ + eigs_int_unwired("bitwise '" OPNAME "'", (slot_is_smi(_as) ? _as : _bs).u); \ /* Mixed/non-numeric: error rather than silently returning 0, \ * matching the arithmetic operators and the strict error model. \ * Capture type names before decref (cf. NUM_CMP above). */ \ @@ -3561,6 +3569,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.stack[g_vm.sp - 1] = slot_from_f64(-d); DISPATCH(); } + /* #1758 R1.1: an int is refused, not a type error, until R1.3 + * gives NEG its int arm (N4b) and deletes eigs_int_unwired. */ + if (slot_is_smi(s)) eigs_int_unwired("negation", s.u); rt_error(EK_TYPE, current_line, "cannot negate %s", slot_type_name(s)); /* #1637: names bool */ slot_decref(s); g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); @@ -3595,6 +3606,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.stack[g_vm.sp - 1] = slot_from_f64(r); DISPATCH(); } + /* #1758 R1.1: an int is refused, not a type error, until R1.3 + * gives the bitwise arms exact int64 operands. */ + if (slot_is_smi(s)) eigs_int_unwired("bitwise '~'", s.u); { const char *_tn = slot_type_name(s); slot_decref(s); @@ -3609,7 +3623,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(EQ): { EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; - double _ad, _bd; + double _ad = 0.0, _bd = 0.0; if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE * branches wrote a 0/1 result INTO a heap-number operand; a bool @@ -3630,7 +3644,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NE): { EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; - double _ad, _bd; + double _ad = 0.0, _bd = 0.0; if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE * branches wrote a 0/1 result INTO a heap-number operand; a bool @@ -3652,7 +3666,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NAME): { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - double _ad, _bd; \ + double _ad = 0.0, _bd = 0.0; \ if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ /* #1637: a bool immediate; no NUM_REUSE (see CASE(EQ)). */ \ int _r = (_ad OP _bd); \ @@ -3673,6 +3687,11 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, DISPATCH(); \ } \ } \ + /* #1758 R1.1: an int operand is refused, not a type error (which \ + * a try would turn into a wrong `false`), until R1.3 gives this \ + * arm N2's exact compare and deletes eigs_int_unwired. */ \ + if (slot_is_smi(_as) || slot_is_smi(_bs)) \ + eigs_int_unwired("compare '" OPNAME "'", (slot_is_smi(_as) ? _as : _bs).u); \ /* Mixed/uncomparable types: error rather than silently returning \ * false (e.g. "3" < 4 used to be 0). Capture type names before \ * decref. ==/!= keep cross-type "not equal"; only ordering errors. */ \ @@ -4590,7 +4609,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.sp -= 2; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_LIST) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { EigsSlot r = slot_read_owned(list_slot(target, i)); @@ -4673,7 +4692,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { target->data.buffer.data[i] = SLOT_F64_RAW(val_s); diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index 759e2a45a..1e0b4450a 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -643,7 +643,7 @@ def slot_population(slots, sigs_by_file): if not params.startswith('('): bad.append('%s:%s: unparsed signature %r' % (rel, k, sig.strip()[:60])) continue - first = re.split(r'[,)]', params[1:], 1)[0].strip() + first = re.split(r'[,)]', params[1:], maxsplit=1)[0].strip() if re.match(r'^(const\s+)?EigsSlot\s+[A-Za-z_]\w*$', first): out.append('%s:%s' % (rel, k)) for line in out: From d807683632ec45a5619985dac79bd262d6873cc6 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 21:48:46 -0500 Subject: [PATCH 008/188] phase2 R1.1 fix: the slot test's full matrix, its channels and its variant (#1758) The C slot test: - Part B, the tag matrix, now runs every one of the 33 population entries against all twelve slot kinds (a double, the canonical NaN, -0.0, null, both bools, an SMI, a heap pointer, the three reserved tags and the sentinel), each with its expected value, refusal or raise; before, only the six predicates and seven deciding readers saw more than an SMI. - Part D drives the operator arms through the VM: a host builtin writes an SMI into a list, and each refusing operator must abort naming its arm, plain and inside a try, while the float control computes the value. - A child expected to abort is made non-dumpable, so a crash reporter on the core pipe (apport here) is not run for each one: 224 s became 0.4 s. Its runner reads each tool on its own channel: the population scan and the test each have a grammar, and a line outside it or any stderr is a FAIL that prints the line (the critic's largest gap: Python 3.13's DeprecationWarning on the scan's stderr was read as two classifiers). The scan runs under python3 -W error; a build warning fails (#1775). [0ff] and [0fk] find the variant the suite binary is (asan or asan-server in the CI ASan shards) through one shared predicate, tests/suite_variant.sh, which asks the Makefile whether that variant builds with ASan; both ran their release flavour in the shards (#1783). tests/section_weights.txt is refreshed from the ASan shard logs of run 38652383231 (head 6fe6f0a3) plus [0fk]'s measured 53.33 s, so the planner no longer assumes 0.5 s for it (#1784). test_system.eigs draws random_int 300 times against its bounds: one draw let a lo+1..hi+1 random_int pass five times in six (the critic's plant D). Closes #1783 Closes #1784 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/slot_layer.c | 613 +++++++++++++++++---- tests/phase2/slot_layer.sh | 72 ++- tests/section_weights.txt | 521 +++++++++-------- tests/sections/0ff-container-slots-1665.sh | 10 +- tests/sections/0fk-phase2-slot-layer.sh | 15 +- tests/suite_variant.sh | 32 ++ tests/test_system.eigs | 19 + 7 files changed, 910 insertions(+), 372 deletions(-) create mode 100644 tests/suite_variant.sh diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index c56dd2966..72401a249 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -15,22 +15,31 @@ * ones (eigs_slot_refuse) and the R1.1 placeholders whose int arm needs * the int Value kind (eigs_int_unwired, deleted in R1.3). An abort runs * in a forked child, and its FATAL line must name the expected reader. - * B the tag matrix: the predicates and the deciding readers against a - * double, the canonical NaN, -0.0, null, both bools, an SMI, a heap - * pointer, the reserved tags and the sentinel. + * B every population entry x twelve slot kinds: a double, the canonical + * NaN, -0.0, null, both bools, an SMI, a heap pointer, the reserved + * tags and the sentinel; each cell runs in a forked child. * C slot_from_int, the one int writer (plant 1's named check, design 9.3): * inside [-2^47, 2^47) the tag is 0xFFFA and the int reads back exactly; * outside, R1.1 refuses (the VAL_INT box lands in R1.3). + * D the VM's operator arms: a host builtin puts an SMI into a list and a + * program applies each operator to it. Every arm must refuse by name, + * inside a `try` too; the same program with a double is the control. * - * Output: one `ENTRY : ...` line per Part A entry (the runner - * compares that set with the derived population, both ways), `FAIL` lines, - * and a final `slot-layer-test: examined=N ... failures=F` line, then its verdict. - * Exit 0 only for failures == 0 with every part non-empty. */ + * Output, every line in one grammar (tests/phase2/slot_layer.sh refuses any + * other line): `ENTRY : values= ok|FAIL` per Part A + * entry and `MATRIX : kinds= ok|FAIL` per Part B entry (the + * runner compares both sets with the derived population, both ways), + * `ARM ok|FAIL` per Part D arm, `slot-layer-test: FAIL ` lines, + * then `slot-layer-test: examined=N ... failures=F` and the verdict. Nothing + * goes to stderr. Exit 0 only for failures == 0 with every part complete. */ #include "eigenscript_all.c" #include #include #include +#ifdef __linux__ +#include +#endif #ifndef EIGS_SLOT_CHECKS #error "build with -DEIGS_SLOT_CHECKED (or ASan): slot_as_ptr's refusal is under test" @@ -38,6 +47,17 @@ static int failures; +/* A child that is EXPECTED to abort must not dump core. On a box whose + * core_pattern pipes to a crash reporter (Ubuntu's apport), the kernel runs + * the reporter for every abort, RLIMIT_CORE notwithstanding: about 1.4 s + * each, which made this test take 224 s instead of seconds. A non-dumpable + * process skips the core dump entirely; the SIGABRT status is unchanged. */ +static void child_no_core(void) { +#ifdef __linux__ + (void)prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); +#endif +} + /* The test's own encoding, independent of value_slot.h's writers. */ #define T_SMI_TAG 0xFFFA000000000000ULL #define T_PAYLOAD 0x0000FFFFFFFFFFFFULL @@ -62,6 +82,7 @@ static int aborts_naming(void (*fn)(EigsSlot), EigsSlot s, const char *who, cons pid_t pid = fork(); if (pid < 0) { FAILF("%s: fork", what); return 0; } if (pid == 0) { + child_no_core(); close(p[0]); dup2(p[1], 2); fn(s); @@ -214,114 +235,390 @@ static int part_a(void) { return calls; } -/* ---- Part B: the tag matrix ---------------------------------------------- */ +/* ---- Part B: every entry against every tag ------------------------------ */ + +/* The twelve slot kinds: three doubles (an ordinary one, the canonical NaN, + * -0.0), null, both bools, an SMI, a heap pointer, the three reserved tags + * and the sentinel. */ +enum { K_F, K_NAN, K_NZ, K_NULL, K_FALSE, K_TRUE, K_SMI, K_HEAP, K_R1, K_R2, K_R3, K_SENT, N_KINDS }; +static const char *KIND_NAMES[N_KINDS] = { + "f64 1.5", "f64 canonical NaN", "f64 -0.0", "null", "false", "true", "SMI 5", + "heap str", "reserved 0xFFFC", "reserved 0xFFFD", "reserved 0xFFFE", "sentinel 0xFFFF", +}; +static uint64_t KB[N_KINDS]; /* each kind's slot bits (main fills K_HEAP) */ +static Value *g_str; /* the heap kind's Value, a string "x" */ +static double KD(int k) { return f64_of(KB[k]); } +enum { C_F64, C_NULL, C_BOOL, C_SMI, C_HEAP, C_RES }; +static int kclass(int k) { + switch (k) { + case K_F: case K_NAN: case K_NZ: return C_F64; + case K_NULL: return C_NULL; + case K_FALSE: case K_TRUE: return C_BOOL; + case K_SMI: return C_SMI; + case K_HEAP: return C_HEAP; + default: return C_RES; + } +} -typedef struct { const char *name; uint64_t u; } Kind; +/* Renderers: every result becomes one comparable token. */ +static uint64_t u64_of(double d) { uint64_t u; memcpy(&u, &d, sizeof u); return u; } +static void r_d(char *b, size_t n, double d) { snprintf(b, n, "d:%016llx", (unsigned long long)u64_of(d)); } +static void r_v(char *b, size_t n, Value *v) { + if (!v) { snprintf(b, n, "v:NULL"); return; } + if (v == g_str) { snprintf(b, n, "v:H"); return; } + switch (v->type) { + case VAL_NUM: snprintf(b, n, "v:num:%016llx", (unsigned long long)u64_of(VAL_NUM_RAW(v))); return; + case VAL_NULL: snprintf(b, n, "v:null"); return; + case VAL_BOOL: snprintf(b, n, "v:%s", v->data.boolean ? "true" : "false"); return; + case VAL_STR: case VAL_LIST: case VAL_DICT: case VAL_FN: case VAL_BUILTIN: + case VAL_BUFFER: case VAL_TEXT_BUILDER: case VAL_JSON_RAW: + snprintf(b, n, "v:%s", val_type_name(v->type)); return; + } +} +static int is_heap_kind(EigsSlot s) { return s.u == KB[K_HEAP]; } -static void b_type_name(EigsSlot s) { (void)slot_type_name(s); } -static void b_truthy(EigsSlot s) { (void)slot_truthy(s); } +/* Cells: call one entry and render its result. Each runs in a forked child. */ +#define CELL(name) static void c_##name(EigsSlot s, char *b, size_t n) +CELL(elem_num) { r_d(b, n, eigs_slot_elem_num(s, "matrix")); } +CELL(num) { r_d(b, n, eigs_slot_num(s, "matrix")); } +CELL(opt_num) { double d = -7.25; int r = eigs_slot_opt_num(s, &d, "matrix"); + snprintf(b, n, "o:%d d:%016llx", r, (unsigned long long)u64_of(d)); } +CELL(store_borrow) { EigsSlot r = eigs_slot_store_borrow(s); snprintf(b, n, "b:%016llx", (unsigned long long)r.u); + if (is_heap_kind(r)) slot_decref(r); } +CELL(store_owned) { if (is_heap_kind(s)) slot_incref(s); + EigsSlot r = eigs_slot_store_owned(s); snprintf(b, n, "b:%016llx", (unsigned long long)r.u); + if (is_heap_kind(r)) slot_decref(r); } +CELL(ent_child) { r_d(b, n, ent_child_slot(s)); } +CELL(store_json) { strbuf sb; strbuf_init(&sb); store_json_encode_slot(s, &sb); + snprintf(b, n, "s:%s", sb.data ? sb.data : ""); strbuf_free(&sb); } +CELL(write_slot) { size_t before = g_out_len; write_slot(s); + snprintf(b, n, "w:%.*s", (int)(g_out_len - before), g_out + before); } +CELL(f64_value) { double d = -7.25; int r = slot_f64_value(s, &d); + snprintf(b, n, "o:%d d:%016llx", r, (unsigned long long)u64_of(d)); } +CELL(int_value) { int64_t i = 7; int r = slot_int_value(s, &i); snprintf(b, n, "o:%d i:%lld", r, (long long)i); } +CELL(is_f64) { snprintf(b, n, "i:%d", slot_is_f64(s)); } +CELL(is_smi) { snprintf(b, n, "i:%d", slot_is_smi(s)); } +CELL(smi_val) { snprintf(b, n, "i:%lld", (long long)slot_smi_val(s)); } +CELL(truthy_imm) { int dec = -1; int t = slot_truthy_immediate(s, &dec); snprintf(b, n, "o:%d dec:%d", t, dec); } +CELL(dump_value) { char buf[160]; obs_dump_value(s, buf, sizeof buf); snprintf(b, n, "s:%s", buf); } +CELL(obs_num) { double d = -7.25; int r = obs_slot_num(s, &d); + snprintf(b, n, "o:%d d:%016llx", r, (unsigned long long)u64_of(d)); } +CELL(truthy) { snprintf(b, n, "i:%d", slot_truthy(s)); } +CELL(type_name) { snprintf(b, n, "s:%s", slot_type_name(s)); } +CELL(decref) { if (is_heap_kind(s)) slot_incref(s); slot_decref(s); snprintf(b, n, "ok"); } +CELL(incref) { slot_incref(s); if (is_heap_kind(s)) slot_decref(s); snprintf(b, n, "ok"); } +CELL(is_bool) { snprintf(b, n, "i:%d", slot_is_bool(s)); } +CELL(is_heap) { snprintf(b, n, "i:%d", slot_is_heap(s)); } +CELL(is_null) { snprintf(b, n, "i:%d", slot_is_null(s)); } +CELL(is_ptr) { snprintf(b, n, "i:%d", slot_is_ptr(s)); } +CELL(slot_box) { Value *v = eigs_slot_box(s); r_v(b, n, v); if (v == g_str) val_decref(v); } +CELL(slot_type) { snprintf(b, n, "t:%s", val_type_name(slot_type(s))); } +CELL(slot_view) { EIGS_VIEW_NOCHECK(view); r_v(b, n, slot_view(s, &view)); } +CELL(to_value) { Value *v = slot_to_value(s); r_v(b, n, v); if (v == g_str) val_decref(v); } +CELL(observable) { snprintf(b, n, "i:%d", obs_slot_observable(s)); } +CELL(unwrap) { r_v(b, n, slot_bridge_unwrap(s)); } +CELL(slot_ref) { r_v(b, n, eigs_slot_ref(s)); } +CELL(as_ptr) { r_v(b, n, slot_as_ptr(s)); } +CELL(obs_value) { r_v(b, n, obs_slot_value(s)); } + +/* Expectations: what each entry must do with each kind, written from its + * contract (container.h, value_slot.h, the 2.5 dispositions). The tokens: + * `A:` an abort naming the reader; ` raise` a type error raised. */ +#define EXP(name) static void e_##name(int k, char *b, size_t n) +#define ABORT(who) snprintf(b, n, "A:%s", who) +static void e_d(char *b, size_t n, double d, int raise) { r_d(b, n, d); if (raise) strncat(b, " raise", n - strlen(b) - 1); } +static void e_bool(char *b, size_t n, int k) { snprintf(b, n, "v:%s", k == K_TRUE ? "true" : "false"); } +EXP(elem_num) { + switch (kclass(k)) { + case C_F64: e_d(b, n, KD(k), 0); break; + case C_NULL: case C_HEAP: e_d(b, n, 0.0, 0); break; /* non-strict element read */ + case C_BOOL: e_d(b, n, 0.0, 1); break; /* a bool raises (#1637) */ + case C_SMI: e_d(b, n, 5.0, 0); break; + default: ABORT("eigs_slot_ref"); + } +} +EXP(num) { + switch (kclass(k)) { + case C_F64: e_d(b, n, KD(k), 0); break; + case C_SMI: e_d(b, n, 5.0, 0); break; + case C_NULL: case C_BOOL: case C_HEAP: e_d(b, n, 0.0, 1); break; /* required: raises */ + default: ABORT("eigs_slot_ref"); + } +} +EXP(opt_num) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "o:1 d:%016llx", (unsigned long long)KB[k]); break; + case C_SMI: snprintf(b, n, "o:1 d:%016llx", (unsigned long long)u64_of(5.0)); break; + case C_NULL: snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(-7.25)); break; + case C_BOOL: case C_HEAP: snprintf(b, n, "o:0 d:%016llx raise", (unsigned long long)u64_of(-7.25)); break; + default: ABORT("eigs_slot_ref"); + } +} +EXP(store_slot) { /* both normalisers: a double is guarded (NaN -> 0), the rest kept */ + snprintf(b, n, "b:%016llx", (unsigned long long)(k == K_NAN ? 0 : KB[k])); +} +EXP(ent_child) { + switch (kclass(k)) { + case C_F64: r_d(b, n, entropy_of_num(KD(k))); break; + case C_SMI: r_d(b, n, entropy_of_num(5.0)); break; + case C_NULL: r_d(b, n, compute_entropy_impl(make_null())); break; + case C_BOOL: r_d(b, n, compute_entropy_impl(make_bool(k == K_TRUE))); break; + case C_HEAP: r_d(b, n, compute_entropy_impl(g_str)); break; + default: ABORT("eigs_slot_ref"); + } +} +EXP(store_json) { + static const char *f64[3] = {"s:1.5", "s:nan", "s:0"}; /* -0.0 takes the %d branch */ + switch (kclass(k)) { + case C_F64: snprintf(b, n, "%s", f64[k]); break; + case C_NULL: snprintf(b, n, "s:null"); break; + case C_BOOL: snprintf(b, n, "s:%s", k == K_TRUE ? "true" : "false"); break; + case C_SMI: snprintf(b, n, "s:5"); break; + case C_HEAP: snprintf(b, n, "s:\"x\""); break; + default: ABORT("eigs_slot_ref"); + } +} +static char g_heap_tape[64]; /* what the tape writer prints for g_str */ +EXP(write_slot) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "w:%.17g", KD(k)); break; + case C_NULL: snprintf(b, n, "w:null"); break; + case C_BOOL: snprintf(b, n, "w:%s", k == K_TRUE ? "true" : "false"); break; + case C_HEAP: snprintf(b, n, "w:%s", g_heap_tape); break; + default: ABORT("write_slot"); /* an SMI: tape v7 is R1.3's; a reserved tag refuses */ + } +} +EXP(f64_value) { + if (kclass(k) == C_F64) snprintf(b, n, "o:1 d:%016llx", (unsigned long long)KB[k]); + else snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(-7.25)); +} +EXP(int_value) { snprintf(b, n, k == K_SMI ? "o:1 i:5" : "o:0 i:7"); } +EXP(is_f64) { snprintf(b, n, "i:%d", kclass(k) == C_F64); } +EXP(is_smi) { snprintf(b, n, "i:%d", k == K_SMI); } +EXP(smi_val) { /* the payload, sign-extended from bit 47, by the test's own arithmetic */ + uint64_t p = KB[k] & T_PAYLOAD; + int64_t v = (p & 0x0000800000000000ULL) ? (int64_t)p - (INT64_C(1) << 48) : (int64_t)p; + snprintf(b, n, "i:%lld", (long long)v); +} +EXP(truthy_imm) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "o:%d dec:1", KD(k) != 0.0); break; /* NaN is truthy, -0.0 is not */ + case C_NULL: snprintf(b, n, "o:0 dec:1"); break; + case C_BOOL: snprintf(b, n, "o:%d dec:1", k == K_TRUE); break; + case C_SMI: snprintf(b, n, "o:1 dec:1"); break; + default: snprintf(b, n, "o:0 dec:0"); /* undecided: no dereference */ + } +} +EXP(dump_value) { + char t[64]; + switch (kclass(k)) { + case C_F64: eigs_num_text(t, sizeof t, KD(k)); snprintf(b, n, "s:%s", t); break; + case C_NULL: snprintf(b, n, "s:null"); break; + case C_BOOL: snprintf(b, n, "s:%s", k == K_TRUE ? "true" : "false"); break; + case C_SMI: snprintf(b, n, "s:5"); break; + case C_HEAP: snprintf(b, n, "s:\"x\""); break; + default: snprintf(b, n, "s:?"); + } +} +EXP(obs_num) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "o:1 d:%016llx", (unsigned long long)KB[k]); break; + case C_SMI: snprintf(b, n, "o:1 d:%016llx", (unsigned long long)u64_of(5.0)); break; + default: snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(-7.25)); + } +} +EXP(truthy) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "i:%d", KD(k) != 0.0); break; + case C_NULL: snprintf(b, n, "i:0"); break; + case C_BOOL: snprintf(b, n, "i:%d", k == K_TRUE); break; + case C_SMI: case C_HEAP: snprintf(b, n, "i:1"); break; + default: ABORT("slot_truthy"); + } +} +EXP(type_name) { + static const char *names[] = {"s:num", "s:none", "s:bool", "s:num", "s:str"}; + if (kclass(k) == C_RES) ABORT("slot_type_name"); else snprintf(b, n, "%s", names[kclass(k)]); +} +EXP(ok) { (void)k; snprintf(b, n, "ok"); } +EXP(is_bool) { snprintf(b, n, "i:%d", kclass(k) == C_BOOL); } +EXP(is_heap) { snprintf(b, n, "i:%d", k == K_HEAP); } +EXP(is_null) { snprintf(b, n, "i:%d", k == K_NULL); } +EXP(slot_box) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "v:num:%016llx", (unsigned long long)(k == K_NAN ? 0 : KB[k])); break; + case C_NULL: snprintf(b, n, "v:null"); break; + case C_BOOL: e_bool(b, n, k); break; + case C_HEAP: snprintf(b, n, "v:H"); break; + case C_SMI: ABORT("slot_to_value"); break; + default: ABORT("eigs_slot_ref"); + } +} +EXP(slot_type) { + static const char *names[] = {"t:num", "t:null", "t:bool", "", "t:str"}; + if (kclass(k) == C_SMI || kclass(k) == C_RES) ABORT("slot_type"); + else snprintf(b, n, "%s", names[kclass(k)]); +} +EXP(slot_view) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "v:num:%016llx", (unsigned long long)KB[k]); break; /* a facade: no guard */ + case C_NULL: snprintf(b, n, "v:null"); break; + case C_BOOL: e_bool(b, n, k); break; + case C_HEAP: snprintf(b, n, "v:H"); break; + case C_SMI: ABORT("slot_view"); break; + default: ABORT("slot_type"); + } +} +EXP(to_value) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "v:num:%016llx", (unsigned long long)(k == K_NAN ? 0 : KB[k])); break; + case C_NULL: snprintf(b, n, "v:null"); break; + case C_BOOL: e_bool(b, n, k); break; + case C_HEAP: snprintf(b, n, "v:H"); break; + default: ABORT("slot_to_value"); + } +} +EXP(observable) { + switch (kclass(k)) { + case C_F64: case C_NULL: snprintf(b, n, "i:0"); break; + case C_BOOL: case C_HEAP: snprintf(b, n, "i:1"); break; + default: ABORT("obs_slot_observable"); + } +} +EXP(unwrap) { + switch (kclass(k)) { + case C_F64: snprintf(b, n, "v:num:%016llx", (unsigned long long)(k == K_NAN ? 0 : KB[k])); break; + case C_NULL: snprintf(b, n, "v:null"); break; + case C_BOOL: e_bool(b, n, k); break; + case C_HEAP: snprintf(b, n, "v:H"); break; + case C_SMI: ABORT("slot_to_value"); break; + default: ABORT("slot_as_ptr"); + } +} +EXP(slot_ref) { + switch (kclass(k)) { + case C_NULL: snprintf(b, n, "v:null"); break; + case C_BOOL: e_bool(b, n, k); break; + case C_HEAP: snprintf(b, n, "v:H"); break; + default: ABORT("eigs_slot_ref"); + } +} +EXP(as_ptr) { if (k == K_HEAP) snprintf(b, n, "v:H"); else ABORT("slot_as_ptr"); } +EXP(obs_value) { + if (kclass(k) == C_BOOL) e_bool(b, n, k); + else if (k == K_HEAP) snprintf(b, n, "v:H"); + else ABORT("slot_as_ptr"); +} + +typedef struct { + const char *name; + void (*cell)(EigsSlot, char *, size_t); + void (*expect)(int, char *, size_t); +} MatrixEntry; +static const MatrixEntry MATRIX[] = { + {"container.h:eigs_slot_elem_num", c_elem_num, e_elem_num}, + {"container.h:eigs_slot_num", c_num, e_num}, + {"container.h:eigs_slot_opt_num", c_opt_num, e_opt_num}, + {"container.h:eigs_slot_store_borrow", c_store_borrow, e_store_slot}, + {"container.h:eigs_slot_store_owned", c_store_owned, e_store_slot}, + {"eigenscript.c:ent_child_slot", c_ent_child, e_ent_child}, + {"ext_store.c:store_json_encode_slot", c_store_json, e_store_json}, + {"trace.c:write_slot", c_write_slot, e_write_slot}, + {"value_slot.h:slot_f64_value", c_f64_value, e_f64_value}, + {"value_slot.h:slot_int_value", c_int_value, e_int_value}, + {"value_slot.h:slot_is_f64", c_is_f64, e_is_f64}, + {"value_slot.h:slot_is_smi", c_is_smi, e_is_smi}, + {"value_slot.h:slot_smi_val", c_smi_val, e_smi_val}, + {"value_slot.h:slot_truthy_immediate", c_truthy_imm, e_truthy_imm}, + {"vm.c:obs_dump_value", c_dump_value, e_dump_value}, + {"vm.c:obs_slot_num", c_obs_num, e_obs_num}, + {"vm.c:slot_truthy", c_truthy, e_truthy}, + {"vm.c:slot_type_name", c_type_name, e_type_name}, + {"value_slot.h:slot_decref", c_decref, e_ok}, + {"value_slot.h:slot_incref", c_incref, e_ok}, + {"value_slot.h:slot_is_bool", c_is_bool, e_is_bool}, + {"value_slot.h:slot_is_heap", c_is_heap, e_is_heap}, + {"value_slot.h:slot_is_null", c_is_null, e_is_null}, + {"value_slot.h:slot_is_ptr", c_is_ptr, e_is_heap}, + {"container.h:eigs_slot_box", c_slot_box, e_slot_box}, + {"container.h:slot_type", c_slot_type, e_slot_type}, + {"container.h:slot_view", c_slot_view, e_slot_view}, + {"eigenscript.c:slot_to_value", c_to_value, e_to_value}, + {"vm.c:obs_slot_observable", c_observable, e_observable}, + {"vm.c:slot_bridge_unwrap", c_unwrap, e_unwrap}, + {"container.h:eigs_slot_ref", c_slot_ref, e_slot_ref}, + {"value_slot.h:slot_as_ptr", c_as_ptr, e_as_ptr}, + {"vm.c:obs_slot_value", c_obs_value, e_obs_value}, +}; +#define N_MATRIX ((int)(sizeof MATRIX / sizeof MATRIX[0])) + +/* Run cell(s) in a child; return its outcome as a token: the rendered result + * (plus " raise" when the call raised), `A:` for an abort with a FATAL + * line naming the reader, `X:...` for anything else (a crash, a bad exit). + * `pre`, when given, receives what the child printed before its result. */ +static void run_cell(void (*cell)(EigsSlot, char *, size_t), EigsSlot s, char *got, size_t gn, + char *pre, size_t pn) { + if (pre) pre[0] = 0; + int p[2]; + if (pipe(p) != 0) { snprintf(got, gn, "X:pipe"); return; } + fflush(stdout); fflush(stderr); + pid_t pid = fork(); + if (pid < 0) { snprintf(got, gn, "X:fork"); return; } + if (pid == 0) { + child_no_core(); + close(p[0]); + dup2(p[1], 1); dup2(p[1], 2); + char b[512]; + g_has_error = 0; + cell(s, b, sizeof b); + printf("R:%s%s\n", b, g_has_error ? " raise" : ""); + fflush(stdout); + _exit(0); + } + close(p[1]); + char buf[2048]; + size_t len = 0; + ssize_t r; + while (len < sizeof buf - 1 && (r = read(p[0], buf + len, sizeof buf - 1 - len)) > 0) len += (size_t)r; + buf[len] = 0; + close(p[0]); + int st = 0; + waitpid(pid, &st, 0); + char *f = strstr(buf, "EigenScript FATAL: "); + if (WIFSIGNALED(st) && WTERMSIG(st) == SIGABRT && f) { + f += strlen("EigenScript FATAL: "); + char *end = strstr(f, ": "); + snprintf(got, gn, "A:%.*s", end ? (int)(end - f) : (int)strcspn(f, "\n"), f); + return; + } + char *rl = (strncmp(buf, "R:", 2) == 0) ? buf : strstr(buf, "\nR:"); + if (rl && rl != buf) rl++; + if (pre && rl) snprintf(pre, pn, "%.*s", (int)(rl - buf), buf); + if (WIFEXITED(st) && WEXITSTATUS(st) == 0 && rl) { + snprintf(got, gn, "%.*s", (int)strcspn(rl + 2, "\n"), rl + 2); + return; + } + snprintf(got, gn, "X:%s %d: %.*s", WIFSIGNALED(st) ? "signal" : "exit", + WIFSIGNALED(st) ? WTERMSIG(st) : WEXITSTATUS(st), (int)strcspn(buf, "\n"), buf); +} static int part_b(void) { - Value *str = make_str("x"); - Kind kinds[] = { - {"f64 1.5", 0x3FF8000000000000ULL}, - {"f64 canonical NaN", 0x7FF8000000000000ULL}, - {"f64 -0.0", 0x8000000000000000ULL}, - {"null", 0xFFF8000000000000ULL}, - {"false", 0xFFF9000000000000ULL}, - {"true", 0xFFF9000000000001ULL}, - {"SMI 5", T_SMI_TAG | 5}, - {"heap str", 0}, - {"reserved 0xFFFC", 0xFFFC000000000000ULL}, - {"reserved 0xFFFD", 0xFFFD000000000000ULL}, - {"reserved 0xFFFE", 0xFFFE000000000000ULL}, - {"sentinel 0xFFFF", 0xFFFF000000000000ULL}, - }; - int nk = (int)(sizeof kinds / sizeof kinds[0]); - kinds[7].u = slot_from_heap(str).u; - /* expected predicate answers, columns: f64 smi null bool heap ptr */ - static const int want_pred[][6] = { - {1,0,0,0,0,0}, {1,0,0,0,0,0}, {1,0,0,0,0,0}, {0,0,1,0,0,0}, {0,0,0,1,0,0}, - {0,0,0,1,0,0}, {0,1,0,0,0,0}, {0,0,0,0,1,1}, {0,0,0,0,0,0}, {0,0,0,0,0,0}, - {0,0,0,0,0,0}, {0,0,0,0,0,0}, - }; - static const char *want_type[] = { - "num", "num", "num", "none", "bool", "bool", "num", "str", 0, 0, 0, 0, - }; - static const int want_truthy[] = { 1, 1, 0, 0, 0, 1, 1, 1, -1, -1, -1, -1 }; - static const int want_f64[] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int rows = 0; - for (int i = 0; i < nk; i++) { - EigsSlot s = bits(kinds[i].u); - int got[6] = { slot_is_f64(s), slot_is_smi(s), slot_is_null(s), slot_is_bool(s), - slot_is_heap(s), slot_is_ptr(s) }; - static const char *pn[6] = {"slot_is_f64", "slot_is_smi", "slot_is_null", - "slot_is_bool", "slot_is_heap", "slot_is_ptr"}; - for (int j = 0; j < 6; j++, rows++) - if (got[j] != want_pred[i][j]) - FAILF("%s(%s) = %d, want %d", pn[j], kinds[i].name, got[j], want_pred[i][j]); - rows++; - if (want_type[i]) { - const char *t = slot_type_name(s); - if (strcmp(t, want_type[i]) != 0) - FAILF("slot_type_name(%s) = %s, want %s", kinds[i].name, t, want_type[i]); - } else { - (void)aborts_naming(b_type_name, s, "slot_type_name", "slot_type_name"); - } - rows++; - if (want_truthy[i] >= 0) { - int t = slot_truthy(s); - if (t != want_truthy[i]) - FAILF("slot_truthy(%s) = %d, want %d", kinds[i].name, t, want_truthy[i]); - } else { - (void)aborts_naming(b_truthy, s, "slot_truthy", "slot_truthy"); - } - rows++; - double d = -7.25; - int f = slot_f64_value(s, &d); - if (f != want_f64[i] || (f && memcmp(&d, &kinds[i].u, sizeof d) != 0)) - FAILF("slot_f64_value(%s) = %d, want %d with the same bits", kinds[i].name, f, want_f64[i]); - rows++; - int64_t iv = 0; - int isint = slot_int_value(s, &iv); - if (isint != (i == 6) || (isint && iv != 5)) - FAILF("slot_int_value(%s) = %d (%lld)", kinds[i].name, isint, (long long)iv); - /* the readers that must refuse every non-pointer, non-null, non-bool */ - rows++; - if (want_pred[i][3] || want_pred[i][2] || want_pred[i][4]) { - Value *r = eigs_slot_ref(s); - Value *want = want_pred[i][4] ? str : want_pred[i][2] ? make_null() : make_bool(i == 5); - if (r != want) FAILF("eigs_slot_ref(%s) is not its Value", kinds[i].name); - } else { - (void)aborts_naming(a_eigs_slot_ref, s, "eigs_slot_ref", "eigs_slot_ref"); - } - rows++; - if (want_pred[i][1]) { - (void)aborts_naming(a_slot_to_value, s, "slot_to_value", "slot_to_value"); - } else if (want_pred[i][0] || want_pred[i][2] || want_pred[i][3] || want_pred[i][4]) { - Value *v = slot_to_value(s); - /* make_num guards: a NaN reads back 0.0 (non-strict, set in main) */ - double wd = want_pred[i][0] ? num_guard(f64_of(kinds[i].u)) : 0.0; - int ok = want_pred[i][0] ? (v->type == VAL_NUM && memcmp(&VAL_NUM_RAW(v), &wd, 8) == 0) - : want_pred[i][2] ? v->type == VAL_NULL - : want_pred[i][3] ? (v->type == VAL_BOOL && v->data.boolean == (i == 5)) - : v == str; - if (!ok) FAILF("slot_to_value(%s) is not its Value", kinds[i].name); - val_decref(v); - } else { - (void)aborts_naming(a_slot_to_value, s, "slot_to_value", "slot_to_value"); - } - rows++; - if (want_pred[i][1] || (!want_pred[i][0] && !want_pred[i][2] && !want_pred[i][3] && !want_pred[i][4])) { - (void)aborts_naming(a_obs_slot_observable, s, "obs_slot_observable", "obs_slot_observable"); - } else { - int o = obs_slot_observable(s); - int wo = want_pred[i][3] || want_pred[i][4]; - if (o != wo) FAILF("obs_slot_observable(%s) = %d, want %d", kinds[i].name, o, wo); + int cells = 0; + for (int i = 0; i < N_MATRIX; i++) { + const MatrixEntry *m = &MATRIX[i]; + int bad = 0; + for (int k = 0; k < N_KINDS; k++, cells++) { + char want[256], got[512]; + m->expect(k, want, sizeof want); + run_cell(m->cell, bits(KB[k]), got, sizeof got, NULL, 0); + if (strcmp(want, got) != 0) { + FAILF("%s(%s): got %s, want %s", m->name, KIND_NAMES[k], got, want); + bad++; + } } + printf("MATRIX %s kinds=%d %s\n", m->name, N_KINDS, bad ? "FAIL" : "ok"); } - val_decref(str); - return rows; + return cells; } /* ---- Part C: slot_from_int (plant 1's named check) ----------------------- */ @@ -357,19 +654,109 @@ static int part_c(void) { return rows; } +/* ---- Part D: the VM's operator arms, with an int in a list ------------- */ + +/* A host builtin puts a hand-built SMI (or, for the control run, the double + * of the same value) into a list element, the way no program can before + * R1.3. Each arm that met an int with a type error -- which a `try` turned + * into a wrong value (the R1.1 critic) -- must now refuse it by name, inside + * a `try` too; the control run proves the program reaches the arm. */ +static int g_poke_smi; +static EigsValue *h_poke(EigsValue *arg) { + Value *t = list_get_ref(arg, 0); + if (!t || t->type != VAL_LIST || t->data.list.count < 1) { printf("POKE: bad target\n"); _exit(97); } + EigsSlot old = t->data.list.items[0]; + t->data.list.items[0] = g_poke_smi ? smi(5) : slot_from_f64(5.0); + slot_decref(old); + return make_null(); +} +typedef struct { const char *name, *expr, *f64_out, *aborts; int in_try; } Arm; +static const Arm ARMS[] = { + {"lt", "xs[0] < 6", "true", "compare '<'", 0}, + {"gt", "xs[0] > 6", "false", "compare '>'", 0}, + {"le", "xs[0] <= 6", "true", "compare '<='", 0}, + {"ge", "xs[0] >= 6", "false", "compare '>='", 0}, + {"lt_in_try", "xs[0] < 6", "true", "compare '<'", 1}, + {"band", "xs[0] & 3", "1", "bitwise '&'", 0}, + {"bor", "xs[0] | 3", "7", "bitwise '|'", 0}, + {"bxor", "xs[0] ^ 3", "6", "bitwise '^'", 0}, + {"shl", "xs[0] << 1", "10", "bitwise '<<'", 0}, + {"shr", "xs[0] >> 1", "2", "bitwise '>>'", 0}, + {"band_in_try", "xs[0] & 3", "1", "bitwise '&'", 1}, + {"neg", "-(xs[0])", "-5", "negation", 0}, + {"neg_in_try", "-(xs[0])", "-5", "negation", 1}, + {"bnot", "~(xs[0])", "-6", "bitwise '~'", 0}, + {"eq", "xs[0] == 5", "true", "slot_to_value", 0}, + {"add", "xs[0] + 1", "6", "slot_to_value", 0}, +}; +#define N_ARMS ((int)(sizeof ARMS / sizeof ARMS[0])) +static const Arm *g_arm; +static void c_arm(EigsSlot s, char *b, size_t n) { + (void)s; + char prog[512]; + if (g_arm->in_try) + snprintf(prog, sizeof prog, "xs is [7.5]\nphase2_poke of ([xs])\ntry:\n print of (%s)\n" + "catch e:\n print of \"caught\"\n", g_arm->expr); + else + snprintf(prog, sizeof prog, "xs is [7.5]\nphase2_poke of ([xs])\nprint of (%s)\n", g_arm->expr); + EigsValue *r = eigs_eval_string(prog); + fflush(stdout); + snprintf(b, n, "%s", r ? "ran" : "eval-error"); +} +static int part_d(void) { + eigs_register_function("phase2_poke", h_poke); + int rows = 0; + for (int i = 0; i < N_ARMS; i++) { + g_arm = &ARMS[i]; + int bad = 0; + char got[512], want[256], pre[512], wpre[64]; + g_poke_smi = 1; + run_cell(c_arm, slot_null(), got, sizeof got, NULL, 0); + snprintf(want, sizeof want, "A:%s", g_arm->aborts); + if (strcmp(got, want) != 0) { FAILF("arm %s with an int: got %s, want %s", g_arm->name, got, want); bad++; } + g_poke_smi = 0; + run_cell(c_arm, slot_null(), got, sizeof got, pre, sizeof pre); + snprintf(wpre, sizeof wpre, "%s\n", g_arm->f64_out); + if (strcmp(got, "ran") != 0 || strcmp(pre, wpre) != 0) { + FAILF("arm %s control (a double): got %s, printed \"%.*s\", want ran and %s", g_arm->name, got, + (int)strcspn(pre, "\n"), pre, g_arm->f64_out); + bad++; + } + rows += 2; + printf("ARM %s %s\n", g_arm->name, bad ? "FAIL" : "ok"); + } + return rows; +} + int main(void) { EigsState *st = eigs_open(); if (!st) { printf("slot-layer-test: FAIL eigs_open\n"); return 1; } /* Part B reads the canonical NaN back through make_num, whose guard * raises under strict mode; the test pins the soft read instead. */ eigs_state_set_strict(st, 0); + g_str = make_str("x"); + static const uint64_t kinds[N_KINDS] = { + 0x3FF8000000000000ULL, 0x7FF8000000000000ULL, 0x8000000000000000ULL, + 0xFFF8000000000000ULL, 0xFFF9000000000000ULL, 0xFFF9000000000001ULL, + T_SMI_TAG | 5, 0, 0xFFFC000000000000ULL, 0xFFFD000000000000ULL, + 0xFFFE000000000000ULL, 0xFFFF000000000000ULL, + }; + memcpy(KB, kinds, sizeof KB); + KB[K_HEAP] = slot_from_heap(g_str).u; + size_t before = g_out_len; + write_value_ptr(g_str); + snprintf(g_heap_tape, sizeof g_heap_tape, "%.*s", (int)(g_out_len - before), g_out + before); int calls = part_a(); - int tag_rows = part_b(); + int matrix_cells = part_b(); int from_int_rows = part_c(); - printf("slot-layer-test: examined=%d smi_values=%d calls=%d tag_rows=%d from_int_rows=%d failures=%d\n", - N_ENTRIES, N_SMI, calls, tag_rows, from_int_rows, failures); + int arm_rows = part_d(); + printf("slot-layer-test: examined=%d smi_values=%d calls=%d matrix=%d kinds=%d matrix_cells=%d " + "from_int_rows=%d arm_rows=%d failures=%d\n", N_ENTRIES, N_SMI, calls, N_MATRIX, N_KINDS, + matrix_cells, from_int_rows, arm_rows, failures); + val_decref(g_str); eigs_close(st); - int ok = failures == 0 && N_ENTRIES > 0 && calls > 0 && tag_rows > 0 && from_int_rows > 0; + int ok = failures == 0 && N_ENTRIES > 0 && calls > 0 && N_MATRIX == N_ENTRIES && + matrix_cells == N_MATRIX * N_KINDS && from_int_rows > 0 && arm_rows == 2 * N_ARMS; printf("slot-layer-test: %s\n", ok ? "PASS" : "FAIL"); return ok ? 0 : 1; } diff --git a/tests/phase2/slot_layer.sh b/tests/phase2/slot_layer.sh index d0967a6dd..559c44048 100755 --- a/tests/phase2/slot_layer.sh +++ b/tests/phase2/slot_layer.sh @@ -5,10 +5,17 @@ # 1. Derive the population: `tools/phase2_inventory.py --slot-population` # lists every slot classifier whose first parameter is an EigsSlot. # 2. Build tests/phase2/slot_layer.c against the amalgamation -# (make phase2-slot-test) and run it. -# 3. The set of `ENTRY` lines it printed must equal the derived population, -# both ways, and its examined count must equal the population's size, -# which must be above zero. The test's own verdict must be PASS. +# (make phase2-slot-test; -O0 for release, -O1 for asan, both -Wall +# -Wextra) and run it. A build warning is a FAIL (#1775). +# 3. The ENTRY lines (Part A) and the MATRIX lines (Part B) must each equal +# the derived population, both ways; the examined count must equal its +# size, which must be above zero; the test's own verdict must be PASS. +# +# Every output this script PARSES is read on its own channel and against its +# own grammar (the R1.1 critic: a Python DeprecationWarning on the scan's +# stderr was read as two classifiers). A tool that writes to stderr, or a line +# outside the grammar, is a FAIL that prints the line; nothing is skipped. +# Python runs with `-W error`, so a new warning fails here, loudly. # Prints the test's whole output, then `slot-layer-population: ...` and a # final `slot-layer: PASS|FAIL` line. Exit 0 only for PASS. set -u @@ -18,43 +25,88 @@ case "$VARIANT" in release|asan) ;; *) echo "slot-layer: FAIL: unknown variant $ TMP=$(mktemp -d "${TMPDIR:-/tmp}/eigs-slot-layer.XXXXXX") || { echo "slot-layer: FAIL: mktemp"; exit 2; } trap 'rm -rf "$TMP"' EXIT fail() { echo "slot-layer: FAIL: $*"; exit 1; } +# show_stderr FILE WHO: a tool that wrote to stderr is a FAIL, with its words +show_stderr() { + if [ -s "$1" ]; then + sed "s/^/ $2 stderr: /" "$1" + fail "$2 wrote to stderr (a population read beside its diagnostics is not trusted)" + fi +} command -v python3 >/dev/null 2>&1 || fail "python3 is required (the population and the amalgamation need it)" -python3 "$ROOT/tools/phase2_inventory.py" --no-write --slot-population > "$TMP/pop.txt" 2>&1 +python3 -W error "$ROOT/tools/phase2_inventory.py" --no-write --slot-population > "$TMP/pop.txt" 2> "$TMP/pop.err" prc=$? +show_stderr "$TMP/pop.err" "the population scan" if [ "$prc" -ne 0 ]; then sed 's/^/ inventory: /' "$TMP/pop.txt" fail "the population scan exited $prc" fi -grep -v "^slot-population:" "$TMP/pop.txt" | LC_ALL=C sort > "$TMP/want" +# The scan's grammar: `file:function` lines, then one `slot-population: entries=N`. +ENTRY_RE='^[A-Za-z0-9_]+[.][ch]:[A-Za-z_][A-Za-z0-9_]*$' +grep -Ev "$ENTRY_RE" "$TMP/pop.txt" | grep -Ev '^slot-population: entries=[0-9]+$' > "$TMP/pop.bad" +if [ -s "$TMP/pop.bad" ]; then + sed 's/^/ UNPARSED population line: /' "$TMP/pop.bad" + fail "the population scan printed lines outside its grammar" +fi +grep -E "$ENTRY_RE" "$TMP/pop.txt" | LC_ALL=C sort > "$TMP/want" n_want=$(grep -c . "$TMP/want") -[ "$n_want" -gt 0 ] || fail "the population scan listed no entry (grep -c gave $n_want)" +declared=$(awk '/^slot-population: entries=/ { sub(/^slot-population: entries=/, ""); print }' "$TMP/pop.txt") +[ -n "$declared" ] && [ "$(grep -c '^slot-population:' "$TMP/pop.txt")" -eq 1 ] || + fail "the population scan printed no single summary line" +[ "$declared" = "$n_want" ] || fail "the population scan declared $declared entries and listed $n_want" +[ "$n_want" -gt 0 ] || fail "the population scan listed no entry" make -s -C "$ROOT" PHASE2_SLOT_VARIANT="$VARIANT" phase2-slot-test > "$TMP/build.txt" 2>&1 brc=$? +BIN="$ROOT/build/phase2/slot_layer_$VARIANT" if [ "$brc" -ne 0 ]; then sed 's/^/ build: /' "$TMP/build.txt" fail "make phase2-slot-test exited $brc" fi -BIN="$ROOT/build/phase2/slot_layer_$VARIANT" +# #1775: the amalgamation compiles warning-free at the slot test's level (-O0 +# for release, ASan's -O1 for asan, both with -Wall -Wextra). A warning fails, +# and the binary is removed so the next run compiles, and warns, again. +if grep -q 'warning:' "$TMP/build.txt"; then + grep 'warning:' "$TMP/build.txt" | sed 's/^/ build warning: /' + rm -f "$BIN" + fail "the slot test build printed $(grep -c 'warning:' "$TMP/build.txt") warning(s) (#1775)" +fi [ -x "$BIN" ] || fail "no binary at $BIN after the build" -"$BIN" > "$TMP/out.txt" 2>&1 +"$BIN" > "$TMP/out.txt" 2> "$TMP/out.err" trc=$? cat "$TMP/out.txt" +show_stderr "$TMP/out.err" "the slot test" +# The test's grammar (its header comment); anything else is refused. +NAME_RE='[A-Za-z0-9_]+[.][ch]:[A-Za-z_][A-Za-z0-9_]*' +grep -Ev "^ENTRY $NAME_RE [A-Za-z_]+ values=[0-9]+ (ok|FAIL)$" "$TMP/out.txt" | + grep -Ev "^MATRIX $NAME_RE kinds=[0-9]+ (ok|FAIL)$" | + grep -Ev '^ARM [a-z_]+ (ok|FAIL)$' | + grep -Ev '^slot-layer-test: (FAIL .+|examined=[0-9]+ .*failures=[0-9]+|PASS|FAIL)$' > "$TMP/out.bad" +if [ -s "$TMP/out.bad" ]; then + sed 's/^/ UNPARSED slot test line: /' "$TMP/out.bad" + fail "the slot test printed lines outside its grammar" +fi awk '$1 == "ENTRY" { print $2 }' "$TMP/out.txt" | LC_ALL=C sort > "$TMP/got" +awk '$1 == "MATRIX" { print $2 }' "$TMP/out.txt" | LC_ALL=C sort > "$TMP/gotm" n_got=$(grep -c . "$TMP/got") +n_gotm=$(grep -c . "$TMP/gotm") examined=$(awk '/^slot-layer-test: examined=/ { sub(/^slot-layer-test: examined=/, ""); sub(/ .*/, ""); print }' "$TMP/out.txt") LC_ALL=C comm -23 "$TMP/want" "$TMP/got" > "$TMP/missing" LC_ALL=C comm -13 "$TMP/want" "$TMP/got" > "$TMP/extra" +LC_ALL=C comm -3 "$TMP/want" "$TMP/gotm" > "$TMP/mdiff" n_missing=$(grep -c . "$TMP/missing") n_extra=$(grep -c . "$TMP/extra") +n_mdiff=$(grep -c . "$TMP/mdiff") sed 's/^/ MISSING (a slot classifier the test never called): /' "$TMP/missing" sed 's/^/ EXTRA (a test entry that is not a derived slot classifier): /' "$TMP/extra" -echo "slot-layer-population: derived=$n_want examined=${examined:-none} entries=$n_got missing=$n_missing extra=$n_extra test_rc=$trc" +sed 's/^/ MATRIX differs from the population: /' "$TMP/mdiff" +echo "slot-layer-population: derived=$n_want examined=${examined:-none} entries=$n_got matrix=$n_gotm missing=$n_missing extra=$n_extra matrix_diff=$n_mdiff test_rc=$trc" [ "$trc" -eq 0 ] || fail "the test exited $trc" grep -q '^slot-layer-test: PASS$' "$TMP/out.txt" || fail "the test printed no PASS verdict" [ "${examined:-x}" = "$n_want" ] || fail "examined=${examined:-none} differs from the derived population ($n_want)" [ "$n_got" -eq "$n_want" ] && [ "$n_missing" -eq 0 ] && [ "$n_extra" -eq 0 ] || fail "the examined entries differ from the derived population" +[ "$n_gotm" -eq "$n_want" ] && [ "$n_mdiff" -eq 0 ] || + fail "the matrix entries differ from the derived population" echo "slot-layer: PASS" diff --git a/tests/section_weights.txt b/tests/section_weights.txt index 3331e56a9..d7d1d45cb 100644 --- a/tests/section_weights.txt +++ b/tests/section_weights.txt @@ -1,270 +1,313 @@ # tests/section_weights.txt — per-section wall seconds, summed per label. # -# MEASURED ON THE CI RUNNER, not on the dev box: run 36102915685, -# head 05bda90, the `asan + ubsan / shard k/N (http+model build)` +# MEASURED ON THE CI RUNNER, not on the dev box: run 38652383231, +# head 6fe6f0a3, the `asan + ubsan / shard k/N (http+model build)` # job logs, concatenated and fed to `--print-weights`. -# 260 SECTION_TIME lines, 260 distinct sections. +# 293 SECTION_TIME lines, 293 distinct sections. # # Refresh from every shard log of the same CI run. Different binary # builds and runner hosts have different section costs. # # Refresh — see docs/CI.md for the gh api recipe: # tools/section_plan.sh --print-weights \ -# --run 36102915685 --head 05bda90 > tests/section_weights.txt -[0] 0.04 -[0a] 23.07 -[0b] 0.27 -[0c] 26.24 -[0d] 0.04 -[0e] 0.15 -[0f] 0.55 -[1/15] 0.07 -[10/15] 0.03 -[100] 0.26 -[101] 0.06 -[102] 0.06 -[103] 0.04 -[103a] 3.54 -[104] 1.49 -[104b] 2.46 -[105] 0.04 -[105b] 0.07 -[105c] 3.17 -[106] 0.09 -[107] 0.87 -[108] 3.47 -[109] 0.12 -[11/15] 0.03 +# --run 38652383231 --head 6fe6f0a3 > tests/section_weights.txt +# +# One row is not from that run: [0fk] (#1758 R1.1, the C slot test) did not +# exist at that head. Its 53.33 s is SECTION_TIME [0fk] from the PR #1776 +# `linux / gcc` lane (job log of 2026-10-14, the release flavour at -O2; the +# slot test now builds at -O0, and the ASan shards run its ASan flavour). +# The next refresh from an ASan run replaces it (#1784). +[0] 0.03 +[0a] 23.67 +[0b] 43.43 +[0c] 0.50 +[0d] 0.02 +[0f] 0.44 +[0f2] 1.03 +[0f4] 0.44 +[0f5] 0.39 +[0f6] 0.42 +[0f7b] 0.01 +[0f8] 0.02 +[0f9] 0.41 +[0fb] 26.68 +[0fc] 22.45 +[0fd] 1.13 +[0fe] 32.19 +[0ff] 0.93 +[0fg] 0.47 +[0fh] 0.03 +[0fi] 1.48 +[0fj] 0.08 +[0fk] 53.33 +[0g] 1.14 +[0h] 0.05 +[100] 0.09 +[101] 0.03 +[10/15] 0.02 +[101a] 1.67 +[102] 0.04 +[102a] 0.03 +[102aa] 0.87 +[103] 0.03 +[103a] 2.28 +[104] 1.11 +[105] 0.02 +[105b] 0.05 +[105c] 2.42 +[105d] 1.54 +[106] 2.35 +[107] 0.73 +[107a] 0.09 +[107b] 0.12 +[108] 2.11 +[108a] 0.03 +[108b] 0.13 +[109] 0.13 [110] 0.03 -[111] 0.11 -[112] 0.04 -[113] 0.09 -[114] 0.27 -[114b] 0.17 -[115] 0.08 -[115b] 0.05 -[116] 0.05 -[117] 0.04 -[118] 0.05 -[119] 0.62 -[12/15] 0.03 -[120] 0.75 -[120b] 0.02 -[121] 0.02 -[122] 0.03 -[123] 0.04 -[124] 13.67 -[124b] 0.00 -[125] 0.31 -[126] 26.26 -[127] 0.04 -[128] 0.04 -[129] 0.05 -[13/15] 0.03 +[111] 0.07 +[11/15] 0.02 +[112] 0.03 +[113] 0.06 +[114] 0.23 +[114b] 0.67 +[1/15] 0.06 +[115] 0.07 +[115b] 0.04 +[116] 0.03 +[117] 0.05 +[118] 0.03 +[119] 0.39 +[120] 0.00 +[120b] 0.07 +[121] 0.04 +[12/15] 0.02 +[122] 0.02 +[123] 0.03 +[124] 6.43 +[124b] 0.02 +[125] 0.28 +[126] 20.20 +[127] 0.03 +[128] 0.03 +[129] 0.04 [130] 0.03 -[131] 0.09 -[132] 0.00 -[133] 0.03 -[134] 0.00 -[135] 0.04 -[137] 367.78 -[14/15] 0.20 -[15/15] 0.07 -[16/16] 0.96 -[17/17] 0.07 +[131] 0.07 +[13/15] 0.06 +[132] 0.20 +[133] 0.73 +[134] 0.44 +[135] 0.02 +[137] 276.41 +[15/15] 0.04 +[16/16] 1.17 +[17/17] 0.06 [18/18] 1.04 -[19/19] 0.05 -[2/15] 0.09 +[19/19] 0.03 [20/21] 0.04 -[22/27] 0.04 -[23/27] 0.03 -[24/27] 0.03 -[25/27] 0.05 +[2/15] 0.06 +[22/27] 0.06 +[23/27] 0.04 +[24/27] 0.02 +[25/27] 0.02 [26/27] 0.03 [27/27] 0.03 -[27b/27] 0.03 -[29/31] 0.03 -[3/15] 0.00 +[27b/27] 0.02 +[29/31] 0.02 [30/31] 0.04 [31/31] 0.03 -[33/33] 0.03 -[35/36] 0.04 +[3/15] 0.00 +[33/33] 0.02 +[35/36] 0.03 [36/36] 0.19 -[38/38] 0.03 -[4/15] 0.04 -[40/40] 0.05 +[38/38] 0.02 +[40/40] 0.03 [41/47] 0.03 -[42/47] 0.90 -[42a/47] 2.30 +[4/15] 0.03 +[42/47] 0.61 [42a2] 0.18 -[42a] 10.30 +[42a/47] 2.16 +[42a] 8.80 +[42b] 0.19 [42b/47] 0.02 -[42b] 0.22 -[42c/47] 0.02 -[42c] 2.69 +[42c] 1.87 +[42c/47] 0.72 [42d/47] 0.05 -[42e/47] 0.03 -[42f2] 2.10 -[42f] 0.51 -[42g] 1.03 -[42h] 0.39 -[42i] 0.78 -[42j] 1.73 -[42k] 1.80 -[42l] 1.23 -[43/47] 0.03 -[43a2] 0.20 -[43a2b] 0.14 -[43a2c] 0.12 -[43a3] 0.07 -[43b/47] 0.15 -[43c/47] 0.08 -[43d/47] 0.06 -[44/47] 0.04 -[45/47] 10.73 -[45a/47] 28.32 +[42e/47] 0.04 +[42f] 0.42 +[42g] 1.08 +[42h] 0.55 +[42i] 0.77 +[42j] 1.56 +[42k] 1.31 +[42l] 0.86 +[42m] 0.02 +[42n] 0.00 +[42p] 0.26 +[43/47] 0.02 +[43a2] 0.16 +[43a2b] 0.09 +[43a2c] 0.10 +[43a3] 0.05 +[43b/47] 0.11 +[43c/47] 0.06 +[43d/47] 0.02 +[44/47] 0.02 +[45/47] 10.29 +[45a/47] 28.15 [45b/47] 9.11 -[45c/47] 0.01 -[46/47] 0.03 -[47/47] 0.30 -[47b/47] 0.11 -[47c/47] 0.09 -[47d/47] 0.27 -[47e/47] 0.29 -[47f/47] 0.07 -[48a] 0.98 -[48b] 0.17 -[48c] 0.10 -[48d] 0.08 -[49] 0.05 -[5/15] 0.05 -[50] 0.03 -[50b] 0.13 -[50c] 0.05 -[50d] 0.05 -[50e] 0.04 -[50f] 0.04 -[50g] 0.04 -[50h] 0.05 -[50i] 0.04 -[50j2] 0.04 -[50j3] 0.04 -[50j4] 0.08 -[50j5] 0.04 -[50j6] 0.05 -[50j] 0.04 -[50k] 0.05 -[50l] 0.05 -[51] 0.04 -[51a] 0.06 -[51b] 0.05 -[52] 0.03 +[45c/47] 0.05 +[46/47] 0.02 +[47/47] 0.25 +[47b/47] 0.09 +[47c/47] 9.33 +[47d/47] 0.21 +[47e/47] 0.21 +[47f/47] 0.06 +[47g/47] 0.05 +[47h/47] 0.00 +[47i] 0.42 +[48a] 0.68 +[48b] 0.10 +[48c] 0.08 +[48d] 0.05 +[49] 0.03 +[50] 0.18 +[50b] 0.08 +[50c] 0.03 +[50d] 0.03 +[50e] 0.03 +[50f] 0.03 +[50g] 0.03 +[50h] 0.03 +[50i] 0.02 +[50j] 0.03 +[50j2] 0.03 +[50j3] 0.02 +[50j4] 0.05 +[50j6] 0.03 +[50k] 0.03 +[50l] 0.03 +[51] 0.03 +[5/15] 0.03 +[51a] 0.05 +[52] 0.02 [53] 0.03 -[543] 0.05 -[543b] 0.06 -[54] 1.08 -[55] 0.06 -[56] 0.07 -[57] 0.04 -[58] 0.03 -[59] 0.03 -[59a] 0.15 -[6/15] 0.03 -[60] 0.06 -[61] 0.03 -[62] 0.00 -[63] 0.66 -[64] 0.03 -[65] 0.03 -[66] 0.03 -[67] 0.03 -[68] 0.14 -[69] 32.49 -[7/15] 0.04 -[70] 0.02 -[70b] 1.06 -[70d] 0.09 -[71] 0.02 -[72] 0.03 +[54] 0.84 +[543] 0.02 +[543b] 0.02 +[55] 0.03 +[55a] 0.03 +[56] 0.05 +[57] 0.03 +[58] 0.02 +[59] 0.02 +[59a] 0.12 +[61] 0.04 +[6/15] 0.02 +[62] 0.07 +[63] 0.48 +[64] 0.02 +[65] 0.02 +[66] 0.02 +[67] 0.02 +[68] 0.13 +[69] 24.11 +[70] 0.39 +[70b] 0.15 +[70d] 0.01 +[70e1] 1.25 +[70e2] 0.07 +[70j1] 0.28 +[71] 0.04 +[7/15] 0.02 +[72] 0.02 [73] 0.03 -[74] 0.03 -[75] 0.06 -[76] 0.03 -[77] 0.14 -[78] 0.06 -[8/15] 0.03 -[80] 46.97 -[81] 8.06 -[81b] 0.67 -[81c] 0.54 -[81u] 122.67 -[82] 0.26 -[83] 0.05 -[84] 0.04 -[85] 0.46 -[86] 0.04 -[87] 0.04 -[88] 24.39 -[89] 7.02 -[8b] 0.04 -[8c] 0.05 +[74] 0.02 +[76] 0.02 +[77] 0.13 +[78] 0.02 +[80] 40.18 +[80b] 0.01 +[8/15] 0.02 +[81] 6.64 +[81b] 0.48 +[81c] 0.43 +[81u] 0.11 +[82] 0.56 +[83] 0.02 +[84] 0.03 +[85] 0.34 +[86] 0.03 +[87] 0.03 +[88] 22.90 +[89] 5.75 +[8b] 0.02 +[8c] 0.03 [8d] 0.03 -[8e] 0.04 -[8f] 0.04 -[8g] 0.04 -[8h] 0.08 -[9/15] 0.07 -[90] 0.71 -[91] 0.03 -[92] 0.04 -[93] 0.04 -[93b] 0.10 -[94] 0.41 -[95] 0.81 -[96] 0.89 -[96b] 0.21 -[97] 43.03 -[98] 0.03 -[99] 0.04 +[8e] 0.03 +[8f] 0.03 +[8g] 0.03 +[8h] 0.06 +[90] 0.49 +[91] 0.02 +[9/15] 0.05 +[92] 0.03 +[93] 0.03 +[93b] 0.06 +[94] 0.26 +[95] 0.72 +[96] 0.66 +[96b] 0.18 +[97] 57.75 +[98] 0.02 +[99] 0.03 [99a] 0.03 -[99aa] 1.53 -[99ab] 0.23 -[99b] 0.16 +[99aa] 0.97 +[99ab] 0.16 +[99ac] 0.02 +[99acb] 2.01 +[99ad] 0.72 +[99b] 0.12 [99c] 2.01 -[99d] 0.53 -[99e] 1.00 -[99f] 0.10 -[99g] 0.10 -[99h] 0.09 -[99i2] 5.10 -[99i] 0.09 -[99j] 0.15 -[99k] 0.08 -[99l] 0.01 -[99m] 0.46 -[99n] 0.02 -[99o] 0.23 -[99p] 0.01 -[99s] 4.15 -[99t] 0.05 -[99u+] 0.77 -[99u] 4.15 +[99d] 0.47 +[99e] 0.87 +[99f] 0.07 +[99g] 0.00 +[99h] 0.06 +[99i] 0.07 +[99i2] 2.79 +[99j] 0.11 +[99k] 0.06 +[99m] 0.34 +[99n] 0.01 +[99n2] 0.02 +[99o] 0.19 +[99p] 0.00 +[99s] 48.37 +[99t] 0.03 +[99u+] 0.63 +[99u] 3.12 [99w] 0.10 -[99x] 0.26 -[99y] 0.43 -[99z] 13.62 -[99za] 0.24 +[99x] 0.19 +[99y] 0.33 +[99yc] 1.04 +[99z] 9.35 +[99za] 0.17 +[99zb0] 0.05 [99zb] 0.01 -[99zc] 26.41 -[99zd] 0.89 -[Call Semantics] 0.04 -[Calls] 0.04 -[Coercion] 0.03 -[JSON Depth / DoS guard] 0.06 -[Number Formatting] 0.02 -[Observer] 0.45 -[STEM Accuracy] 0.12 +[99zc] 17.72 +[99zd] 0.10 +[99zdc] 0.11 +[99ze] 0.06 +[Calls] 0.03 +[Call Semantics] 0.03 +[Coercion] 0.02 +[JSON Depth / DoS guard] 0.04 +[loop-halting] 0.31 +[Number Formatting] 0.01 +[Observer] 0.29 [Security Hardening] 0.05 -[Structural Equality] 0.03 -[loop-halting] 0.34 -[stdlib] 9.50 +[stdlib] 7.12 +[STEM Accuracy] 0.09 +[Structural Equality] 0.02 diff --git a/tests/sections/0ff-container-slots-1665.sh b/tests/sections/0ff-container-slots-1665.sh index be1273234..78e9968f5 100644 --- a/tests/sections/0ff-container-slots-1665.sh +++ b/tests/sections/0ff-container-slots-1665.sh @@ -1,9 +1,11 @@ echo "[0ff] Container slot API (#1665 B0, slot storage B10)" TOTAL=$((TOTAL + 1)) -variant=release -if [ -e ../build/asan/eigenscript ] && [ ./eigenscript -ef ../build/asan/eigenscript ]; then - variant=asan -fi +# #1783: the variant the suite binary IS (asan or asan-server in the CI ASan +# shards), through the one predicate [0fk] shares; anything else is release. +. "$TESTS_DIR/suite_variant.sh" +variant=$(suite_binary_variant) +suite_variant_is_asan "$variant" || variant=release +echo " test binary variant: $variant" if make -s -C .. SLOT_TEST_VARIANT="$variant" container-slot-test && \ ../build/$variant/test_container_slots; then # Planted fault: a builtin result that is a numeric view must abort in diff --git a/tests/sections/0fk-phase2-slot-layer.sh b/tests/sections/0fk-phase2-slot-layer.sh index 23d015aa1..6653aaf55 100644 --- a/tests/sections/0fk-phase2-slot-layer.sh +++ b/tests/sections/0fk-phase2-slot-layer.sh @@ -4,19 +4,22 @@ # examined exactly the population tools/phase2_inventory.py derives. echo "[0fk] Phase 2 slot layer: every slot classifier against an SMI (#1758)" TOTAL=$((TOTAL + 1)) +# #1783: an ASan suite binary (asan, or asan-server in the CI shards) runs +# the slot test under ASan/UBSan; anything else runs the release flavour. +. "$TESTS_DIR/suite_variant.sh" slot_variant=release -if [ -e ../build/asan/eigenscript ] && [ ./eigenscript -ef ../build/asan/eigenscript ]; then - slot_variant=asan -fi +suite_variant_is_asan "$(suite_binary_variant)" && slot_variant=asan slot_rc=0 -bash ../tests/phase2/slot_layer.sh "$slot_variant" > /tmp/eigs-slot-layer.$$ 2>&1 || slot_rc=$? +bash ../tests/phase2/slot_layer.sh "$slot_variant" > /tmp/eigs-slot-layer.$$ 2> /tmp/eigs-slot-layer-err.$$ || slot_rc=$? slot_last=$(tail -1 /tmp/eigs-slot-layer.$$) -if [ "$slot_rc" -eq 0 ] && [ "$slot_last" = "slot-layer: PASS" ]; then +if [ "$slot_rc" -eq 0 ] && [ "$slot_last" = "slot-layer: PASS" ] && [ ! -s /tmp/eigs-slot-layer-err.$$ ]; then PASS=$((PASS + 1)) + echo " slot test variant: $slot_variant" grep '^slot-layer' /tmp/eigs-slot-layer.$$ | sed 's/^/ /' else FAIL=$((FAIL + 1)); echo " FAIL: slot layer ($slot_variant) rc=$slot_rc" sed 's/^/ | /' /tmp/eigs-slot-layer.$$ + sed 's/^/ | stderr: /' /tmp/eigs-slot-layer-err.$$ fi -rm -f /tmp/eigs-slot-layer.$$ +rm -f /tmp/eigs-slot-layer.$$ /tmp/eigs-slot-layer-err.$$ echo "" diff --git a/tests/suite_variant.sh b/tests/suite_variant.sh new file mode 100644 index 000000000..f5461427e --- /dev/null +++ b/tests/suite_variant.sh @@ -0,0 +1,32 @@ +# tests/suite_variant.sh -- which build the suite binary is (sourced; cwd is +# src/, as for every section). +# +# One predicate for the sections that build a C test against the suite +# binary's own variant ([0ff] test_container_slots, [0fk] the C slot test). +# Each used to look only for build/asan, so in the CI ASan shards, which +# build `asan-server`, both compiled their RELEASE variant: no ASan, no LSan, +# no UBSan (#1783, found by the #1758 R1.1 critic). +# +# suite_binary_variant: print the build/ whose eigenscript the suite +# binary ./eigenscript is (a hard link: the same file); print nothing when +# it is none of them. +# suite_variant_is_asan VARIANT: the Makefile builds VARIANT with +# AddressSanitizer -- asked of the build system (`make print-FLAGS_`), +# not inferred from the name. +suite_binary_variant() { + for sbv_cand in ../build/*/eigenscript; do + if [ -f "$sbv_cand" ] && [ ./eigenscript -ef "$sbv_cand" ]; then + basename "$(dirname "$sbv_cand")" + return 0 + fi + done + return 0 +} +suite_variant_is_asan() { + [ -n "$1" ] || return 1 + sva_flags=$(make -s --no-print-directory -C .. "print-FLAGS_$1" 2>/dev/null) + case "$sva_flags" in + *sanitize=address*) return 0 ;; + esac + return 1 +} diff --git a/tests/test_system.eigs b/tests/test_system.eigs index 89e8793bb..4b7b32400 100644 --- a/tests/test_system.eigs +++ b/tests/test_system.eigs @@ -10,6 +10,25 @@ ri is random_int of [5, 10] assert of [ri >= 5, "RI1 random_int >= lo"] assert of [ri <= 10, "RI2 random_int <= hi"] +# One draw sees an off-by-one in the range one time in six (#1758 R1.1 critic, +# plant D: random_int answering lo+1..hi+1 passed). 300 draws stay inside +# [5, 10] and reach both ends; missing an end by chance is about 2^-78. +ri_out is 0 +ri_lo is 0 +ri_hi is 0 +ri_k is 0 +loop while ri_k < 300: + ri_v is random_int of [5, 10] + if ri_v < 5 or ri_v > 10: + ri_out is ri_out + 1 + if ri_v == 5: + ri_lo is 1 + if ri_v == 10: + ri_hi is 1 + ri_k is ri_k + 1 +assert of [ri_out == 0, "RI5 300 draws stay in [5, 10]"] +assert of [ri_lo == 1 and ri_hi == 1, "RI6 300 draws reach both 5 and 10"] + # #725: span exactly 2^31 is the widest range lrand48 can serve — must NOT raise ri_max is random_int of [0, 2147483647] assert of [ri_max >= 0, "RI3 random_int boundary span >= lo"] From 0a4748f1a47ff357cd41bb0bfe51483a37bc04f5 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 21:48:57 -0500 Subject: [PATCH 009/188] phase2 R1.1 fix: the differential v2, the int-source tag check, checker self-tests (#1758) The corpus differential (tools/phase2_corpus_diff.sh), after the critic's plants B and D passed it: - each binary runs each file twice; a file is deterministic when the baseline's two runs agree, and then any branch run that differs is a DIFF (a branch wrong on alternate runs read NONDET before); - randomness runs live: the runtime has no seed flag or variable, so an LD_PRELOAD shim pins the clock^pid self-seed to one constant and passes small explicit seeds through (test_numerics and test_optimize are now compared live); two pinned draws must agree or the run fails; - a tape is the last resort, for files whose baseline disagrees with itself even pinned (timings, threads); each is listed as REPLAYED, since a builtin's own behaviour is invisible there; - no blanket memory cap: only gfx/ui/audio files run under ulimit -v (handles_full.eigs varied only because of the old cap); - a restricted run (the calibration's file list) prints RESTRICTED and exits 3, never PASS. The int-source check fails on TAG_SMI or the SMI bit pattern anywhere outside its value_slot.h definitions (the critic's P3 and P5), and the mechanical gates of R1.1/R1.2 add `smi-trap`: the corpus differential against a `make smi-trap` build (P4, an int made inside an allowed writer). phase2_check.py's tool() keeps a gate's stderr apart and fails on it; the hot-table and bytecode readers accept only their own shapes, and the bytecode dump is read from stderr alone; the checker runs under -W error. The calibration and the plants run when their checkers change, as tools/selftests.txt rows (docs/PRINCIPLES.md 5), never per suite or CI run: `phase2_check.py --selftest` builds v0.46.0 and four planted binaries and adds the differential's plants A, B (both phases) and D and the int-source plants P1-P5, static and dynamic; `phase2_plants.sh` adds the arm-refusal, stderr-noise, stdout-noise and #1775 return-type plants. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tools/phase2_check.py | 442 +++++++++++++++++++++++++++++------- tools/phase2_check.sh | 7 +- tools/phase2_corpus_diff.sh | 242 +++++++++++++------- tools/phase2_plants.sh | 87 ++++++- tools/selftests.txt | 4 + 5 files changed, 606 insertions(+), 176 deletions(-) diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 4c434056c..a155174ef 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -35,10 +35,15 @@ MECHANICAL ROUNDS (R1.1, R1.2, R2.1) have no rows of their own; --through one of them runs its gates instead: the token gate (every token a landed -round deleted is absent from code), the int-source check (before R1.3 no -runtime code calls slot_from_int or make_int outside the canonicalizing -writers; make_int does not exist), the C slot test, and the corpus -differential against --baseline (the binary from before the round). +round deleted is absent from code), the int-source check in two halves -- +static: before R1.3 no runtime code calls slot_from_int or make_int outside +the canonicalizing writers, make_int does not exist, and TAG_SMI or an SMI +bit pattern is spelled only at its value_slot.h homes; dynamic (--smi-trap, +R1.1/R1.2): the corpus differential against a `make smi-trap` build, on +which every slot classifier aborts at an SMI -- the C slot test, and the +corpus differential against --baseline (the binary from before the round). +A gate tool that writes to stderr fails, with its words (tool()); the +checker runs under `python3 -W error` (tools/phase2_check.sh). Exit 0 iff the population checks pass, every tier has examined == tag_fail == branch_pass > 0 (or the round is mechanical and every gate passed), @@ -61,8 +66,8 @@ ROUNDS = ['R1.1', 'R1.2', 'R1.3', 'R1.4', 'R1.5', 'R1.6', 'R1.7', 'R1.8', 'R2.1', 'R2.2', 'R2.3', 'R2.4', 'R2.5', 'R2.6', 'R3'] MECHANICAL = { - 'R1.1': ('tokens', 'int-source', 'slot-test', 'corpus-diff'), - 'R1.2': ('tokens', 'int-source', 'slot-test', 'corpus-diff'), + 'R1.1': ('tokens', 'int-source', 'slot-test', 'corpus-diff', 'smi-trap'), + 'R1.2': ('tokens', 'int-source', 'slot-test', 'corpus-diff', 'smi-trap'), 'R2.1': ('tokens', 'slot-test', 'corpus-diff'), } ITEMS = ['N%d' % i for i in range(1, 15)] + ['N4b', 'A', 'B', 'T1', 'O1', 'O2', 'O3', 'O4'] @@ -73,10 +78,22 @@ 'R1.3': ['eigs_int_unwired'], 'R2.2': ['num_guard', 'num_guard_named', 'EIGS_NUM_MAX'], } -# design 2.1: the canonicalizing writers, the only runtime callers of an int -# writer allowed before R1.3 (they convert an existing VAL_INT). -INT_SOURCE_ALLOWED = {'eigs_container_slot', 'eigs_slot_adopt', 'eigs_slot_store_owned', - 'eigs_slot_store_borrow', 'slot_from_value'} +# design 2.1: the canonicalizing writers convert an existing VAL_INT, so they +# are the only runtime callers of an int writer allowed once VAL_INT exists +# (R1.2). In R1.1 no VAL_INT exists, so no runtime code may call one at all. +INT_SOURCE_ALLOWED = { + 'R1.1': set(), + 'R1.2': {'eigs_container_slot', 'eigs_slot_adopt', 'eigs_slot_store_owned', + 'eigs_slot_store_borrow', 'slot_from_value'}, +} +# The SMI tag's own definitions, the only code that may name TAG_SMI or spell +# its bits: a producer that writes the bits itself calls no writer, so a scan +# of writer names never sees it (the R1.1 critic's P3 and P5). +SMI_TAG_HOMES = {('value_slot.h', '#define TAG_SMI'), ('value_slot.h', '#define SLOT_SMI_TRAP'), + ('value_slot.h', 'slot_is_smi'), ('value_slot.h', 'slot_from_int')} +# TAG_SMI, or a literal whose top 16 bits are the tag: 0xFFFA itself (a tag +# compare) or a 16-digit 0xFFFA............ (the full tag word). +SMI_BITS_RE = re.compile(r'\bTAG_SMI\b|\b0[xX][fF]{3}[aA](?:[0-9a-fA-F]{12})?[uUlL]*\b') WITNESS_KINDS = {'none', 'leaf', 'leaf-gen', 'fn', 'fn-stop', 'osr', 'osr-stop'} TIERS = ['off', 'default', 'osr', 'trace'] HOT_HDR = re.compile(r'^chunk\s+exec\s+jit\s+pct\s+adv\s+len\s+nat%\s+bked\s+osr\s+oadv\s+oent\s+stop$') @@ -86,6 +103,16 @@ def rindex(r): return ROUNDS.index(r) +def read_text(path, **kw): + with open(path, encoding='utf-8', **kw) as f: + return f.read() + + +def write_text(path, text): + with open(path, 'w', encoding='utf-8') as f: + f.write(text) + + # ---- the MAP --------------------------------------------------------------- ROW_LINE = re.compile(r'^- `([^`]+)` (?:\[([^\]]+)\]|\((control)\))') SHAPE_LINE = re.compile(r'^\s+shape:\s*([LFO])\s+witness:\s*(.*?)\s+ops:\s*(.*?)\s*$') @@ -103,7 +130,7 @@ def parse_witness(text): def parse_map(path): rows, bad, item = [], [], None - lines = open(path, encoding='utf-8').read().split('\n') + lines = read_text(path).split('\n') for n, line in enumerate(lines, 1): m = re.match(r'^### (\S+)\s*$', line) if m: @@ -144,7 +171,7 @@ def parse_map(path): def header(path): h = {} - for line in open(path, encoding='utf-8'): + for line in read_text(path).split('\n'): m = re.match(r'^#\s*([A-Z-]+):\s*(.*?)\s*$', line) if not m: if line.strip() and not line.startswith('#'): @@ -187,19 +214,32 @@ def run(binary, path, env_extra, scratch): 'trace': {'EIGS_TRACE': '@'}} +HOT_TITLE = re.compile(r'^=== Hot chunks \(top (\d+) of (\d+)\) ===$') + + def hot_rows(err): - lines = err.split('\n') - try: - i = next(k for k, l in enumerate(lines) if HOT_HDR.match(l.strip())) - except StopIteration: + """The EIGS_JIT_HOT table, read against its own shape: the title declares + N rows; the column header, exactly N twelve-column rows and the + `native-byte share` line follow. Anything else is an instrument failure + (None), never a shorter table.""" + lines = [l.strip() for l in err.split('\n')] + titles = [k for k, l in enumerate(lines) if HOT_TITLE.match(l)] + if len(titles) != 1: + return None + t = titles[0] + want = int(HOT_TITLE.match(lines[t]).group(1)) + if t + 3 + want >= len(lines) or not lines[t + 1].startswith('total chunk entries:') \ + or not HOT_HDR.match(lines[t + 2]): return None rows = {} - for l in lines[i + 1:]: + for l in lines[t + 3:t + 3 + want]: w = l.split() - if len(w) != 12 or not w[1].isdigit(): - break + if len(w) != 12 or not w[1].isdigit() or w[0] in rows: + return None rows[w[0]] = dict(exec=int(w[1]), jit=w[2], adv=w[4], len=int(w[5]), osr=w[8], oadv=int(w[9]), oent=int(w[10]), stop=w[11]) + if not lines[t + 3 + want].startswith('native-byte share'): + return None return rows @@ -209,16 +249,24 @@ def compiled(err): def bytecode(text, chunk): - ops, cur = {}, None + """offset -> opcode for from EIGS_DUMP_BC. The chunk's header must + occur exactly once and its offsets must start at 0 and rise; otherwise {} + (an instrument failure, which the witness reports).""" + ops, cur, headers, last = {}, None, 0, -1 for l in text.split('\n'): m = re.match(r'^=== (\S+) \((\S+?), (\d+) bytes', l) if m: cur = m.group(2) + headers += cur == chunk continue m = re.match(r'^(\d{4}) \[L\d+\] (\S+)', l) if m and cur == chunk: - ops[int(m.group(1))] = m.group(2) - return ops + off = int(m.group(1)) + if off <= last or (last < 0 and off != 0): + return {} + ops[off] = m.group(2) + last = off + return ops if headers == 1 else {} def witness(binary, path, w, scratch): @@ -265,8 +313,10 @@ def witness(binary, path, w, scratch): elif kind == 'osr': ok = ok and r['osr'] == 'yes' and r['oadv'] == r['len'] else: - _, dout, derr = run(binary, path, dict(TIER_ENV[tier], EIGS_DUMP_BC='1'), scratch) - ops = bytecode(dout + '\n' + derr, c) + # EIGS_DUMP_BC writes to stderr; the program's own stdout is + # never read as a dump line (the R1.1 critic's class) + _, _, derr = run(binary, path, dict(TIER_ENV[tier], EIGS_DUMP_BC='1'), scratch) + ops = bytecode(derr, c) if kind == 'fn-stop': at = None if r['adv'] in ('RET', '?') else int(r['adv']) ok = ok and r['jit'] == 'yes' and at is not None and ops.get(at) == op @@ -342,7 +392,7 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): for t in TIERS} ctl_n = ctl_both = witnessed = 0 for r, p, h in todo: - want = open(p.rsplit('.', 1)[0] + '.out', encoding='utf-8').read() + want = read_text(p.rsplit('.', 1)[0] + '.out') want_rc = int(h.get('EXPECT-RC', '0')) tiers = h.get('TIERS', ' '.join(TIERS)).split() is_ctl = r['kind'] == 'control' @@ -402,7 +452,7 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): # ---- mechanical gates ---------------------------------------------------------- def code_text(path): - return inv.strip_c(open(path, encoding='utf-8', errors='replace').read()) + return inv.strip_c(read_text(path, errors='replace')) def c_files(root, dirs=('src',), recurse_tests=True): @@ -431,16 +481,20 @@ def token_gate(root, through, out): return bool(files) and bool(toks) and not hits -def int_source(src, out): - """Before R1.3: runtime calls of slot_from_int / make_int only inside the - canonicalizing writers; make_int is not defined; slot_from_int is defined - exactly once.""" +def int_source(src, out, through='R1.1'): + """The static half of "no int before R1.3": no runtime call of + slot_from_int / make_int outside the round's allowed writers; make_int is + not defined; slot_from_int is defined exactly once; and nothing outside the + tag's own definitions names TAG_SMI or spells its bits. The dynamic half + is the smi-trap build (value_slot.h EIGS_SMI_TRAP).""" + allowed = INT_SOURCE_ALLOWED[through] files = sorted(os.path.join(src, f) for f in os.listdir(src) if f.endswith(('.c', '.h'))) defs = {'slot_from_int': 0, 'make_int': 0} - calls, bad = [], [] + calls, bad, tags, homes = [], [], [], set() for p in files: + rel = os.path.basename(p) text = code_text(p) - scope = inv.scopes_for(text, os.path.basename(p)) + scope = inv.scopes_for(text, rel) for ln, line in enumerate(text.split('\n'), 1): for m in re.finditer(r'\b(slot_from_int|make_int)\s*\(', line): fn = scope[ln].split('/')[0] @@ -448,37 +502,62 @@ def int_source(src, out): if fn == '' or fn == name: defs[name] += 1 # a definition or a prototype continue - calls.append((os.path.basename(p), ln, fn, name)) - if fn not in INT_SOURCE_ALLOWED: - bad.append('%s:%d: %s calls %s' % (os.path.basename(p), ln, fn, name)) + calls.append((rel, ln, fn, name)) + if fn not in allowed: + bad.append('%s:%d: %s calls %s' % (rel, ln, fn, name)) + for m in SMI_BITS_RE.finditer(line): + fn = scope[ln].split('/')[0] + if (rel, fn) in SMI_TAG_HOMES: + homes.add((rel, fn)) + continue + tags.append('%s:%d: %s spells the SMI tag (%s)' % (rel, ln, fn, m.group(0))) for b in bad: out(' INT-SOURCE %s: no int may be produced before R1.3' % b) + for t in tags: + out(' INT-SOURCE %s outside its definitions: a producer that writes the bits itself' % t) if defs['make_int']: out(' INT-SOURCE make_int is defined before R1.3') if defs['slot_from_int'] != 1: out(' INT-SOURCE slot_from_int is defined %d times, want 1 (did the scan find it?)' % defs['slot_from_int']) - out('int-source: files=%d slot_from_int_defs=%d make_int_defs=%d calls=%d outside_writers=%d' % ( - len(files), defs['slot_from_int'], defs['make_int'], len(calls), len(bad))) - return bool(files) and not bad and not defs['make_int'] and defs['slot_from_int'] == 1 - - -def tool(cmd, out, tail_re): - p = subprocess.run(cmd, cwd=ROOT, stdin=subprocess.DEVNULL, capture_output=True) - text = (p.stdout + p.stderr).decode('utf-8', 'replace') + if homes != SMI_TAG_HOMES: + out(' INT-SOURCE the tag definitions found %d of %d homes (%s missing): the scan is blind' + % (len(homes), len(SMI_TAG_HOMES), sorted(SMI_TAG_HOMES - homes))) + out('int-source: through=%s files=%d slot_from_int_defs=%d make_int_defs=%d calls=%d ' + 'outside_writers=%d tag_homes=%d/%d tag_spellings_outside=%d' % ( + through, len(files), defs['slot_from_int'], defs['make_int'], len(calls), len(bad), + len(homes), len(SMI_TAG_HOMES), len(tags))) + return (bool(files) and not bad and not tags and not defs['make_int'] + and defs['slot_from_int'] == 1 and homes == SMI_TAG_HOMES) + + +def tool(cmd, out, tail_re, env=None): + """Run a gate tool; echo the lines matching tail_re. Its verdict is its + exit code, and a tool that writes to stderr fails here with its words: + its stdout is read beside nothing else (the R1.1 critic's class).""" + p = subprocess.run(cmd, cwd=ROOT, stdin=subprocess.DEVNULL, capture_output=True, + env=dict(os.environ, **(env or {}))) + text = p.stdout.decode('utf-8', 'replace') + err = p.stderr.decode('utf-8', 'replace') for l in text.split('\n'): if re.match(tail_re, l): out(' ' + l) - return p.returncode == 0, text + for l in err.split('\n'): + if l: + out(' STDERR %s: %s' % (os.path.basename(cmd[1]), l)) + return p.returncode == 0 and not err, text + +DIFF_TAIL = r'^(corpus-diff: (seed pin|baseline|branch|examined|RESTRICTED|PASS|FAIL)|DIFF|DELETED|NEW|NONDET|REPLAYED|BOTH-|CAPPED)' -def mechanical(through, baseline, branch, out): + +def mechanical(through, baseline, branch, out, smi_trap=None): res = {} for g in MECHANICAL[through]: if g == 'tokens': res[g] = token_gate(ROOT, through, out) elif g == 'int-source': - res[g] = int_source(os.path.join(ROOT, 'src'), out) + res[g] = int_source(os.path.join(ROOT, 'src'), out, through) elif g == 'slot-test': res[g], _ = tool(['bash', 'tests/phase2/slot_layer.sh', 'release'], out, r'^(slot-layer|slot-layer-population|slot-layer-test: (examined|FAIL))') @@ -487,8 +566,15 @@ def mechanical(through, baseline, branch, out): out(' corpus-diff: a mechanical round needs --baseline ') res[g] = False else: - res[g], _ = tool(['bash', 'tools/phase2_corpus_diff.sh', baseline, branch], out, - r'^(corpus-diff: (baseline|branch|examined|PASS|FAIL)|DIFF|DELETED|NEW|NONDET|BOTH-)') + res[g], _ = tool(['bash', 'tools/phase2_corpus_diff.sh', baseline, branch], out, DIFF_TAIL) + elif g == 'smi-trap': + # the dynamic half of the int-source check: the corpus on a build + # where every slot classifier aborts on an SMI (make smi-trap) + if not baseline or not smi_trap: + out(' smi-trap: %s needs --baseline and --smi-trap ' % through) + res[g] = False + else: + res[g], _ = tool(['bash', 'tools/phase2_corpus_diff.sh', baseline, smi_trap], out, DIFF_TAIL) out('mechanical %s: %s' % (g, 'PASS' if res[g] else 'FAIL')) return all(res.values()) and bool(res) @@ -498,8 +584,7 @@ def plan_checks(map_rows, bad, out): for item in ITEMS: if not any(r['item'] == item for r in map_rows if r['kind'] != 'control'): bad.append('item %s has no row in the MAP' % item) - arms, lines, inside = {}, open(os.path.join(ROOT, 'docs/design/phase2-inventory.txt')).read( - ).split('\n'), False + arms, lines, inside = {}, read_text(os.path.join(ROOT, 'docs/design/phase2-inventory.txt')).split('\n'), False for l in lines: if l.startswith('## Numeric arms'): inside = True @@ -552,7 +637,7 @@ def main_check(args, out): map_rows, args.rows, args.controls, args.tag, args.branch, args.through, scratch, out) mech_ok = None if args.through in MECHANICAL: - mech_ok = mechanical(args.through, args.baseline, args.branch, out) + mech_ok = mechanical(args.through, args.baseline, args.branch, out, args.smi_trap) if landed == 0: if mech_ok is None: out(' ZERO-ROWS: %s has no landed row and no mechanical gates' % args.through) @@ -650,12 +735,12 @@ def stray(rd): case('a round with neither rows nor gates fails', any('round R2.3' in b for b in pb), True) # the int-source check against a planted production call with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: - shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src')) + shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src'), ignore=c_sources_only) p = os.path.join(d, 'src', 'trace.c') - text = open(p).read() + text = read_text(p) anchor = ' *out = slot_from_f64((double)count);' n_anchor = text.count(anchor) - open(p, 'w').write(text.replace(anchor, ' *out = slot_from_int(count);')) + write_text(p, text.replace(anchor, ' *out = slot_from_int(count);')) lines = [] ok = int_source(os.path.join(d, 'src'), lines.append) case('int-source plant (slot_from_int(count) in trace.c) applied once', n_anchor, 1) @@ -675,8 +760,76 @@ def stray(rd): lines = [] case('token plant (slot_is_num reintroduced): the gate fails', (token_gate(d, 'R1.1', lines.append), any('slot_is_num' in l for l in lines)), (False, True)) + # the int-source plants of the R1.1 critic, both halves + for name, edits in INTSRC_PLANTS: + with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: + shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src'), ignore=c_sources_only) + counts = [] + for f, old, new in edits: + p = os.path.join(d, 'src', f) + text = read_text(p) + counts.append(text.count(old)) + write_text(p, text.replace(old, new)) + if counts != [1] * len(edits): + case('%s: every edit applied once' % name, counts, [1] * len(edits)) + continue + for through in ('R1.1', 'R1.2'): + lines = [] + ok = int_source(os.path.join(d, 'src'), lines.append, through) + want = not (name.startswith('P4') and through == 'R1.2') # R1.2 allows that writer + case('%s, static half at %s: %s' % (name, through, 'fails, naming it' if want + else 'passes (the dynamic half owns it)'), + (not ok, any('INT-SOURCE' in l for l in lines)) if want else ok, + (True, True) if want else True) + # the corpus differential's plants: A and B are wrapper branches, D a build + base = args.branch + files = ['tests/test_dispatch.eigs', 'tests/test_bool.eigs'] + with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: + a = wrapper_tree(os.path.join(d, 'A'), args.branch, files, + 'case "$*" in *test_dispatch.eigs*) "$REAL" "$@"; rc=$?; echo "PLANTED A"; exit $rc ;; esac\n' + 'exec "$REAL" "$@"') + rc, text, v = diff_restricted(base, a, files) + case('differential plant A (a deterministic file prints one more line): DIFF, control same', + (rc, v.get('tests/test_dispatch.eigs'), v.get('tests/test_bool.eigs'), v.get('')), + (3, 'DIFF', 'same', None)) + for phase in (0, 1): + bdir = os.path.join(d, 'B%d' % phase) + bw = wrapper_tree(bdir, args.branch, files, + 'case "$*" in *test_dispatch.eigs*) if [ $(((N + %d) %% 2)) -eq 0 ]; then\n' + ' "$REAL" "$@"; rc=$?; echo "PLANTED B"; exit $rc; fi ;; esac\nexec "$REAL" "$@"' % phase) + rc, text, v = diff_restricted(base, bw, files) + case('differential plant B, phase %d (wrong on alternate runs): DIFF, never NONDET' % phase, + (rc, v.get('tests/test_dispatch.eigs'), v.get('tests/test_bool.eigs'), v.get('')), + (3, 'DIFF', 'same', None)) if args.build_plants: - args.planted_leaf_scan, args.planted_leaf_mul = build_leaf_plants(out) + args.planted_leaf_scan = build_plant('leaf-scan', out) + args.planted_leaf_mul = build_plant('leaf-mul', out) + args.planted_random_int = build_plant('random-int', out) + args.planted_p4_trap = build_plant('p4-trap', out) + if args.planted_random_int: + # test_system.eigs asserts random_int's bounds over 300 draws, so it + # sees the plant whatever the seed; test_optimize.eigs prints a search + # driven by random_int and is comparable live only because the seed + # is pinned (unpinned, its baseline disagrees with itself and a tape + # would serve the baseline's draws): this case calibrates the pin. + files = ['tests/test_system.eigs', 'tests/test_optimize.eigs', 'tests/test_bool.eigs'] + rc, text, v = diff_restricted(base, args.planted_random_int, files) + case('differential plant D (random_int answers lo+1..hi+1): both files DIFF live', + (rc,) + tuple(v.get(f) for f in files) + (v.get(''),), (3, 'DIFF', 'DIFF', 'same', None)) + else: + out('CAL %-58s NOT RUN (no --planted-random-int binary; --build-plants builds it)' % 'plant D') + results.append(False) + if args.planted_p4_trap: + # both files bind 1 through slot_from_value (loop_iter_store -> + # env_set_local_hashed), where P4 makes an int + files = ['tests/test_bool.eigs', 'tests/test_system.eigs'] + rc, text, v = diff_restricted(base, args.planted_p4_trap, files) + case('P4 on the smi-trap build (the dynamic half): each file DIFF, aborting at the int', + (rc,) + tuple(v.get(f) for f in files) + (v.get(''), 'slot_from_int under EIGS_SMI_TRAP' in text), + (3, 'DIFF', 'DIFF', None, True)) + else: + out('CAL %-58s NOT RUN (no --planted-p4-trap binary; --build-plants builds it)' % 'P4 dynamic') + results.append(False) for label, flag, b in (('leaf-scanner-early-return', '--planted-leaf-scan', args.planted_leaf_scan), ('leaf-mul-plus-one', '--planted-leaf-mul', args.planted_leaf_mul)): if not b: @@ -696,55 +849,178 @@ def stray(rd): return 0 if results and n_ok == len(results) else 1 -LEAF_PLANTS = ( - # (file, original, planted): the two scratch builds of design 9.2 - ('src/chunk.c', ' c->leaf_accessor = 0;\n if (c->param_count > LEAF_ACCESSOR_MAX_DEPTH) return;', - ' c->leaf_accessor = 0;\n return; /* PLANT: the leaf scanner never admits a chunk */\n' - ' if (c->param_count > LEAF_ACCESSOR_MAX_DEPTH) return;'), - ('src/vm.c', ' r = a * b;\n', ' r = a * b + 1; /* PLANT */\n'), -) +# The calibration's planted builds: (file, original, planted, make target). +# Each is `git archive HEAD` into a scratch tree, one exact-once replacement, +# plain make; the binary is that tree's src/eigenscript. +BUILD_PLANTS = { + # design 9.2: a leaf scanner that never admits a chunk; a leaf MUL that adds 1 + 'leaf-scan': ('src/chunk.c', ' c->leaf_accessor = 0;\n if (c->param_count > LEAF_ACCESSOR_MAX_DEPTH) return;', + ' c->leaf_accessor = 0;\n return; /* PLANT: the leaf scanner never admits a chunk */\n' + ' if (c->param_count > LEAF_ACCESSOR_MAX_DEPTH) return;', 'build'), + 'leaf-mul': ('src/vm.c', ' r = a * b;\n', ' r = a * b + 1; /* PLANT */\n', 'build'), + # the R1.1 critic's plant D: random_int answers lo+1..hi+1 + 'random-int': ('src/builtins.c', 'make_num(lo_i + (eigs_random_long() % (int64_t)span))', + 'make_num(lo_i + 1 + (eigs_random_long() % (int64_t)span))', 'build'), + # the critic's P4 (an int produced inside an allowed writer) on the smi-trap build + 'p4-trap': ('src/eigenscript.c', ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', + ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n' + ' if (n == 1.0) return slot_from_int(1); /* PLANT P4 */\n return slot_from_f64(n);', + 'smi-trap'), +} _PLANT_DIR = [] -def build_leaf_plants(out): - """git archive HEAD twice into scratch trees (no .git), apply one plant to - each (exactly once before, present after), build each with plain make.""" - paths = [] - for f, old, new in LEAF_PLANTS: - d = tempfile.mkdtemp(prefix='eigs-p2leaf-') +def build_plant(name, out): + f, old, new, target = BUILD_PLANTS[name] + d = tempfile.mkdtemp(prefix='eigs-p2plant-') + _PLANT_DIR.append(d) + subprocess.run('git -C %s archive HEAD | tar -x -C %s' % (ROOT, d), shell=True, check=True) + p = os.path.join(d, f) + text = read_text(p) + if text.count(old) != 1: + out(' PLANT %s: the original occurs %d times in %s, want 1 (BROKEN)' % (name, text.count(old), f)) + return None + write_text(p, text.replace(old, new)) + r = subprocess.run(['make', target], cwd=d, capture_output=True) + b = os.path.join(d, 'src', 'eigenscript') + ok = r.returncode == 0 and os.access(b, os.X_OK) + out(' PLANT %s built in %s (make %s): %s' % (name, d, target, + 'ok' if ok else 'BROKEN (make rc=%d)' % r.returncode)) + return b if ok else None + + +# The R1.1 critic's int-source plants (/tmp/phase2-r11-critic/intsrc), as +# exact-once replacements in a copy of src/: (name, [(file, old, new), ...]). +_NUM_ONE = ' CASE(NUM_ONE): {\n vm_push_slot(slot_from_f64(1.0));' +INTSRC_PLANTS = [ + ('P1 a call in builtins.c', [('builtins.c', 'Value* builtin_len(Value *arg) {', + 'static EigsSlot p1_smi(int64_t n) { return slot_from_int(n); }\nValue* builtin_len(Value *arg) {')]), + ('P2 a header macro that calls the writer', [ + ('value_slot.h', '/* Constructors */', '/* Constructors */\n#define SLOT_SMI_OF(i) slot_from_int(i)'), + ('vm.c', _NUM_ONE, ' CASE(NUM_ONE): {\n vm_push_slot(SLOT_SMI_OF(1));')]), + ('P3 raw TAG_SMI bits in vm.c', [ + ('vm.c', _NUM_ONE, ' CASE(NUM_ONE): {\n { EigsSlot one; one.u = TAG_SMI | 1u; vm_push_slot(one); }')]), + ('P4 a producer inside an allowed writer', [ + ('eigenscript.c', ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', + ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n if (n == 1.0) return slot_from_int(1);\n' + ' return slot_from_f64(n);')]), + ('P5 a raw-bits header macro', [ + ('value_slot.h', '/* Constructors */', '/* Constructors */\n' + '#define SLOT_SMI_BITS(i) ((EigsSlot){ .u = TAG_SMI | ((uint64_t)(i) & SLOT_PAYLOAD_MASK) })'), + ('vm.c', _NUM_ONE, ' CASE(NUM_ONE): {\n vm_push_slot(SLOT_SMI_BITS(1));')]), +] + + +def c_sources_only(d, names): + """copytree ignore: keep directories and C sources (the int-source check + reads nothing else), skip binaries and objects.""" + return [n for n in names if not n.endswith(('.c', '.h')) and not os.path.isdir(os.path.join(d, n))] + + +def diff_restricted(base, branch, files): + """The corpus differential over a restricted list (calibration only): + (rc, stdout, {file: 'DIFF'|'same'|...}). Anything on its stderr is shown + and recorded as the verdict '' (the tool never writes there).""" + with tempfile.TemporaryDirectory(prefix='eigs-p2diff-') as d: + lst = os.path.join(d, 'files') + write_text(lst, '\n'.join(files) + '\n') + p = subprocess.run(['bash', os.path.join(ROOT, 'tools/phase2_corpus_diff.sh'), base, branch], + cwd=ROOT, stdin=subprocess.DEVNULL, capture_output=True, + env=dict(os.environ, PHASE2_DIFF_FILES=lst)) + text = p.stdout.decode('utf-8', 'replace') + err = p.stderr.decode('utf-8', 'replace') + verdicts = {} + for l in text.split('\n'): + m = re.match(r'^\.\. \d+/\d+ (\S+) (\S+) ', l) + if m: + verdicts[m.group(1)] = m.group(2) + if err: + for l in err.split('\n'): + print(' STDERR phase2_corpus_diff.sh: ' + l, flush=True) + verdicts[''] = 'present' + return p.returncode, text, verdicts + + +def wrapper_tree(d, real, files, script): + """A fake branch tree: src/eigenscript runs `script` (bash, $REAL is the + real binary, $N the per-tree invocation count), tests/ holds the files.""" + os.makedirs(os.path.join(d, 'src')) + for f in files: + os.makedirs(os.path.join(d, os.path.dirname(f)), exist_ok=True) + shutil.copy(os.path.join(ROOT, f), os.path.join(d, f)) + w = os.path.join(d, 'src', 'eigenscript') + write_text(w, '#!/usr/bin/env bash\nREAL=%s\nSTATE=%s\nN=$(cat "$STATE" 2>/dev/null || echo 0)\n' + 'echo $((N + 1)) > "$STATE"\n%s\n' % (real, os.path.join(d, 'n'), script)) + os.chmod(w, 0o755) + return w + + +TAG = 'v0.46.0' + + +def selftest(out): + """--selftest, a tools/selftests.txt row: the calibration runs when the + checker changes (docs/PRINCIPLES.md 5), never on every run. The branch + binary is this tree's src/eigenscript (the self-test job builds it first); + the tag binary is $PHASE2_TAG_BIN, else a build of v0.46.0 from `git + archive`; the planted binaries are built from HEAD. Plain make, one build + at a time.""" + branch = os.path.join(ROOT, 'src', 'eigenscript') + if not os.access(branch, os.X_OK): + out('phase2-check: FAIL: --selftest needs a built %s (run make first)' % branch) + return 2 + tag = os.environ.get('PHASE2_TAG_BIN') + if not tag: + if subprocess.run(['git', '-C', ROOT, 'rev-parse', '-q', '--verify', TAG + '^{commit}'], + capture_output=True).returncode != 0: + out('phase2-check: FAIL: --selftest needs the tag %s in this clone (git fetch --tags)' % TAG) + return 2 + d = tempfile.mkdtemp(prefix='eigs-p2tag-') _PLANT_DIR.append(d) - subprocess.run('git -C %s archive HEAD | tar -x -C %s' % (ROOT, d), shell=True, check=True) - p = os.path.join(d, f) - text = open(p).read() - if text.count(old) != 1: - out(' PLANT %s: the original occurs %d times, want 1 (BROKEN)' % (f, text.count(old))) - paths.append(None) - continue - open(p, 'w').write(text.replace(old, new)) + subprocess.run('git -C %s archive %s | tar -x -C %s' % (ROOT, TAG, d), shell=True, check=True) r = subprocess.run(['make'], cwd=d, capture_output=True) - b = os.path.join(d, 'src', 'eigenscript') - ok = r.returncode == 0 and os.access(b, os.X_OK) - out(' PLANT %s built in %s: %s' % (f, d, 'ok' if ok else 'BROKEN (make rc=%d)' % r.returncode)) - paths.append(b if ok else None) - return paths + tag = os.path.join(d, 'src', 'eigenscript') + if r.returncode != 0 or not os.access(tag, os.X_OK): + out('phase2-check: FAIL: the %s build failed (make rc=%d)' % (TAG, r.returncode)) + return 2 + out(' TAG %s built in %s' % (TAG, d)) + args = argparse.Namespace(tag=os.path.abspath(tag), branch=branch, build_plants=True, + planted_leaf_scan=None, planted_leaf_mul=None, + planted_random_int=None, planted_p4_trap=None) + return calibrate(args, out) def main(): + if sys.argv[1:] == ['--selftest']: + try: + return selftest(lambda s: print(s, flush=True)) + finally: + for d in _PLANT_DIR: + shutil.rmtree(d, ignore_errors=True) ap = argparse.ArgumentParser(prog='tools/phase2_check.sh') + ap.add_argument('--selftest', action='store_true', + help='the calibration with every plant built (alone: a tools/selftests.txt row)') ap.add_argument('tag', help='the v0.46.0 tag binary') ap.add_argument('branch', help='the branch binary') ap.add_argument('--through', default=ROUNDS[-1], choices=ROUNDS) ap.add_argument('--baseline', help='the binary from before a mechanical round (corpus differential)') + ap.add_argument('--smi-trap', help='R1.1/R1.2: a `make smi-trap` build of the branch (in its own tree)') ap.add_argument('--map', default=os.path.join(ROOT, 'tests/phase2/MAP.md')) ap.add_argument('--rows', default=os.path.join(ROOT, 'tests/phase2/rows')) ap.add_argument('--controls', default=os.path.join(ROOT, 'tests/phase2/controls')) ap.add_argument('--calibrate', action='store_true') ap.add_argument('--planted-leaf-scan', help='calibration: a build whose leaf scanner returns early') ap.add_argument('--planted-leaf-mul', help='calibration: a build whose leaf MUL computes a*b+1') + ap.add_argument('--planted-random-int', help='calibration: a build whose random_int answers lo+1..hi+1') + ap.add_argument('--planted-p4-trap', help='calibration: a smi-trap build with the P4 producer planted') ap.add_argument('--build-plants', action='store_true', - help='calibration: build both planted binaries from HEAD (two release builds)') + help='calibration: build the four planted binaries from HEAD') args = ap.parse_args() - for b in (args.tag, args.branch, args.baseline, args.planted_leaf_scan, args.planted_leaf_mul): + if args.selftest: + print('phase2-check: FAIL: --selftest takes no other argument') + return 2 + for b in (args.tag, args.branch, args.baseline, args.smi_trap, args.planted_leaf_scan, + args.planted_leaf_mul, args.planted_random_int, args.planted_p4_trap): if b and not os.access(b, os.X_OK): print('phase2-check: FAIL: %s is not an executable' % b) return 2 diff --git a/tools/phase2_check.sh b/tools/phase2_check.sh index ade46f62e..54bd8005c 100755 --- a/tools/phase2_check.sh +++ b/tools/phase2_check.sh @@ -1,8 +1,11 @@ #!/usr/bin/env bash -# tools/phase2_check.sh [--through Rk] [--baseline BIN] [--calibrate] +# tools/phase2_check.sh [--through Rk] [--baseline BIN] [--smi-trap BIN] [--calibrate] # #1758 Phase 2's row checker (docs/design/phase2-numbers.md 9.2): the MAP's # landed rows on the v0.46.0 tag and the branch in four tiers, their tier # witnesses, and a mechanical round's gates. The work is in # tools/phase2_check.py, whose docstring is the reference. +# -W error: a Python warning (a DeprecationWarning on a newer Python, an +# unclosed file) is a FAIL here, never a line inside a parsed output (the +# R1.1 critic: Python 3.13's warning was read as two classifiers). command -v python3 >/dev/null 2>&1 || { echo "phase2-check: FAIL: python3 is required"; exit 2; } -exec python3 "$(dirname "$0")/phase2_check.py" "$@" +exec python3 -W error "$(dirname "$0")/phase2_check.py" "$@" diff --git a/tools/phase2_corpus_diff.sh b/tools/phase2_corpus_diff.sh index 97857e00d..eafe56004 100755 --- a/tools/phase2_corpus_diff.sh +++ b/tools/phase2_corpus_diff.sh @@ -3,37 +3,61 @@ # behaviour differential of a mechanical round (docs/design/phase2-numbers.md # 8, R1.1 and R1.2): "unchanged" is measured, not inferred from a green suite. # -# Every .eigs file under the BRANCH tree's tests/ runs once with each binary, -# both from the branch tree's src/ (the suite's cwd) as `../tests/`, so -# a file and everything it loads by a relative path are the same bytes for -# both; only the binary and the stdlib next to it differ. stdin /dev/null, -# a 60 s bound, under -# `env -u XAUTHORITY DISPLAY=:99` and a 2 GiB address-space limit. stdout, -# stderr and the exit code must all be byte-identical after one -# normalisation: each tree's absolute root is replaced by ``, so a test -# that prints its own path compares equal. +# Every .eigs file under the BRANCH tree's tests/ runs twice with each binary, +# all four runs from the branch tree's src/ (the suite's cwd) as +# `../tests/`, so a file and whatever it loads by a relative path are the +# same bytes for both; only the binary and the stdlib next to it differ. +# stdin /dev/null, a 60 s bound, `env -u XAUTHORITY DISPLAY=:99`. stdout, +# stderr and the exit code are compared byte for byte after one +# normalisation: each tree's absolute root becomes ``. # -# A file whose outputs differ is re-run: the baseline a second time (if it -# disagrees with itself the file is NONDET -- timing, randomness, scheduling), -# then the branch a second time (if it now agrees, the branch side is NONDET -# too). Only a difference that both re-runs keep is a DIFF row. -# A NONDET file is then adjudicated on a tape (docs/TRACE.md: a tape recorded -# by one binary replays on another): the baseline records it once, and the -# baseline replays it twice and the branch once. Two baseline replays that -# agree make the tape an oracle; the branch's replay must then match it -# (`same-under-replay`) or it is a DIFF. Replays that disagree with each -# other (threads, subprocesses: the documented boundary) stay NONDET. -# A crash or timeout both binaries agree on is named in its own counter, -# never silently "same". +# THE SEED PIN. The runtime has no seed flag or variable: an unseeded program +# seeds itself from CLOCK_MONOTONIC ^ getpid() (src/builtins.c, +# random_seed_once). An LD_PRELOAD shim, built here, pins every srand48 seed +# of 2^20 or more (the self-seed's range) to one constant and passes smaller +# ones (an explicit `seed_random of 99`) through. So a program that draws +# random numbers runs deterministically and LIVE in both binaries, and a +# branch change to a random builtin shows wherever the corpus observes it +# (test_optimize.eigs prints a genetic search driven by random_int; +# test_system.eigs checks random_int's bounds over 300 draws). The run checks +# its precondition first: two pinned `random` draws must agree, else the shim +# did not load and the run fails. That the pin is what makes such a file +# comparable live is calibrated once (phase2_check.py --selftest, plant D), +# not re-proven here. Blind spot: an explicit seed of 2^20 or more is pinned +# too, so a branch change in how `seed_random` uses such a seed is invisible. # -# A file only the branch tree has (a new fixture) is counted as `new`; a -# file only the baseline tree has is a DELETED row, a failure: a deleted test -# would hide a behaviour change. -# Prints `.. / s` per file as it goes, a -# DIFF/DELETED row per failure, the NONDET and crash lists, and -# `corpus-diff: examined=N same=S same_under_replay=R nondet=K diff=D new=W -# deleted=X crash_both=C timeout_both=T`. Exit 0 only for diff=0 deleted=0 -# and examined equal to the number of files listed (> 0). +# VERDICTS. A file is DETERMINISTIC when the baseline's two runs agree; then +# any branch run that disagrees is a DIFF row (no second chance: a branch +# that is wrong on alternate runs is wrong). When the baseline disagrees with +# itself even with the seed pin (timing, thread scheduling) the file is +# adjudicated on a TAPE, the last resort (docs/TRACE.md: a tape recorded by +# one binary replays on another): the baseline records it and replays it +# twice, the branch replays it once, and the branch must match +# (`same_under_replay`) or it is a DIFF. Replay serves the baseline's +# recorded nondeterministic values, so a builtin's own behaviour is +# INVISIBLE on those files; the report lists them. Replays that disagree +# with each other (the documented thread/subprocess boundary) are NONDET. +# A crash or timeout both binaries agree on is counted by name, never "same". +# +# MEMORY. No blanket cap (a 2 GiB `ulimit -v` made handles_full.eigs's 300 +# spawns fail at 134-214, which read as nondeterminism -- the R1.1 critic). +# Only a file that drives the gfx/ui/audio surface runs under +# `ulimit -v 2097152` (an unbounded GUI run can freeze the 4 GB box); the +# capped files are listed. +# +# A file only the branch tree has (a new fixture) is counted as `new`; a file +# only the baseline tree has is a DELETED row (a deleted test hides a change). +# Prints `.. / s` per file, DIFF/DELETED rows, the +# replay, NONDET, crash and cap lists, then `corpus-diff: examined=N same=S +# same_under_replay=R nondet=K diff=D new=W deleted=X crash_both=C +# timeout_both=T capped=M` and `corpus-diff: PASS|FAIL`. Exit 0 only for +# diff=0 deleted=0, examined equal to the files listed (> 0), and a seed pin +# that proved itself. +# +# PHASE2_DIFF_FILES= restricts the corpus to the listed relative +# paths, for the calibration (tools/phase2_check.sh --calibrate). A restricted +# run prints `corpus-diff: RESTRICTED ...` instead of a verdict and exits 3: +# it can never pass for the whole corpus. set -u [ $# -eq 2 ] || { echo "usage: tools/phase2_corpus_diff.sh "; exit 2; } abspath() { (cd "$(dirname "$1")" && printf '%s/%s\n' "$(pwd -P)" "$(basename "$1")"); } @@ -43,26 +67,67 @@ BASE_ROOT=$(cd "$(dirname "$BASE_BIN")/.." && pwd -P) BR_ROOT=$(cd "$(dirname "$BR_BIN")/.." && pwd -P) for b in "$BASE_BIN" "$BR_BIN"; do [ -x "$b" ] || { echo "corpus-diff: FAIL: $b is not executable"; exit 2; }; done command -v timeout >/dev/null 2>&1 || { echo "corpus-diff: FAIL: needs coreutils timeout (local tool)"; exit 2; } +command -v cc >/dev/null 2>&1 || { echo "corpus-diff: FAIL: needs a C compiler for the seed pin"; exit 2; } TMP=$(mktemp -d "${TMPDIR:-/tmp}/eigs-corpus-diff.XXXXXX") || exit 2 DONE=0 trap 'rc=$?; [ "$DONE" = 1 ] || echo "corpus-diff: FAIL: exited ($rc) before a verdict, at: $BASH_COMMAND"; rm -rf "$TMP"' EXIT -(cd "$BR_ROOT" && find tests -name '*.eigs' -type f | LC_ALL=C sort) > "$TMP/files" +# ---- the seed pin -------------------------------------------------------- +cat > "$TMP/seedpin.c" <<'CSRC' +#define _GNU_SOURCE +#include +/* phase2_corpus_diff.sh: pin the runtime's clock^pid self-seed (>= 2^20) to + * a constant; an explicit small seed passes through. */ +void srand48(long seed) { + static void (*real)(long); + if (!real) real = (void (*)(long))dlsym(RTLD_NEXT, "srand48"); + real((seed >= (1L << 20) || seed < 0) ? 0x5EEDL : seed); +} +CSRC +WERROR_FLAGS_FILE="$(dirname "$0")/werror_flags.txt" +. "$(dirname "$0")/read_werror_flags.sh" 2>&1 || exit 2 +# shellcheck disable=SC2086 # the shared flags are one word each +if ! cc $WERROR_FLAGS -shared -fPIC -O2 -o "$TMP/seedpin.so" "$TMP/seedpin.c" -ldl > "$TMP/seedpin.log" 2>&1; then + sed 's/^/ seedpin cc: /' "$TMP/seedpin.log" + echo "corpus-diff: FAIL: the seed pin did not build"; DONE=1; exit 1 +fi +SHIM="$TMP/seedpin.so" +printf 'print of (random of null)\n' > "$TMP/seedprobe.eigs" +# Each probe answers one number on stdout and nothing on stderr; anything +# else is shown and fails (the probe's grammar, not a substring of it). +p1=$(cd "$TMP" && LD_PRELOAD="$SHIM" "$BR_BIN" seedprobe.eigs 2> "$TMP/probe1.err" < /dev/null) +p2=$(cd "$TMP" && LD_PRELOAD="$SHIM" "$BR_BIN" seedprobe.eigs 2> "$TMP/probe2.err" < /dev/null) +echo "corpus-diff: seed pin: two pinned draws $p1 / $p2" +sed 's/^/ seed probe stderr: /' "$TMP/probe1.err" "$TMP/probe2.err" +if [ -s "$TMP/probe1.err" ] || [ -s "$TMP/probe2.err" ] || ! grep -Eqx '[0-9]+([.][0-9]+)?(e-[0-9]+)?' <<< "$p1" \ + || [ "$p1" != "$p2" ]; then + echo "corpus-diff: FAIL: the seed pin did not take (two pinned draws must print one equal number, no stderr)" + DONE=1; exit 1 +fi + +# ---- the population ------------------------------------------------------ +if [ -n "${PHASE2_DIFF_FILES:-}" ]; then + LC_ALL=C sort "$PHASE2_DIFF_FILES" > "$TMP/files" + while IFS= read -r rel; do + [ -f "$BR_ROOT/$rel" ] || { echo "corpus-diff: FAIL: restricted list names $rel, absent from the branch tree"; DONE=1; exit 1; } + done < "$TMP/files" +else + (cd "$BR_ROOT" && find tests -name '*.eigs' -type f | LC_ALL=C sort) > "$TMP/files" +fi listed=$(grep -c . "$TMP/files") -[ "$listed" -gt 0 ] || { echo "corpus-diff: FAIL: no .eigs file under $BR_ROOT/tests"; exit 1; } +[ "$listed" -gt 0 ] || { echo "corpus-diff: FAIL: no .eigs file to run"; DONE=1; exit 1; } echo "corpus-diff: baseline $BASE_BIN ($("$BASE_BIN" --version 2>&1 | head -1)) sha256 $(sha256sum "$BASE_BIN" | cut -c1-16)" echo "corpus-diff: branch $BR_BIN ($("$BR_BIN" --version 2>&1 | head -1)) sha256 $(sha256sum "$BR_BIN" | cut -c1-16)" -echo "corpus-diff: files=$listed" +echo "corpus-diff: files=$listed${PHASE2_DIFF_FILES:+ (RESTRICTED by PHASE2_DIFF_FILES)}" -# run BIN ROOT REL OUT [VAR=value] -> OUT.out OUT.err OUT.rc (ROOT is the -# binary's own tree, which only its stdlib comes from), root paths -# normalised +# run BIN REL OUT CAP [VAR=value] -> OUT.out OUT.err OUT.rc, root paths +# normalised; CAP=1 runs under the GUI memory cap. run() { - local bin="$1" root="$2" rel="$3" out="$4" extra="${5:-PHASE2_DIFF=1}" rc + local bin="$1" rel="$2" out="$3" cap="$4" extra="${5:-PHASE2_DIFF=1}" rc ( cd "$BR_ROOT/src" || exit 99 - ulimit -v 2097152 - exec env -u XAUTHORITY DISPLAY=:99 "$extra" timeout 60 "$bin" "../$rel" + [ "$cap" = 1 ] && ulimit -v 2097152 + exec env -u XAUTHORITY DISPLAY=:99 LD_PRELOAD="$SHIM" "$extra" timeout 60 "$bin" "../$rel" ) < /dev/null > "$out.rawout" 2> "$out.rawerr" rc=$? echo "$rc" > "$out.rc" @@ -70,76 +135,89 @@ run() { sed "s|$BASE_ROOT||g; s|$BR_ROOT||g" "$out.rawerr" > "$out.err" } same() { cmp -s "$1.out" "$2.out" && cmp -s "$1.err" "$2.err" && cmp -s "$1.rc" "$2.rc"; } +show_diff() { + diff "$1.out" "$2.out" | head -8 | sed 's/^/ stdout: /' + diff "$1.err" "$2.err" | head -8 | sed 's/^/ stderr: /' +} -examined=0; nsame=0; nreplay=0; nondet=0; ndiff=0; new=0; crash_both=0; timeout_both=0 -: > "$TMP/new" +examined=0; nsame=0; nreplay=0; nondet=0; ndiff=0; new=0; crash_both=0; timeout_both=0; capped=0 +: > "$TMP/new"; : > "$TMP/nondet"; : > "$TMP/crash"; : > "$TMP/replayed"; : > "$TMP/capped" (cd "$BASE_ROOT" && find tests -name '*.eigs' -type f | LC_ALL=C sort) > "$TMP/basefiles" -LC_ALL=C comm -23 "$TMP/basefiles" "$TMP/files" > "$TMP/deleted" +if [ -n "${PHASE2_DIFF_FILES:-}" ]; then + : > "$TMP/deleted" +else + LC_ALL=C comm -23 "$TMP/basefiles" "$TMP/files" > "$TMP/deleted" +fi deleted=$(grep -c . "$TMP/deleted") sed 's/^/DELETED (in the baseline tree, not the branch): /' "$TMP/deleted" -# replay_adjudicate REL: 0 same under replay, 1 a DIFF, 2 still NONDET +# replay_adjudicate REL CAP: 0 same under replay, 1 a DIFF, 2 still NONDET replay_adjudicate() { - local rel="$1" rm -f "$TMP/tape" - run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/t0" "EIGS_TRACE=$TMP/tape" + run "$BASE_BIN" "$1" "$TMP/t0" "$2" "EIGS_TRACE=$TMP/tape" [ -s "$TMP/tape" ] || return 2 - run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/p1" "EIGS_REPLAY=$TMP/tape" - run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/p2" "EIGS_REPLAY=$TMP/tape" + run "$BASE_BIN" "$1" "$TMP/p1" "$2" "EIGS_REPLAY=$TMP/tape" + run "$BASE_BIN" "$1" "$TMP/p2" "$2" "EIGS_REPLAY=$TMP/tape" same "$TMP/p1" "$TMP/p2" || return 2 [ "$(cat "$TMP/p1.rc")" -lt 124 ] || return 2 - run "$BR_BIN" "$BR_ROOT" "$rel" "$TMP/q1" "EIGS_REPLAY=$TMP/tape" + run "$BR_BIN" "$1" "$TMP/q1" "$2" "EIGS_REPLAY=$TMP/tape" same "$TMP/p1" "$TMP/q1" && return 0 return 1 } -: > "$TMP/nondet"; : > "$TMP/crash" while IFS= read -r rel; do examined=$((examined + 1)) t0=$(date +%s) [ -f "$BASE_ROOT/$rel" ] || { new=$((new + 1)); echo "$rel" >> "$TMP/new"; } - run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/b1" - run "$BR_BIN" "$BR_ROOT" "$rel" "$TMP/r1" - if same "$TMP/b1" "$TMP/r1"; then - nsame=$((nsame + 1)) - rc=$(cat "$TMP/b1.rc") - if [ "$rc" -eq 124 ]; then timeout_both=$((timeout_both + 1)); echo "$rel rc=124" >> "$TMP/crash" - elif [ "$rc" -ge 128 ]; then crash_both=$((crash_both + 1)); echo "$rel rc=$rc" >> "$TMP/crash"; fi - echo ".. $examined/$listed $rel same rc=$rc $(( $(date +%s) - t0 ))s" - continue + cap=0 + if grep -Eq '(gfx|ui|audio)_[a-z_]+' "$BR_ROOT/$rel"; then + cap=1; capped=$((capped + 1)); echo "$rel" >> "$TMP/capped" fi - run "$BASE_BIN" "$BASE_ROOT" "$rel" "$TMP/b2" - if ! same "$TMP/b1" "$TMP/b2"; then - replay_adjudicate "$rel"; ra=$? - if [ "$ra" -eq 0 ]; then - nreplay=$((nreplay + 1)) - echo ".. $examined/$listed $rel same-under-replay $(( $(date +%s) - t0 ))s"; continue - elif [ "$ra" -eq 1 ]; then - ndiff=$((ndiff + 1)) - echo ".. $examined/$listed $rel DIFF-under-replay $(( $(date +%s) - t0 ))s" - echo "DIFF $rel: replaying the baseline's tape, rc baseline=$(cat "$TMP/p1.rc") branch=$(cat "$TMP/q1.rc")" - diff "$TMP/p1.out" "$TMP/q1.out" | head -8 | sed 's/^/ stdout: /' - diff "$TMP/p1.err" "$TMP/q1.err" | head -8 | sed 's/^/ stderr: /' + run "$BASE_BIN" "$rel" "$TMP/b1" "$cap" + run "$BASE_BIN" "$rel" "$TMP/b2" "$cap" + run "$BR_BIN" "$rel" "$TMP/r1" "$cap" + run "$BR_BIN" "$rel" "$TMP/r2" "$cap" + if same "$TMP/b1" "$TMP/b2"; then + if same "$TMP/b1" "$TMP/r1" && same "$TMP/b1" "$TMP/r2"; then + nsame=$((nsame + 1)) + rc=$(cat "$TMP/b1.rc") + if [ "$rc" -eq 124 ]; then timeout_both=$((timeout_both + 1)); echo "$rel rc=124" >> "$TMP/crash" + elif [ "$rc" -ge 128 ]; then crash_both=$((crash_both + 1)); echo "$rel rc=$rc" >> "$TMP/crash"; fi + echo ".. $examined/$listed $rel same rc=$rc $(( $(date +%s) - t0 ))s" continue fi - nondet=$((nondet + 1)); echo "$rel (the baseline disagrees with itself, and its replays too)" >> "$TMP/nondet" - echo ".. $examined/$listed $rel nondet $(( $(date +%s) - t0 ))s"; continue + ndiff=$((ndiff + 1)) + echo ".. $examined/$listed $rel DIFF $(( $(date +%s) - t0 ))s" + if same "$TMP/b1" "$TMP/r1"; then wrong=r2; else wrong=r1; fi + echo "DIFF $rel: the baseline is deterministic (two runs agree); branch run $wrong differs: rc baseline=$(cat "$TMP/b1.rc") branch=$(cat "$TMP/$wrong.rc")" + show_diff "$TMP/b1" "$TMP/$wrong" + continue fi - run "$BR_BIN" "$BR_ROOT" "$rel" "$TMP/r2" - if same "$TMP/b1" "$TMP/r2"; then - nondet=$((nondet + 1)); echo "$rel (the branch disagreed once, then agreed)" >> "$TMP/nondet" - echo ".. $examined/$listed $rel nondet $(( $(date +%s) - t0 ))s"; continue + replay_adjudicate "$rel" "$cap"; ra=$? + if [ "$ra" -eq 0 ]; then + nreplay=$((nreplay + 1)); echo "$rel" >> "$TMP/replayed" + echo ".. $examined/$listed $rel same-under-replay $(( $(date +%s) - t0 ))s" + elif [ "$ra" -eq 1 ]; then + ndiff=$((ndiff + 1)) + echo ".. $examined/$listed $rel DIFF-under-replay $(( $(date +%s) - t0 ))s" + echo "DIFF $rel: replaying the baseline's tape, rc baseline=$(cat "$TMP/p1.rc") branch=$(cat "$TMP/q1.rc")" + show_diff "$TMP/p1" "$TMP/q1" + else + nondet=$((nondet + 1)); echo "$rel" >> "$TMP/nondet" + echo ".. $examined/$listed $rel nondet $(( $(date +%s) - t0 ))s" fi - ndiff=$((ndiff + 1)) - echo ".. $examined/$listed $rel DIFF $(( $(date +%s) - t0 ))s" - echo "DIFF $rel: rc baseline=$(cat "$TMP/b1.rc") branch=$(cat "$TMP/r2.rc")" - diff "$TMP/b1.out" "$TMP/r2.out" | head -8 | sed 's/^/ stdout: /' - diff "$TMP/b1.err" "$TMP/r2.err" | head -8 | sed 's/^/ stderr: /' done < "$TMP/files" sed 's/^/NEW (only the branch tree has it) /' "$TMP/new" -sed 's/^/NONDET /' "$TMP/nondet" +sed 's/^/REPLAYED (compared on the baseline tape; its nondeterministic builtins did not run live) /' "$TMP/replayed" +sed 's/^/NONDET (the baseline disagrees with itself, and its tape replays too) /' "$TMP/nondet" sed 's/^/BOTH-CRASH-OR-TIMEOUT /' "$TMP/crash" -echo "corpus-diff: examined=$examined same=$nsame same_under_replay=$nreplay nondet=$nondet diff=$ndiff new=$new deleted=$deleted crash_both=$crash_both timeout_both=$timeout_both" +sed 's/^/CAPPED (gfx\/ui\/audio: ulimit -v 2097152) /' "$TMP/capped" +summary="examined=$examined same=$nsame same_under_replay=$nreplay nondet=$nondet diff=$ndiff new=$new deleted=$deleted crash_both=$crash_both timeout_both=$timeout_both capped=$capped" DONE=1 +if [ -n "${PHASE2_DIFF_FILES:-}" ]; then + echo "corpus-diff: RESTRICTED $summary" + exit 3 +fi +echo "corpus-diff: $summary" if [ "$examined" -eq "$listed" ] && [ "$examined" -gt 0 ] && [ "$ndiff" -eq 0 ] && [ "$deleted" -eq 0 ]; then echo "corpus-diff: PASS"; exit 0 fi diff --git a/tools/phase2_plants.sh b/tools/phase2_plants.sh index 33d7adc25..665387800 100755 --- a/tools/phase2_plants.sh +++ b/tools/phase2_plants.sh @@ -1,6 +1,10 @@ #!/usr/bin/env bash -# tools/phase2_plants.sh [--ref REF] -- #1758: Phase 2's planted faults -# (docs/design/phase2-numbers.md 9.3). Each plant: +# tools/phase2_plants.sh [--ref REF] [--selftest] -- #1758: Phase 2's planted +# faults (docs/design/phase2-numbers.md 9.3). A check proves it fires when it +# is written or changed (docs/PRINCIPLES.md 5), so this runs as a +# tools/selftests.txt row keyed on the checks the plants name, never on every +# suite or CI run; `--selftest` is that row's spelling of the same run. Each +# plant: # 1. `git archive REF` (default HEAD) into a scratch tree with no .git; # 2. applies one replacement, refusing unless the original text occurs # exactly once before and the planted text after (else BROKEN); @@ -13,16 +17,21 @@ # exactly the deletion of the assertion that names it. # # Plants land with their named checks: plant 1 with R1.1 (the C slot test); -# 2-7 name MAP rows that land in R1.3-R2.2 and join this table then. +# 2-7 name MAP rows that land in R1.3-R2.2 and join this table then. The R1.1 +# fix round added three instrument plants on the slot test: an operator arm +# that lost its int refusal (Part D), and a population scan that writes noise +# to stderr or an unparsed line to stdout (the critic's class); and #1775's +# plant, the missing return that makes the -O0 amalgamation warn. # Prints one line per plant and `plants=N killed=N survived=0 broken=0 -# transverse=N`; exit 0 only for exactly that, with N > 0. About 7 minutes -# per plant on the 4 GB box (two compiles of the amalgamated slot test). +# transverse=N`; exit 0 only for exactly that, with N > 0. About 3 minutes +# per plant on the 4 GB box (two -O0 compiles of the amalgamated slot test). set -u ROOT="$(cd "$(dirname "$0")/.." && pwd)" REF=HEAD while [ $# -gt 0 ]; do case "$1" in --ref) REF="$2"; shift 2 ;; + --selftest) shift ;; *) echo "phase2-plants: FAIL: unknown argument $1"; exit 2 ;; esac done @@ -37,10 +46,11 @@ trap 'rc=$?; [ "$VERDICT_DONE" = 1 ] || echo "phase2-plants: FAIL: exited ($rc) # replace FILE OLD NEW: exactly one OLD before, NEW present after. replace() { - python3 - "$1" "$2" "$3" <<'PY' + python3 -W error - "$1" "$2" "$3" <<'PY' import sys path, old, new = sys.argv[1], sys.argv[2], sys.argv[3] -text = open(path, encoding='utf-8').read() +with open(path, encoding='utf-8') as f: + text = f.read() n = text.count(old) if n != 1: print('replace: %s: the original occurs %d times, want exactly 1' % (path, n)) @@ -49,7 +59,8 @@ text = text.replace(old, new) if new not in text: print('replace: %s: the planted text is absent after the replacement' % path) sys.exit(1) -open(path, 'w', encoding='utf-8').write(text) +with open(path, 'w', encoding='utf-8') as f: + f.write(text) PY } @@ -68,8 +79,13 @@ run_plant() { if ! replace "$dir/$file" "$old" "$new"; then verdict=BROKEN; break; fi if [ "$mode" = transverse ] && ! replace "$dir/$cfile" "$cold" "$cnew"; then trans=BROKEN; break; fi local log="$WORK/$id-$mode.log" - (cd "$dir" && $TMO "$@") > "$log" 2>&1 + (cd "$dir" && $TMO "$@") > "$log" 2> "$log.err" local rc=$? + if [ -s "$log.err" ]; then # the check's own stderr: unexpected, shown, BROKEN + sed 's/^/ check stderr: /' "$log.err" + [ "$mode" = plant ] && verdict=BROKEN || trans=BROKEN + break + fi if [ "$mode" = plant ]; then if grep -Eq "$re" "$log"; then verdict=KILLED elif [ "$rc" -eq 124 ] || grep -q 'build: \|make phase2-slot-test exited' "$log"; then @@ -105,6 +121,59 @@ run_plant 1 src/value_slot.h \ '^slot-layer-test: FAIL slot_from_int\(0\): bits 0x' \ bash tests/phase2/slot_layer.sh release +# An operator arm that lost its int refusal: NUM_CMP raises a type error for +# an SMI again (a `try` turns it into a wrong value). Named check: the slot +# test's Part D row for `<`. +run_plant arm-refusal src/vm.c \ + " if (slot_is_smi(_as) || slot_is_smi(_bs)) \\ + eigs_int_unwired(\"compare '\" OPNAME \"'\", (slot_is_smi(_as) ? _as : _bs).u); \\ +" \ + "" \ + tests/phase2/slot_layer.c \ + ' if (strcmp(got, want) != 0) { FAILF("arm %s with an int: got %s, want %s", g_arm->name, got, want); bad++; }' \ + ' if (0) { FAILF("arm %s with an int: got %s, want %s", g_arm->name, got, want); bad++; }' \ + "^slot-layer-test: FAIL arm lt with an int: got " \ + bash tests/phase2/slot_layer.sh release + +# The critic's class: a population scan whose diagnostics reach the parser. +# Named checks: the runner's stderr refusal, and its grammar whitelist. +run_plant stderr-noise tools/phase2_inventory.py \ + " out, bad = [], [] + for (rel, k), (cls, c) in sorted(slots.items()):" \ + " print('phase2-plant: noise on stderr', file=sys.stderr) + out, bad = [], [] + for (rel, k), (cls, c) in sorted(slots.items()):" \ + tests/phase2/slot_layer.sh \ + 'show_stderr "$TMP/pop.err" "the population scan"' \ + ':' \ + "^slot-layer: FAIL: the population scan wrote to stderr" \ + bash tests/phase2/slot_layer.sh release +run_plant stdout-noise tools/phase2_inventory.py \ + " out, bad = [], [] + for (rel, k), (cls, c) in sorted(slots.items()):" \ + " print('phase2-plant: an unparsed line') + out, bad = [], [] + for (rel, k), (cls, c) in sorted(slots.items()):" \ + tests/phase2/slot_layer.sh \ + 'if [ -s "$TMP/pop.bad" ]; then' \ + 'if false; then' \ + "^slot-layer: FAIL: the population scan printed lines outside its grammar" \ + bash tests/phase2/slot_layer.sh release + +# #1775: the missing return comes back. -O0 does not fold ARG_GUARD's +# constant test, so the amalgamation warns (-Wreturn-type). Named check: the +# runner's build-warning refusal. +run_plant return-type src/builtins_tensor.c \ + " return make_null(); /* unreachable: the guard above always returns, but + * -O0 does not fold its constant test (#1775) */ +" \ + "" \ + tests/phase2/slot_layer.sh \ + "if grep -q 'warning:' \"\$TMP/build.txt\"; then" \ + 'if false; then' \ + "^slot-layer: FAIL: the slot test build printed [0-9]+ warning" \ + bash tests/phase2/slot_layer.sh release + echo "plants=$plants killed=$killed survived=$survived broken=$broken transverse=$transverse" VERDICT_DONE=1 if [ "$plants" -gt 0 ] && [ "$killed" -eq "$plants" ] && [ "$transverse" -eq "$plants" ]; then diff --git a/tools/selftests.txt b/tools/selftests.txt index 7e39146a9..b761e3c69 100644 --- a/tools/selftests.txt +++ b/tools/selftests.txt @@ -53,3 +53,7 @@ tools/workflow_yaml_check.sh tests/sections/99zd-container-commands.sh | timeout tools/strict_shape_contract.py tools/strict_shape_contracts.json tests/strict_shape_cases.json | timeout 30 python3 tools/strict_shape_contract.py --selftest | [{"pattern":"^PASS:","count":20},{"pattern":"^FAIL:","count":0},{"pattern":"^SHAPE_CONTRACT_SELFTEST: 20 passed, 0 failed, 20 declared$","count":1}] tools/strict_differential.sh tests/lsan_classify.sh | timeout 30 bash tools/strict_differential.sh --selftest | [{"pattern":"^ PASS:","count":88},{"pattern":"^ FAIL:","count":0},{"pattern":"^SHAPE_CAPTURE_SELFTEST: 88 passed, 0 failed, 88 declared$","count":1}] tools/selftests.sh tools/selftests_selection_selftest.sh | timeout 30 bash tools/selftests_selection_selftest.sh --selftest | [{"pattern":"^ PASS:","count":7},{"pattern":"^ FAIL:","count":0},{"pattern":"^SELFTEST_SELECTION: 7 passed, 0 failed, 7 declared$","count":1}] +# #1758 Phase 2: the row checker's calibration (5 release builds: v0.46.0 and four planted binaries) and the +# slot test's planted faults (two -O0 slot-test builds per plant). Keyed on the checkers, never on src/ (#1352). +tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* | timeout 5400 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=([0-9]+) as-expected=\\1 unexpected=0$","count":1}] +tools/phase2_plants.sh tests/phase2/slot_layer.sh tests/phase2/slot_layer.c tools/phase2_inventory.py | timeout 3600 bash tools/phase2_plants.sh --selftest | [{"pattern":"^plants=5 killed=5 survived=0 broken=0 transverse=5$","count":1}] From cdfb128f25220d7b9a81307783d2666c219f9e6f Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 14 Oct 2026 22:34:09 -0500 Subject: [PATCH 010/188] phase2 R1.1 fix: keep a signal-killed run's report off the differential's stderr (#1758) The calibration's P4 case (a smi-trap build with a planted int producer) showed the corpus differential writing bash's own report of a run killed by SIGABRT ("line N: PID Aborted ...") to its stderr, which the gates now refuse. A brace group's 2>/dev/null takes that report; each run's own stderr still goes to its file and is compared. The self-test rows take bounds from the dev-box measurements (calibration 662 s, plants 446 s) and pin the calibration's 42 cases. The design doc records that the calibration and the plants run as self-test rows. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 11 ++++++++++- tools/phase2_corpus_diff.sh | 17 +++++++++++------ tools/selftests.txt | 9 +++++---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 282e3afee..150942203 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2287,6 +2287,11 @@ fails if a round named here has neither rows nor its mechanical gates.) allowed writer and the static half passes it); and P4 built into a smi-trap binary, which the dynamic half must stop. A restricted run (the calibration's file list) prints `RESTRICTED` and exits 3, never PASS. + The calibration is a `tools/selftests.txt` row (`phase2_check.py + --selftest`, which builds v0.46.0 and the four planted binaries itself): + it runs when the checker or its fixtures change, and nightly, never on + every suite or CI run (docs/PRINCIPLES.md 5: a check proves it fires once, + when it is written or changed). ### 9.3 `tools/phase2_plants.sh` (round 1 builds it; detached, about 7 release builds) @@ -2334,7 +2339,11 @@ deleted; named line `slot-layer-test: FAIL arm lt with an int: got ...`), `slot-layer: FAIL: the population scan wrote to stderr`) and `stdout-noise` (the scan prints a line outside its grammar; named line `slot-layer: FAIL: the population scan printed lines outside its -grammar`). The tool also fails a plant whose check writes to stderr. +grammar`). The tool also fails a plant whose check writes to stderr. Like +the calibration, the plants are a `tools/selftests.txt` row (`phase2_plants.sh +--selftest`), keyed on the checks they name (the slot test, its runner and +the population scan), so they run when those change, never per suite or CI +run (docs/PRINCIPLES.md 5). ### 9.4 The per-builtin behaviour table (R1.6's gate; replaces the int-fuzz class check) diff --git a/tools/phase2_corpus_diff.sh b/tools/phase2_corpus_diff.sh index eafe56004..d238f11f2 100755 --- a/tools/phase2_corpus_diff.sh +++ b/tools/phase2_corpus_diff.sh @@ -124,12 +124,17 @@ echo "corpus-diff: files=$listed${PHASE2_DIFF_FILES:+ (RESTRICTED by PHASE2_DIFF # normalised; CAP=1 runs under the GUI memory cap. run() { local bin="$1" rel="$2" out="$3" cap="$4" extra="${5:-PHASE2_DIFF=1}" rc - ( - cd "$BR_ROOT/src" || exit 99 - [ "$cap" = 1 ] && ulimit -v 2097152 - exec env -u XAUTHORITY DISPLAY=:99 LD_PRELOAD="$SHIM" "$extra" timeout 60 "$bin" "../$rel" - ) < /dev/null > "$out.rawout" 2> "$out.rawerr" - rc=$? + # The run's stderr is its file. The brace group's 2>/dev/null takes only + # bash's own report of a run killed by a signal ("line N: PID Aborted"), + # which would otherwise reach this tool's stderr, where a gate refuses it. + { + ( + cd "$BR_ROOT/src" || exit 99 + [ "$cap" = 1 ] && ulimit -v 2097152 + exec env -u XAUTHORITY DISPLAY=:99 LD_PRELOAD="$SHIM" "$extra" timeout 60 "$bin" "../$rel" + ) < /dev/null > "$out.rawout" 2> "$out.rawerr" + rc=$? + } 2> /dev/null echo "$rc" > "$out.rc" sed "s|$BASE_ROOT||g; s|$BR_ROOT||g" "$out.rawout" > "$out.out" sed "s|$BASE_ROOT||g; s|$BR_ROOT||g" "$out.rawerr" > "$out.err" diff --git a/tools/selftests.txt b/tools/selftests.txt index b761e3c69..539e27c30 100644 --- a/tools/selftests.txt +++ b/tools/selftests.txt @@ -53,7 +53,8 @@ tools/workflow_yaml_check.sh tests/sections/99zd-container-commands.sh | timeout tools/strict_shape_contract.py tools/strict_shape_contracts.json tests/strict_shape_cases.json | timeout 30 python3 tools/strict_shape_contract.py --selftest | [{"pattern":"^PASS:","count":20},{"pattern":"^FAIL:","count":0},{"pattern":"^SHAPE_CONTRACT_SELFTEST: 20 passed, 0 failed, 20 declared$","count":1}] tools/strict_differential.sh tests/lsan_classify.sh | timeout 30 bash tools/strict_differential.sh --selftest | [{"pattern":"^ PASS:","count":88},{"pattern":"^ FAIL:","count":0},{"pattern":"^SHAPE_CAPTURE_SELFTEST: 88 passed, 0 failed, 88 declared$","count":1}] tools/selftests.sh tools/selftests_selection_selftest.sh | timeout 30 bash tools/selftests_selection_selftest.sh --selftest | [{"pattern":"^ PASS:","count":7},{"pattern":"^ FAIL:","count":0},{"pattern":"^SELFTEST_SELECTION: 7 passed, 0 failed, 7 declared$","count":1}] -# #1758 Phase 2: the row checker's calibration (5 release builds: v0.46.0 and four planted binaries) and the -# slot test's planted faults (two -O0 slot-test builds per plant). Keyed on the checkers, never on src/ (#1352). -tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* | timeout 5400 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=([0-9]+) as-expected=\\1 unexpected=0$","count":1}] -tools/phase2_plants.sh tests/phase2/slot_layer.sh tests/phase2/slot_layer.c tools/phase2_inventory.py | timeout 3600 bash tools/phase2_plants.sh --selftest | [{"pattern":"^plants=5 killed=5 survived=0 broken=0 transverse=5$","count":1}] +# #1758 Phase 2: the row checker's calibration (5 release builds: v0.46.0 and four planted binaries; 662 s on +# the 4 GB dev box) and the slot test's planted faults (two -O0 slot-test builds per plant; 446 s there). +# Keyed on the checkers, never on src/ (#1352). +tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* | timeout 2400 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=42 as-expected=42 unexpected=0$","count":1}] +tools/phase2_plants.sh tests/phase2/slot_layer.sh tests/phase2/slot_layer.c tools/phase2_inventory.py | timeout 1500 bash tools/phase2_plants.sh --selftest | [{"pattern":"^plants=5 killed=5 survived=0 broken=0 transverse=5$","count":1}] From 176b3d6a397e44f1bcd4bfa1ab1acfe99eefc649 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 05:21:15 -0500 Subject: [PATCH 011/188] phase2 R1.1 fix 2: #1775's warnings fixed in the callees, at no hot-path cost (#1758) The first fix round silenced -Wmaybe-uninitialized by initialising `_ad`/`_bd` (5 sites) and the index `i` (4 sites) where they are declared, in vm_run_ex's hot arms and the JIT index helpers. The second R1.1 critic measured the cost against R1.1 (9ce8e0bd) with callgrind: +2.07% Ir on the DMG 500K canary and +4.17% on a JIT-off float loop, and reverting only the initialisers restored R1.1's counts. The initialisers are gone. The two readers that fill those locals write their out-parameter on every path instead, so the extra store is on the cold path: slot_f64_value writes 0.0 when it answers 0, and vm_index_is_int writes the truncation before its round-trip test (no caller reads it when the answer is 0). The amalgamation compiles with no warning at -O0 and -O1 (-Wall -Wextra), and the release build at -O2 has none. The C slot test's slot_f64_value rows now expect the written 0.0 where they expected the out-parameter untouched. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- src/value_slot.h | 7 ++++++- src/vm.c | 24 +++++++++++++----------- tests/phase2/slot_layer.c | 7 ++++--- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/value_slot.h b/src/value_slot.h index 23dc6135f..02d084de4 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -235,13 +235,18 @@ static inline int slot_truthy_immediate(EigsSlot s, int *out_decided) { /* #1758: a float's double, from an immediate or a VAL_NUM box (the VM boxes * numbers on purpose: the lifts, a for-in variable). 0 for anything else, * an int (an SMI, later a VAL_INT box) included: the caller sends it to its - * slow path. Replaces vm.c's slot_as_double. */ + * slow path. Replaces vm.c's slot_as_double. + * *out is written on EVERY path (0.0 when the answer is 0), so a caller's + * local is never read uninitialised and needs no initialiser of its own: the + * store sits on the cold failure path, and an initialiser in vm_run_ex's hot + * arms cost +2.07% Ir on DMG and +4.17% on a JIT-off float loop (#1775). */ static inline int slot_f64_value(EigsSlot s, double *out) { if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } if (slot_is_heap(s)) { Value *v = slot_as_ptr(s); if (v->type == VAL_NUM) { *out = VAL_NUM_RAW(v); return 1; } } + *out = 0.0; return 0; } /* #1758: an int's value. R1.1 knows the SMI; R1.2a adds the VAL_INT box diff --git a/src/vm.c b/src/vm.c index 3da4b68f7..2cbd59cf5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1838,9 +1838,11 @@ int jit_helper_iter_next(void) { * >= 0 range check downstream, unchanged. */ static inline int vm_index_is_int(double d, int *out) { int i = (int)d; - if ((double)i != d) return 0; + /* #1775: *out is written on every path (the truncation when the answer is + * 0, which no caller reads), so a caller's index local needs no + * initialiser for -Wmaybe-uninitialized at -O1. */ *out = i; - return 1; + return (double)i == d; } /* 0.13.0: resolve negative index against len, then bounds-check. @@ -2201,7 +2203,7 @@ void jit_helper_index_set(void) { EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { target->data.buffer.data[i] = SLOT_F64_RAW(val_s); @@ -2271,7 +2273,7 @@ int jit_helper_index_get(void) { g_vm.sp -= 2; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_LIST) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { EigsSlot r = slot_read_owned(list_slot(target, i)); @@ -3322,7 +3324,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, #define ARITH_FAST(OP, UF) do { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - double _ad = 0.0, _bd = 0.0; \ + double _ad, _bd; \ if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ double _r = num_guard(_ad OP _bd); \ if ((UF) && _r == 0.0 && _ad != 0.0 && _bd != 0.0) \ @@ -3492,7 +3494,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NAME): { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - double _ad = 0.0, _bd = 0.0; \ + double _ad, _bd; \ if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ int64_t _ai, _bi; \ if (__builtin_expect(!num_to_i64_exact(_ad, &_ai) || \ @@ -3623,7 +3625,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(EQ): { EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; - double _ad = 0.0, _bd = 0.0; + double _ad, _bd; if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE * branches wrote a 0/1 result INTO a heap-number operand; a bool @@ -3644,7 +3646,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NE): { EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; - double _ad = 0.0, _bd = 0.0; + double _ad, _bd; if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE * branches wrote a 0/1 result INTO a heap-number operand; a bool @@ -3666,7 +3668,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NAME): { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - double _ad = 0.0, _bd = 0.0; \ + double _ad, _bd; \ if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ /* #1637: a bool immediate; no NUM_REUSE (see CASE(EQ)). */ \ int _r = (_ad OP _bd); \ @@ -4609,7 +4611,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.sp -= 2; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_LIST) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { EigsSlot r = slot_read_owned(list_slot(target, i)); @@ -4692,7 +4694,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { target->data.buffer.data[i] = SLOT_F64_RAW(val_s); diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index 72401a249..809e6d295 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -131,7 +131,8 @@ static int r_store_json_encode_slot(int64_t v) { strbuf_free(&sb); return bad; } -static int r_slot_f64_value(int64_t v) { double d = -7.25; return slot_f64_value(smi(v), &d) != 0 || d != -7.25; } +/* #1775: the reader writes its out-param on every path (0.0 when it answers 0) */ +static int r_slot_f64_value(int64_t v) { double d = -7.25; return slot_f64_value(smi(v), &d) != 0 || d != 0.0; } static int r_slot_int_value(int64_t v) { int64_t i = 7; return slot_int_value(smi(v), &i) != 1 || i != v; } static int r_slot_is_f64(int64_t v) { return slot_is_f64(smi(v)) != 0; } static int r_slot_is_smi(int64_t v) { return slot_is_smi(smi(v)) != 1; } @@ -186,7 +187,7 @@ static const Entry ENTRIES[] = { {"container.h:eigs_slot_store_owned", r_eigs_slot_store_owned, 0, 0, "canonical storage: unchanged"}, {"eigenscript.c:ent_child_slot", r_ent_child_slot, 0, 0, "the entropy of its double"}, {"ext_store.c:store_json_encode_slot", r_store_json_encode_slot, 0, 0, "exact digits"}, - {"value_slot.h:slot_f64_value", r_slot_f64_value, 0, 0, "not a float: 0, out untouched"}, + {"value_slot.h:slot_f64_value", r_slot_f64_value, 0, 0, "not a float: 0, out 0.0"}, {"value_slot.h:slot_int_value", r_slot_int_value, 0, 0, "the int"}, {"value_slot.h:slot_is_f64", r_slot_is_f64, 0, 0, "0"}, {"value_slot.h:slot_is_smi", r_slot_is_smi, 0, 0, "1"}, @@ -390,7 +391,7 @@ EXP(write_slot) { } EXP(f64_value) { if (kclass(k) == C_F64) snprintf(b, n, "o:1 d:%016llx", (unsigned long long)KB[k]); - else snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(-7.25)); + else snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(0.0)); /* written on every path (#1775) */ } EXP(int_value) { snprintf(b, n, k == K_SMI ? "o:1 i:5" : "o:0 i:7"); } EXP(is_f64) { snprintf(b, n, "i:%d", kclass(k) == C_F64); } From 076ac7c0aea88a4a3fb2feecf231c3fd727a556e Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 05:21:15 -0500 Subject: [PATCH 012/188] One loader for per-program run conditions: suite, jit_diff, replay_diff (#1758) tests/suite_program_env.txt was the policy the suite and jit_diff.sh read (#1395), but the suite still spelled five programs' conditions inline: four EIGS_STRICT=0 runs (test_coalesce_legacy, test_audio, test_gfx_text, test_gfx_argtypes, the last two with the SDL dummy drivers) and one SDL_VIDEODRIVER=dummy run (test_ui_containment_gfx). They are rows now, and those sites run through suite_program_run, so the table is the one source. tools/replay_diff.sh ran every corpus program in default strict mode; it now applies the same conditions, as jit_diff.sh does. tests/suite_program_env.sh: the conditions are checked against a whitelist of forms (EIGS_STRICT=0, SDL_VIDEODRIVER=dummy, SDL_AUDIODRIVER=dummy), and a word outside it is refused by name; suite_program_check validates without running. jit_diff.sh runs every arm through suite_program_run instead of its own copy of the case, and its completion pin and tests/test_jit_diff_env.sh's population follow the table (10 -> 15 programs). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/run_all_tests.sh | 10 ++--- tests/sections/0f8-coalesce-legacy.sh | 2 +- tests/suite_program_env.sh | 53 ++++++++++++++++++++++----- tests/suite_program_env.txt | 13 +++++-- tests/test_jit_diff_env.sh | 13 +++++-- tools/jit_diff.sh | 13 +++---- tools/replay_diff.sh | 8 +++- 7 files changed, 80 insertions(+), 32 deletions(-) diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh index b5aa7cac7..a46edacc8 100755 --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -3478,7 +3478,7 @@ rm -f "$AUDIO_PROBE_FILE" echo "[62] Audio Synthesis" if ! echo "$AUDIO_PROBE_OUT" | grep -q "undefined variable"; then # #1361 EIGS_STRICT=0: pins the rejected-argument stand-ins audio_sine/audio_mix -> [], audio_play_loop -> 0, audio_stream_push -> 0. - AU_OUTPUT=$(EIGS_STRICT=0 ./eigenscript ../tests/test_audio.eigs 2>&1); AU_OUTPUT_RC=$? + AU_OUTPUT=$(suite_program_run test_audio.eigs ./eigenscript ../tests/test_audio.eigs 2>&1); AU_OUTPUT_RC=$? if rc_ok "$AU_OUTPUT_RC" "$AU_OUTPUT" && echo "$AU_OUTPUT" | grep -q "All tests passed"; then TOTAL=$((TOTAL + 1)) PASS=$((PASS + 1)) @@ -3511,8 +3511,8 @@ rm -f "$GT_PROBE_FILE" echo "[120b] Gfx Text Metrics" if ! echo "$GT_PROBE_OUT" | grep -q "undefined variable"; then # #1361 EIGS_STRICT=0: pins gfx_text_width of a non-string answering 0 (line 38), in both renderer modes. - GT_FB=$(EIGS_STRICT=0 SDL_VIDEODRIVER=dummy EIGS_GFX_FONT=/nonexistent/eigs-no-font.ttf ./eigenscript ../tests/test_gfx_text.eigs 2>&1); GT_FB_RC=$? - GT_DEF=$(EIGS_STRICT=0 SDL_VIDEODRIVER=dummy ./eigenscript ../tests/test_gfx_text.eigs 2>&1); GT_DEF_RC=$? + GT_FB=$(EIGS_GFX_FONT=/nonexistent/eigs-no-font.ttf suite_program_run test_gfx_text.eigs ./eigenscript ../tests/test_gfx_text.eigs 2>&1); GT_FB_RC=$? + GT_DEF=$(suite_program_run test_gfx_text.eigs ./eigenscript ../tests/test_gfx_text.eigs 2>&1); GT_DEF_RC=$? if rc_ok "$GT_FB_RC" "$GT_FB" && echo "$GT_FB" | grep -q "All tests passed" \ && echo "$GT_FB" | grep -q "fallback-mode: 1" \ && rc_ok "$GT_DEF_RC" "$GT_DEF" && echo "$GT_DEF" | grep -q "All tests passed"; then @@ -3581,7 +3581,7 @@ rm -f "$GA_PROBE_FILE" echo "[133] Gfx Argument-Type Guards" if ! echo "$GA_PROBE_OUT" | grep -q "undefined variable"; then # #1361 EIGS_STRICT=0: the plain pass pins the ext_gfx wrong-type stand-ins (0/null); the strict pass below raises. - GA_PLAIN=$(EIGS_STRICT=0 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy ./eigenscript ../tests/test_gfx_argtypes.eigs 2>&1); GA_PLAIN_RC=$? + GA_PLAIN=$(suite_program_run test_gfx_argtypes.eigs ./eigenscript ../tests/test_gfx_argtypes.eigs 2>&1); GA_PLAIN_RC=$? GA_STRICT=$(EIGS_STRICT=1 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy ./eigenscript ../tests/test_gfx_argtypes.eigs 2>&1); GA_STRICT_RC=$? # THIRD PASS: the tape. audio_capture_open is trace-recorded, so a guard @@ -3905,7 +3905,7 @@ rm -f "$UC_PROBE_FILE" echo "[132] UI Containment Render-Decode Oracle" if ! echo "$UC_PROBE_OUT" | grep -q "undefined variable"; then - UC_OUTPUT=$(SDL_VIDEODRIVER=dummy ./eigenscript ../tests/test_ui_containment_gfx.eigs 2>&1); UC_RC=$? + UC_OUTPUT=$(suite_program_run test_ui_containment_gfx.eigs ./eigenscript ../tests/test_ui_containment_gfx.eigs 2>&1); UC_RC=$? UC_N=$(derive_count "$UC_OUTPUT" "[132] UI Containment Render-Decode Oracle") if rc_ok "$UC_RC" "$UC_OUTPUT" && echo "$UC_OUTPUT" | grep -q "All tests passed"; then TOTAL=$((TOTAL + UC_N)) diff --git a/tests/sections/0f8-coalesce-legacy.sh b/tests/sections/0f8-coalesce-legacy.sh index 0288aaec5..5694260b6 100644 --- a/tests/sections/0f8-coalesce-legacy.sh +++ b/tests/sections/0f8-coalesce-legacy.sh @@ -1,3 +1,3 @@ echo "[0f8] Coalesce explicit compatibility values (#1398)" -EIGS_STRICT=0 check_eigs_suite "coalesce compatibility retains the legacy result" test_coalesce_legacy.eigs "All tests passed" +suite_program_run test_coalesce_legacy.eigs check_eigs_suite "coalesce compatibility retains the legacy result" test_coalesce_legacy.eigs "All tests passed" echo "" diff --git a/tests/suite_program_env.sh b/tests/suite_program_env.sh index 91245f72d..c08ec0a18 100644 --- a/tests/suite_program_env.sh +++ b/tests/suite_program_env.sh @@ -1,7 +1,22 @@ #!/usr/bin/env bash -# One lookup for per-program suite environment. Both run_all_tests.sh and -# tools/jit_diff.sh source this file; suite_program_env.txt is the policy. +# One loader for per-program run conditions. tests/run_all_tests.sh, +# tools/jit_diff.sh, tools/replay_diff.sh and tools/phase2_corpus_diff.sh all +# source this file; tests/suite_program_env.txt is the policy, and nothing +# else spells a program's conditions (#1395; #1758's R1.1 critics found a +# corpus differential that ignored it and compared two early deaths). +# +# A row is a program's basename and its conditions: environment assignments, +# each one of SUITE_PROGRAM_FORMS. The forms are a whitelist: any other word +# is refused by name, never passed through. The suite runs every corpus +# program from src/ with stdin /dev/null and no arguments, so a row has no +# argument, stdin or working-directory field; a program that needs one (a +# generator fed by its child script, a fixture of another host) does not run +# standalone, and the corpus differential's ledger declares it +# (tests/phase2/corpus_nonzero.txt). +SUITE_PROGRAM_FORMS=" EIGS_STRICT=0 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy " + +# suite_program_env NAME: print NAME's row (its conditions, possibly empty). suite_program_env() { local name="${1##*/}" file="${EIGS_TEST_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}/suite_program_env.txt" awk -v name="$name" ' @@ -14,16 +29,34 @@ suite_program_env() { ' "$file" } -suite_program_run() { - local name="$1" setting - shift +# suite_program_check NAME: print NAME's conditions after checking every word +# against SUITE_PROGRAM_FORMS; rc 2, with the reason on stderr, for a +# duplicate row or a word outside the forms. +suite_program_check() { + local name="$1" setting w setting=$(suite_program_env "$name") || { echo "suite-program-env: invalid duplicate entry for ${name##*/}" >&2 return 2 } - case "$setting" in - "") "$@" ;; - EIGS_STRICT=0) EIGS_STRICT=0 "$@" ;; - *) echo "suite-program-env: unsupported environment for ${name##*/}: $setting" >&2; return 2 ;; - esac + for w in $setting; do + case "$SUITE_PROGRAM_FORMS" in + *" $w "*) ;; + *) echo "suite-program-env: unsupported condition for ${name##*/}: $w" >&2; return 2 ;; + esac + done + printf '%s\n' "$setting" +} + +# suite_program_run NAME CMD...: run CMD (a command or a shell function) +# under NAME's conditions, as prefix assignments, so they reach CMD's +# children. Every word was checked against the whitelist before the eval. +suite_program_run() { + local name="$1" setting + shift + setting=$(suite_program_check "$name") || return 2 + if [ -z "$setting" ]; then + "$@" + return + fi + eval "$setting"' "$@"' } diff --git a/tests/suite_program_env.txt b/tests/suite_program_env.txt index a9dc0cbe5..a2cf581ac 100644 --- a/tests/suite_program_env.txt +++ b/tests/suite_program_env.txt @@ -1,6 +1,8 @@ -# Per-program environment shared by the suite and differential runners. -# Format: test basename, followed by environment assignments understood by -# suite_program_run. Keep policy here rather than in either caller. +# Per-program run conditions: the ONE source, read by tests/suite_program_env.sh +# for the suite, tools/jit_diff.sh, tools/replay_diff.sh and +# tools/phase2_corpus_diff.sh. Format: a test basename, then its conditions, +# each one of the loader's SUITE_PROGRAM_FORMS (anything else is refused). +# A program listed here must run to completion (rc 0) under its conditions. test_file_io.eigs EIGS_STRICT=0 test_numeric_guard.eigs EIGS_STRICT=0 test_stdlib_fixes.eigs EIGS_STRICT=0 @@ -11,3 +13,8 @@ test_file_rename.eigs EIGS_STRICT=0 test_json_hard.eigs EIGS_STRICT=0 test_tensor_buffer_ops.eigs EIGS_STRICT=0 test_buffer_nonfinite_read.eigs EIGS_STRICT=0 +test_coalesce_legacy.eigs EIGS_STRICT=0 +test_audio.eigs EIGS_STRICT=0 +test_gfx_text.eigs EIGS_STRICT=0 SDL_VIDEODRIVER=dummy +test_gfx_argtypes.eigs EIGS_STRICT=0 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy +test_ui_containment_gfx.eigs SDL_VIDEODRIVER=dummy diff --git a/tests/test_jit_diff_env.sh b/tests/test_jit_diff_env.sh index 726ef773a..0ea45dd95 100755 --- a/tests/test_jit_diff_env.sh +++ b/tests/test_jit_diff_env.sh @@ -6,17 +6,22 @@ TESTS_DIR="$(cd "$(dirname "$0")" && pwd)" export EIGS_TEST_DIR="$TESTS_DIR" . "$TESTS_DIR/suite_program_env.sh" || exit 1 -expected='test_buffer_nonfinite_read.eigs +expected='test_audio.eigs +test_buffer_nonfinite_read.eigs test_builtin_contracts.eigs test_builtin_indirect.eigs +test_coalesce_legacy.eigs test_file_io.eigs test_file_rename.eigs +test_gfx_argtypes.eigs +test_gfx_text.eigs test_json_hard.eigs test_numeric_guard.eigs test_stdlib_fixes.eigs test_stream_io.eigs -test_tensor_buffer_ops.eigs' -actual=$(awk '$0 !~ /^[[:space:]]*#/ && NF { print $1 }' "$TESTS_DIR/suite_program_env.txt" | sort) +test_tensor_buffer_ops.eigs +test_ui_containment_gfx.eigs' +actual=$(awk '$0 !~ /^[[:space:]]*#/ && NF { print $1 }' "$TESTS_DIR/suite_program_env.txt" | LC_ALL=C sort) [ "$actual" = "$expected" ] || { echo "FAIL: suite environment population changed:"; printf '%s\n' "$actual"; exit 1; } out=$(suite_program_run test_file_io.eigs "$TESTS_DIR/../src/eigenscript" "$TESTS_DIR/test_file_io.eigs" 2>&1); rc=$? @@ -33,4 +38,4 @@ grep -q 'suite-env completed=\$n_suite_env' "$TESTS_DIR/../tools/jit_diff.sh" || echo "FAIL: jit_diff does not report the suite-environment completion population" exit 1 } -echo "PASS: jit_diff and the suite share 10 per-program environments; fail-soft program reached its final marker" +echo "PASS: jit_diff and the suite share 15 per-program environments; fail-soft program reached its final marker" diff --git a/tools/jit_diff.sh b/tools/jit_diff.sh index 447f7f183..3b948c8c8 100755 --- a/tools/jit_diff.sh +++ b/tools/jit_diff.sh @@ -33,13 +33,10 @@ OSR=(-u EIGS_JIT_OFF -u EIGS_OBS_FORCE -u EIGS_OBS_GATE_STATS EIGS_JIT_OSR_THRES OBS=(-u EIGS_JIT_OSR_THRESHOLD -u EIGS_OBS_GATE_STATS EIGS_JIT_OFF=1 EIGS_OBS_FORCE=1) run() { # $1 out-file, $2 seconds, rest = env args (options first) local out="$1" sec="$2"; shift 2 - local setting - setting=$(suite_program_env "$prog") || { echo "jit_diff: FAIL: suite environment lookup failed for $prog" >&2; exit 1; } - case "$setting" in - "") env "$@" timeout "$sec" "$EIG" "$prog" "$out" 2>&1 ;; - EIGS_STRICT=0) env "$@" EIGS_STRICT=0 timeout "$sec" "$EIG" "$prog" "$out" 2>&1 ;; - *) echo "jit_diff: FAIL: unsupported suite environment for $prog: $setting" >&2; exit 1 ;; - esac + # The program's run conditions come from the shared loader, which refuses + # an unsupported one by name (tests/suite_program_env.sh). + suite_program_check "$prog" > /dev/null || { echo "jit_diff: FAIL: suite environment lookup failed for $prog" >&2; exit 1; } + suite_program_run "$prog" env "$@" timeout "$sec" "$EIG" "$prog" "$out" 2>&1 echo "rc=$?" >> "$out" } arm_env() { case "$1" in @@ -130,7 +127,7 @@ $obs_files EOF sort -o "$got" "$got" [ "$n" -ge 100 ] || { echo "jit_diff: only $n JIT programs found -- the scan is vacuous"; exit 1; } -[ "$n_suite_env" -eq 10 ] || { echo "jit_diff: FAIL: suite-environment programs completed=$n_suite_env, expected=10"; exit 1; } +[ "$n_suite_env" -eq 15 ] || { echo "jit_diff: FAIL: suite-environment programs completed=$n_suite_env, expected=15"; exit 1; } [ "$n_obs" -ge 500 ] || { echo "jit_diff: FAIL: OBS examined=$n_obs denied=$n_deny (floor 500)"; exit 1; } echo "jit_diff: OBS examined=$n_obs denied=$n_deny" if [ "${1:-}" = "--record" ]; then diff --git a/tools/replay_diff.sh b/tools/replay_diff.sh index dff529201..c8f4542bf 100755 --- a/tools/replay_diff.sh +++ b/tools/replay_diff.sh @@ -45,6 +45,11 @@ TMO="" if command -v timeout >/dev/null 2>&1; then TMO="timeout 300" elif command -v gtimeout >/dev/null 2>&1; then TMO="gtimeout 300"; fi +# Each program runs under its run conditions from the one shared loader +# (tests/suite_program_env.sh: the suite's, jit_diff's and the Phase 2 +# differential's), so a fail-soft test is replayed past its first strict raise. +export EIGS_TEST_DIR="$ROOT/tests" +. "$ROOT/tests/suite_program_env.sh" || exit 1 corpus_dir() { printf '%s' "${REPLAY_DIFF_CORPUS:-$ROOT/tests}"; } eig_bin() { printf '%s' "${REPLAY_DIFF_EIG:-./eigenscript}"; } norm() { sed -E 's/0x[0-9a-f]+/0xADDR/g' "$1"; } @@ -60,7 +65,8 @@ ledger_count() { # exited 3 -- a phantom row from the environment, not the tape. run() { local out="$1" rc; shift - env -u EIGS_JIT_OSR_THRESHOLD EIGS_JIT_OFF=1 "$@" $TMO "$(eig_bin)" "$(corpus_dir)/$b" > "$out" 2>&1 /dev/null || { echo "replay_diff: FAIL: run-condition lookup failed for $b" >&2; exit 1; } + suite_program_run "$b" env -u EIGS_JIT_OSR_THRESHOLD EIGS_JIT_OFF=1 "$@" $TMO "$(eig_bin)" "$(corpus_dir)/$b" > "$out" 2>&1 > "$out" # Runs include self-check and second adjudication arms. Never compare, # excuse as NONDET/boundary, or ledger a possibly incomplete exit-124 run. From 8e1a638b0be815233e7ba9b7c2b828ef1f64548f Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 05:21:31 -0500 Subject: [PATCH 013/188] phase2 differential: run conditions, declared nonzero exits, an exact seed pin (#1758) The second R1.1 critic: the corpus differential (and with it the smi-trap gate) started every file in default strict mode. 14 fail-soft numeric-boundary files died at an early strict raise on both binaries and were counted `same`, about 394 asserts never ran, and two planted defects passed the whole oracle (C: buffer equality reading raw elements, which the suite's [42c] catches; B2: an int whose tag bits are spelled from SLOT_QNAN_MASK). The class was already closed in jit_diff.sh (#1395). - Each file runs under its conditions from the suite's loader (tests/suite_program_env.sh), read from the branch tree. - jit_diff's rule: a file with conditions must complete (rc 0) on both baseline runs, or it is INCOMPLETE, never compared, and the run fails. - tests/phase2/corpus_nonzero.txt declares, with code and reason, the 32 files whose baseline exits nonzero standalone (deliberate errors, fixtures of other hosts, capabilities the release build lacks, the runaway guard's fixture). An undeclared nonzero exit is UNDECLARED-NONZERO and a row whose file exits otherwise is STALE; both fail the run, so a file that loses its conditions is red. The ledger's grammar is a whitelist: a malformed row is refused by name. Every declared file is listed (SAME-NONZERO) with its code. - A timeout or crash all four runs agree on is counted as timeout_both or crash_both, no longer also as same (the old comment claimed this). - The seed pin: the drand48 self-seed is recognised exactly (the shim records each thread's last CLOCK_MONOTONIC reading; a seed equal to tv_sec ^ tv_nsec ^ getpid() of it is pinned, whatever its value), where the first fix round pinned seeds >= 2^20 and let 5 of 3,000 self-seeds through; 3,000 of 3,000 are pinned now. Every srand call (main's srand(time(NULL)), behind audio_noise's rand()) is pinned. random_hex's /dev/urandom stays unpinned by design; the shim marks the runs that open it and those files are listed as UNPINNED with their verdicts. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/corpus_nonzero.txt | 39 ++++++ tools/phase2_corpus_diff.sh | 228 +++++++++++++++++++++++++------- 2 files changed, 220 insertions(+), 47 deletions(-) create mode 100644 tests/phase2/corpus_nonzero.txt diff --git a/tests/phase2/corpus_nonzero.txt b/tests/phase2/corpus_nonzero.txt new file mode 100644 index 000000000..92ad72d7a --- /dev/null +++ b/tests/phase2/corpus_nonzero.txt @@ -0,0 +1,39 @@ +# tests/phase2/corpus_nonzero.txt -- the corpus files whose BASELINE exits +# nonzero when run standalone under their run conditions, each with that exit +# code and the reason (#1758; tools/phase2_corpus_diff.sh). One row per file: +# +# An exit nobody declared is UNDECLARED-NONZERO, and a row whose file now +# exits otherwise is STALE: both fail the differential. A file with run +# conditions (tests/suite_program_env.txt) must complete and cannot be listed. +tests/_runaway_guard_selftest.eigs 124 the suite runner's runaway-guard self-test fixture: it never terminates, by design +tests/bool_fuzz_gen.eigs 1 a generator: tests/test_bool_fuzz.sh runs it with the binary's --api JSON as its argument +tests/embed_roads/eigs_modules/entrywrapper/entrywrapper.eigs 1 a fixture of the embed-roads host (tools/embed_roads.py), which registers host_scope_clean +tests/embed_roads/entry.eigs 1 a fixture of the embed-roads host (tools/embed_roads.py), which registers host_scope_clean +tests/embed_roads/helper/functions.eigs 1 a fixture of the embed-roads host (tools/embed_roads.py), which registers host_scope_clean +tests/embed_roads/helper/peer.eigs 1 a fixture of the embed-roads host (tools/embed_roads.py), which registers host_scope_clean +tests/embed_roads/import_entry.eigs 1 a fixture of the embed-roads host (tools/embed_roads.py), which registers host_scope_clean +tests/gfx_asan_corpus/06_rejected.eigs 1 a deliberate rejected gfx call: tests/test_asan_gfx.sh expects the raise +tests/line_after_callback_halt.eigs 1 a deliberate error: the suite's line-after-return rows check its trace (#1434) +tests/line_after_return_fn.eigs 1 a deliberate error: the suite's line-after-return rows check its trace +tests/line_after_return_module.eigs 1 a deliberate error: the suite's line-after-return rows check its trace +tests/line_after_return_null.eigs 1 a deliberate error: the suite's line-after-return rows check its trace +tests/loader_mt_modules/lm_cyc_a.eigs 1 a circular-load fixture of tests/test_loader_mt.sh: loaded alone, it reports the cycle +tests/loader_mt_modules/lm_cyc_b.eigs 1 a circular-load fixture of tests/test_loader_mt.sh: loaded alone, it reports the cycle +tests/roads/assets/eval_loaded/caller.eigs 1 a fixture of tools/road_diff.py: it runs inside a generated project tree +tests/roads/assets/hardlinks/b/child.eigs 1 a fixture of tools/road_diff.py: it runs inside a generated project tree +tests/roads/assets/hardlinks/b/entry.eigs 1 a fixture of tools/road_diff.py: it runs inside a generated project tree +tests/roads/assets/no_project/cwd_only.eigs 1 a fixture of tools/road_diff.py: it throws if a load falls back to the cwd +tests/roads/assets/no_project/parent.eigs 1 a fixture of tools/road_diff.py: it throws if a load falls back to the parent +tests/roads/assets/observer/assets/observer/target.eigs 1 a fixture of tools/road_diff.py: it runs inside a generated project tree +tests/roads/assets/observer/entry.eigs 1 a fixture of tools/road_diff.py: it runs inside a generated project tree +tests/task_deadlock.eigs 1 a deliberate deadlock: the suite's check_task_exit expects exit 1 naming it (#483, #509) +tests/task_deadlock_worker_try.eigs 1 a deliberate deadlock inside a worker's try: the suite's check_task_exit expects exit 1 +tests/task_exit_detached_death.eigs 1 a deliberate worker death: the suite's check_task_exit expects exit 1 (#530) +tests/task_exit_unjoined_death.eigs 1 a deliberate worker death: the suite's check_task_exit expects exit 1 +tests/test_assert_fail.eigs 1 a deliberate assert failure: the suite requires it to fail +tests/test_db.eigs 1 needs the server-db build (the release build has no database capability) +tests/test_http.eigs 1 needs the server build (the release build has no HTTP capability) +tests/test_inflate.eigs 1 needs the zlib build (make zlib) +tests/test_net.eigs 1 needs the server build (the release build has no network capability) +tests/tsan_worker_exit.eigs 5 a deliberate exit 5 from a worker: tests/test_tsan.sh expects rc 5 +tests/ui_native_input.eigs 1 a fixture of tests/ui_native_input.py, which sends it native window events; alone it reaches its deadline diff --git a/tools/phase2_corpus_diff.sh b/tools/phase2_corpus_diff.sh index d238f11f2..c78210b98 100755 --- a/tools/phase2_corpus_diff.sh +++ b/tools/phase2_corpus_diff.sh @@ -11,20 +11,40 @@ # stderr and the exit code are compared byte for byte after one # normalisation: each tree's absolute root becomes ``. # -# THE SEED PIN. The runtime has no seed flag or variable: an unseeded program -# seeds itself from CLOCK_MONOTONIC ^ getpid() (src/builtins.c, -# random_seed_once). An LD_PRELOAD shim, built here, pins every srand48 seed -# of 2^20 or more (the self-seed's range) to one constant and passes smaller -# ones (an explicit `seed_random of 99`) through. So a program that draws -# random numbers runs deterministically and LIVE in both binaries, and a -# branch change to a random builtin shows wherever the corpus observes it -# (test_optimize.eigs prints a genetic search driven by random_int; -# test_system.eigs checks random_int's bounds over 300 draws). The run checks -# its precondition first: two pinned `random` draws must agree, else the shim -# did not load and the run fails. That the pin is what makes such a file -# comparable live is calibrated once (phase2_check.py --selftest, plant D), -# not re-proven here. Blind spot: an explicit seed of 2^20 or more is pinned -# too, so a branch change in how `seed_random` uses such a seed is invisible. +# RUN CONDITIONS. Each file runs under its conditions from the ONE loader the +# suite, tools/jit_diff.sh and tools/replay_diff.sh use +# (tests/suite_program_env.sh, policy tests/suite_program_env.txt): a +# fail-soft test runs with EIGS_STRICT=0 as the suite runs it, instead of +# dying at its first strict raise on both binaries and comparing two early +# deaths (the R1.1 critic's plants C and B2 passed that way). A file with +# conditions must complete (rc 0) on both baseline runs, jit_diff's rule; if +# it does not it is INCOMPLETE, never compared, and the run fails. +# +# DECLARED NONZERO EXITS. A file whose baseline exits nonzero (the same code +# on both runs) compares little or nothing, so it must be declared with that +# code and a reason in tests/phase2/corpus_nonzero.txt (a deliberate error, a +# fixture of another host, a capability the release build lacks, the runaway +# guard's own fixture). An undeclared one is UNDECLARED-NONZERO, and a row +# whose file now exits otherwise is STALE: either fails the run. So a file +# that loses its run conditions, or a new test that dies early, is red here. +# Every declared file is listed with its code. +# +# THE SEED PIN. The runtime has no seed flag or variable. An LD_PRELOAD shim, +# built here, pins what the runtime seeds from the clock: +# - drand48 (random, random_int, random_normal, the samplers): the self-seed +# is srand48(ts.tv_sec ^ ts.tv_nsec ^ getpid()) from a CLOCK_MONOTONIC +# reading taken just before (src/builtins.c, random_seed_once). The shim +# records each thread's last CLOCK_MONOTONIC reading and pins an srand48 +# seed that equals that formula, whatever its value; a script's +# `seed_random of N` reaches srand48 unchanged (an explicit seed equal to +# the formula by chance would be pinned too). +# - libc rand() (audio_noise): main() seeds it with srand(time(NULL)); every +# srand call is pinned (main's are its only callers). +# random_hex reads /dev/urandom by design (cryptographic) and stays unpinned: +# the shim marks each run that opens /dev/urandom, and those files are listed +# as UNPINNED with their verdict. The run checks its precondition first: two +# pinned `random` draws must agree. That the pin makes a random file +# comparable live is calibrated once (phase2_check.py --selftest, plant D). # # VERDICTS. A file is DETERMINISTIC when the baseline's two runs agree; then # any branch run that disagrees is a DIFF row (no second chance: a branch @@ -37,7 +57,8 @@ # recorded nondeterministic values, so a builtin's own behaviour is # INVISIBLE on those files; the report lists them. Replays that disagree # with each other (the documented thread/subprocess boundary) are NONDET. -# A crash or timeout both binaries agree on is counted by name, never "same". +# A timeout (rc 124) or a crash (rc >= 128) that all four runs agree on is +# counted as timeout_both or crash_both, never as same. # # MEMORY. No blanket cap (a 2 GiB `ulimit -v` made handles_full.eigs's 300 # spawns fail at 134-214, which read as nondeterminism -- the R1.1 critic). @@ -47,12 +68,10 @@ # # A file only the branch tree has (a new fixture) is counted as `new`; a file # only the baseline tree has is a DELETED row (a deleted test hides a change). -# Prints `.. / s` per file, DIFF/DELETED rows, the -# replay, NONDET, crash and cap lists, then `corpus-diff: examined=N same=S -# same_under_replay=R nondet=K diff=D new=W deleted=X crash_both=C -# timeout_both=T capped=M` and `corpus-diff: PASS|FAIL`. Exit 0 only for -# diff=0 deleted=0, examined equal to the files listed (> 0), and a seed pin -# that proved itself. +# Prints `.. / s` per file, the named rows, then +# `corpus-diff: examined=N ...` and `corpus-diff: PASS|FAIL`. Exit 0 only for +# examined equal to the files listed (> 0), diff=0, deleted=0, incomplete=0, +# undeclared=0, stale=0, and a seed pin that proved itself. # # PHASE2_DIFF_FILES= restricts the corpus to the listed relative # paths, for the calibration (tools/phase2_check.sh --calibrate). A restricted @@ -68,6 +87,11 @@ BR_ROOT=$(cd "$(dirname "$BR_BIN")/.." && pwd -P) for b in "$BASE_BIN" "$BR_BIN"; do [ -x "$b" ] || { echo "corpus-diff: FAIL: $b is not executable"; exit 2; }; done command -v timeout >/dev/null 2>&1 || { echo "corpus-diff: FAIL: needs coreutils timeout (local tool)"; exit 2; } command -v cc >/dev/null 2>&1 || { echo "corpus-diff: FAIL: needs a C compiler for the seed pin"; exit 2; } +[ -f "$BR_ROOT/tests/suite_program_env.sh" ] || { echo "corpus-diff: FAIL: no run-condition loader in the branch tree"; exit 2; } +LEDGER="$BR_ROOT/tests/phase2/corpus_nonzero.txt" +[ -f "$LEDGER" ] || { echo "corpus-diff: FAIL: no ledger $LEDGER"; exit 2; } +export EIGS_TEST_DIR="$BR_ROOT/tests" +. "$BR_ROOT/tests/suite_program_env.sh" || { echo "corpus-diff: FAIL: the run-condition loader did not load"; exit 2; } TMP=$(mktemp -d "${TMPDIR:-/tmp}/eigs-corpus-diff.XXXXXX") || exit 2 DONE=0 trap 'rc=$?; [ "$DONE" = 1 ] || echo "corpus-diff: FAIL: exited ($rc) before a verdict, at: $BASH_COMMAND"; rm -rf "$TMP"' EXIT @@ -76,20 +100,52 @@ trap 'rc=$?; [ "$DONE" = 1 ] || echo "corpus-diff: FAIL: exited ($rc) before a v cat > "$TMP/seedpin.c" <<'CSRC' #define _GNU_SOURCE #include -/* phase2_corpus_diff.sh: pin the runtime's clock^pid self-seed (>= 2^20) to - * a constant; an explicit small seed passes through. */ +#include +#include +#include +#include +#include +#include +/* phase2_corpus_diff.sh's seed pin (the tool's header says what it pins). */ +static __thread struct timespec last_mono; +static __thread int have_mono; +int clock_gettime(clockid_t id, struct timespec *ts) { + static int (*real)(clockid_t, struct timespec *); + if (!real) real = (int (*)(clockid_t, struct timespec *))dlsym(RTLD_NEXT, "clock_gettime"); + int r = real(id, ts); + if (r == 0 && id == CLOCK_MONOTONIC) { last_mono = *ts; have_mono = 1; } + return r; +} void srand48(long seed) { static void (*real)(long); if (!real) real = (void (*)(long))dlsym(RTLD_NEXT, "srand48"); - real((seed >= (1L << 20) || seed < 0) ? 0x5EEDL : seed); + if (have_mono && seed == (long)(last_mono.tv_sec ^ last_mono.tv_nsec ^ (long)getpid())) seed = 0x5EEDL; + real(seed); +} +void srand(unsigned int seed) { + static void (*real)(unsigned int); + if (!real) real = (void (*)(unsigned int))dlsym(RTLD_NEXT, "srand"); + (void)seed; + real(0x5EEDu); +} +FILE *fopen(const char *path, const char *mode) { + static FILE *(*real)(const char *, const char *); + if (!real) real = (FILE *(*)(const char *, const char *))dlsym(RTLD_NEXT, "fopen"); + const char *mark = getenv("PHASE2_URANDOM_MARK"); + if (mark && path && strcmp(path, "/dev/urandom") == 0) { + int fd = open(mark, O_WRONLY | O_CREAT, 0644); + if (fd >= 0) close(fd); + } + return real(path, mode); } CSRC WERROR_FLAGS_FILE="$(dirname "$0")/werror_flags.txt" . "$(dirname "$0")/read_werror_flags.sh" 2>&1 || exit 2 # shellcheck disable=SC2086 # the shared flags are one word each -if ! cc $WERROR_FLAGS -shared -fPIC -O2 -o "$TMP/seedpin.so" "$TMP/seedpin.c" -ldl > "$TMP/seedpin.log" 2>&1; then +if ! cc -Wall -Wextra $WERROR_FLAGS -shared -fPIC -O2 -o "$TMP/seedpin.so" "$TMP/seedpin.c" -ldl > "$TMP/seedpin.log" 2>&1 \ + || [ -s "$TMP/seedpin.log" ]; then sed 's/^/ seedpin cc: /' "$TMP/seedpin.log" - echo "corpus-diff: FAIL: the seed pin did not build"; DONE=1; exit 1 + echo "corpus-diff: FAIL: the seed pin did not build cleanly"; DONE=1; exit 1 fi SHIM="$TMP/seedpin.so" printf 'print of (random of null)\n' > "$TMP/seedprobe.eigs" @@ -105,6 +161,31 @@ if [ -s "$TMP/probe1.err" ] || [ -s "$TMP/probe2.err" ] || ! grep -Eqx '[0-9]+([ DONE=1; exit 1 fi +# ---- the ledger of declared nonzero exits -------------------------------- +# A row: ` `; `#` lines and blank lines +# are prose. Any other line is refused by name (a whitelist, not a skip). +: > "$TMP/ledger" +lnum=0; ledger_bad=0 +while IFS= read -r line || [ -n "$line" ]; do + lnum=$((lnum + 1)) + case "$line" in ''|'#'*) continue ;; esac + lpath=${line%% *}; rest=${line#* }; lrc=${rest%% *}; why=${rest#* } + if ! grep -Eq '^tests/[A-Za-z0-9_./-]+[.]eigs$' <<< "$lpath" || ! grep -Eq '^[1-9][0-9]{0,2}$' <<< "$lrc" \ + || [ "$lrc" -gt 255 ] || [ "$why" = "$rest" ] || [ -z "$why" ]; then + echo "LEDGER-REFUSED corpus_nonzero.txt:$lnum: not ' ': $line" + ledger_bad=$((ledger_bad + 1)); continue + fi + if grep -q "^$lpath " "$TMP/ledger"; then + echo "LEDGER-REFUSED corpus_nonzero.txt:$lnum: $lpath declared twice"; ledger_bad=$((ledger_bad + 1)); continue + fi + if [ -n "$(suite_program_env "$lpath" 2>/dev/null)" ]; then + echo "LEDGER-REFUSED corpus_nonzero.txt:$lnum: $lpath has run conditions, so it must complete; it cannot be declared nonzero" + ledger_bad=$((ledger_bad + 1)); continue + fi + printf '%s %s\n' "$lpath" "$lrc" >> "$TMP/ledger" +done < "$LEDGER" +declared=$(grep -c . "$TMP/ledger") + # ---- the population ------------------------------------------------------ if [ -n "${PHASE2_DIFF_FILES:-}" ]; then LC_ALL=C sort "$PHASE2_DIFF_FILES" > "$TMP/files" @@ -118,12 +199,14 @@ listed=$(grep -c . "$TMP/files") [ "$listed" -gt 0 ] || { echo "corpus-diff: FAIL: no .eigs file to run"; DONE=1; exit 1; } echo "corpus-diff: baseline $BASE_BIN ($("$BASE_BIN" --version 2>&1 | head -1)) sha256 $(sha256sum "$BASE_BIN" | cut -c1-16)" echo "corpus-diff: branch $BR_BIN ($("$BR_BIN" --version 2>&1 | head -1)) sha256 $(sha256sum "$BR_BIN" | cut -c1-16)" -echo "corpus-diff: files=$listed${PHASE2_DIFF_FILES:+ (RESTRICTED by PHASE2_DIFF_FILES)}" +echo "corpus-diff: files=$listed declared_nonzero=$declared${PHASE2_DIFF_FILES:+ (RESTRICTED by PHASE2_DIFF_FILES)}" -# run BIN REL OUT CAP [VAR=value] -> OUT.out OUT.err OUT.rc, root paths -# normalised; CAP=1 runs under the GUI memory cap. +# run BIN REL OUT CAP [VAR=value] -> OUT.out OUT.err OUT.rc (and OUT.urandom +# when the run opened /dev/urandom), root paths normalised; CAP=1 runs under +# the GUI memory cap. The file's run conditions come from the shared loader. run() { local bin="$1" rel="$2" out="$3" cap="$4" extra="${5:-PHASE2_DIFF=1}" rc + rm -f "$out.urandom" # The run's stderr is its file. The brace group's 2>/dev/null takes only # bash's own report of a run killed by a signal ("line N: PID Aborted"), # which would otherwise reach this tool's stderr, where a gate refuses it. @@ -131,7 +214,8 @@ run() { ( cd "$BR_ROOT/src" || exit 99 [ "$cap" = 1 ] && ulimit -v 2097152 - exec env -u XAUTHORITY DISPLAY=:99 LD_PRELOAD="$SHIM" "$extra" timeout 60 "$bin" "../$rel" + suite_program_run "$rel" env -u XAUTHORITY DISPLAY=:99 LD_PRELOAD="$SHIM" \ + PHASE2_URANDOM_MARK="$out.urandom" "$extra" timeout 60 "$bin" "../$rel" ) < /dev/null > "$out.rawout" 2> "$out.rawerr" rc=$? } 2> /dev/null @@ -145,8 +229,9 @@ show_diff() { diff "$1.err" "$2.err" | head -8 | sed 's/^/ stderr: /' } -examined=0; nsame=0; nreplay=0; nondet=0; ndiff=0; new=0; crash_both=0; timeout_both=0; capped=0 -: > "$TMP/new"; : > "$TMP/nondet"; : > "$TMP/crash"; : > "$TMP/replayed"; : > "$TMP/capped" +examined=0; nsame=0; same_nonzero=0; nreplay=0; nondet=0; ndiff=0; new=0; crash_both=0; timeout_both=0 +capped=0; conditioned=0; incomplete=0; undeclared=0; stale=0; unpinned=0 +for f in new nondet crash replayed capped samenz urandom used; do : > "$TMP/$f"; done (cd "$BASE_ROOT" && find tests -name '*.eigs' -type f | LC_ALL=C sort) > "$TMP/basefiles" if [ -n "${PHASE2_DIFF_FILES:-}" ]; then : > "$TMP/deleted" @@ -155,6 +240,7 @@ else fi deleted=$(grep -c . "$TMP/deleted") sed 's/^/DELETED (in the baseline tree, not the branch): /' "$TMP/deleted" +took() { echo $(( $(date +%s) - t0 )); } # replay_adjudicate REL CAP: 0 same under replay, 1 a DIFF, 2 still NONDET replay_adjudicate() { rm -f "$TMP/tape" @@ -172,6 +258,11 @@ while IFS= read -r rel; do examined=$((examined + 1)) t0=$(date +%s) [ -f "$BASE_ROOT/$rel" ] || { new=$((new + 1)); echo "$rel" >> "$TMP/new"; } + if ! cond=$(suite_program_check "$rel" 2> "$TMP/cond.err"); then + sed 's/^/ /' "$TMP/cond.err" + echo "corpus-diff: FAIL: the run conditions of $rel were refused"; DONE=1; exit 1 + fi + [ -n "$cond" ] && conditioned=$((conditioned + 1)) cap=0 if grep -Eq '(gfx|ui|audio)_[a-z_]+' "$BR_ROOT/$rel"; then cap=1; capped=$((capped + 1)); echo "$rel" >> "$TMP/capped" @@ -180,50 +271,93 @@ while IFS= read -r rel; do run "$BASE_BIN" "$rel" "$TMP/b2" "$cap" run "$BR_BIN" "$rel" "$TMP/r1" "$cap" run "$BR_BIN" "$rel" "$TMP/r2" "$cap" + rb1=$(cat "$TMP/b1.rc"); rb2=$(cat "$TMP/b2.rc") + # The runs that opened /dev/urandom (random_hex): its values are live. + urand=0 + for a in b1 b2 r1 r2; do [ -e "$TMP/$a.urandom" ] && urand=1; done + # jit_diff's rule: a file with run conditions completes, or it is never compared. + if [ -n "$cond" ] && { [ "$rb1" != 0 ] || [ "$rb2" != 0 ]; }; then + incomplete=$((incomplete + 1)) + echo ".. $examined/$listed $rel INCOMPLETE $(took)s" + echo "INCOMPLETE $rel: the baseline exits $rb1/$rb2 under its run conditions ($cond); a file with conditions must complete (rc 0), so it was not compared" + sed -n '1,6p' "$TMP/b1.err" | sed 's/^/ baseline stderr: /' + continue + fi + # A nonzero exit the baseline repeats must be declared with that code. + if [ "$rb1" = "$rb2" ] && [ "$rb1" != 0 ]; then + want=$(awk -v p="$rel" '$1 == p { print $2 }' "$TMP/ledger") + if [ -z "$want" ]; then + undeclared=$((undeclared + 1)) + echo "UNDECLARED-NONZERO $rel rc=$rb1: the baseline exits $rb1 and tests/phase2/corpus_nonzero.txt does not declare it (an early exit compares nothing: give it run conditions in tests/suite_program_env.txt, or declare it with a reason)" + sed -n '1,4p' "$TMP/b1.err" | sed 's/^/ baseline stderr: /' + elif [ "$want" = "$rb1" ]; then + echo "$rel" >> "$TMP/used" + fi + fi if same "$TMP/b1" "$TMP/b2"; then if same "$TMP/b1" "$TMP/r1" && same "$TMP/b1" "$TMP/r2"; then - nsame=$((nsame + 1)) - rc=$(cat "$TMP/b1.rc") - if [ "$rc" -eq 124 ]; then timeout_both=$((timeout_both + 1)); echo "$rel rc=124" >> "$TMP/crash" - elif [ "$rc" -ge 128 ]; then crash_both=$((crash_both + 1)); echo "$rel rc=$rc" >> "$TMP/crash"; fi - echo ".. $examined/$listed $rel same rc=$rc $(( $(date +%s) - t0 ))s" + if [ "$rb1" -eq 124 ]; then + timeout_both=$((timeout_both + 1)); echo "$rel rc=124" >> "$TMP/crash"; verdict=timeout-both + elif [ "$rb1" -ge 128 ]; then + crash_both=$((crash_both + 1)); echo "$rel rc=$rb1" >> "$TMP/crash"; verdict=crash-both + else + nsame=$((nsame + 1)); verdict=same + if [ "$rb1" != 0 ]; then same_nonzero=$((same_nonzero + 1)); echo "$rel rc=$rb1" >> "$TMP/samenz"; fi + fi + echo ".. $examined/$listed $rel $verdict rc=$rb1 $(took)s" + [ "$urand" = 1 ] && echo "$rel $verdict" >> "$TMP/urandom" continue fi ndiff=$((ndiff + 1)) - echo ".. $examined/$listed $rel DIFF $(( $(date +%s) - t0 ))s" + echo ".. $examined/$listed $rel DIFF $(took)s" if same "$TMP/b1" "$TMP/r1"; then wrong=r2; else wrong=r1; fi - echo "DIFF $rel: the baseline is deterministic (two runs agree); branch run $wrong differs: rc baseline=$(cat "$TMP/b1.rc") branch=$(cat "$TMP/$wrong.rc")" + echo "DIFF $rel: the baseline is deterministic (two runs agree); branch run $wrong differs: rc baseline=$rb1 branch=$(cat "$TMP/$wrong.rc")" show_diff "$TMP/b1" "$TMP/$wrong" + [ "$urand" = 1 ] && echo "$rel DIFF" >> "$TMP/urandom" continue fi replay_adjudicate "$rel" "$cap"; ra=$? if [ "$ra" -eq 0 ]; then - nreplay=$((nreplay + 1)); echo "$rel" >> "$TMP/replayed" - echo ".. $examined/$listed $rel same-under-replay $(( $(date +%s) - t0 ))s" + nreplay=$((nreplay + 1)); echo "$rel" >> "$TMP/replayed"; verdict=same-under-replay + echo ".. $examined/$listed $rel same-under-replay $(took)s" elif [ "$ra" -eq 1 ]; then - ndiff=$((ndiff + 1)) - echo ".. $examined/$listed $rel DIFF-under-replay $(( $(date +%s) - t0 ))s" + ndiff=$((ndiff + 1)); verdict=DIFF-under-replay + echo ".. $examined/$listed $rel DIFF-under-replay $(took)s" echo "DIFF $rel: replaying the baseline's tape, rc baseline=$(cat "$TMP/p1.rc") branch=$(cat "$TMP/q1.rc")" show_diff "$TMP/p1" "$TMP/q1" else - nondet=$((nondet + 1)); echo "$rel" >> "$TMP/nondet" - echo ".. $examined/$listed $rel nondet $(( $(date +%s) - t0 ))s" + nondet=$((nondet + 1)); echo "$rel" >> "$TMP/nondet"; verdict=nondet + echo ".. $examined/$listed $rel nondet $(took)s" fi + [ "$urand" = 1 ] && echo "$rel $verdict" >> "$TMP/urandom" done < "$TMP/files" +# A declared row must be examined and must still exit with its code. +while IFS=' ' read -r lpath lrc; do + if ! grep -qxF "$lpath" "$TMP/files"; then + [ -n "${PHASE2_DIFF_FILES:-}" ] && continue + stale=$((stale + 1)); echo "STALE $lpath: declared rc=$lrc in tests/phase2/corpus_nonzero.txt, but no such corpus file was examined" + elif ! grep -qxF "$lpath" "$TMP/used"; then + stale=$((stale + 1)); echo "STALE $lpath: declared rc=$lrc in tests/phase2/corpus_nonzero.txt, but the baseline does not exit with it (correct or remove the row)" + fi +done < "$TMP/ledger" +unpinned=$(grep -c . "$TMP/urandom") sed 's/^/NEW (only the branch tree has it) /' "$TMP/new" sed 's/^/REPLAYED (compared on the baseline tape; its nondeterministic builtins did not run live) /' "$TMP/replayed" sed 's/^/NONDET (the baseline disagrees with itself, and its tape replays too) /' "$TMP/nondet" sed 's/^/BOTH-CRASH-OR-TIMEOUT /' "$TMP/crash" +sed 's/^/SAME-NONZERO (declared: both binaries exit so; compared up to the exit) /' "$TMP/samenz" +sed 's/^/UNPINNED (opened \/dev\/urandom: random_hex values are live, by design) /' "$TMP/urandom" sed 's/^/CAPPED (gfx\/ui\/audio: ulimit -v 2097152) /' "$TMP/capped" -summary="examined=$examined same=$nsame same_under_replay=$nreplay nondet=$nondet diff=$ndiff new=$new deleted=$deleted crash_both=$crash_both timeout_both=$timeout_both capped=$capped" +summary="examined=$examined same=$nsame same_nonzero=$same_nonzero same_under_replay=$nreplay nondet=$nondet diff=$ndiff new=$new deleted=$deleted crash_both=$crash_both timeout_both=$timeout_both conditioned=$conditioned incomplete=$incomplete undeclared=$undeclared stale=$stale ledger_refused=$ledger_bad unpinned=$unpinned capped=$capped" DONE=1 if [ -n "${PHASE2_DIFF_FILES:-}" ]; then echo "corpus-diff: RESTRICTED $summary" exit 3 fi echo "corpus-diff: $summary" -if [ "$examined" -eq "$listed" ] && [ "$examined" -gt 0 ] && [ "$ndiff" -eq 0 ] && [ "$deleted" -eq 0 ]; then +if [ "$examined" -eq "$listed" ] && [ "$examined" -gt 0 ] && [ "$ndiff" -eq 0 ] && [ "$deleted" -eq 0 ] \ + && [ "$incomplete" -eq 0 ] && [ "$undeclared" -eq 0 ] && [ "$stale" -eq 0 ] && [ "$ledger_bad" -eq 0 ]; then echo "corpus-diff: PASS"; exit 0 fi echo "corpus-diff: FAIL"; exit 1 From 348ab6a64df6aca183b64e9d196fc7b34881ebd3 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 05:21:31 -0500 Subject: [PATCH 014/188] phase2 checker: the inventory's verdict gated, the inventory fresh, new plants (#1758) Nothing ran tools/phase2_inventory.py's verdict, so a slot classifier with no reviewed disposition row passed `phase2_check.sh --through R1.1`, and the committed docs/design/phase2-inventory.txt had gone stale (it still showed the four refusing arms as `guarded` and 98 dispositions). - phase2_inventory.py --check writes nothing and fails when the committed file differs from the generated text; the file is regenerated. - phase2_check runs two gates in every mode: the token gate (which the design already said ran in every mode, but ran only in the mechanical rounds) and the inventory gate (`--check` under -W error; PASS only for rc 0, no stderr and a last line `phase2-inventory: PASS`). - The calibration adds: plants C and B2 (built from HEAD, the second on the smi-trap build), each of which must make the differential name a conditioned file DIFF; a removed policy row (UNDECLARED-NONZERO); a ledger row for a completing file (STALE); a conditioned file that does not complete (INCOMPLETE); the unplanted branch with conditioned files (all same); and the inventory gate on an unchanged copy, a stale committed copy, and the critic's `vm.c:critic_new_reader`. - The design doc's claims about the seed pin, #1775's fix, the token gate and the differential are corrected. Closes #1804 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 741 ++++++++++++++++--------------- docs/design/phase2-numbers.md | 74 ++- tools/phase2_check.py | 159 ++++++- tools/phase2_inventory.py | 19 +- tools/selftests.txt | 2 +- 5 files changed, 599 insertions(+), 396 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index b16fc0303..dadd9de10 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,15 +1,15 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1818 classified=1818 unclassified=0 -files=64 tokens=43 role_rules=8 derived_accessors=18 wrappers=7 +examined=1826 classified=1826 unclassified=0 +files=65 tokens=43 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 394 CASE=52 DATA=3 TEST=337 YIELD=2 +(a) type tests 399 CASE=52 DATA=3 TEST=342 YIELD=2 (b) payload reads 534 RAW=119 READ=415 (c) producers 469 GUARD=71 PARSE=3 PRODUCE=370 TAGSET=3 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 16 CASE=1 FORMAT=3 PARSE=1 RAW=2 READ=3 TEST=6 -(f) equality, ordering and hashing 27 CASE=1 PRODUCE=4 RAW=5 READ=9 TEST=8 +(f) equality, ordering and hashing 30 CASE=1 PRODUCE=4 RAW=5 READ=9 TEST=11 (g) tape encode and decode 21 CASE=2 DATA=2 PARSE=7 PRODUCE=5 RAW=3 TEST=2 (h) JSON, store and db encoders 72 CASE=2 FORMAT=3 PARSE=5 PRODUCE=19 RAW=1 READ=24 TEST=18 (i) observer numeric paths 94 CASE=4 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=5 TEST=24 @@ -29,7 +29,7 @@ slot_is_f64 50 eigs_value_as_num 48 slot_from_f64 41 buffer_read_num 38 -slot_is_smi 29 +slot_is_smi 37 buffer_read_byte 22 list_set_num 22 slot_smi_val 17 @@ -65,7 +65,7 @@ data.num (AST) 7 ## Per file (category counts) builtins.c 319 a=74 b=94 c=111 e=6 f=8 h=15 i=11 -vm.c 288 a=72 b=97 c=68 e=2 f=6 i=43 +vm.c 296 a=77 b=97 c=68 e=2 f=9 i=43 ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 184 a=39 b=59 c=86 builtins_buf.c 97 a=21 b=37 c=39 @@ -184,7 +184,7 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=56 D2=19 D3=23 T=67 dispositions=98 missing=0 stale=0 +D1=56 D2=19 D3=24 T=67 dispositions=99 missing=0 stale=0 D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 @@ -212,8 +212,8 @@ D1 value_slot.h:slot_is_smi smi-arm SLOT_TAG_MASK=1 T D1 value_slot.h:slot_smi_val smi-arm SLOT_PAYLOAD_MASK=1 SLOT_SMI_SIGN=2 slot_smi_val=1 D1 value_slot.h:slot_truthy_immediate smi-arm SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 slot_is_f64=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:#define ARITH_FAST guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 -D1 vm.c:#define INT_BINOP_R guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 -D1 vm.c:#define NUM_CMP guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 +D1 vm.c:#define INT_BINOP_R unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_is_smi=3 +D1 vm.c:#define NUM_CMP unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_is_smi=3 D1 vm.c:#define READ_SLICE_BOUND smi-arm slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:jit_helper_dot_set guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:jit_helper_index_get guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 @@ -229,7 +229,7 @@ D1 vm.c:slot_truthy smi-arm slot_as_ptr=1 slo D1 vm.c:slot_type_name smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL guarded slot_f64_value=2 D1 vm.c:vm_leaf_accessor_exec/OP_INDEX_GET guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(BNOT) guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(BNOT) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_run_ex/CASE(DISPATCH) smi-arm slot_as_ptr=4 slot_is_f64=1 slot_is_ptr=2 slot_is_smi=1 slot_smi_val=1 D1 vm.c:vm_run_ex/CASE(DOT_SET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(EQ) guarded slot_f64_value=2 @@ -238,7 +238,7 @@ D1 vm.c:vm_run_ex/CASE(INDEX_SET) guarded slot_as_ptr=1 slo D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(NE) guarded slot_f64_value=2 -D1 vm.c:vm_run_ex/CASE(NEG) guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(NEG) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_slot_lift smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_store_local_slot guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 D2 builtins.c:bool_gate_name guarded slot_as_ptr=1 slot_is_ptr=1 @@ -266,6 +266,7 @@ D3 jit.c:jit_compile_to_thunk/OP_NEG not-a-classifier SLOT_FALSE_BITS=1 D3 jit.c:jit_compile_to_thunk/OP_NULL not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 D3 jit_smoke.c:run_bool_cases not-a-classifier SLOT_FALSE_BITS=2 SLOT_TRUE_BITS=3 D3 jit_smoke.c:run_index_bail_cases guarded slot_is_null=1 +D3 value_slot.h:#define SLOT_SMI_TRAP refuse SLOT_TAG_MASK=1 TAG_SMI=1 D3 value_slot.h:slot_decref guarded SLOT_PAYLOAD_MASK=1 SLOT_QNAN_MASK=2 SLOT_TAG_MASK=1 TAG_HEAP=1 D3 value_slot.h:slot_false not-a-classifier SLOT_FALSE_BITS=1 D3 value_slot.h:slot_from_bool not-a-classifier TAG_BOOL=1 @@ -1100,74 +1101,74 @@ builtins_tensor.c:1569 builtin_tensor_gather eigs_num_arg READ b builtins_tensor.c:1575 builtin_tensor_gather eigs_slot_elem_num READ b builtins_tensor.c:1577 builtin_tensor_gather make_num PRODUCE c builtins_tensor.c:1586 builtin_tensor_gather make_num PRODUCE c -builtins_tensor.c:1686 builtin_random_normal eigs_list_num READ b -builtins_tensor.c:1687 builtin_random_normal eigs_list_num READ b builtins_tensor.c:1688 builtin_random_normal eigs_list_num READ b -builtins_tensor.c:1698 builtin_random_normal make_num PRODUCE c -builtins_tensor.c:1706 builtin_random_normal eigs_list_num READ b -builtins_tensor.c:1707 builtin_random_normal eigs_list_num READ b -builtins_tensor.c:1713 builtin_random_normal make_num PRODUCE c -builtins_tensor.c:1724 builtin_tensor_shape VAL_NUM TEST a -builtins_tensor.c:1732 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1733 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1737 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1743 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1751 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1752 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1757 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1766 numerical_loss VAL_NUM TEST a -builtins_tensor.c:1767 numerical_loss eigs_num_arg READ b -builtins_tensor.c:1802 tensor_cells_numeric VAL_NUM TEST a -builtins_tensor.c:1803 tensor_cells_numeric eigs_slot_num READ b -builtins_tensor.c:1806 tensor_cells_numeric VAL_NUM TEST a -builtins_tensor.c:1807 tensor_cells_numeric eigs_slot_num READ b -builtins_tensor.c:1824 builtin_numerical_grad eigs_slot_opt_num READ b -builtins_tensor.c:1860 builtin_numerical_grad eigs_slot_num READ b -builtins_tensor.c:1861 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1689 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1690 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1700 builtin_random_normal make_num PRODUCE c +builtins_tensor.c:1708 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1709 builtin_random_normal eigs_list_num READ b +builtins_tensor.c:1715 builtin_random_normal make_num PRODUCE c +builtins_tensor.c:1726 builtin_tensor_shape VAL_NUM TEST a +builtins_tensor.c:1734 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1735 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1739 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1745 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1753 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1754 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1759 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1768 numerical_loss VAL_NUM TEST a +builtins_tensor.c:1769 numerical_loss eigs_num_arg READ b +builtins_tensor.c:1804 tensor_cells_numeric VAL_NUM TEST a +builtins_tensor.c:1805 tensor_cells_numeric eigs_slot_num READ b +builtins_tensor.c:1808 tensor_cells_numeric VAL_NUM TEST a +builtins_tensor.c:1809 tensor_cells_numeric eigs_slot_num READ b +builtins_tensor.c:1826 builtin_numerical_grad eigs_slot_opt_num READ b +builtins_tensor.c:1862 builtin_numerical_grad eigs_slot_num READ b builtins_tensor.c:1863 builtin_numerical_grad list_set_num PRODUCE c builtins_tensor.c:1865 builtin_numerical_grad list_set_num PRODUCE c -builtins_tensor.c:1867 builtin_numerical_grad make_num PRODUCE c -builtins_tensor.c:1883 builtin_numerical_grad eigs_slot_num READ b -builtins_tensor.c:1884 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1867 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1869 builtin_numerical_grad make_num PRODUCE c +builtins_tensor.c:1885 builtin_numerical_grad eigs_slot_num READ b builtins_tensor.c:1886 builtin_numerical_grad list_set_num PRODUCE c builtins_tensor.c:1888 builtin_numerical_grad list_set_num PRODUCE c -builtins_tensor.c:1889 builtin_numerical_grad make_num PRODUCE c -builtins_tensor.c:1910 builtin_sgd_update eigs_slot_opt_num READ b -builtins_tensor.c:1931 builtin_sgd_update eigs_slot_num READ b -builtins_tensor.c:1932 builtin_sgd_update eigs_slot_num READ b -builtins_tensor.c:1933 builtin_sgd_update list_set_num PRODUCE c -builtins_tensor.c:1946 builtin_sgd_update eigs_slot_num READ b -builtins_tensor.c:1947 builtin_sgd_update eigs_slot_num READ b -builtins_tensor.c:1948 builtin_sgd_update list_set_num PRODUCE c -builtins_tensor.c:1972 builtin_numerical_grad_rows eigs_slot_opt_num READ b -builtins_tensor.c:2023 builtin_numerical_grad_rows make_num PRODUCE c -builtins_tensor.c:2042 builtin_numerical_grad_rows eigs_slot_num READ b -builtins_tensor.c:2043 builtin_numerical_grad_rows list_set_num PRODUCE c +builtins_tensor.c:1890 builtin_numerical_grad list_set_num PRODUCE c +builtins_tensor.c:1891 builtin_numerical_grad make_num PRODUCE c +builtins_tensor.c:1912 builtin_sgd_update eigs_slot_opt_num READ b +builtins_tensor.c:1933 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1934 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1935 builtin_sgd_update list_set_num PRODUCE c +builtins_tensor.c:1948 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1949 builtin_sgd_update eigs_slot_num READ b +builtins_tensor.c:1950 builtin_sgd_update list_set_num PRODUCE c +builtins_tensor.c:1974 builtin_numerical_grad_rows eigs_slot_opt_num READ b +builtins_tensor.c:2025 builtin_numerical_grad_rows make_num PRODUCE c +builtins_tensor.c:2044 builtin_numerical_grad_rows eigs_slot_num READ b builtins_tensor.c:2045 builtin_numerical_grad_rows list_set_num PRODUCE c builtins_tensor.c:2047 builtin_numerical_grad_rows list_set_num PRODUCE c builtins_tensor.c:2049 builtin_numerical_grad_rows list_set_num PRODUCE c -builtins_tensor.c:2072 builtin_sgd_update_rows eigs_slot_opt_num READ b -builtins_tensor.c:2109 builtin_sgd_update_rows eigs_slot_num READ b -builtins_tensor.c:2110 builtin_sgd_update_rows eigs_slot_num READ b -builtins_tensor.c:2111 builtin_sgd_update_rows list_set_num PRODUCE c -builtins_tensor.c:2134 builtin_numerical_grad_cols eigs_slot_opt_num READ b -builtins_tensor.c:2183 builtin_numerical_grad_cols make_num PRODUCE c -builtins_tensor.c:2201 builtin_numerical_grad_cols eigs_slot_num READ b -builtins_tensor.c:2203 builtin_numerical_grad_cols list_set_num PRODUCE c -builtins_tensor.c:2206 builtin_numerical_grad_cols list_set_num PRODUCE c -builtins_tensor.c:2209 builtin_numerical_grad_cols list_set_num PRODUCE c -builtins_tensor.c:2212 builtin_numerical_grad_cols list_set_num PRODUCE c -builtins_tensor.c:2235 builtin_sgd_update_cols eigs_slot_opt_num READ b -builtins_tensor.c:2273 builtin_sgd_update_cols eigs_slot_num READ b -builtins_tensor.c:2274 builtin_sgd_update_cols eigs_slot_num READ b -builtins_tensor.c:2275 builtin_sgd_update_cols list_set_num PRODUCE c -builtins_tensor.c:2385 tensor_load_record_verdict make_num PRODUCE c -builtins_tensor.c:2386 tensor_load_record_verdict make_num PRODUCE c -builtins_tensor.c:2403 builtin_tensor_load VAL_NUM TEST a -builtins_tensor.c:2404 builtin_tensor_load VAL_NUM TEST a -builtins_tensor.c:2405 builtin_tensor_load eigs_list_num READ b -builtins_tensor.c:2406 builtin_tensor_load eigs_list_num READ b -builtins_tensor.c:2483 builtin_tensor_load num_guard_named GUARD c +builtins_tensor.c:2051 builtin_numerical_grad_rows list_set_num PRODUCE c +builtins_tensor.c:2074 builtin_sgd_update_rows eigs_slot_opt_num READ b +builtins_tensor.c:2111 builtin_sgd_update_rows eigs_slot_num READ b +builtins_tensor.c:2112 builtin_sgd_update_rows eigs_slot_num READ b +builtins_tensor.c:2113 builtin_sgd_update_rows list_set_num PRODUCE c +builtins_tensor.c:2136 builtin_numerical_grad_cols eigs_slot_opt_num READ b +builtins_tensor.c:2185 builtin_numerical_grad_cols make_num PRODUCE c +builtins_tensor.c:2203 builtin_numerical_grad_cols eigs_slot_num READ b +builtins_tensor.c:2205 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2208 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2211 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2214 builtin_numerical_grad_cols list_set_num PRODUCE c +builtins_tensor.c:2237 builtin_sgd_update_cols eigs_slot_opt_num READ b +builtins_tensor.c:2275 builtin_sgd_update_cols eigs_slot_num READ b +builtins_tensor.c:2276 builtin_sgd_update_cols eigs_slot_num READ b +builtins_tensor.c:2277 builtin_sgd_update_cols list_set_num PRODUCE c +builtins_tensor.c:2387 tensor_load_record_verdict make_num PRODUCE c +builtins_tensor.c:2388 tensor_load_record_verdict make_num PRODUCE c +builtins_tensor.c:2405 builtin_tensor_load VAL_NUM TEST a +builtins_tensor.c:2406 builtin_tensor_load VAL_NUM TEST a +builtins_tensor.c:2407 builtin_tensor_load eigs_list_num READ b +builtins_tensor.c:2408 builtin_tensor_load eigs_list_num READ b +builtins_tensor.c:2485 builtin_tensor_load num_guard_named GUARD c chunk.c:194 const_hash_value VAL_NUM TEST f chunk.c:195 const_hash_value VAL_NUM_RAW RAW f chunk.c:213 const_equal VAL_NUM TEST f @@ -1356,29 +1357,29 @@ eigenscript.c:1897 slot_to_value SLOT_F64_RAW RAW b eigenscript.c:1897 slot_to_value make_num PRODUCE c eigenscript.c:1897 slot_to_value slot_is_f64 TEST a eigenscript.c:1905 slot_to_value slot_is_smi TEST a -eigenscript.c:2405 module_ns_project slot_is_f64 TEST a -eigenscript.c:2405 module_ns_project slot_is_f64 TEST a -eigenscript.c:2410 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2410 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2655 chan_clone_rec VAL_NUM TEST a -eigenscript.c:2658 chan_clone_rec VAL_NUM CASE a -eigenscript.c:2658 chan_clone_rec VAL_NUM_RAW RAW b -eigenscript.c:2658 chan_clone_rec make_num PRODUCE c -eigenscript.c:2846 is_truthy VAL_NUM CASE a -eigenscript.c:2846 is_truthy VAL_NUM_RAW RAW b +eigenscript.c:2404 module_ns_project slot_is_f64 TEST a +eigenscript.c:2404 module_ns_project slot_is_f64 TEST a +eigenscript.c:2409 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2409 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2654 chan_clone_rec VAL_NUM TEST a +eigenscript.c:2657 chan_clone_rec VAL_NUM CASE a +eigenscript.c:2657 chan_clone_rec VAL_NUM_RAW RAW b +eigenscript.c:2657 chan_clone_rec make_num PRODUCE c +eigenscript.c:2845 is_truthy VAL_NUM CASE a +eigenscript.c:2845 is_truthy VAL_NUM_RAW RAW b +eigenscript.c:2881 values_equal_impl VAL_NUM TEST f eigenscript.c:2882 values_equal_impl VAL_NUM TEST f -eigenscript.c:2883 values_equal_impl VAL_NUM TEST f -eigenscript.c:2897 values_equal_impl VAL_NUM CASE f -eigenscript.c:2897 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2897 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2927 values_equal_impl buffer_read_num READ f -eigenscript.c:2929 values_equal_impl buffer_read_num READ f -eigenscript.c:2965 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:2980 eigs_num_text strtod PARSE e -eigenscript.c:2990 value_to_string VAL_NUM CASE e -eigenscript.c:2991 value_to_string VAL_NUM_RAW RAW e -eigenscript.c:2991 value_to_string eigs_num_text FORMAT e -eigenscript.c:4213 gc_value_is_node VAL_NUM CASE a +eigenscript.c:2896 values_equal_impl VAL_NUM CASE f +eigenscript.c:2896 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2896 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2926 values_equal_impl buffer_read_num READ f +eigenscript.c:2928 values_equal_impl buffer_read_num READ f +eigenscript.c:2964 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:2979 eigs_num_text strtod PARSE e +eigenscript.c:2989 value_to_string VAL_NUM CASE e +eigenscript.c:2990 value_to_string VAL_NUM_RAW RAW e +eigenscript.c:2990 value_to_string eigs_num_text FORMAT e +eigenscript.c:4212 gc_value_is_node VAL_NUM CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a eigenscript.h:270 VAL_NUM DATA a @@ -2031,26 +2032,26 @@ trace.c:2837 write_slot slot_is_f64 TEST g trace.c:2844 write_slot slot_is_smi TEST g trace.c:2958 write_value_ptr_full VAL_NUM CASE g trace.c:2958 write_value_ptr_full VAL_NUM_RAW RAW g -value_slot.h:89 slot_is_f64 slot_is_f64 TEST a -value_slot.h:94 slot_is_smi slot_is_smi TEST a -value_slot.h:105 #define SLOT_F64_RAW SLOT_F64_RAW RAW b -value_slot.h:105 #define SLOT_F64_RAW d_ RAW b -value_slot.h:116 slot_smi_val slot_smi_val RAW b -value_slot.h:123 slot_from_f64 SLOT_F64_RAW WRITE c -value_slot.h:123 slot_from_f64 slot_from_f64 PRODUCE c -value_slot.h:128 slot_from_int slot_from_int PRODUCE c -value_slot.h:202 slot_truthy_immediate SLOT_F64_RAW RAW b -value_slot.h:202 slot_truthy_immediate slot_is_f64 TEST a -value_slot.h:205 slot_truthy_immediate slot_is_smi TEST a -value_slot.h:205 slot_truthy_immediate slot_smi_val RAW b -value_slot.h:214 slot_f64_value slot_f64_value READ b -value_slot.h:215 slot_f64_value SLOT_F64_RAW RAW b -value_slot.h:215 slot_f64_value slot_is_f64 TEST a -value_slot.h:218 slot_f64_value VAL_NUM TEST a -value_slot.h:218 slot_f64_value VAL_NUM_RAW RAW b -value_slot.h:224 slot_int_value slot_int_value READ b -value_slot.h:225 slot_int_value slot_is_smi TEST a -value_slot.h:225 slot_int_value slot_smi_val RAW b +value_slot.h:106 slot_is_f64 slot_is_f64 TEST a +value_slot.h:112 slot_is_smi slot_is_smi TEST a +value_slot.h:123 #define SLOT_F64_RAW SLOT_F64_RAW RAW b +value_slot.h:123 #define SLOT_F64_RAW d_ RAW b +value_slot.h:135 slot_smi_val slot_smi_val RAW b +value_slot.h:143 slot_from_f64 SLOT_F64_RAW WRITE c +value_slot.h:143 slot_from_f64 slot_from_f64 PRODUCE c +value_slot.h:148 slot_from_int slot_from_int PRODUCE c +value_slot.h:227 slot_truthy_immediate SLOT_F64_RAW RAW b +value_slot.h:227 slot_truthy_immediate slot_is_f64 TEST a +value_slot.h:230 slot_truthy_immediate slot_is_smi TEST a +value_slot.h:230 slot_truthy_immediate slot_smi_val RAW b +value_slot.h:243 slot_f64_value slot_f64_value READ b +value_slot.h:244 slot_f64_value SLOT_F64_RAW RAW b +value_slot.h:244 slot_f64_value slot_is_f64 TEST a +value_slot.h:247 slot_f64_value VAL_NUM TEST a +value_slot.h:247 slot_f64_value VAL_NUM_RAW RAW b +value_slot.h:254 slot_int_value slot_int_value READ b +value_slot.h:255 slot_int_value slot_is_smi TEST a +value_slot.h:255 slot_int_value slot_smi_val RAW b vm.c:107 obs_dump_num eigs_num_text FORMAT i vm.c:118 obs_dump_value SLOT_F64_RAW RAW i vm.c:118 obs_dump_value slot_is_f64 TEST i @@ -2075,267 +2076,275 @@ vm.c:872 slot_truthy SLOT_F64_RAW RAW b vm.c:872 slot_truthy slot_is_f64 TEST a vm.c:876 slot_truthy slot_is_smi TEST a vm.c:876 slot_truthy slot_smi_val RAW b -vm.c:931 make_iter_state make_num PRODUCE c -vm.c:944 make_iter_state make_num PRODUCE c -vm.c:1163 vm_store_local_slot slot_is_f64 TEST a -vm.c:1167 vm_store_local_slot VAL_NUM TEST a -vm.c:1169 vm_store_local_slot SLOT_F64_RAW RAW b -vm.c:1169 vm_store_local_slot VAL_NUM_RAW WRITE c -vm.c:1360 jit_helper_local_idx_get buffer_read_num READ b -vm.c:1360 jit_helper_local_idx_get slot_from_f64 PRODUCE c -vm.c:1521 jit_helper_dot_set slot_is_f64 TEST a -vm.c:1524 jit_helper_dot_set SLOT_F64_RAW RAW b -vm.c:1591 jit_helper_local_dot_set slot_is_f64 TEST a -vm.c:1592 jit_helper_local_dot_set SLOT_F64_RAW RAW b -vm.c:1642 obs_slot_observable slot_is_f64 TEST i -vm.c:1649 obs_slot_num SLOT_F64_RAW RAW i -vm.c:1649 obs_slot_num slot_is_f64 TEST i -vm.c:1650 obs_slot_num slot_is_smi TEST i -vm.c:1650 obs_slot_num slot_smi_val RAW i -vm.c:1797 jit_helper_iter_next VAL_NUM TEST a -vm.c:1798 jit_helper_iter_next eigs_slot_num READ b -vm.c:1808 jit_helper_iter_next VAL_NUM TEST a -vm.c:1809 jit_helper_iter_next VAL_NUM_RAW RAW b -vm.c:1816 jit_helper_iter_next buffer_read_num READ b -vm.c:1816 jit_helper_iter_next num_guard GUARD c -vm.c:1816 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1822 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1892 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b -vm.c:1892 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1896 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1899 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1938 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1952 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1952 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:1963 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1964 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1982 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:1982 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2065 loop_iter_store make_num PRODUCE c -vm.c:2072 loop_iter_store slot_is_f64 TEST a -vm.c:2073 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2078 loop_iter_store make_num PRODUCE c -vm.c:2200 jit_helper_index_set slot_is_f64 TEST a -vm.c:2202 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2203 jit_helper_index_set slot_is_f64 TEST a -vm.c:2205 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2207 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2217 jit_helper_index_set slot_is_f64 TEST a -vm.c:2219 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2220 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2222 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2234 jit_helper_index_set VAL_NUM TEST a -vm.c:2236 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2237 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2244 jit_helper_index_set VAL_NUM TEST a -vm.c:2246 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2247 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2250 jit_helper_index_set VAL_NUM TEST a +vm.c:933 make_iter_state make_num PRODUCE c +vm.c:946 make_iter_state make_num PRODUCE c +vm.c:1165 vm_store_local_slot slot_is_f64 TEST a +vm.c:1169 vm_store_local_slot VAL_NUM TEST a +vm.c:1171 vm_store_local_slot SLOT_F64_RAW RAW b +vm.c:1171 vm_store_local_slot VAL_NUM_RAW WRITE c +vm.c:1362 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1362 jit_helper_local_idx_get slot_from_f64 PRODUCE c +vm.c:1523 jit_helper_dot_set slot_is_f64 TEST a +vm.c:1526 jit_helper_dot_set SLOT_F64_RAW RAW b +vm.c:1593 jit_helper_local_dot_set slot_is_f64 TEST a +vm.c:1594 jit_helper_local_dot_set SLOT_F64_RAW RAW b +vm.c:1644 obs_slot_observable slot_is_f64 TEST i +vm.c:1651 obs_slot_num SLOT_F64_RAW RAW i +vm.c:1651 obs_slot_num slot_is_f64 TEST i +vm.c:1652 obs_slot_num slot_is_smi TEST i +vm.c:1652 obs_slot_num slot_smi_val RAW i +vm.c:1799 jit_helper_iter_next VAL_NUM TEST a +vm.c:1800 jit_helper_iter_next eigs_slot_num READ b +vm.c:1810 jit_helper_iter_next VAL_NUM TEST a +vm.c:1811 jit_helper_iter_next VAL_NUM_RAW RAW b +vm.c:1818 jit_helper_iter_next buffer_read_num READ b +vm.c:1818 jit_helper_iter_next num_guard GUARD c +vm.c:1818 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1824 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1896 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b +vm.c:1896 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1900 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1903 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1942 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:1956 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1956 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:1967 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1968 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1986 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:1986 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2069 loop_iter_store make_num PRODUCE c +vm.c:2076 loop_iter_store slot_is_f64 TEST a +vm.c:2077 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2082 loop_iter_store make_num PRODUCE c +vm.c:2204 jit_helper_index_set slot_is_f64 TEST a +vm.c:2206 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2207 jit_helper_index_set slot_is_f64 TEST a +vm.c:2209 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2211 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2221 jit_helper_index_set slot_is_f64 TEST a +vm.c:2223 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2224 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2226 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2238 jit_helper_index_set VAL_NUM TEST a +vm.c:2240 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2241 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2248 jit_helper_index_set VAL_NUM TEST a +vm.c:2250 jit_helper_index_set VAL_NUM_RAW RAW b vm.c:2251 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2270 jit_helper_index_get slot_is_f64 TEST a -vm.c:2272 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2279 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2290 jit_helper_index_get buffer_read_num READ b -vm.c:2292 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2294 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2310 jit_helper_index_get VAL_NUM TEST a -vm.c:2312 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2313 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2325 jit_helper_index_get VAL_NUM TEST a -vm.c:2327 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2328 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2337 jit_helper_index_get VAL_NUM TEST a -vm.c:2339 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2340 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2342 jit_helper_index_get buffer_read_num READ b -vm.c:2342 jit_helper_index_get make_num PRODUCE c -vm.c:2928 vm_take_error_value make_num PRODUCE c -vm.c:3032 slot_type_name slot_is_f64 TEST e -vm.c:3033 slot_type_name slot_is_smi TEST e -vm.c:3273 vm_run_ex/CASE(CONST) VAL_NUM TEST a -vm.c:3274 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b -vm.c:3274 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3288 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3293 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3313 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3313 #define NUM_REUSE VAL_NUM TEST a -vm.c:3324 #define ARITH_FAST slot_f64_value READ b -vm.c:3324 #define ARITH_FAST slot_f64_value READ b -vm.c:3325 #define ARITH_FAST num_guard GUARD c -vm.c:3330 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3331 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3339 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3340 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3348 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3358 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3358 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3359 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3359 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3359 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3360 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3360 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3361 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3361 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3362 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3411 #define NUM_BINOP VAL_NUM TEST a -vm.c:3411 #define NUM_BINOP VAL_NUM TEST a -vm.c:3412 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3412 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3412 #define NUM_BINOP num_guard GUARD c -vm.c:3413 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3413 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3415 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3415 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3416 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3416 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3417 #define NUM_BINOP make_num PRODUCE c +vm.c:2254 jit_helper_index_set VAL_NUM TEST a +vm.c:2255 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2274 jit_helper_index_get slot_is_f64 TEST a +vm.c:2276 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2283 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2294 jit_helper_index_get buffer_read_num READ b +vm.c:2296 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2298 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2314 jit_helper_index_get VAL_NUM TEST a +vm.c:2316 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2317 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2329 jit_helper_index_get VAL_NUM TEST a +vm.c:2331 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2332 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2341 jit_helper_index_get VAL_NUM TEST a +vm.c:2343 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2344 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2346 jit_helper_index_get buffer_read_num READ b +vm.c:2346 jit_helper_index_get make_num PRODUCE c +vm.c:2932 vm_take_error_value make_num PRODUCE c +vm.c:3036 slot_type_name slot_is_f64 TEST e +vm.c:3037 slot_type_name slot_is_smi TEST e +vm.c:3277 vm_run_ex/CASE(CONST) VAL_NUM TEST a +vm.c:3278 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b +vm.c:3278 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3292 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3297 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3317 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3317 #define NUM_REUSE VAL_NUM TEST a +vm.c:3328 #define ARITH_FAST slot_f64_value READ b +vm.c:3328 #define ARITH_FAST slot_f64_value READ b +vm.c:3329 #define ARITH_FAST num_guard GUARD c +vm.c:3334 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3335 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3343 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3344 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3352 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3362 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3362 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3363 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3364 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3365 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3365 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3366 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3415 #define NUM_BINOP VAL_NUM TEST a +vm.c:3415 #define NUM_BINOP VAL_NUM TEST a +vm.c:3416 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3416 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3416 #define NUM_BINOP num_guard GUARD c +vm.c:3417 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3417 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3419 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3419 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3420 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3420 #define NUM_BINOP VAL_NUM_RAW WRITE c vm.c:3421 #define NUM_BINOP make_num PRODUCE c -vm.c:3439 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3439 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3440 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3442 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3425 #define NUM_BINOP make_num PRODUCE c +vm.c:3443 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3443 vm_run_ex/CASE(DIV) VAL_NUM TEST a vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3444 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3447 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3449 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3449 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3450 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3450 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3451 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3456 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3464 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3464 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3464 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3465 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3465 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3465 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3466 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3466 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3467 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3467 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3468 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3475 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3494 #define INT_BINOP_R slot_f64_value READ b -vm.c:3494 #define INT_BINOP_R slot_f64_value READ b -vm.c:3496 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3497 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3446 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3448 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3448 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3448 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3451 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3453 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3453 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3454 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3454 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3455 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3460 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3468 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3468 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3468 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3469 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3470 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3471 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3471 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3472 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3474 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3474 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3479 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3498 #define INT_BINOP_R slot_f64_value READ b +vm.c:3498 #define INT_BINOP_R slot_f64_value READ b vm.c:3500 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3501 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3508 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3508 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3501 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3504 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3505 #define INT_BINOP_R slot_from_f64 PRODUCE c vm.c:3512 #define INT_BINOP_R NUM_REUSE TEST a vm.c:3512 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3515 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3528 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3555 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3558 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3558 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c -vm.c:3561 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3566 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3581 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3583 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b -vm.c:3586 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3592 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a -vm.c:3592 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c -vm.c:3595 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3603 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3613 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3613 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3634 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3634 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3656 #define NUM_CMP slot_f64_value READ f -vm.c:3656 #define NUM_CMP slot_f64_value READ f -vm.c:4591 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4593 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4600 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4610 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4612 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:3516 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3516 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3519 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3527 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3527 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3528 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3538 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3565 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3568 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3568 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c +vm.c:3571 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3576 vm_run_ex/CASE(NEG) slot_is_smi TEST a +vm.c:3579 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3594 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3596 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b +vm.c:3599 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3605 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a +vm.c:3605 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c +vm.c:3608 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3613 vm_run_ex/CASE(BNOT) slot_is_smi TEST a +vm.c:3619 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3629 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3629 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3650 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3650 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3672 #define NUM_CMP slot_f64_value READ f +vm.c:3672 #define NUM_CMP slot_f64_value READ f +vm.c:3695 #define NUM_CMP slot_is_smi TEST f +vm.c:3695 #define NUM_CMP slot_is_smi TEST f +vm.c:3696 #define NUM_CMP slot_is_smi TEST f +vm.c:4612 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a vm.c:4614 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4629 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4631 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4632 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4642 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4644 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4645 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4652 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4654 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4655 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4657 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4657 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c -vm.c:4674 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4676 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4677 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4679 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4681 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4691 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4693 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4693 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4695 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4707 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4709 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4710 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4717 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4719 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4720 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4723 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4724 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4780 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4783 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4844 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4845 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4871 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4871 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:4977 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:4978 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5023 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5029 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5037 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5038 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5051 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5055 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5055 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5395 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5396 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5397 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5431 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5432 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5433 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5497 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5497 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i -vm.c:5497 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5501 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5502 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5503 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5504 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5508 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:4621 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4631 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4633 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4635 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4650 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4652 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4653 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4663 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4665 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4666 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4673 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4675 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4676 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4678 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4678 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c +vm.c:4695 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4697 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4698 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4700 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4702 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4712 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4714 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4714 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4716 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4728 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4730 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4731 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4738 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4740 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4741 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4744 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4745 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4801 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4804 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4865 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4866 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4892 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4892 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:4998 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:4999 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5044 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5050 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5058 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5059 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5072 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5076 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5076 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5416 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5417 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5418 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5452 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5453 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5454 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5518 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5518 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i +vm.c:5518 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5522 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5523 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5524 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5525 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5545 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5571 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5574 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5575 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5578 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5594 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i -vm.c:5601 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i -vm.c:5621 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i -vm.c:5622 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i -vm.c:5752 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a -vm.c:5769 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5770 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5772 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5779 #define READ_SLICE_BOUND VAL_NUM TEST a -vm.c:5780 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5783 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5794 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5797 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6391 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6392 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6393 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6396 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6406 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a -vm.c:6407 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b +vm.c:5529 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5543 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5544 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5545 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5546 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5566 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5592 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5595 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5596 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5599 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5615 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i +vm.c:5622 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i +vm.c:5642 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i +vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i +vm.c:5773 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a +vm.c:5790 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5791 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5793 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5800 #define READ_SLICE_BOUND VAL_NUM TEST a +vm.c:5801 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5804 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5815 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5818 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6412 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6413 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6414 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6417 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6427 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a +vm.c:6428 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 150942203..f2aa741a9 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -634,8 +634,13 @@ result).** abort naming its arm, where the float control computes the value. - **The slot test builds at -O0** (about 41 s instead of 162 s, and well under -O2's 602 MB peak), after the warnings #1775 listed were fixed: - `builtin_tensor_gather`'s missing return and the maybe-uninitialized - `num_to_i64_exact` and `vm_index_resolve` locals. + `builtin_tensor_gather`'s missing return, and the maybe-uninitialized + locals behind `num_to_i64_exact` and `vm_index_resolve`. The first fix + round initialised those locals in `vm_run_ex`'s hot arms, which cost + +2.07% Ir on DMG and +4.17% on a JIT-off float loop (the second R1.1 + critic). The second fix round removed the initialisers: the readers + that fill them, `slot_f64_value` and `vm_index_is_int`, write their + out-parameter on every path, so the store sits on the cold path. - **Its runner reads each tool on its own channel.** The scan and the test each have a grammar; a line outside it, or any stderr, is a FAIL that prints the line (the R1.1 critic: Python 3.13's DeprecationWarning on the @@ -2238,6 +2243,14 @@ fails if a round named here has neither rows nor its mechanical gates.) witness either way. - **The token gate** checks, in every mode, that each token a landed round deleted (2.7) occurs in no code line of `src/` or `tests/` C files. + (Until the second R1.1 fix round it ran only in the mechanical rounds; + it runs in every mode now, as this line said.) +- **The inventory gate** runs in every mode too: + `tools/phase2_inventory.py --check` must PASS, so a slot classifier with + no reviewed disposition row fails the check, and so does a committed + `docs/design/phase2-inventory.txt` that is not exactly the generated + file (#1804: nothing ran the inventory's verdict, and the committed file + had gone stale). - **The corpus differential** is `tools/phase2_corpus_diff.sh `: both binaries run every `.eigs` under the branch tree's `tests/` from the branch tree's `src/` (the suite's cwd), so the file and @@ -2250,11 +2263,20 @@ fails if a round named here has neither rows nor its mechanical gates.) baseline's two runs agree, and then any branch run that differs is a DIFF: a branch that is wrong on every other run is wrong; - randomness runs LIVE with a pinned seed. The runtime has no seed flag - or variable (an unseeded program seeds from `CLOCK_MONOTONIC ^ pid`), so - the tool builds an `LD_PRELOAD` shim that pins every self-seed (>= 2^20) - to one constant and passes a small explicit seed through, and checks the - shim first (pinned draws agree, unpinned ones differ). A random builtin - changed on the branch therefore shows wherever the corpus observes it; + or variable, so the tool builds an `LD_PRELOAD` shim. The drand48 + self-seed is `srand48(tv_sec ^ tv_nsec ^ getpid())` from a + `CLOCK_MONOTONIC` reading taken just before; the shim records each + thread's last such reading and pins a seed equal to that formula, + whatever its value, while a script's `seed_random of N` passes + unchanged. (The first fix round's shim pinned seeds >= 2^20 instead, + and the self-seed falls below that: 5 of 3,000 draws went unpinned; the + second round's pinned 3,000 of 3,000.) libc `rand()`, which + `audio_noise` draws from and `main()` seeds with `srand(time(NULL))`, + is pinned at every `srand` call. `random_hex` reads `/dev/urandom` by + design and stays unpinned; the shim marks every run that opens it, and + those files are listed (`UNPINNED`) with their verdicts. The tool + checks the shim first (two pinned draws agree). A random builtin changed + on the branch therefore shows wherever the corpus observes it; `test_system.eigs` now draws `random_int` 300 times against its bounds; - a tape is the last resort, for a file whose baseline disagrees with itself even pinned (timing, threads): the baseline records it and @@ -2266,6 +2288,31 @@ fails if a round named here has neither rows nor its mechanical gates.) - no blanket memory cap: only files that drive the gfx, ui or audio surface run under `ulimit -v 2097152` (listed as `CAPPED`). `handles_full.eigs` varied only because of the old blanket cap. + + **As corrected in the second R1.1 fix round** (the second critic's plants + C and B2 passed the whole oracle while the suite went red on C): + - each file runs under its run conditions from the one loader the suite, + `jit_diff.sh` and `replay_diff.sh` use (`tests/suite_program_env.sh`, + policy `tests/suite_program_env.txt`). Before, every file started in + the default strict mode, so 14 fail-soft numeric-boundary files died at + an early strict raise on both binaries, about 394 asserts never ran, and + the two early deaths were counted `same`. The four files the suite ran + with an inline `EIGS_STRICT=0` (and one with an inline + `SDL_VIDEODRIVER=dummy`) now have rows there, so there is no second + source; + - a file with conditions must complete (rc 0) on both baseline runs, the + rule `jit_diff.sh` already applied; otherwise it is INCOMPLETE and + never compared; + - every file whose baseline exits nonzero must be declared, with that + code and a reason, in `tests/phase2/corpus_nonzero.txt` (32 rows: the + runaway guard's fixture, deliberate errors, fixtures of other hosts, + capabilities the release build lacks). An undeclared exit is + UNDECLARED-NONZERO and a row whose file exits otherwise is STALE: both + fail the run. So removing a file's run conditions turns the + differential red, and so does a new test that dies early. Every + declared file is listed with its code (`SAME-NONZERO`); + - a timeout or a crash all four runs agree on is counted as + `timeout_both` or `crash_both`, no longer also as `same`. - **The smi-trap gate** (`--smi-trap BIN`, R1.1 and R1.2) runs the same differential with a `make smi-trap` build as the branch; until R1.3 it must show no difference, because no program may make an int. @@ -2285,8 +2332,17 @@ fails if a round named here has neither rows nor its mechanical gates.) differential name the file DIFF; the int-source plants P1-P5, each of which the static half must name at R1.1 (at R1.2, P4 sits inside an allowed writer and the static half passes it); and P4 built into a - smi-trap binary, which the dynamic half must stop. A restricted run (the - calibration's file list) prints `RESTRICTED` and exits 3, never PASS. + smi-trap binary, which the dynamic half must stop. The second fix round + added the second critic's plants C (a build whose buffer equality reads + raw elements) and B2 (an int whose tag bits are spelled from + `SLOT_QNAN_MASK`, which the static half does not see, on the smi-trap + build), each of which must make the differential name a conditioned file + DIFF; a removed policy row, which must be UNDECLARED-NONZERO; a ledger row + for a completing file (STALE); a conditioned file that does not complete + (INCOMPLETE); and the inventory gate's plants (`vm.c:critic_new_reader` + with no disposition row, and a stale committed inventory). A restricted + run (the calibration's file list) prints `RESTRICTED` and exits 3, never + PASS. The calibration is a `tools/selftests.txt` row (`phase2_check.py --selftest`, which builds v0.46.0 and the four planted binaries itself): it runs when the checker or its fixtures change, and nightly, never on diff --git a/tools/phase2_check.py b/tools/phase2_check.py index a155174ef..a2eaa90b2 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -33,15 +33,23 @@ A -stop whose op is the chunk's compile stop must also be named by EIGS_JIT_STOPS. +EVERY MODE runs two gates: the token gate (every token a landed round +deleted is absent from code) and the inventory's own verdict +(tools/phase2_inventory.py --check: every slot classifier has a reviewed +disposition, and the committed docs/design/phase2-inventory.txt is exactly +the generated one, #1804). + MECHANICAL ROUNDS (R1.1, R1.2, R2.1) have no rows of their own; --through -one of them runs its gates instead: the token gate (every token a landed -round deleted is absent from code), the int-source check in two halves -- +one of them runs its gates instead: the int-source check in two halves -- static: before R1.3 no runtime code calls slot_from_int or make_int outside the canonicalizing writers, make_int does not exist, and TAG_SMI or an SMI bit pattern is spelled only at its value_slot.h homes; dynamic (--smi-trap, R1.1/R1.2): the corpus differential against a `make smi-trap` build, on which every slot classifier aborts at an SMI -- the C slot test, and the corpus differential against --baseline (the binary from before the round). +The differential runs each file under its run conditions from the suite's +loader (tests/suite_program_env.sh) and requires every nonzero exit to be +declared (tests/phase2/corpus_nonzero.txt); its header is the reference. A gate tool that writes to stderr fails, with its words (tool()); the checker runs under `python3 -W error` (tools/phase2_check.sh). @@ -65,10 +73,14 @@ ROUNDS = ['R1.1', 'R1.2', 'R1.3', 'R1.4', 'R1.5', 'R1.6', 'R1.7', 'R1.8', 'R2.1', 'R2.2', 'R2.3', 'R2.4', 'R2.5', 'R2.6', 'R3'] +# Gates every mode runs: the token gate (a landed round's deleted tokens stay +# deleted) and the inventory's own verdict, which includes the committed +# docs/design/phase2-inventory.txt being exactly the generated one (#1804). +EVERY_MODE = ('tokens', 'inventory') MECHANICAL = { - 'R1.1': ('tokens', 'int-source', 'slot-test', 'corpus-diff', 'smi-trap'), - 'R1.2': ('tokens', 'int-source', 'slot-test', 'corpus-diff', 'smi-trap'), - 'R2.1': ('tokens', 'slot-test', 'corpus-diff'), + 'R1.1': ('int-source', 'slot-test', 'corpus-diff', 'smi-trap'), + 'R1.2': ('int-source', 'slot-test', 'corpus-diff', 'smi-trap'), + 'R2.1': ('slot-test', 'corpus-diff'), } ITEMS = ['N%d' % i for i in range(1, 15)] + ['N4b', 'A', 'B', 'T1', 'O1', 'O2', 'O3', 'O4'] # design 2.7: the tokens each round deletes. A later round adds its list here @@ -542,21 +554,42 @@ def tool(cmd, out, tail_re, env=None): for l in text.split('\n'): if re.match(tail_re, l): out(' ' + l) + who = next((os.path.basename(a) for a in cmd if a.endswith(('.py', '.sh'))), cmd[0]) for l in err.split('\n'): if l: - out(' STDERR %s: %s' % (os.path.basename(cmd[1]), l)) + out(' STDERR %s: %s' % (who, l)) return p.returncode == 0 and not err, text -DIFF_TAIL = r'^(corpus-diff: (seed pin|baseline|branch|examined|RESTRICTED|PASS|FAIL)|DIFF|DELETED|NEW|NONDET|REPLAYED|BOTH-|CAPPED)' +INVENTORY_TAIL = r'^(FAIL: |UNCLASSIFIED: |slot classifiers: |examined=|phase2-inventory: )' + + +def inventory_gate(out, extra=()): + """The inventory's own verdict, under -W error, with --check: every slot + classifier has a reviewed disposition and the committed inventory file is + exactly the generated one. PASS only for rc 0, no stderr, and a last line + `phase2-inventory: PASS`.""" + ok, text = tool([sys.executable, '-W', 'error', os.path.join(ROOT, 'tools/phase2_inventory.py'), '--check'] + + list(extra), out, INVENTORY_TAIL) + lines = [l for l in text.split('\n') if l] + return ok and lines[-1:] == ['phase2-inventory: PASS'] + + +DIFF_TAIL = (r'^(corpus-diff: (seed pin|baseline|branch|files|examined|RESTRICTED|PASS|FAIL)|DIFF|DELETED|NEW|NONDET|' + r'REPLAYED|BOTH-|SAME-NONZERO|UNPINNED|INCOMPLETE|UNDECLARED|STALE|LEDGER|CAPPED)') + + +def every_mode(through, out): + res = {'tokens': token_gate(ROOT, through, out), 'inventory': inventory_gate(out)} + for g in EVERY_MODE: + out('gate %s: %s' % (g, 'PASS' if res[g] else 'FAIL')) + return all(res[g] for g in EVERY_MODE) def mechanical(through, baseline, branch, out, smi_trap=None): res = {} for g in MECHANICAL[through]: - if g == 'tokens': - res[g] = token_gate(ROOT, through, out) - elif g == 'int-source': + if g == 'int-source': res[g] = int_source(os.path.join(ROOT, 'src'), out, through) elif g == 'slot-test': res[g], _ = tool(['bash', 'tests/phase2/slot_layer.sh', 'release'], out, @@ -635,15 +668,16 @@ def main_check(args, out): with tempfile.TemporaryDirectory(prefix='eigs-p2-') as scratch: pop_ok, rows_ok, ctl_ok, landed, cnt, _ = check( map_rows, args.rows, args.controls, args.tag, args.branch, args.through, scratch, out) + always_ok = every_mode(args.through, out) mech_ok = None if args.through in MECHANICAL: mech_ok = mechanical(args.through, args.baseline, args.branch, out, args.smi_trap) if landed == 0: if mech_ok is None: out(' ZERO-ROWS: %s has no landed row and no mechanical gates' % args.through) - verdict = bool(mech_ok) and pop_ok and not bad and ctl_ok + verdict = bool(mech_ok) and pop_ok and not bad and ctl_ok and always_ok else: - verdict = rows_ok and pop_ok and not bad and ctl_ok and mech_ok is not False + verdict = rows_ok and pop_ok and not bad and ctl_ok and mech_ok is not False and always_ok out('phase2-check: %s' % ('PASS' if verdict else 'FAIL')) return 0 if verdict else 1 @@ -801,11 +835,80 @@ def stray(rd): case('differential plant B, phase %d (wrong on alternate runs): DIFF, never NONDET' % phase, (rc, v.get('tests/test_dispatch.eigs'), v.get('tests/test_bool.eigs'), v.get('')), (3, 'DIFF', 'same', None)) + # the run conditions and the nonzero ledger (the second R1.1 critic): + # fake trees that run the real branch binary with one input changed + with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: + files = ['tests/test_numeric_guard.eigs', 'tests/test_buffer_nonfinite_read.eigs', 'tests/test_bool.eigs'] + rc, text, v = diff_restricted(base, args.branch, files) + case('unplanted branch, conditioned files included: all same, nothing undeclared', + (rc,) + tuple(v.get(f) for f in files) + (v.get(''), + bool(re.search(r' incomplete=0 undeclared=0 stale=0 ledger_refused=0 ', text))), + (3, 'same', 'same', 'same', None, True)) + cut = wrapper_tree(os.path.join(d, 'cut'), args.branch, files[:1] + files[2:], 'exec "$REAL" "$@"', + {'tests/suite_program_env.txt': + lambda t: re.sub(r'(?m)^test_numeric_guard\.eigs .*\n', '', t)}) + rc, text, v = diff_restricted(base, cut, files[:1] + files[2:]) + case('a policy row removed: its file exits early on both, UNDECLARED-NONZERO', + (rc, 'UNDECLARED-NONZERO tests/test_numeric_guard.eigs rc=1' in text, + ' undeclared=1 ' in text, v.get('')), (3, True, True, None)) + stale = wrapper_tree(os.path.join(d, 'stale'), args.branch, files[2:], 'exec "$REAL" "$@"', + {'tests/phase2/corpus_nonzero.txt': + lambda t: t + 'tests/test_bool.eigs 1 planted: test_bool completes\n'}) + rc, text, v = diff_restricted(base, stale, files[2:]) + case('a ledger row for a file that completes: STALE', + (rc, 'STALE tests/test_bool.eigs:' in text, ' stale=1 ' in text), (3, True, True)) + inc = wrapper_tree(os.path.join(d, 'inc'), args.branch, ['tests/test_assert_fail.eigs'], 'exec "$REAL" "$@"', + {'tests/suite_program_env.txt': lambda t: t + 'test_assert_fail.eigs EIGS_STRICT=0\n', + 'tests/phase2/corpus_nonzero.txt': + lambda t: re.sub(r'(?m)^tests/test_assert_fail\.eigs .*\n', '', t)}) + rc, text, v = diff_restricted(base, inc, ['tests/test_assert_fail.eigs']) + case('a conditioned file that does not complete: INCOMPLETE, never compared', + (rc, v.get('tests/test_assert_fail.eigs'), ' incomplete=1 ' in text), (3, 'INCOMPLETE', True)) + # the inventory gate (#1804): a classifier with no reviewed disposition, + # and a committed inventory that is not the generated one + with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: + shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src'), ignore=c_sources_only) + os.makedirs(os.path.join(d, 'docs/design')) + for f in ('docs/design/phase2-numbers.md', 'docs/design/phase2-inventory.txt'): + shutil.copy(os.path.join(ROOT, f), os.path.join(d, f)) + inv_args = ['--src', os.path.join(d, 'src'), '--doc', os.path.join(d, 'docs/design/phase2-numbers.md'), + '--out', os.path.join(d, 'docs/design/phase2-inventory.txt')] + lines = [] + case('inventory gate on an unchanged copy passes', inventory_gate(lines.append, inv_args), True) + inv_path = os.path.join(d, 'docs/design/phase2-inventory.txt') + committed = read_text(inv_path) + write_text(inv_path, committed.replace('dispositions=', 'dispositions=0', 1)) + lines = [] + case('a committed inventory that is not the generated one: the gate fails, saying stale', + (inventory_gate(lines.append, inv_args), any('is stale' in l for l in lines)), (False, True)) + write_text(inv_path, committed) + with open(os.path.join(d, 'src', 'vm.c'), 'a') as f: + f.write('\nint critic_new_reader(Value *v) {\n EigsSlot s = slot_from_heap(v);\n' + ' return slot_is_bool(s) ? 1 : (slot_is_null(s) ? 2 : 0);\n}\n') + lines = [] + case('an unreviewed slot classifier (critic_new_reader): the gate fails, naming it', + (inventory_gate(lines.append, inv_args), + any('`vm.c:critic_new_reader` has no disposition row' in l for l in lines)), (False, True)) if args.build_plants: args.planted_leaf_scan = build_plant('leaf-scan', out) args.planted_leaf_mul = build_plant('leaf-mul', out) args.planted_random_int = build_plant('random-int', out) args.planted_p4_trap = build_plant('p4-trap', out) + args.planted_value_eq = build_plant('value-eq-raw', out) + args.planted_b2_trap = build_plant('b2-trap', out) + for label, b, files, want in ( + ('plant C (buffer equality reads raw elements), release build', args.planted_value_eq, + ['tests/test_numeric_guard.eigs', 'tests/test_bool.eigs'], ('DIFF', 'same')), + ('plant B2 (an int from spelled tag bits) on the smi-trap build', args.planted_b2_trap, + ['tests/test_buffer_nonfinite_read.eigs', 'tests/test_numeric_guard.eigs', 'tests/test_bool.eigs'], + ('DIFF', 'DIFF', 'same'))): + if not b: + out('CAL %-58s NOT RUN (no binary; --build-plants builds it)' % label) + results.append(False) + continue + rc, text, v = diff_restricted(base, b, files) + case('differential %s: DIFF where its conditioned file reaches it' % label, + (rc,) + tuple(v.get(f) for f in files) + (v.get(''),), (3,) + want + (None,)) if args.planted_random_int: # test_system.eigs asserts random_int's bounds over 300 draws, so it # sees the plant whatever the seed; test_optimize.eigs prints a search @@ -861,6 +964,14 @@ def stray(rd): # the R1.1 critic's plant D: random_int answers lo+1..hi+1 'random-int': ('src/builtins.c', 'make_num(lo_i + (eigs_random_long() % (int64_t)span))', 'make_num(lo_i + 1 + (eigs_random_long() % (int64_t)span))', 'build'), + # the second R1.1 critic's plant C: equality of two buffers reads raw + # elements (no read normalisation); the suite's [42c] goes red on it + 'value-eq-raw': ('src/eigenscript.c', ' case VAL_BUFFER: {\n if (a->data.buffer.count != b->data.buffer.count) return 0;\n for (int i = 0; i < a->data.buffer.count; i++) {\n double av = buffer_read_num(a, i);\n if (g_has_error) return 0;\n double bv = buffer_read_num(b, i);\n', + ' case VAL_BUFFER: {\n if (a->data.buffer.count != b->data.buffer.count) return 0;\n for (int i = 0; i < a->data.buffer.count; i++) {\n double av = a->data.buffer.data[i]; /* CRITIC PLANT C: raw element, no read normalisation */\n if (g_has_error) return 0;\n double bv = b->data.buffer.data[i];\n', 'build'), + # the second critic's plant B2: an int produced by spelling the tag's bits + # (no TAG_SMI, so the static half cannot see it), on the smi-trap build + 'b2-trap': ('src/vm.c', ' if (target->type == VAL_BUFFER) {\n if (_ok && vm_index_resolve(&i, target->data.buffer.count)) {\n double v = buffer_read_num(target, i);\n slot_decref(tgt_s);\n vm_push_slot(slot_from_f64(v));\n } else {\n if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s));\n else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)",\n', + ' if (target->type == VAL_BUFFER) {\n if (_ok && vm_index_resolve(&i, target->data.buffer.count)) {\n double v = buffer_read_num(target, i);\n slot_decref(tgt_s);\n if (isnan(target->data.buffer.data[i])) { /* CRITIC PLANT B2: an int producer, bits spelled */\n EigsSlot p; p.u = (SLOT_QNAN_MASK | (UINT64_C(2) << 48)) | 7u;\n vm_push_slot(p);\n } else {\n vm_push_slot(slot_from_f64(v));\n }\n } else {\n if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s));\n else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)",\n', 'smi-trap'), # the critic's P4 (an int produced inside an allowed writer) on the smi-trap build 'p4-trap': ('src/eigenscript.c', ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n' @@ -941,13 +1052,19 @@ def diff_restricted(base, branch, files): return p.returncode, text, verdicts -def wrapper_tree(d, real, files, script): +RUN_POLICY = ('tests/suite_program_env.sh', 'tests/suite_program_env.txt', 'tests/phase2/corpus_nonzero.txt') + + +def wrapper_tree(d, real, files, script, edit=None): """A fake branch tree: src/eigenscript runs `script` (bash, $REAL is the - real binary, $N the per-tree invocation count), tests/ holds the files.""" + real binary, $N the per-tree invocation count), tests/ holds the files and + the run-condition loader, its table and the nonzero ledger, each of which + `edit` ({path: function(text) -> text}) may change.""" os.makedirs(os.path.join(d, 'src')) - for f in files: + for f in list(files) + list(RUN_POLICY): os.makedirs(os.path.join(d, os.path.dirname(f)), exist_ok=True) - shutil.copy(os.path.join(ROOT, f), os.path.join(d, f)) + text = read_text(os.path.join(ROOT, f)) + write_text(os.path.join(d, f), (edit or {}).get(f, lambda t: t)(text)) w = os.path.join(d, 'src', 'eigenscript') write_text(w, '#!/usr/bin/env bash\nREAL=%s\nSTATE=%s\nN=$(cat "$STATE" 2>/dev/null || echo 0)\n' 'echo $((N + 1)) > "$STATE"\n%s\n' % (real, os.path.join(d, 'n'), script)) @@ -986,7 +1103,8 @@ def selftest(out): out(' TAG %s built in %s' % (TAG, d)) args = argparse.Namespace(tag=os.path.abspath(tag), branch=branch, build_plants=True, planted_leaf_scan=None, planted_leaf_mul=None, - planted_random_int=None, planted_p4_trap=None) + planted_random_int=None, planted_p4_trap=None, + planted_value_eq=None, planted_b2_trap=None) return calibrate(args, out) @@ -1013,14 +1131,17 @@ def main(): ap.add_argument('--planted-leaf-mul', help='calibration: a build whose leaf MUL computes a*b+1') ap.add_argument('--planted-random-int', help='calibration: a build whose random_int answers lo+1..hi+1') ap.add_argument('--planted-p4-trap', help='calibration: a smi-trap build with the P4 producer planted') + ap.add_argument('--planted-value-eq', help='calibration: a build whose buffer equality reads raw elements (C)') + ap.add_argument('--planted-b2-trap', help='calibration: a smi-trap build with the B2 producer planted') ap.add_argument('--build-plants', action='store_true', - help='calibration: build the four planted binaries from HEAD') + help='calibration: build the six planted binaries from HEAD') args = ap.parse_args() if args.selftest: print('phase2-check: FAIL: --selftest takes no other argument') return 2 for b in (args.tag, args.branch, args.baseline, args.smi_trap, args.planted_leaf_scan, - args.planted_leaf_mul, args.planted_random_int, args.planted_p4_trap): + args.planted_leaf_mul, args.planted_random_int, args.planted_p4_trap, + args.planted_value_eq, args.planted_b2_trap): if b and not os.access(b, os.X_OK): print('phase2-check: FAIL: %s is not an executable' % b) return 2 diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index 1e0b4450a..bd68b8f87 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -44,6 +44,7 @@ token never fires, or nothing was examined. """ import argparse +import difflib import glob import os import re @@ -740,6 +741,8 @@ def main(): ap.add_argument('--doc', default=os.path.join(ROOT, 'docs/design/phase2-numbers.md')) ap.add_argument('--out', default=os.path.join(ROOT, 'docs/design/phase2-inventory.txt')) ap.add_argument('--no-write', action='store_true') + ap.add_argument('--check', action='store_true', + help='write nothing, and FAIL when --out differs from the generated text (#1804)') ap.add_argument('--sites', action='store_true', help='print every site') ap.add_argument('--slot-population', action='store_true', help='print the C slot test population (design 2.5) and exit') @@ -911,7 +914,18 @@ def main(): out.append('%s:%d %s %s %s %s' % (rel, ln, scope, tok, kind, cat)) text = '\n'.join(out) + '\n' - if not args.no_write: + stale = None + if args.check: + # the committed file must be exactly what this run generates + try: + with open(args.out, encoding='utf-8') as f: + committed = f.read() + except OSError: + committed = '' + if committed != text: + stale = sum(1 for l in difflib.unified_diff(committed.split('\n'), text.split('\n'), n=0, lineterm='') + if l[:1] in '+-' and not l.startswith(('+++', '---'))) + elif not args.no_write: os.makedirs(os.path.dirname(args.out), exist_ok=True) with open(args.out, 'w', encoding='utf-8') as f: f.write(text) @@ -943,6 +957,9 @@ def main(): fail.append('slot classifier `%s` has no disposition row' % n) for n in slot_stale: fail.append('disposition row `%s` names no D1/D2/D3 slot classifier' % n) + if stale is not None: + fail.append('%s is stale: %d line(s) differ from the generated inventory; regenerate it with ' + 'tools/phase2_inventory.py' % (os.path.relpath(args.out, ROOT), stale)) for f_ in fail: print('FAIL: ' + f_) print('builtins: registered=%d numeric=%d classified=%d unclassified=%d stale=%d' % ( diff --git a/tools/selftests.txt b/tools/selftests.txt index e32123036..96bb33f46 100644 --- a/tools/selftests.txt +++ b/tools/selftests.txt @@ -57,5 +57,5 @@ tools/observer_oracle/* | timeout 600 python3 tools/observer_oracle/plants.py -- # #1758 Phase 2: the row checker's calibration (5 release builds: v0.46.0 and four planted binaries; 662 s on # the 4 GB dev box) and the slot test's planted faults (two -O0 slot-test builds per plant; 446 s there). # Keyed on the checkers, never on src/ (#1352). -tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* | timeout 2400 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=42 as-expected=42 unexpected=0$","count":1}] +tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* tests/phase2/corpus_nonzero.txt tests/suite_program_env.sh tests/suite_program_env.txt | timeout 3600 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=51 as-expected=51 unexpected=0$","count":1}] tools/phase2_plants.sh tests/phase2/slot_layer.sh tests/phase2/slot_layer.c tools/phase2_inventory.py | timeout 1500 bash tools/phase2_plants.sh --selftest | [{"pattern":"^plants=5 killed=5 survived=0 broken=0 transverse=5$","count":1}] From 162b39230db2d54c8a63aa4d65b42787f5320a7a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 05:47:07 -0500 Subject: [PATCH 015/188] phase2 R1.1 fix 2: #1775's three warning sites initialised, nothing else (#1758) Supersedes 176b3d6a's mechanism, which callgrind refuted. Writing the out-parameter in the readers cost what the initialisers did: against R1.1 (9ce8e0bd), the JIT-off float loop measured +3.84% with slot_f64_value writing 0.0 on its failure path (+4.50% writing the slot's bits instead) and +0.44% with vm_index_is_int writing on both paths alone. The float loop executes neither failure path: any of these changed vm_run_ex's generated code, not its executed stores. Both readers are back to R1.1's form. The initialisation stays at exactly the three declarations GCC flags at -O1 (INT_BINOP_R's _ad/_bd, the `i` of CASE(INDEX_SET) and of jit_helper_index_set), with a comment at each. Callgrind Ir against R1.1, same inputs as the critic's: JIT-off float loop 364,223,332 -> 364,223,042 (-0.0001%) float loop, JIT on 172,204,323 -> 172,204,413 (+0.0001%) DMG 500K canary 1,191,977,525 (mean of 3) -> 1,191,026,282 (-0.080%) The amalgamation compiles with no warning at -O0 and -O1 (-Wall -Wextra), and the release build at -O2 has none. The C slot test's slot_f64_value rows expect the untouched out-parameter again; the inventory is regenerated for the moved lines. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 466 +++++++++++++++---------------- docs/design/phase2-numbers.md | 14 +- src/value_slot.h | 12 +- src/vm.c | 19 +- tests/phase2/slot_layer.c | 7 +- 5 files changed, 264 insertions(+), 254 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index dadd9de10..f66913da6 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -2044,11 +2044,11 @@ value_slot.h:227 slot_truthy_immediate SLOT_F64_RAW RAW b value_slot.h:227 slot_truthy_immediate slot_is_f64 TEST a value_slot.h:230 slot_truthy_immediate slot_is_smi TEST a value_slot.h:230 slot_truthy_immediate slot_smi_val RAW b -value_slot.h:243 slot_f64_value slot_f64_value READ b -value_slot.h:244 slot_f64_value SLOT_F64_RAW RAW b -value_slot.h:244 slot_f64_value slot_is_f64 TEST a -value_slot.h:247 slot_f64_value VAL_NUM TEST a -value_slot.h:247 slot_f64_value VAL_NUM_RAW RAW b +value_slot.h:244 slot_f64_value slot_f64_value READ b +value_slot.h:245 slot_f64_value SLOT_F64_RAW RAW b +value_slot.h:245 slot_f64_value slot_is_f64 TEST a +value_slot.h:248 slot_f64_value VAL_NUM TEST a +value_slot.h:248 slot_f64_value VAL_NUM_RAW RAW b value_slot.h:254 slot_int_value slot_int_value READ b value_slot.h:255 slot_int_value slot_is_smi TEST a value_slot.h:255 slot_int_value slot_smi_val RAW b @@ -2101,250 +2101,250 @@ vm.c:1818 jit_helper_iter_next buffer_read_num READ b vm.c:1818 jit_helper_iter_next num_guard GUARD c vm.c:1818 jit_helper_iter_next slot_from_f64 PRODUCE c vm.c:1824 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1896 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b -vm.c:1896 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1900 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1903 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1942 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1956 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1956 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:1967 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1968 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1986 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:1986 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2069 loop_iter_store make_num PRODUCE c -vm.c:2076 loop_iter_store slot_is_f64 TEST a -vm.c:2077 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2082 loop_iter_store make_num PRODUCE c -vm.c:2204 jit_helper_index_set slot_is_f64 TEST a -vm.c:2206 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2207 jit_helper_index_set slot_is_f64 TEST a -vm.c:2209 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2211 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2221 jit_helper_index_set slot_is_f64 TEST a -vm.c:2223 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2224 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2226 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2238 jit_helper_index_set VAL_NUM TEST a -vm.c:2240 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:1894 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b +vm.c:1894 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1898 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1901 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1940 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:1954 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1954 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:1965 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1966 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1984 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:1984 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2067 loop_iter_store make_num PRODUCE c +vm.c:2074 loop_iter_store slot_is_f64 TEST a +vm.c:2075 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2080 loop_iter_store make_num PRODUCE c +vm.c:2202 jit_helper_index_set slot_is_f64 TEST a +vm.c:2207 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2208 jit_helper_index_set slot_is_f64 TEST a +vm.c:2210 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2212 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2222 jit_helper_index_set slot_is_f64 TEST a +vm.c:2224 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2225 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2227 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2239 jit_helper_index_set VAL_NUM TEST a vm.c:2241 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2248 jit_helper_index_set VAL_NUM TEST a -vm.c:2250 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2242 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2249 jit_helper_index_set VAL_NUM TEST a vm.c:2251 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2254 jit_helper_index_set VAL_NUM TEST a -vm.c:2255 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2274 jit_helper_index_get slot_is_f64 TEST a -vm.c:2276 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2283 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2294 jit_helper_index_get buffer_read_num READ b -vm.c:2296 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2298 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2314 jit_helper_index_get VAL_NUM TEST a -vm.c:2316 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2252 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2255 jit_helper_index_set VAL_NUM TEST a +vm.c:2256 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2275 jit_helper_index_get slot_is_f64 TEST a +vm.c:2277 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2284 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2295 jit_helper_index_get buffer_read_num READ b +vm.c:2297 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2299 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2315 jit_helper_index_get VAL_NUM TEST a vm.c:2317 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2329 jit_helper_index_get VAL_NUM TEST a -vm.c:2331 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2318 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2330 jit_helper_index_get VAL_NUM TEST a vm.c:2332 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2341 jit_helper_index_get VAL_NUM TEST a -vm.c:2343 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2333 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2342 jit_helper_index_get VAL_NUM TEST a vm.c:2344 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2346 jit_helper_index_get buffer_read_num READ b -vm.c:2346 jit_helper_index_get make_num PRODUCE c -vm.c:2932 vm_take_error_value make_num PRODUCE c -vm.c:3036 slot_type_name slot_is_f64 TEST e -vm.c:3037 slot_type_name slot_is_smi TEST e -vm.c:3277 vm_run_ex/CASE(CONST) VAL_NUM TEST a -vm.c:3278 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b -vm.c:3278 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3292 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3297 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3317 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3317 #define NUM_REUSE VAL_NUM TEST a -vm.c:3328 #define ARITH_FAST slot_f64_value READ b -vm.c:3328 #define ARITH_FAST slot_f64_value READ b -vm.c:3329 #define ARITH_FAST num_guard GUARD c -vm.c:3334 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3335 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3343 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3344 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3352 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3362 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3362 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3363 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3364 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:2345 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2347 jit_helper_index_get buffer_read_num READ b +vm.c:2347 jit_helper_index_get make_num PRODUCE c +vm.c:2933 vm_take_error_value make_num PRODUCE c +vm.c:3037 slot_type_name slot_is_f64 TEST e +vm.c:3038 slot_type_name slot_is_smi TEST e +vm.c:3278 vm_run_ex/CASE(CONST) VAL_NUM TEST a +vm.c:3279 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b +vm.c:3279 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3293 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3298 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3318 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3318 #define NUM_REUSE VAL_NUM TEST a +vm.c:3329 #define ARITH_FAST slot_f64_value READ b +vm.c:3329 #define ARITH_FAST slot_f64_value READ b +vm.c:3330 #define ARITH_FAST num_guard GUARD c +vm.c:3335 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3336 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3344 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3345 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3353 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3364 vm_run_ex/CASE(ADD) num_guard GUARD c vm.c:3365 vm_run_ex/CASE(ADD) NUM_REUSE TEST a vm.c:3365 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3366 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3415 #define NUM_BINOP VAL_NUM TEST a -vm.c:3415 #define NUM_BINOP VAL_NUM TEST a -vm.c:3416 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3416 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3416 #define NUM_BINOP num_guard GUARD c +vm.c:3366 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3366 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3367 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3416 #define NUM_BINOP VAL_NUM TEST a +vm.c:3416 #define NUM_BINOP VAL_NUM TEST a vm.c:3417 #define NUM_BINOP VAL_NUM_RAW RAW b vm.c:3417 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3419 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3419 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3417 #define NUM_BINOP num_guard GUARD c +vm.c:3418 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3418 #define NUM_BINOP VAL_NUM_RAW RAW b vm.c:3420 #define NUM_BINOP NUM_REUSE TEST a vm.c:3420 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3421 #define NUM_BINOP make_num PRODUCE c -vm.c:3425 #define NUM_BINOP make_num PRODUCE c -vm.c:3443 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3443 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3446 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3448 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3448 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3448 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3451 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3453 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3453 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3421 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3421 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3422 #define NUM_BINOP make_num PRODUCE c +vm.c:3426 #define NUM_BINOP make_num PRODUCE c +vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3445 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3447 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3449 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3449 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3449 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3452 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b vm.c:3454 vm_run_ex/CASE(DIV) NUM_REUSE TEST a vm.c:3454 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3455 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3460 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3468 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3468 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3468 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3455 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3455 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3456 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3461 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM TEST a vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3469 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3470 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3470 vm_run_ex/CASE(MOD) num_guard GUARD c vm.c:3471 vm_run_ex/CASE(MOD) NUM_REUSE TEST a vm.c:3471 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3472 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3474 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3474 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3479 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3498 #define INT_BINOP_R slot_f64_value READ b -vm.c:3498 #define INT_BINOP_R slot_f64_value READ b -vm.c:3500 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3501 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3504 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3505 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3512 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3512 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3516 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3516 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3519 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3527 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3527 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3528 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3538 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3565 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3568 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3568 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c -vm.c:3571 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3576 vm_run_ex/CASE(NEG) slot_is_smi TEST a -vm.c:3579 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3594 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3596 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b -vm.c:3599 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3605 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a -vm.c:3605 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c -vm.c:3608 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3613 vm_run_ex/CASE(BNOT) slot_is_smi TEST a -vm.c:3619 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3629 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3629 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3650 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3650 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3672 #define NUM_CMP slot_f64_value READ f -vm.c:3672 #define NUM_CMP slot_f64_value READ f -vm.c:3695 #define NUM_CMP slot_is_smi TEST f -vm.c:3695 #define NUM_CMP slot_is_smi TEST f -vm.c:3696 #define NUM_CMP slot_is_smi TEST f -vm.c:4612 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4614 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4621 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4631 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4633 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4635 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4650 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4652 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4653 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4663 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4665 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4666 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4673 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4675 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4676 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4678 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4678 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c -vm.c:4695 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4697 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4698 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4700 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:3472 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3472 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3473 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3475 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3475 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3480 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3503 #define INT_BINOP_R slot_f64_value READ b +vm.c:3503 #define INT_BINOP_R slot_f64_value READ b +vm.c:3505 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3506 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3509 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3510 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3517 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3517 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3521 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3521 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3524 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3532 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3532 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3533 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3543 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3570 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3573 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3573 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c +vm.c:3576 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3581 vm_run_ex/CASE(NEG) slot_is_smi TEST a +vm.c:3584 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3599 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3601 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b +vm.c:3604 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3610 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a +vm.c:3610 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c +vm.c:3613 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3618 vm_run_ex/CASE(BNOT) slot_is_smi TEST a +vm.c:3624 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3634 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3634 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3655 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3655 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3677 #define NUM_CMP slot_f64_value READ f +vm.c:3677 #define NUM_CMP slot_f64_value READ f +vm.c:3700 #define NUM_CMP slot_is_smi TEST f +vm.c:3700 #define NUM_CMP slot_is_smi TEST f +vm.c:3701 #define NUM_CMP slot_is_smi TEST f +vm.c:4617 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4619 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4626 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4636 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4638 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4640 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4655 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4657 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4658 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4668 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4670 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4671 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4678 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a +vm.c:4680 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4681 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4683 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4683 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c +vm.c:4700 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a vm.c:4702 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4712 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4714 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4714 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4716 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4728 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4730 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4731 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4738 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4740 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4741 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4744 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4703 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4705 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4707 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4717 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4719 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4719 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4721 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4733 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4735 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4736 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4743 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a vm.c:4745 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4801 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4804 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4865 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4866 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4892 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4892 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:4998 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:4999 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5044 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5050 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5058 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5059 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5072 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5076 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5076 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5416 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5417 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5418 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5452 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5453 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5454 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5518 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5518 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i -vm.c:5518 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5522 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:4746 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4749 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4750 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4806 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4809 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4870 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4871 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4897 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4897 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5003 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5004 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5049 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5055 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5063 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5064 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5077 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5081 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5081 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5421 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5422 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5423 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5457 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5458 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5459 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5523 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5523 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i vm.c:5523 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5524 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5525 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5529 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5543 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5544 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5545 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5546 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5566 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5592 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5595 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5596 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5599 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5615 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i -vm.c:5622 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i -vm.c:5642 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i -vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i -vm.c:5773 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a -vm.c:5790 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5791 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5793 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5800 #define READ_SLICE_BOUND VAL_NUM TEST a -vm.c:5801 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5804 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5815 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5818 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6412 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6413 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6414 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6417 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6427 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a -vm.c:6428 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b +vm.c:5527 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5528 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5529 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5530 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5534 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5548 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5549 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5571 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5597 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5600 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5601 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5604 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5620 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i +vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i +vm.c:5647 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i +vm.c:5648 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i +vm.c:5778 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a +vm.c:5795 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5796 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5798 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5805 #define READ_SLICE_BOUND VAL_NUM TEST a +vm.c:5806 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5809 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5820 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5823 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6417 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6418 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6419 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6422 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6432 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a +vm.c:6433 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index f2aa741a9..fb2ba9eb6 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -636,11 +636,17 @@ result).** under -O2's 602 MB peak), after the warnings #1775 listed were fixed: `builtin_tensor_gather`'s missing return, and the maybe-uninitialized locals behind `num_to_i64_exact` and `vm_index_resolve`. The first fix - round initialised those locals in `vm_run_ex`'s hot arms, which cost + round initialised those locals at all nine declarations, which cost +2.07% Ir on DMG and +4.17% on a JIT-off float loop (the second R1.1 - critic). The second fix round removed the initialisers: the readers - that fill them, `slot_f64_value` and `vm_index_is_int`, write their - out-parameter on every path, so the store sits on the cold path. + critic). Moving the write into the readers instead (`slot_f64_value` + writing 0.0, or the slot's bits, when it answers 0; `vm_index_is_int` + writing on both paths) cost the same: measured with callgrind, any of + them changed `vm_run_ex`'s code, +3.8% (+0.44% for `vm_index_is_int` + alone) on the float loop, which executes neither failure path. What + stays is the initialisation at exactly the three declarations GCC + flags at -O1 (`INT_BINOP_R`'s `_ad`/`_bd`, the `i` of `CASE(INDEX_SET)` + and of `jit_helper_index_set`): against R1.1, -0.0001% on the JIT-off + float loop, +0.0001% with the JIT, -0.08% on the DMG canary. - **Its runner reads each tool on its own channel.** The scan and the test each have a grammar; a line outside it, or any stderr, is a FAIL that prints the line (the R1.1 critic: Python 3.13's DeprecationWarning on the diff --git a/src/value_slot.h b/src/value_slot.h index 02d084de4..4667febcd 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -235,18 +235,18 @@ static inline int slot_truthy_immediate(EigsSlot s, int *out_decided) { /* #1758: a float's double, from an immediate or a VAL_NUM box (the VM boxes * numbers on purpose: the lifts, a for-in variable). 0 for anything else, * an int (an SMI, later a VAL_INT box) included: the caller sends it to its - * slow path. Replaces vm.c's slot_as_double. - * *out is written on EVERY path (0.0 when the answer is 0), so a caller's - * local is never read uninitialised and needs no initialiser of its own: the - * store sits on the cold failure path, and an initialiser in vm_run_ex's hot - * arms cost +2.07% Ir on DMG and +4.17% on a JIT-off float loop (#1775). */ + * slow path; *out is written only when the answer is 1. Replaces vm.c's + * slot_as_double. + * Leave it so: its callers sit in vm_run_ex's hot arms, and making it write + * *out on every path (0.0, or the slot's bits, on the failure path) changed + * vm_run_ex's code and cost +3.8% Ir on a JIT-off float loop, as much as + * initialising the callers' locals did (#1775, measured with callgrind). */ static inline int slot_f64_value(EigsSlot s, double *out) { if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } if (slot_is_heap(s)) { Value *v = slot_as_ptr(s); if (v->type == VAL_NUM) { *out = VAL_NUM_RAW(v); return 1; } } - *out = 0.0; return 0; } /* #1758: an int's value. R1.1 knows the SMI; R1.2a adds the VAL_INT box diff --git a/src/vm.c b/src/vm.c index 2cbd59cf5..2b02314cb 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1838,11 +1838,9 @@ int jit_helper_iter_next(void) { * >= 0 range check downstream, unchanged. */ static inline int vm_index_is_int(double d, int *out) { int i = (int)d; - /* #1775: *out is written on every path (the truncation when the answer is - * 0, which no caller reads), so a caller's index local needs no - * initialiser for -Wmaybe-uninitialized at -O1. */ + if ((double)i != d) return 0; *out = i; - return (double)i == d; + return 1; } /* 0.13.0: resolve negative index against len, then bounds-check. @@ -2203,7 +2201,10 @@ void jit_helper_index_set(void) { EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + /* #1775: `i` is read only when _ok, but GCC at -O1 cannot see that + * through vm_index_resolve; this is one of the three sites it flags, + * and the only initialisations kept (callgrind: none costs Ir). */ + int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { target->data.buffer.data[i] = SLOT_F64_RAW(val_s); @@ -3494,7 +3495,11 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NAME): { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - double _ad, _bd; \ + /* #1775: -O1 cannot see that the fast path's & of two successes \ + * wrote _ad before num_to_i64_exact reads it; initialised here \ + * only, where GCC warns (callgrind: no Ir cost; initialising the \ + * other arms' locals cost +2% on DMG). */ \ + double _ad = 0.0, _bd = 0.0; \ if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ int64_t _ai, _bi; \ if (__builtin_expect(!num_to_i64_exact(_ad, &_ai) || \ @@ -4694,7 +4699,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot tgt_s = g_vm.stack[g_vm.sp - 3]; if (slot_is_f64(idx_s) && slot_is_ptr(tgt_s)) { Value *target = slot_as_ptr(tgt_s); - int i, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); + int i = 0, _ok = vm_index_is_int(SLOT_F64_RAW(idx_s), &i); /* #1775, as in jit_helper_index_set */ if (target->type == VAL_BUFFER && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { target->data.buffer.data[i] = SLOT_F64_RAW(val_s); diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index 809e6d295..72401a249 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -131,8 +131,7 @@ static int r_store_json_encode_slot(int64_t v) { strbuf_free(&sb); return bad; } -/* #1775: the reader writes its out-param on every path (0.0 when it answers 0) */ -static int r_slot_f64_value(int64_t v) { double d = -7.25; return slot_f64_value(smi(v), &d) != 0 || d != 0.0; } +static int r_slot_f64_value(int64_t v) { double d = -7.25; return slot_f64_value(smi(v), &d) != 0 || d != -7.25; } static int r_slot_int_value(int64_t v) { int64_t i = 7; return slot_int_value(smi(v), &i) != 1 || i != v; } static int r_slot_is_f64(int64_t v) { return slot_is_f64(smi(v)) != 0; } static int r_slot_is_smi(int64_t v) { return slot_is_smi(smi(v)) != 1; } @@ -187,7 +186,7 @@ static const Entry ENTRIES[] = { {"container.h:eigs_slot_store_owned", r_eigs_slot_store_owned, 0, 0, "canonical storage: unchanged"}, {"eigenscript.c:ent_child_slot", r_ent_child_slot, 0, 0, "the entropy of its double"}, {"ext_store.c:store_json_encode_slot", r_store_json_encode_slot, 0, 0, "exact digits"}, - {"value_slot.h:slot_f64_value", r_slot_f64_value, 0, 0, "not a float: 0, out 0.0"}, + {"value_slot.h:slot_f64_value", r_slot_f64_value, 0, 0, "not a float: 0, out untouched"}, {"value_slot.h:slot_int_value", r_slot_int_value, 0, 0, "the int"}, {"value_slot.h:slot_is_f64", r_slot_is_f64, 0, 0, "0"}, {"value_slot.h:slot_is_smi", r_slot_is_smi, 0, 0, "1"}, @@ -391,7 +390,7 @@ EXP(write_slot) { } EXP(f64_value) { if (kclass(k) == C_F64) snprintf(b, n, "o:1 d:%016llx", (unsigned long long)KB[k]); - else snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(0.0)); /* written on every path (#1775) */ + else snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(-7.25)); } EXP(int_value) { snprintf(b, n, k == K_SMI ? "o:1 i:5" : "o:0 i:7"); } EXP(is_f64) { snprintf(b, n, "i:%d", kclass(k) == C_F64); } From 9607cfa3439f27c9cb306dfe965e88dffd74639e Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 05:49:43 -0500 Subject: [PATCH 016/188] smi-trap build: no maybe-uninitialized false positives from the trap (#1758) With #1775's initialisers back to the three sites GCC flags in release, the smi-trap variant printed four -Wmaybe-uninitialized warnings in vm_run_ex's compare arms: the trap's noreturn refusal inside every slot predicate defeats GCC's flow analysis there (`_ad` is read only after both reads succeeded). The variant builds with -Wno-maybe-uninitialized; release compiles the same source with the warning on and has none. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 61a94db36..bbf13c0a3 100644 --- a/Makefile +++ b/Makefile @@ -188,8 +188,12 @@ LIBS_jit-checked := $(LDFLAGS) -ldl # (value_slot.h EIGS_SMI_TRAP); slot_as_ptr checks its tag too. Until R1.3 no # program may make an int, so this build must run the corpus exactly as # release does: tools/phase2_check.sh --through R1.1 --smi-trap . +# -Wno-maybe-uninitialized: the trap's noreturn refusal inside every slot +# predicate defeats GCC's flow analysis in vm_run_ex's four compare arms +# (false positives on _ad, read only after both reads succeeded). Release +# compiles the same source with the warning on and has none (#1775). SRC_V_smi-trap := $(HOSTED_SOURCES) -FLAGS_smi-trap := $(CFLAGS) $(DEFS_OFF) -DEIGENSCRIPT_EXT_GFX=1 -DEIGS_SMI_TRAP -DEIGS_SLOT_CHECKED $(VERDEF) +FLAGS_smi-trap := $(CFLAGS) $(DEFS_OFF) -DEIGENSCRIPT_EXT_GFX=1 -DEIGS_SMI_TRAP -DEIGS_SLOT_CHECKED -Wno-maybe-uninitialized $(VERDEF) LIBS_smi-trap := $(LDFLAGS) -ldl VARIANTS := release server server-db zlib asan asan-server tsan tsan-server valgrind poison pool-off asan-pool-off pool-off-num pool-off-callenv jit-checked smi-trap From f404a608b33532ae31609ac8eb2d6c8c8203108a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 06:43:50 -0500 Subject: [PATCH 017/188] phase2 differential: SDL's dummy audio device for every run (#1758) With its run conditions applied, test_audio.eigs reaches the capture test, and a real capture device delivers samples or not by timing: on some runs the file prints a SKIP line. The baseline's two runs agreed, so the file was taken as deterministic, and one branch run that differed was reported as a DIFF (the smi-trap differential of a full run under Python 3.12, a false red: rc 0 on both sides). Every run now uses SDL_AUDIODRIVER=dummy, like the display is Xvfb: six baseline runs of test_audio are identical, and it compares live (`same`), where it was replay-adjudicated before. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 7 ++++++- tools/phase2_corpus_diff.sh | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index fb2ba9eb6..a02764534 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2318,7 +2318,12 @@ fails if a round named here has neither rows nor its mechanical gates.) differential red, and so does a new test that dies early. Every declared file is listed with its code (`SAME-NONZERO`); - a timeout or a crash all four runs agree on is counted as - `timeout_both` or `crash_both`, no longer also as `same`. + `timeout_both` or `crash_both`, no longer also as `same`; + - every run uses SDL's dummy audio device (`SDL_AUDIODRIVER=dummy`): a + real capture device delivers samples or not by timing, so + `test_audio.eigs` printed a SKIP on some runs, and with its conditions + applied the two-run baseline check let it through as deterministic and + a branch run that differed read as a DIFF. - **The smi-trap gate** (`--smi-trap BIN`, R1.1 and R1.2) runs the same differential with a `make smi-trap` build as the branch; until R1.3 it must show no difference, because no program may make an int. diff --git a/tools/phase2_corpus_diff.sh b/tools/phase2_corpus_diff.sh index c78210b98..ba322a009 100755 --- a/tools/phase2_corpus_diff.sh +++ b/tools/phase2_corpus_diff.sh @@ -7,8 +7,12 @@ # all four runs from the branch tree's src/ (the suite's cwd) as # `../tests/`, so a file and whatever it loads by a relative path are the # same bytes for both; only the binary and the stdlib next to it differ. -# stdin /dev/null, a 60 s bound, `env -u XAUTHORITY DISPLAY=:99`. stdout, -# stderr and the exit code are compared byte for byte after one +# stdin /dev/null, a 60 s bound, `env -u XAUTHORITY DISPLAY=:99 +# SDL_AUDIODRIVER=dummy` (the X server is Xvfb; SDL's dummy audio device +# because a real capture device delivers samples or not by timing, so +# test_audio.eigs printed a SKIP on some runs and two agreeing baseline runs +# did not make it deterministic: a branch run that differed read as a DIFF). +# stdout, stderr and the exit code are compared byte for byte after one # normalisation: each tree's absolute root becomes ``. # # RUN CONDITIONS. Each file runs under its conditions from the ONE loader the @@ -214,7 +218,7 @@ run() { ( cd "$BR_ROOT/src" || exit 99 [ "$cap" = 1 ] && ulimit -v 2097152 - suite_program_run "$rel" env -u XAUTHORITY DISPLAY=:99 LD_PRELOAD="$SHIM" \ + suite_program_run "$rel" env -u XAUTHORITY DISPLAY=:99 SDL_AUDIODRIVER=dummy LD_PRELOAD="$SHIM" \ PHASE2_URANDOM_MARK="$out.urandom" "$extra" timeout 60 "$bin" "../$rel" ) < /dev/null > "$out.rawout" 2> "$out.rawerr" rc=$? From 0ab55f9271095d66f9a5572c0f6bf4dc08f76d59 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 10:43:11 -0500 Subject: [PATCH 018/188] phase2 R1.2a: VAL_INT appended, the number tokens renamed with deprecated aliases (#1758) Design 8, R1.2a: - ValType: VAL_NUM becomes VAL_FLOAT (still 0); VAL_INT is appended after VAL_BOOL; VAL_NUM stays as a deprecated alias of VAL_FLOAT. The union's double is f64_ (num_ stays as a deprecated alias member), and VAL_INT's payload is i64_. VAL_F64_RAW, VAL_I64_RAW and VAL_F64_OFFSET are the new raw macros; VAL_NUM_RAW and VAL_NUM_OFFSET spell the deprecated member, so every remaining use warns. The warnings are R1.2's progress meter (365 distinct lines in 21 files, all five configurations); R1.2z deletes the aliases. make_int does not exist: nothing produces an int before R1.3. - val_type_name(VAL_INT) is "num"; `type of` an int is "num" (B). - eigs_json_encode_value's `default:` is deleted; the types it answered "null" for are listed (null, fn, builtin, raw JSON, buffer), unchanged. Forced sites: appending VAL_INT stopped the 15 exhaustive ValType switches at -Werror=switch, plus the JSON encoder once its default went (16). Each has its VAL_INT arm, dead until R1.3: - final semantics: value_to_string, the JSON and store encoders and the SIGUSR1 dump print exact digits (eigs_int_text); is_truthy (nonzero); values_equal_impl (two ints compare their int64); compute_entropy_impl (an int's entropy is its double's, design 7); type and embed type ("num", EIGS_TYPE_NUM); free_value, gc_value_is_node, desc_isolate_const and the slice error (a scalar with nothing owned, not sliceable); - refused through eigs_int_unwired (R1.3's token): the tape writers (write_value_ptr, write_value_ptr_full: tape v7) and chan_clone_rec (a fresh int box needs make_int). Tools: num_read_check.sh counts the new raw macros (and the deprecated ones until R1.2z); the allowlist rows for the functions that gained an int read are re-reviewed. phase2_inventory.py knows the new vocabulary; the inventory is regenerated. Builds: release, server-db, zlib, freestanding and the extra TUs compile with 0 errors and no warning besides the deprecations. The C slot test, which fails on any build warning, is red until R1.2z by design. Callgrind against f404a608 (same path; DMG's work depends on wall time -- it updates a window title every 2000 ms -- so its count moves with load): float loop JIT off +0.00005%, JIT on +0.00007%, DMG 500K +0.112% under a concurrent build in another worktree; quiet-machine paired samples follow in the round's report. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-value-layer.md | 1 + docs/design/phase2-inventory.txt | 1486 ++++++++++--------- src/builtins.c | 18 +- src/eigenscript.c | 22 +- src/eigenscript.h | 38 +- src/eigs_embed.c | 1 + src/ext_store.c | 6 + src/trace.c | 4 + src/vm.c | 3 +- tools/num_read_allowlist.txt | 21 +- tools/num_read_check.sh | 17 +- tools/phase2_inventory.py | 27 +- 12 files changed, 889 insertions(+), 755 deletions(-) create mode 100644 changes/internal/1758-phase2-value-layer.md diff --git a/changes/internal/1758-phase2-value-layer.md b/changes/internal/1758-phase2-value-layer.md new file mode 100644 index 000000000..e7c31a985 --- /dev/null +++ b/changes/internal/1758-phase2-value-layer.md @@ -0,0 +1 @@ +- #1758 Phase 2 round R1.2, the Value layer: the number Value type is renamed (`VAL_FLOAT`), an exact int64 Value type (`VAL_INT`) exists, and every switch and type test over a value's type decides what an int does there; nothing produces an int yet (R1.3), so no program behaves differently. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index f66913da6..8f1e8bdc7 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,23 +1,23 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1826 classified=1826 unclassified=0 -files=65 tokens=43 role_rules=8 derived_accessors=18 wrappers=7 +examined=1863 classified=1863 unclassified=0 +files=65 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 399 CASE=52 DATA=3 TEST=342 YIELD=2 -(b) payload reads 534 RAW=119 READ=415 -(c) producers 469 GUARD=71 PARSE=3 PRODUCE=370 TAGSET=3 WRITE=22 +(a) type tests 409 CASE=60 DATA=5 TEST=342 YIELD=2 +(b) payload reads 542 RAW=127 READ=415 +(c) producers 470 GUARD=71 PARSE=3 PRODUCE=370 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 -(e) number formatting 16 CASE=1 FORMAT=3 PARSE=1 RAW=2 READ=3 TEST=6 -(f) equality, ordering and hashing 30 CASE=1 PRODUCE=4 RAW=5 READ=9 TEST=11 -(g) tape encode and decode 21 CASE=2 DATA=2 PARSE=7 PRODUCE=5 RAW=3 TEST=2 -(h) JSON, store and db encoders 72 CASE=2 FORMAT=3 PARSE=5 PRODUCE=19 RAW=1 READ=24 TEST=18 -(i) observer numeric paths 94 CASE=4 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=5 TEST=24 -(j) embed API 64 CASE=1 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 +(e) number formatting 18 CASE=2 FORMAT=3 PARSE=1 RAW=3 READ=3 TEST=6 +(f) equality, ordering and hashing 33 CASE=2 PRODUCE=4 RAW=7 READ=9 TEST=11 +(g) tape encode and decode 25 CASE=4 DATA=2 PARSE=7 PRODUCE=5 RAW=5 TEST=2 +(h) JSON, store and db encoders 76 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=3 READ=24 TEST=18 +(i) observer numeric paths 98 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=25 READ=5 TEST=24 +(j) embed API 65 CASE=2 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 ## Per token make_num 364 -VAL_NUM 329 +VAL_NUM 328 eigs_num_arg 145 eigs_list_num 130 VAL_NUM_RAW 92 @@ -32,10 +32,12 @@ buffer_read_num 38 slot_is_smi 37 buffer_read_byte 22 list_set_num 22 +VAL_INT 18 slot_smi_val 17 slot_f64_value 16 strtod 16 NUM_REUSE 15 +VAL_I64_RAW 12 eigs_slot_opt_num 12 eigs_num_arg_slow 9 EIGS_NUM_MAX 8 @@ -49,43 +51,48 @@ num_val 5 VAL_NUM_OFFSET 4 buf_num_arg 4 dict_value_rewrite_num 4 +VAL_FLOAT 3 list_rewrite_num 3 eigs_elem_num 2 +f64_ 2 list_append_num 2 make_num_permanent 2 num_ 2 +VAL_F64_OFFSET 1 +VAL_F64_RAW 1 atof 1 d_ 1 dict_value_get_num 1 dict_value_set_num 1 +i64_ 1 list_get_num 1 slot_from_int 1 slot_int_value 1 data.num (AST) 7 ## Per file (category counts) -builtins.c 319 a=74 b=94 c=111 e=6 f=8 h=15 i=11 -vm.c 296 a=77 b=97 c=68 e=2 f=9 i=43 +builtins.c 323 a=76 b=94 c=111 e=6 f=8 h=17 i=11 +vm.c 299 a=78 b=97 c=68 e=2 f=9 i=45 ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 184 a=39 b=59 c=86 +eigenscript.c 102 a=19 b=15 c=12 e=7 f=10 i=39 builtins_buf.c 97 a=21 b=37 c=39 jit.c 96 d=96 container.h 89 a=35 b=29 c=25 -eigenscript.c 88 a=14 b=13 c=12 e=5 f=7 i=37 -ext_store.c 52 h=52 +ext_store.c 54 h=54 embed_smoke.c 50 j=50 builtins_host.c 47 a=11 b=24 c=12 -eigenscript.h 33 a=3 b=18 c=11 e=1 +eigenscript.h 42 a=5 b=24 c=12 e=1 jit_smoke.c 31 d=31 lint.c 29 a=29 compiler.c 21 a=13 b=5 c=1 i=2 +trace.c 20 g=20 value_slot.h 20 a=7 b=10 c=3 ext_net.c 19 a=5 b=7 c=7 model_infer.c 16 a=1 b=6 c=9 -trace.c 16 g=16 ext_http.c 14 a=3 b=4 c=7 chunk.c 11 a=3 e=2 f=6 -eigs_embed.c 7 j=7 +eigs_embed.c 8 j=8 model_train.c 7 a=1 b=4 c=1 i=1 embed_concurrent.c 6 j=6 parser.c 5 a=2 b=1 c=2 @@ -397,8 +404,8 @@ inflate builtin_inflate int-requiring join builtin_join other - - eigs_num_text json_build builtin_json_build other LOSS - VAL_NUM,eigs_num_arg,eigs_num_text json_decode builtin_json_decode other LOSS - make_num,strtod -json_encode builtin_json_encode other LOSS - VAL_NUM,eigs_num_arg,eigs_num_text -json_path builtin_json_path other LOSS - VAL_NUM,eigs_num_arg,eigs_num_text,make_num,strtod +json_encode builtin_json_encode other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_num_text +json_path builtin_json_path other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_num_text,make_num,strtod leaky_relu builtin_tensor_leaky_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num len builtin_len int-preserving - - make_num list_contains builtin_list_contains other - - values_equal @@ -456,7 +463,7 @@ recv_timeout builtin_recv_timeout int-requiring relu builtin_tensor_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num reshape builtin_reshape int-requiring - - VAL_NUM,eigs_list_num round builtin_round int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num -sandbox_run builtin_sandbox_run int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +sandbox_run builtin_sandbox_run int-requiring - - VAL_INT,VAL_NUM,eigs_list_num,eigs_num_arg,make_num scan_int_tokens builtin_scan_int_tokens int-preserving LOSS - make_num scan_ints builtin_scan_ints int-preserving LOSS - make_num scatter_add builtin_tensor_scatter_add float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard @@ -478,16 +485,16 @@ sort_by builtin_sort_by other spawn builtin_spawn int-preserving - - make_num sqrt builtin_tensor_sqrt float-producing - - VAL_NUM,eigs_num_arg,make_num state_at builtin_state_at int-requiring - - VAL_NUM,eigs_num_arg -store_close builtin_store_close int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val +store_close builtin_store_close int-requiring - - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val store_collections builtin_store_collections int-requiring - - VAL_NUM,eigs_num_arg store_count builtin_store_count int-requiring - - VAL_NUM,eigs_num_arg,make_num store_delete builtin_store_delete int-requiring LOSS - VAL_NUM,eigs_num_arg -store_drop builtin_store_drop int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val +store_drop builtin_store_drop int-requiring - - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val store_get builtin_store_get int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,strtod store_open builtin_store_open int-preserving - - VAL_NUM,eigs_num_arg,make_num,strtod -store_put builtin_store_put other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val +store_put builtin_store_put other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val store_query builtin_store_query other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod -store_update builtin_store_update other LOSS - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val +store_update builtin_store_update other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val str builtin_str other - - eigs_num_text str_from_bytes builtin_str_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte stream_open builtin_stream_open int-requiring - - VAL_NUM,eigs_num_arg @@ -513,9 +520,9 @@ thread_join builtin_thread_join int-requiring throw builtin_throw other - - eigs_num_text token_name builtin_token_name int-requiring - - VAL_NUM,eigs_num_arg try_recv builtin_try_recv int-requiring - - VAL_NUM,eigs_num_arg -type builtin_type other - - VAL_NUM +type builtin_type other - - VAL_INT,VAL_NUM usleep builtin_usleep other - magnitude VAL_NUM,eigs_num_arg -vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_NUM,eigs_num_arg +vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_INT,VAL_NUM,eigs_num_arg write builtin_write other - - eigs_num_text write_bytes builtin_write_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num zeros builtin_tensor_zeros int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num @@ -568,279 +575,283 @@ builtins.c:783 builtin_observe make_num PRODUCE i builtins.c:784 builtin_observe make_num PRODUCE i builtins.c:785 builtin_observe make_num PRODUCE i builtins.c:867 builtin_type VAL_NUM CASE a -builtins.c:915 eigs_json_encode_value VAL_NUM CASE h -builtins.c:922 eigs_json_encode_value eigs_num_arg READ h -builtins.c:922 eigs_json_encode_value eigs_num_text FORMAT h -builtins.c:1278 eigs_json_parse_number make_num PRODUCE h -builtins.c:1285 eigs_json_parse_number make_num PRODUCE h -builtins.c:1294 eigs_json_parse_number make_num PRODUCE h -builtins.c:1299 eigs_json_parse_number strtod PARSE h -builtins.c:1309 eigs_json_parse_number strtod PARSE h -builtins.c:1313 eigs_json_parse_number make_num PRODUCE h -builtins.c:1484 builtin_json_build VAL_NUM TEST h -builtins.c:1486 builtin_json_build eigs_num_arg READ h -builtins.c:1486 builtin_json_build eigs_num_text FORMAT h -builtins.c:1672 builtin_scan_ints make_num PRODUCE c -builtins.c:1786 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1787 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1788 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1789 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1790 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1791 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1894 builtin_char_at VAL_NUM TEST a -builtins.c:1896 builtin_char_at eigs_num_arg READ b -builtins.c:1930 builtin_substr VAL_NUM TEST a -builtins.c:1931 builtin_substr VAL_NUM TEST a -builtins.c:1933 builtin_substr eigs_num_arg READ b -builtins.c:1934 builtin_substr eigs_num_arg READ b -builtins.c:1964 builtin_index_of make_num PRODUCE c -builtins.c:1971 builtin_index_of make_num PRODUCE c -builtins.c:1976 builtin_index_of make_num PRODUCE c -builtins.c:1977 builtin_index_of make_num PRODUCE c -builtins.c:1985 builtin_sin VAL_NUM TEST a -builtins.c:1985 builtin_sin make_num PRODUCE c -builtins.c:1986 builtin_sin eigs_num_arg READ b -builtins.c:1986 builtin_sin make_num PRODUCE c -builtins.c:1990 builtin_cos VAL_NUM TEST a -builtins.c:1990 builtin_cos make_num PRODUCE c -builtins.c:1991 builtin_cos eigs_num_arg READ b -builtins.c:1991 builtin_cos make_num PRODUCE c -builtins.c:1995 builtin_tan VAL_NUM TEST a -builtins.c:1995 builtin_tan make_num PRODUCE c -builtins.c:1996 builtin_tan eigs_num_arg READ b -builtins.c:1996 builtin_tan make_num PRODUCE c -builtins.c:2000 builtin_asin VAL_NUM TEST a -builtins.c:2000 builtin_asin make_num PRODUCE c -builtins.c:2001 builtin_asin eigs_num_arg READ b -builtins.c:2006 builtin_asin make_num PRODUCE c -builtins.c:2010 builtin_asin make_num PRODUCE c -builtins.c:2014 builtin_acos VAL_NUM TEST a -builtins.c:2014 builtin_acos make_num PRODUCE c -builtins.c:2015 builtin_acos eigs_num_arg READ b -builtins.c:2020 builtin_acos make_num PRODUCE c -builtins.c:2024 builtin_acos make_num PRODUCE c -builtins.c:2028 builtin_atan VAL_NUM TEST a -builtins.c:2028 builtin_atan make_num PRODUCE c -builtins.c:2029 builtin_atan eigs_num_arg READ b -builtins.c:2029 builtin_atan make_num PRODUCE c -builtins.c:2034 builtin_atan2 make_num PRODUCE c -builtins.c:2037 builtin_atan2 VAL_NUM TEST a -builtins.c:2037 builtin_atan2 VAL_NUM TEST a -builtins.c:2037 builtin_atan2 make_num PRODUCE c -builtins.c:2038 builtin_atan2 eigs_num_arg READ b -builtins.c:2038 builtin_atan2 eigs_num_arg READ b -builtins.c:2038 builtin_atan2 make_num PRODUCE c -builtins.c:2042 builtin_floor VAL_NUM TEST a -builtins.c:2042 builtin_floor make_num PRODUCE c -builtins.c:2043 builtin_floor eigs_num_arg READ b -builtins.c:2043 builtin_floor make_num PRODUCE c -builtins.c:2047 builtin_ceil VAL_NUM TEST a -builtins.c:2047 builtin_ceil make_num PRODUCE c -builtins.c:2048 builtin_ceil eigs_num_arg READ b -builtins.c:2048 builtin_ceil make_num PRODUCE c -builtins.c:2052 builtin_round VAL_NUM TEST a -builtins.c:2052 builtin_round make_num PRODUCE c -builtins.c:2053 builtin_round eigs_num_arg READ b -builtins.c:2053 builtin_round make_num PRODUCE c -builtins.c:2057 builtin_abs VAL_NUM TEST a -builtins.c:2057 builtin_abs make_num PRODUCE c -builtins.c:2058 builtin_abs eigs_num_arg READ b -builtins.c:2058 builtin_abs make_num PRODUCE c -builtins.c:2067 minmax_reduce VAL_NUM TEST a -builtins.c:2067 minmax_reduce eigs_num_arg READ b -builtins.c:2067 minmax_reduce make_num PRODUCE c -builtins.c:2072 minmax_reduce make_num PRODUCE c -builtins.c:2075 minmax_reduce make_num PRODUCE c -builtins.c:2079 minmax_reduce VAL_NUM TEST a -builtins.c:2079 minmax_reduce make_num PRODUCE c -builtins.c:2080 minmax_reduce eigs_num_arg READ b -builtins.c:2080 minmax_reduce eigs_num_arg READ b -builtins.c:2081 minmax_reduce eigs_num_arg READ b -builtins.c:2083 minmax_reduce make_num PRODUCE c -builtins.c:2092 builtin_pi make_num PRODUCE c -builtins.c:2148 builtin_random make_num PRODUCE c -builtins.c:2157 builtin_random_int make_num PRODUCE c -builtins.c:2160 builtin_random_int VAL_NUM TEST a -builtins.c:2160 builtin_random_int VAL_NUM TEST a -builtins.c:2161 builtin_random_int make_num PRODUCE c -builtins.c:2165 builtin_random_int eigs_num_arg READ b -builtins.c:2166 builtin_random_int eigs_num_arg READ b +builtins.c:868 builtin_type VAL_INT CASE a +builtins.c:916 eigs_json_encode_value VAL_NUM CASE h +builtins.c:923 eigs_json_encode_value eigs_num_arg READ h +builtins.c:923 eigs_json_encode_value eigs_num_text FORMAT h +builtins.c:927 eigs_json_encode_value VAL_INT CASE h +builtins.c:929 eigs_json_encode_value VAL_I64_RAW RAW h +builtins.c:1293 eigs_json_parse_number make_num PRODUCE h +builtins.c:1300 eigs_json_parse_number make_num PRODUCE h +builtins.c:1309 eigs_json_parse_number make_num PRODUCE h +builtins.c:1314 eigs_json_parse_number strtod PARSE h +builtins.c:1324 eigs_json_parse_number strtod PARSE h +builtins.c:1328 eigs_json_parse_number make_num PRODUCE h +builtins.c:1499 builtin_json_build VAL_NUM TEST h +builtins.c:1501 builtin_json_build eigs_num_arg READ h +builtins.c:1501 builtin_json_build eigs_num_text FORMAT h +builtins.c:1687 builtin_scan_ints make_num PRODUCE c +builtins.c:1801 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1802 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1803 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1804 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1805 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1806 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1909 builtin_char_at VAL_NUM TEST a +builtins.c:1911 builtin_char_at eigs_num_arg READ b +builtins.c:1945 builtin_substr VAL_NUM TEST a +builtins.c:1946 builtin_substr VAL_NUM TEST a +builtins.c:1948 builtin_substr eigs_num_arg READ b +builtins.c:1949 builtin_substr eigs_num_arg READ b +builtins.c:1979 builtin_index_of make_num PRODUCE c +builtins.c:1986 builtin_index_of make_num PRODUCE c +builtins.c:1991 builtin_index_of make_num PRODUCE c +builtins.c:1992 builtin_index_of make_num PRODUCE c +builtins.c:2000 builtin_sin VAL_NUM TEST a +builtins.c:2000 builtin_sin make_num PRODUCE c +builtins.c:2001 builtin_sin eigs_num_arg READ b +builtins.c:2001 builtin_sin make_num PRODUCE c +builtins.c:2005 builtin_cos VAL_NUM TEST a +builtins.c:2005 builtin_cos make_num PRODUCE c +builtins.c:2006 builtin_cos eigs_num_arg READ b +builtins.c:2006 builtin_cos make_num PRODUCE c +builtins.c:2010 builtin_tan VAL_NUM TEST a +builtins.c:2010 builtin_tan make_num PRODUCE c +builtins.c:2011 builtin_tan eigs_num_arg READ b +builtins.c:2011 builtin_tan make_num PRODUCE c +builtins.c:2015 builtin_asin VAL_NUM TEST a +builtins.c:2015 builtin_asin make_num PRODUCE c +builtins.c:2016 builtin_asin eigs_num_arg READ b +builtins.c:2021 builtin_asin make_num PRODUCE c +builtins.c:2025 builtin_asin make_num PRODUCE c +builtins.c:2029 builtin_acos VAL_NUM TEST a +builtins.c:2029 builtin_acos make_num PRODUCE c +builtins.c:2030 builtin_acos eigs_num_arg READ b +builtins.c:2035 builtin_acos make_num PRODUCE c +builtins.c:2039 builtin_acos make_num PRODUCE c +builtins.c:2043 builtin_atan VAL_NUM TEST a +builtins.c:2043 builtin_atan make_num PRODUCE c +builtins.c:2044 builtin_atan eigs_num_arg READ b +builtins.c:2044 builtin_atan make_num PRODUCE c +builtins.c:2049 builtin_atan2 make_num PRODUCE c +builtins.c:2052 builtin_atan2 VAL_NUM TEST a +builtins.c:2052 builtin_atan2 VAL_NUM TEST a +builtins.c:2052 builtin_atan2 make_num PRODUCE c +builtins.c:2053 builtin_atan2 eigs_num_arg READ b +builtins.c:2053 builtin_atan2 eigs_num_arg READ b +builtins.c:2053 builtin_atan2 make_num PRODUCE c +builtins.c:2057 builtin_floor VAL_NUM TEST a +builtins.c:2057 builtin_floor make_num PRODUCE c +builtins.c:2058 builtin_floor eigs_num_arg READ b +builtins.c:2058 builtin_floor make_num PRODUCE c +builtins.c:2062 builtin_ceil VAL_NUM TEST a +builtins.c:2062 builtin_ceil make_num PRODUCE c +builtins.c:2063 builtin_ceil eigs_num_arg READ b +builtins.c:2063 builtin_ceil make_num PRODUCE c +builtins.c:2067 builtin_round VAL_NUM TEST a +builtins.c:2067 builtin_round make_num PRODUCE c +builtins.c:2068 builtin_round eigs_num_arg READ b +builtins.c:2068 builtin_round make_num PRODUCE c +builtins.c:2072 builtin_abs VAL_NUM TEST a +builtins.c:2072 builtin_abs make_num PRODUCE c +builtins.c:2073 builtin_abs eigs_num_arg READ b +builtins.c:2073 builtin_abs make_num PRODUCE c +builtins.c:2082 minmax_reduce VAL_NUM TEST a +builtins.c:2082 minmax_reduce eigs_num_arg READ b +builtins.c:2082 minmax_reduce make_num PRODUCE c +builtins.c:2087 minmax_reduce make_num PRODUCE c +builtins.c:2090 minmax_reduce make_num PRODUCE c +builtins.c:2094 minmax_reduce VAL_NUM TEST a +builtins.c:2094 minmax_reduce make_num PRODUCE c +builtins.c:2095 minmax_reduce eigs_num_arg READ b +builtins.c:2095 minmax_reduce eigs_num_arg READ b +builtins.c:2096 minmax_reduce eigs_num_arg READ b +builtins.c:2098 minmax_reduce make_num PRODUCE c +builtins.c:2107 builtin_pi make_num PRODUCE c +builtins.c:2163 builtin_random make_num PRODUCE c +builtins.c:2172 builtin_random_int make_num PRODUCE c +builtins.c:2175 builtin_random_int VAL_NUM TEST a +builtins.c:2175 builtin_random_int VAL_NUM TEST a builtins.c:2176 builtin_random_int make_num PRODUCE c -builtins.c:2188 builtin_random_int make_num PRODUCE c -builtins.c:2193 builtin_seed_random VAL_NUM TEST a -builtins.c:2195 builtin_seed_random eigs_num_arg READ b -builtins.c:2423 builtin_json_path VAL_NUM TEST h -builtins.c:2425 builtin_json_path eigs_num_arg READ h -builtins.c:2425 builtin_json_path eigs_num_text FORMAT h -builtins.c:2529 builtin_token_name VAL_NUM TEST a -builtins.c:2530 builtin_token_name eigs_num_arg READ b -builtins.c:2566 builtin_state_at VAL_NUM TEST i -builtins.c:2567 builtin_state_at eigs_num_arg READ i -builtins.c:2613 builtin_chr VAL_NUM TEST a -builtins.c:2617 builtin_chr eigs_num_arg READ b -builtins.c:2641 builtin_hex VAL_NUM TEST e -builtins.c:2642 builtin_hex eigs_num_arg READ e -builtins.c:2644 builtin_hex VAL_NUM TEST e -builtins.c:2645 builtin_hex VAL_NUM TEST e -builtins.c:2646 builtin_hex eigs_list_num READ e -builtins.c:2647 builtin_hex eigs_list_num READ e -builtins.c:2674 builtin_ord make_num PRODUCE c -builtins.c:2677 builtin_ord make_num PRODUCE c -builtins.c:2678 builtin_ord make_num PRODUCE c -builtins.c:2795 vm_desc_abi_error VAL_NUM TEST a -builtins.c:2803 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2808 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2904 desc_isolate_const VAL_NUM CASE a -builtins.c:3022 vm_build_chunk_desc_body VAL_NUM TEST a -builtins.c:3027 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3083 vm_build_chunk_desc_body VAL_NUM TEST a -builtins.c:3084 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3401 builtin_sandbox_run VAL_NUM TEST a -builtins.c:3402 builtin_sandbox_run eigs_list_num READ b -builtins.c:3408 builtin_sandbox_run VAL_NUM TEST a -builtins.c:3409 builtin_sandbox_run eigs_list_num READ b -builtins.c:3410 builtin_sandbox_run eigs_list_num READ b +builtins.c:2180 builtin_random_int eigs_num_arg READ b +builtins.c:2181 builtin_random_int eigs_num_arg READ b +builtins.c:2191 builtin_random_int make_num PRODUCE c +builtins.c:2203 builtin_random_int make_num PRODUCE c +builtins.c:2208 builtin_seed_random VAL_NUM TEST a +builtins.c:2210 builtin_seed_random eigs_num_arg READ b +builtins.c:2438 builtin_json_path VAL_NUM TEST h +builtins.c:2440 builtin_json_path eigs_num_arg READ h +builtins.c:2440 builtin_json_path eigs_num_text FORMAT h +builtins.c:2544 builtin_token_name VAL_NUM TEST a +builtins.c:2545 builtin_token_name eigs_num_arg READ b +builtins.c:2581 builtin_state_at VAL_NUM TEST i +builtins.c:2582 builtin_state_at eigs_num_arg READ i +builtins.c:2628 builtin_chr VAL_NUM TEST a +builtins.c:2632 builtin_chr eigs_num_arg READ b +builtins.c:2656 builtin_hex VAL_NUM TEST e +builtins.c:2657 builtin_hex eigs_num_arg READ e +builtins.c:2659 builtin_hex VAL_NUM TEST e +builtins.c:2660 builtin_hex VAL_NUM TEST e +builtins.c:2661 builtin_hex eigs_list_num READ e +builtins.c:2662 builtin_hex eigs_list_num READ e +builtins.c:2689 builtin_ord make_num PRODUCE c +builtins.c:2692 builtin_ord make_num PRODUCE c +builtins.c:2693 builtin_ord make_num PRODUCE c +builtins.c:2810 vm_desc_abi_error VAL_NUM TEST a +builtins.c:2818 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2823 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2919 desc_isolate_const VAL_NUM CASE a +builtins.c:2920 desc_isolate_const VAL_INT CASE a +builtins.c:3038 vm_build_chunk_desc_body VAL_NUM TEST a +builtins.c:3043 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3099 vm_build_chunk_desc_body VAL_NUM TEST a +builtins.c:3100 vm_build_chunk_desc_body eigs_num_arg READ b builtins.c:3417 builtin_sandbox_run VAL_NUM TEST a builtins.c:3418 builtin_sandbox_run eigs_list_num READ b -builtins.c:3460 builtin_sandbox_run make_num PRODUCE c -builtins.c:3641 builtin_sandbox_run make_num PRODUCE c -builtins.c:3653 builtin_sandbox_run make_num PRODUCE c -builtins.c:3667 builtin_sandbox_run make_num PRODUCE c -builtins.c:3701 builtin_sandbox_run make_num PRODUCE c -builtins.c:3727 builtin_record_history VAL_NUM TEST i -builtins.c:3733 builtin_record_history eigs_num_arg READ i -builtins.c:3738 builtin_record_history make_num PRODUCE i -builtins.c:3766 builtin_copy_into VAL_NUM TEST a -builtins.c:3771 builtin_copy_into eigs_num_arg READ b -builtins.c:3783 builtin_copy_into VAL_NUM TEST a -builtins.c:3788 builtin_copy_into eigs_num_arg READ b -builtins.c:3821 builtin_list_slice VAL_NUM TEST a -builtins.c:3821 builtin_list_slice VAL_NUM TEST a -builtins.c:3824 builtin_list_slice eigs_num_arg READ b -builtins.c:3825 builtin_list_slice eigs_num_arg READ b -builtins.c:3847 builtin_num_copy VAL_NUM TEST a -builtins.c:3848 builtin_num_copy eigs_num_arg READ b -builtins.c:3848 builtin_num_copy make_num PRODUCE c -builtins.c:3892 builtin_range VAL_NUM TEST a -builtins.c:3894 builtin_range eigs_num_arg READ b -builtins.c:3901 builtin_range VAL_NUM TEST a -builtins.c:3909 builtin_range eigs_list_num READ b -builtins.c:3912 builtin_range eigs_list_num READ b -builtins.c:3916 builtin_range eigs_list_num READ b -builtins.c:3960 builtin_range make_num PRODUCE c -builtins.c:3976 builtin_fill eigs_list_num READ b -builtins.c:3998 at_index VAL_NUM TEST a -builtins.c:4002 at_index eigs_num_arg READ b -builtins.c:4006 at_index eigs_num_arg READ b -builtins.c:4017 buf_at_index VAL_NUM TEST a -builtins.c:4022 buf_at_index eigs_num_arg READ b -builtins.c:4026 buf_at_index eigs_num_arg READ b -builtins.c:4067 builtin_set_at VAL_NUM TEST a -builtins.c:4072 builtin_set_at eigs_num_arg READ b -builtins.c:4133 builtin_get_at buffer_read_num READ b -builtins.c:4133 builtin_get_at make_num PRODUCE c -builtins.c:4141 builtin_get_at buffer_read_num READ b -builtins.c:4141 builtin_get_at make_num PRODUCE c -builtins.c:4503 builtin_spawn make_num PRODUCE c -builtins.c:4509 builtin_spawn make_num PRODUCE c -builtins.c:4510 builtin_spawn make_num PRODUCE c -builtins.c:4535 builtin_thread_join VAL_NUM TEST a -builtins.c:4539 builtin_thread_join eigs_num_arg READ b -builtins.c:4540 builtin_thread_join VAL_NUM TEST a -builtins.c:4540 builtin_thread_join eigs_num_arg READ b -builtins.c:4620 get_channel_why VAL_NUM TEST a -builtins.c:4621 get_channel_why eigs_num_arg READ b -builtins.c:4623 get_channel_why VAL_NUM TEST a -builtins.c:4623 get_channel_why eigs_num_arg READ b -builtins.c:4688 builtin_channel make_num PRODUCE c -builtins.c:4689 builtin_channel make_num PRODUCE c -builtins.c:4791 builtin_recv_timeout VAL_NUM TEST a -builtins.c:4795 builtin_recv_timeout eigs_num_arg READ b -builtins.c:4977 builtin_task_spawn make_num PRODUCE c -builtins.c:4987 task_handle_resolve VAL_NUM TEST a -builtins.c:4988 task_handle_resolve eigs_num_arg READ b -builtins.c:5039 builtin_task_join VAL_NUM TEST a -builtins.c:5081 builtin_task_send VAL_NUM TEST a -builtins.c:5089 builtin_task_send eigs_num_arg READ b -builtins.c:5112 builtin_task_kill VAL_NUM TEST a -builtins.c:5124 builtin_task_alive VAL_NUM TEST a -builtins.c:5146 builtin_task_sleep VAL_NUM TEST a -builtins.c:5152 builtin_task_sleep eigs_num_arg READ b -builtins.c:5184 builtin_task_self make_num PRODUCE c -builtins.c:5196 builtin_task_detach VAL_NUM TEST a -builtins.c:5201 builtin_task_detach make_num PRODUCE c -builtins.c:5202 builtin_task_detach make_num PRODUCE c -builtins.c:5213 builtin_task_sched_seed VAL_NUM TEST a -builtins.c:5217 builtin_task_sched_seed eigs_num_arg READ b -builtins.c:5366 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5367 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5368 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5369 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5370 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5426 builtin_nearest_in_range VAL_NUM TEST a -builtins.c:5426 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5450 builtin_nearest_in_range eigs_num_arg_slow READ b -builtins.c:5453 builtin_nearest_in_range VAL_NUM TEST a -builtins.c:5453 builtin_nearest_in_range VAL_NUM TEST a -builtins.c:5455 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5456 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5470 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5471 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5472 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5473 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5498 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5499 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5500 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5555 builtin_nearest_in_range_all VAL_NUM TEST a -builtins.c:5555 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5575 builtin_nearest_in_range_all eigs_num_arg_slow READ b -builtins.c:5578 builtin_nearest_in_range_all VAL_NUM TEST a -builtins.c:5578 builtin_nearest_in_range_all VAL_NUM TEST a -builtins.c:5582 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5583 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5624 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5625 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5626 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5627 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5650 builtin_sign_extend make_num PRODUCE c -builtins.c:5660 builtin_sign_extend VAL_NUM TEST a -builtins.c:5660 builtin_sign_extend VAL_NUM TEST a -builtins.c:5660 builtin_sign_extend make_num PRODUCE c -builtins.c:5661 builtin_sign_extend eigs_num_arg READ b -builtins.c:5662 builtin_sign_extend eigs_num_arg READ b -builtins.c:5663 builtin_sign_extend make_num PRODUCE c +builtins.c:3424 builtin_sandbox_run VAL_NUM TEST a +builtins.c:3425 builtin_sandbox_run eigs_list_num READ b +builtins.c:3426 builtin_sandbox_run eigs_list_num READ b +builtins.c:3433 builtin_sandbox_run VAL_NUM TEST a +builtins.c:3434 builtin_sandbox_run eigs_list_num READ b +builtins.c:3476 builtin_sandbox_run make_num PRODUCE c +builtins.c:3657 builtin_sandbox_run make_num PRODUCE c +builtins.c:3669 builtin_sandbox_run make_num PRODUCE c +builtins.c:3683 builtin_sandbox_run make_num PRODUCE c +builtins.c:3717 builtin_sandbox_run make_num PRODUCE c +builtins.c:3743 builtin_record_history VAL_NUM TEST i +builtins.c:3749 builtin_record_history eigs_num_arg READ i +builtins.c:3754 builtin_record_history make_num PRODUCE i +builtins.c:3782 builtin_copy_into VAL_NUM TEST a +builtins.c:3787 builtin_copy_into eigs_num_arg READ b +builtins.c:3799 builtin_copy_into VAL_NUM TEST a +builtins.c:3804 builtin_copy_into eigs_num_arg READ b +builtins.c:3837 builtin_list_slice VAL_NUM TEST a +builtins.c:3837 builtin_list_slice VAL_NUM TEST a +builtins.c:3840 builtin_list_slice eigs_num_arg READ b +builtins.c:3841 builtin_list_slice eigs_num_arg READ b +builtins.c:3863 builtin_num_copy VAL_NUM TEST a +builtins.c:3864 builtin_num_copy eigs_num_arg READ b +builtins.c:3864 builtin_num_copy make_num PRODUCE c +builtins.c:3908 builtin_range VAL_NUM TEST a +builtins.c:3910 builtin_range eigs_num_arg READ b +builtins.c:3917 builtin_range VAL_NUM TEST a +builtins.c:3925 builtin_range eigs_list_num READ b +builtins.c:3928 builtin_range eigs_list_num READ b +builtins.c:3932 builtin_range eigs_list_num READ b +builtins.c:3976 builtin_range make_num PRODUCE c +builtins.c:3992 builtin_fill eigs_list_num READ b +builtins.c:4014 at_index VAL_NUM TEST a +builtins.c:4018 at_index eigs_num_arg READ b +builtins.c:4022 at_index eigs_num_arg READ b +builtins.c:4033 buf_at_index VAL_NUM TEST a +builtins.c:4038 buf_at_index eigs_num_arg READ b +builtins.c:4042 buf_at_index eigs_num_arg READ b +builtins.c:4083 builtin_set_at VAL_NUM TEST a +builtins.c:4088 builtin_set_at eigs_num_arg READ b +builtins.c:4149 builtin_get_at buffer_read_num READ b +builtins.c:4149 builtin_get_at make_num PRODUCE c +builtins.c:4157 builtin_get_at buffer_read_num READ b +builtins.c:4157 builtin_get_at make_num PRODUCE c +builtins.c:4519 builtin_spawn make_num PRODUCE c +builtins.c:4525 builtin_spawn make_num PRODUCE c +builtins.c:4526 builtin_spawn make_num PRODUCE c +builtins.c:4551 builtin_thread_join VAL_NUM TEST a +builtins.c:4555 builtin_thread_join eigs_num_arg READ b +builtins.c:4556 builtin_thread_join VAL_NUM TEST a +builtins.c:4556 builtin_thread_join eigs_num_arg READ b +builtins.c:4636 get_channel_why VAL_NUM TEST a +builtins.c:4637 get_channel_why eigs_num_arg READ b +builtins.c:4639 get_channel_why VAL_NUM TEST a +builtins.c:4639 get_channel_why eigs_num_arg READ b +builtins.c:4704 builtin_channel make_num PRODUCE c +builtins.c:4705 builtin_channel make_num PRODUCE c +builtins.c:4807 builtin_recv_timeout VAL_NUM TEST a +builtins.c:4811 builtin_recv_timeout eigs_num_arg READ b +builtins.c:4993 builtin_task_spawn make_num PRODUCE c +builtins.c:5003 task_handle_resolve VAL_NUM TEST a +builtins.c:5004 task_handle_resolve eigs_num_arg READ b +builtins.c:5055 builtin_task_join VAL_NUM TEST a +builtins.c:5097 builtin_task_send VAL_NUM TEST a +builtins.c:5105 builtin_task_send eigs_num_arg READ b +builtins.c:5128 builtin_task_kill VAL_NUM TEST a +builtins.c:5140 builtin_task_alive VAL_NUM TEST a +builtins.c:5162 builtin_task_sleep VAL_NUM TEST a +builtins.c:5168 builtin_task_sleep eigs_num_arg READ b +builtins.c:5200 builtin_task_self make_num PRODUCE c +builtins.c:5212 builtin_task_detach VAL_NUM TEST a +builtins.c:5217 builtin_task_detach make_num PRODUCE c +builtins.c:5218 builtin_task_detach make_num PRODUCE c +builtins.c:5229 builtin_task_sched_seed VAL_NUM TEST a +builtins.c:5233 builtin_task_sched_seed eigs_num_arg READ b +builtins.c:5382 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5383 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5384 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5385 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5386 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5442 builtin_nearest_in_range VAL_NUM TEST a +builtins.c:5442 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5466 builtin_nearest_in_range eigs_num_arg_slow READ b +builtins.c:5469 builtin_nearest_in_range VAL_NUM TEST a +builtins.c:5469 builtin_nearest_in_range VAL_NUM TEST a +builtins.c:5471 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5472 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5486 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5487 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5488 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5489 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5514 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5515 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5516 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5571 builtin_nearest_in_range_all VAL_NUM TEST a +builtins.c:5571 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5591 builtin_nearest_in_range_all eigs_num_arg_slow READ b +builtins.c:5594 builtin_nearest_in_range_all VAL_NUM TEST a +builtins.c:5594 builtin_nearest_in_range_all VAL_NUM TEST a +builtins.c:5598 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5599 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5640 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5641 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5642 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5643 builtin_nearest_in_range_all make_num PRODUCE c builtins.c:5666 builtin_sign_extend make_num PRODUCE c -builtins.c:5667 builtin_sign_extend make_num PRODUCE c -builtins.c:5684 builtin_list_truncate VAL_NUM TEST a -builtins.c:5688 builtin_list_truncate eigs_num_arg READ b -builtins.c:5714 builtin_list_remove_at VAL_NUM TEST a -builtins.c:5715 builtin_list_remove_at eigs_num_arg READ b -builtins.c:5736 builtin_list_insert_at VAL_NUM TEST a -builtins.c:5737 builtin_list_insert_at eigs_num_arg READ b -builtins.c:5764 builtin_list_index_of make_num PRODUCE f -builtins.c:5768 builtin_list_index_of make_num PRODUCE f -builtins.c:5774 builtin_list_index_of make_num PRODUCE f -builtins.c:5778 builtin_list_index_of make_num PRODUCE f -builtins.c:5841 builtin_sort_by VAL_NUM TEST f -builtins.c:5850 builtin_sort_by eigs_num_arg READ f -builtins.c:5869 sort_cmp_num eigs_slot_num READ b -builtins.c:5870 sort_cmp_num eigs_slot_num READ b -builtins.c:5888 builtin_sort VAL_NUM TEST f -builtins.c:5895 builtin_sort VAL_NUM TEST f -builtins.c:5916 builtin_dispatch VAL_NUM TEST a -builtins.c:5920 builtin_dispatch eigs_num_arg READ b -builtins.c:5921 builtin_dispatch eigs_num_arg READ b -builtins.c:5923 builtin_dispatch eigs_num_arg READ b -builtins.c:5946 builtin_dispatch VAL_NUM TEST a -builtins.c:5947 builtin_dispatch eigs_num_arg READ b -builtins.c:5947 builtin_dispatch make_num PRODUCE c -builtins.c:6023 builtin_dot make_num PRODUCE c -builtins.c:6026 builtin_dot make_num PRODUCE c -builtins.c:6031 builtin_dot buffer_read_num READ b -builtins.c:6033 builtin_dot buffer_read_num READ b -builtins.c:6035 builtin_dot num_guard GUARD c -builtins.c:6035 builtin_dot num_guard GUARD c -builtins.c:6037 builtin_dot make_num PRODUCE c +builtins.c:5676 builtin_sign_extend VAL_NUM TEST a +builtins.c:5676 builtin_sign_extend VAL_NUM TEST a +builtins.c:5676 builtin_sign_extend make_num PRODUCE c +builtins.c:5677 builtin_sign_extend eigs_num_arg READ b +builtins.c:5678 builtin_sign_extend eigs_num_arg READ b +builtins.c:5679 builtin_sign_extend make_num PRODUCE c +builtins.c:5682 builtin_sign_extend make_num PRODUCE c +builtins.c:5683 builtin_sign_extend make_num PRODUCE c +builtins.c:5700 builtin_list_truncate VAL_NUM TEST a +builtins.c:5704 builtin_list_truncate eigs_num_arg READ b +builtins.c:5730 builtin_list_remove_at VAL_NUM TEST a +builtins.c:5731 builtin_list_remove_at eigs_num_arg READ b +builtins.c:5752 builtin_list_insert_at VAL_NUM TEST a +builtins.c:5753 builtin_list_insert_at eigs_num_arg READ b +builtins.c:5780 builtin_list_index_of make_num PRODUCE f +builtins.c:5784 builtin_list_index_of make_num PRODUCE f +builtins.c:5790 builtin_list_index_of make_num PRODUCE f +builtins.c:5794 builtin_list_index_of make_num PRODUCE f +builtins.c:5857 builtin_sort_by VAL_NUM TEST f +builtins.c:5866 builtin_sort_by eigs_num_arg READ f +builtins.c:5885 sort_cmp_num eigs_slot_num READ b +builtins.c:5886 sort_cmp_num eigs_slot_num READ b +builtins.c:5904 builtin_sort VAL_NUM TEST f +builtins.c:5911 builtin_sort VAL_NUM TEST f +builtins.c:5932 builtin_dispatch VAL_NUM TEST a +builtins.c:5936 builtin_dispatch eigs_num_arg READ b +builtins.c:5937 builtin_dispatch eigs_num_arg READ b +builtins.c:5939 builtin_dispatch eigs_num_arg READ b +builtins.c:5962 builtin_dispatch VAL_NUM TEST a +builtins.c:5963 builtin_dispatch eigs_num_arg READ b +builtins.c:5963 builtin_dispatch make_num PRODUCE c +builtins.c:6039 builtin_dot make_num PRODUCE c +builtins.c:6042 builtin_dot make_num PRODUCE c +builtins.c:6047 builtin_dot buffer_read_num READ b +builtins.c:6049 builtin_dot buffer_read_num READ b +builtins.c:6051 builtin_dot num_guard GUARD c +builtins.c:6051 builtin_dot num_guard GUARD c +builtins.c:6053 builtin_dot make_num PRODUCE c builtins_buf.c:35 builtin_buffer VAL_NUM TEST a builtins_buf.c:36 builtin_buffer VAL_NUM TEST a builtins_buf.c:37 builtin_buffer eigs_list_num READ b @@ -1292,134 +1303,158 @@ container.h:321 dict_value_get_num slot_is_f64 TEST a container.h:322 dict_value_get_num SLOT_F64_RAW RAW b eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a -eigenscript.c:309 val_type_name VAL_NUM CASE a -eigenscript.c:431 ent_child_slot SLOT_F64_RAW RAW i -eigenscript.c:431 ent_child_slot slot_is_f64 TEST i -eigenscript.c:433 ent_child_slot slot_is_smi TEST i -eigenscript.c:433 ent_child_slot slot_smi_val RAW i -eigenscript.c:441 compute_entropy_impl VAL_NUM CASE i -eigenscript.c:441 compute_entropy_impl VAL_NUM_RAW RAW i -eigenscript.c:790 observer_slot_update VAL_NUM TEST i -eigenscript.c:792 observer_slot_update VAL_NUM_RAW RAW i -eigenscript.c:854 observer_slot_sample_gated VAL_NUM TEST i -eigenscript.c:855 observer_slot_sample_gated VAL_NUM_RAW RAW i -eigenscript.c:938 observer_slot_saturated EIGS_NUM_MAX GUARD i -eigenscript.c:1386 observer_entropy_now slot_is_f64 TEST i -eigenscript.c:1388 observer_entropy_now SLOT_F64_RAW RAW i -eigenscript.c:1389 observer_entropy_now slot_is_smi TEST i -eigenscript.c:1391 observer_entropy_now slot_smi_val RAW i -eigenscript.c:1436 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1437 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:309 val_type_name VAL_FLOAT CASE a +eigenscript.c:310 val_type_name VAL_INT CASE a +eigenscript.c:432 ent_child_slot SLOT_F64_RAW RAW i +eigenscript.c:432 ent_child_slot slot_is_f64 TEST i +eigenscript.c:434 ent_child_slot slot_is_smi TEST i +eigenscript.c:434 ent_child_slot slot_smi_val RAW i +eigenscript.c:442 compute_entropy_impl VAL_NUM CASE i +eigenscript.c:442 compute_entropy_impl VAL_NUM_RAW RAW i +eigenscript.c:445 compute_entropy_impl VAL_I64_RAW RAW i +eigenscript.c:445 compute_entropy_impl VAL_INT CASE i +eigenscript.c:794 observer_slot_update VAL_NUM TEST i +eigenscript.c:796 observer_slot_update VAL_NUM_RAW RAW i +eigenscript.c:858 observer_slot_sample_gated VAL_NUM TEST i +eigenscript.c:859 observer_slot_sample_gated VAL_NUM_RAW RAW i +eigenscript.c:942 observer_slot_saturated EIGS_NUM_MAX GUARD i +eigenscript.c:1390 observer_entropy_now slot_is_f64 TEST i +eigenscript.c:1392 observer_entropy_now SLOT_F64_RAW RAW i +eigenscript.c:1393 observer_entropy_now slot_is_smi TEST i +eigenscript.c:1395 observer_entropy_now slot_smi_val RAW i eigenscript.c:1440 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1441 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1444 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1445 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1446 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1447 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1453 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1485 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1485 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1486 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1486 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1486 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1488 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1502 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1502 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1507 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1508 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1517 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1522 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1535 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1540 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1643 free_value VAL_NUM TEST a -eigenscript.c:1725 free_value VAL_NUM CASE a -eigenscript.c:1734 make_num make_num PRODUCE c -eigenscript.c:1735 make_num num_guard GUARD c -eigenscript.c:1751 make_num VAL_NUM TAGSET c -eigenscript.c:1752 make_num VAL_NUM_RAW WRITE c -eigenscript.c:1758 recycle_intermediate VAL_NUM TEST a -eigenscript.c:1780 make_num_permanent make_num_permanent PRODUCE c -eigenscript.c:1781 make_num_permanent num_guard GUARD c -eigenscript.c:1783 make_num_permanent VAL_NUM TAGSET c -eigenscript.c:1784 make_num_permanent VAL_NUM_RAW WRITE c -eigenscript.c:1813 eigs_num_arg_slow eigs_num_arg_slow READ b -eigenscript.c:1814 eigs_num_arg_slow VAL_NUM TEST a -eigenscript.c:1814 eigs_num_arg_slow VAL_NUM_RAW RAW b -eigenscript.c:1821 eigs_list_num eigs_list_num READ b -eigenscript.c:1828 eigs_list_num eigs_slot_num READ b -eigenscript.c:1831 eigs_elem_num eigs_elem_num READ b -eigenscript.c:1832 eigs_elem_num eigs_slot_elem_num READ b -eigenscript.c:1835 eigs_opt_num eigs_opt_num READ b -eigenscript.c:1836 eigs_opt_num eigs_slot_opt_num READ b -eigenscript.c:1872 slot_from_value VAL_NUM TEST a -eigenscript.c:1876 slot_from_value VAL_NUM_RAW RAW b -eigenscript.c:1878 slot_from_value slot_from_f64 PRODUCE c -eigenscript.c:1897 slot_to_value SLOT_F64_RAW RAW b -eigenscript.c:1897 slot_to_value make_num PRODUCE c -eigenscript.c:1897 slot_to_value slot_is_f64 TEST a -eigenscript.c:1905 slot_to_value slot_is_smi TEST a -eigenscript.c:2404 module_ns_project slot_is_f64 TEST a -eigenscript.c:2404 module_ns_project slot_is_f64 TEST a -eigenscript.c:2409 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2409 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2654 chan_clone_rec VAL_NUM TEST a -eigenscript.c:2657 chan_clone_rec VAL_NUM CASE a -eigenscript.c:2657 chan_clone_rec VAL_NUM_RAW RAW b -eigenscript.c:2657 chan_clone_rec make_num PRODUCE c -eigenscript.c:2845 is_truthy VAL_NUM CASE a -eigenscript.c:2845 is_truthy VAL_NUM_RAW RAW b -eigenscript.c:2881 values_equal_impl VAL_NUM TEST f -eigenscript.c:2882 values_equal_impl VAL_NUM TEST f -eigenscript.c:2896 values_equal_impl VAL_NUM CASE f -eigenscript.c:2896 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2896 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2926 values_equal_impl buffer_read_num READ f -eigenscript.c:2928 values_equal_impl buffer_read_num READ f -eigenscript.c:2964 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:2979 eigs_num_text strtod PARSE e -eigenscript.c:2989 value_to_string VAL_NUM CASE e -eigenscript.c:2990 value_to_string VAL_NUM_RAW RAW e -eigenscript.c:2990 value_to_string eigs_num_text FORMAT e -eigenscript.c:4212 gc_value_is_node VAL_NUM CASE a +eigenscript.c:1448 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1449 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1450 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1451 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1457 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1489 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1489 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1490 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1490 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1490 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1492 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1506 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1506 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1511 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1512 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1521 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1526 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1539 observer_slot_from_trajectory VAL_NUM TEST i +eigenscript.c:1544 observer_slot_from_trajectory VAL_NUM_RAW RAW i +eigenscript.c:1647 free_value VAL_NUM TEST a +eigenscript.c:1729 free_value VAL_NUM CASE a +eigenscript.c:1730 free_value VAL_INT CASE a +eigenscript.c:1739 make_num make_num PRODUCE c +eigenscript.c:1740 make_num num_guard GUARD c +eigenscript.c:1756 make_num VAL_NUM TAGSET c +eigenscript.c:1757 make_num VAL_NUM_RAW WRITE c +eigenscript.c:1763 recycle_intermediate VAL_NUM TEST a +eigenscript.c:1785 make_num_permanent make_num_permanent PRODUCE c +eigenscript.c:1786 make_num_permanent num_guard GUARD c +eigenscript.c:1788 make_num_permanent VAL_NUM TAGSET c +eigenscript.c:1789 make_num_permanent VAL_NUM_RAW WRITE c +eigenscript.c:1818 eigs_num_arg_slow eigs_num_arg_slow READ b +eigenscript.c:1819 eigs_num_arg_slow VAL_NUM TEST a +eigenscript.c:1819 eigs_num_arg_slow VAL_NUM_RAW RAW b +eigenscript.c:1826 eigs_list_num eigs_list_num READ b +eigenscript.c:1833 eigs_list_num eigs_slot_num READ b +eigenscript.c:1836 eigs_elem_num eigs_elem_num READ b +eigenscript.c:1837 eigs_elem_num eigs_slot_elem_num READ b +eigenscript.c:1840 eigs_opt_num eigs_opt_num READ b +eigenscript.c:1841 eigs_opt_num eigs_slot_opt_num READ b +eigenscript.c:1877 slot_from_value VAL_NUM TEST a +eigenscript.c:1881 slot_from_value VAL_NUM_RAW RAW b +eigenscript.c:1883 slot_from_value slot_from_f64 PRODUCE c +eigenscript.c:1902 slot_to_value SLOT_F64_RAW RAW b +eigenscript.c:1902 slot_to_value make_num PRODUCE c +eigenscript.c:1902 slot_to_value slot_is_f64 TEST a +eigenscript.c:1910 slot_to_value slot_is_smi TEST a +eigenscript.c:2409 module_ns_project slot_is_f64 TEST a +eigenscript.c:2409 module_ns_project slot_is_f64 TEST a +eigenscript.c:2414 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2414 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2659 chan_clone_rec VAL_NUM TEST a +eigenscript.c:2662 chan_clone_rec VAL_NUM CASE a +eigenscript.c:2662 chan_clone_rec VAL_NUM_RAW RAW b +eigenscript.c:2662 chan_clone_rec make_num PRODUCE c +eigenscript.c:2665 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:2665 chan_clone_rec VAL_INT CASE a +eigenscript.c:2853 is_truthy VAL_NUM CASE a +eigenscript.c:2853 is_truthy VAL_NUM_RAW RAW b +eigenscript.c:2854 is_truthy VAL_I64_RAW RAW b +eigenscript.c:2854 is_truthy VAL_INT CASE a +eigenscript.c:2890 values_equal_impl VAL_NUM TEST f +eigenscript.c:2891 values_equal_impl VAL_NUM TEST f +eigenscript.c:2905 values_equal_impl VAL_NUM CASE f +eigenscript.c:2905 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2905 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2906 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2906 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2906 values_equal_impl VAL_INT CASE f +eigenscript.c:2936 values_equal_impl buffer_read_num READ f +eigenscript.c:2938 values_equal_impl buffer_read_num READ f +eigenscript.c:2979 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:2994 eigs_num_text strtod PARSE e +eigenscript.c:3004 value_to_string VAL_NUM CASE e +eigenscript.c:3005 value_to_string VAL_NUM_RAW RAW e +eigenscript.c:3005 value_to_string eigs_num_text FORMAT e +eigenscript.c:3008 value_to_string VAL_INT CASE e +eigenscript.c:3009 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4231 gc_value_is_node VAL_NUM CASE a +eigenscript.c:4232 gc_value_is_node VAL_INT CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a -eigenscript.h:270 VAL_NUM DATA a -eigenscript.h:285 #define VAL_NUM_RAW VAL_NUM_RAW RAW b -eigenscript.h:285 #define VAL_NUM_RAW num_ RAW b -eigenscript.h:286 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b -eigenscript.h:286 #define VAL_NUM_OFFSET num_ RAW b -eigenscript.h:1390 eigs_num_arg_slow READ b -eigenscript.h:1391 eigs_num_arg eigs_num_arg READ b -eigenscript.h:1392 eigs_num_arg VAL_NUM TEST a -eigenscript.h:1392 eigs_num_arg VAL_NUM_RAW RAW b -eigenscript.h:1393 eigs_num_arg eigs_num_arg_slow READ b -eigenscript.h:1395 eigs_list_num READ b -eigenscript.h:1400 eigs_elem_num READ b -eigenscript.h:1401 eigs_opt_num READ b -eigenscript.h:1772 make_num PRODUCE c -eigenscript.h:1782 make_num_permanent PRODUCE c -eigenscript.h:1834 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1876 num_guard num_guard GUARD c -eigenscript.h:1884 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1884 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1885 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1885 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1894 buffer_read_num buffer_read_num READ b -eigenscript.h:1895 buffer_read_num num_guard GUARD c -eigenscript.h:1901 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1910 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1919 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1920 buffer_read_byte buffer_read_num READ b -eigenscript.h:1922 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1933 num_guard_named num_guard_named GUARD c -eigenscript.h:1939 num_guard_named num_guard GUARD c -eigenscript.h:2251 eigs_num_text FORMAT e +eigenscript.h:281 VAL_FLOAT DATA a +eigenscript.h:289 VAL_INT DATA a +eigenscript.h:290 VAL_FLOAT TAGSET c +eigenscript.h:290 VAL_NUM DATA a +eigenscript.h:302 #define VAL_F64_RAW VAL_F64_RAW RAW b +eigenscript.h:302 #define VAL_F64_RAW f64_ RAW b +eigenscript.h:303 #define VAL_I64_RAW VAL_I64_RAW RAW b +eigenscript.h:303 #define VAL_I64_RAW i64_ RAW b +eigenscript.h:304 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b +eigenscript.h:304 #define VAL_F64_OFFSET f64_ RAW b +eigenscript.h:306 #define VAL_NUM_RAW VAL_NUM_RAW RAW b +eigenscript.h:306 #define VAL_NUM_RAW num_ RAW b +eigenscript.h:307 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b +eigenscript.h:307 #define VAL_NUM_OFFSET num_ RAW b +eigenscript.h:1413 eigs_num_arg_slow READ b +eigenscript.h:1414 eigs_num_arg eigs_num_arg READ b +eigenscript.h:1415 eigs_num_arg VAL_NUM TEST a +eigenscript.h:1415 eigs_num_arg VAL_NUM_RAW RAW b +eigenscript.h:1416 eigs_num_arg eigs_num_arg_slow READ b +eigenscript.h:1418 eigs_list_num READ b +eigenscript.h:1423 eigs_elem_num READ b +eigenscript.h:1424 eigs_opt_num READ b +eigenscript.h:1795 make_num PRODUCE c +eigenscript.h:1805 make_num_permanent PRODUCE c +eigenscript.h:1857 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1899 num_guard num_guard GUARD c +eigenscript.h:1907 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1907 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1908 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1908 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1917 buffer_read_num buffer_read_num READ b +eigenscript.h:1918 buffer_read_num num_guard GUARD c +eigenscript.h:1924 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1933 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1942 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1943 buffer_read_byte buffer_read_num READ b +eigenscript.h:1945 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1956 num_guard_named num_guard_named GUARD c +eigenscript.h:1962 num_guard_named num_guard GUARD c +eigenscript.h:2274 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_NUM CASE j -eigs_embed.c:339 eigs_value_as_num eigs_value_as_num READ j -eigs_embed.c:341 eigs_value_as_num VAL_NUM TEST j -eigs_embed.c:341 eigs_value_as_num VAL_NUM_RAW RAW j -eigs_embed.c:394 eigs_value_buffer_get buffer_read_num READ j -eigs_embed.c:433 eigs_trace_declare_kind VAL_NUM DATA j +eigs_embed.c:315 eigs_value_type VAL_INT CASE j +eigs_embed.c:340 eigs_value_as_num eigs_value_as_num READ j +eigs_embed.c:342 eigs_value_as_num VAL_NUM TEST j +eigs_embed.c:342 eigs_value_as_num VAL_NUM_RAW RAW j +eigs_embed.c:395 eigs_value_buffer_get buffer_read_num READ j +eigs_embed.c:434 eigs_trace_declare_kind VAL_NUM DATA j eigs_embed.h:171 eigs_value_as_num READ j embed_concurrent.c:106 global_worker eigs_value_as_num READ j embed_concurrent.c:768 take_drain eigs_value_as_num READ j @@ -1770,52 +1805,54 @@ ext_store.c:181 store_json_encode_slot slot_is_smi TEST h ext_store.c:183 store_json_encode_slot slot_smi_val RAW h ext_store.c:195 store_json_encode VAL_NUM CASE h ext_store.c:196 store_json_encode eigs_num_arg READ h -ext_store.c:328 store_json_parse_number strtod PARSE h -ext_store.c:331 store_json_parse_number make_num PRODUCE h -ext_store.c:367 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:367 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:377 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:377 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:397 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:412 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:412 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:750 store_load_catalog VAL_NUM TEST h -ext_store.c:750 store_load_catalog VAL_NUM TEST h -ext_store.c:755 store_load_catalog eigs_num_arg READ h -ext_store.c:822 get_store_why VAL_NUM TEST h -ext_store.c:823 get_store_why eigs_num_arg READ h -ext_store.c:825 get_store_why VAL_NUM TEST h -ext_store.c:825 get_store_why eigs_num_arg READ h -ext_store.c:973 builtin_store_open make_num PRODUCE h -ext_store.c:974 builtin_store_open make_num PRODUCE h -ext_store.c:987 builtin_store_close VAL_NUM TEST h -ext_store.c:987 builtin_store_close eigs_num_arg READ h -ext_store.c:989 builtin_store_close VAL_NUM TEST h -ext_store.c:989 builtin_store_close eigs_num_arg READ h -ext_store.c:1035 builtin_store_put make_num PRODUCE h -ext_store.c:1036 builtin_store_put make_num PRODUCE h -ext_store.c:1050 builtin_store_put eigs_num_arg READ h -ext_store.c:1051 builtin_store_put eigs_num_arg READ h -ext_store.c:1063 builtin_store_put make_num PRODUCE h -ext_store.c:1187 builtin_store_get VAL_NUM TEST h -ext_store.c:1188 builtin_store_get eigs_num_arg READ h -ext_store.c:1197 builtin_store_get eigs_num_arg READ h -ext_store.c:1255 store_locate eigs_num_arg READ h -ext_store.c:1351 builtin_store_delete VAL_NUM TEST h -ext_store.c:1352 builtin_store_delete eigs_num_arg READ h -ext_store.c:1398 builtin_store_query eigs_num_arg READ h -ext_store.c:1433 builtin_store_count make_num PRODUCE h -ext_store.c:1441 builtin_store_count make_num PRODUCE h -ext_store.c:1442 builtin_store_count make_num PRODUCE h -ext_store.c:1445 builtin_store_count make_num PRODUCE h +ext_store.c:209 store_json_encode VAL_INT CASE h +ext_store.c:211 store_json_encode VAL_I64_RAW RAW h +ext_store.c:334 store_json_parse_number strtod PARSE h +ext_store.c:337 store_json_parse_number make_num PRODUCE h +ext_store.c:373 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:373 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:383 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:383 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:403 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:418 store_buffer_from_tag VAL_NUM TEST h +ext_store.c:418 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:756 store_load_catalog VAL_NUM TEST h +ext_store.c:756 store_load_catalog VAL_NUM TEST h +ext_store.c:761 store_load_catalog eigs_num_arg READ h +ext_store.c:828 get_store_why VAL_NUM TEST h +ext_store.c:829 get_store_why eigs_num_arg READ h +ext_store.c:831 get_store_why VAL_NUM TEST h +ext_store.c:831 get_store_why eigs_num_arg READ h +ext_store.c:979 builtin_store_open make_num PRODUCE h +ext_store.c:980 builtin_store_open make_num PRODUCE h +ext_store.c:993 builtin_store_close VAL_NUM TEST h +ext_store.c:993 builtin_store_close eigs_num_arg READ h +ext_store.c:995 builtin_store_close VAL_NUM TEST h +ext_store.c:995 builtin_store_close eigs_num_arg READ h +ext_store.c:1041 builtin_store_put make_num PRODUCE h +ext_store.c:1042 builtin_store_put make_num PRODUCE h +ext_store.c:1056 builtin_store_put eigs_num_arg READ h +ext_store.c:1057 builtin_store_put eigs_num_arg READ h +ext_store.c:1069 builtin_store_put make_num PRODUCE h +ext_store.c:1193 builtin_store_get VAL_NUM TEST h +ext_store.c:1194 builtin_store_get eigs_num_arg READ h +ext_store.c:1203 builtin_store_get eigs_num_arg READ h +ext_store.c:1261 store_locate eigs_num_arg READ h +ext_store.c:1357 builtin_store_delete VAL_NUM TEST h +ext_store.c:1358 builtin_store_delete eigs_num_arg READ h +ext_store.c:1404 builtin_store_query eigs_num_arg READ h +ext_store.c:1439 builtin_store_count make_num PRODUCE h +ext_store.c:1447 builtin_store_count make_num PRODUCE h +ext_store.c:1448 builtin_store_count make_num PRODUCE h ext_store.c:1451 builtin_store_count make_num PRODUCE h -ext_store.c:1455 builtin_store_count make_num PRODUCE h -ext_store.c:1456 builtin_store_count eigs_num_arg READ h -ext_store.c:1467 builtin_store_count make_num PRODUCE h +ext_store.c:1457 builtin_store_count make_num PRODUCE h +ext_store.c:1461 builtin_store_count make_num PRODUCE h +ext_store.c:1462 builtin_store_count eigs_num_arg READ h ext_store.c:1473 builtin_store_count make_num PRODUCE h -ext_store.c:1507 builtin_store_update VAL_NUM TEST h -ext_store.c:1508 builtin_store_update eigs_num_arg READ h -ext_store.c:1649 builtin_store_drop eigs_num_arg READ h +ext_store.c:1479 builtin_store_count make_num PRODUCE h +ext_store.c:1513 builtin_store_update VAL_NUM TEST h +ext_store.c:1514 builtin_store_update eigs_num_arg READ h +ext_store.c:1655 builtin_store_drop eigs_num_arg READ h jit.c:1282 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d jit.c:1406 emit_addsd_xmm0_xmm1 emit_addsd_xmm0_xmm1 EMIT d jit.c:1410 emit_subsd_xmm0_xmm1 emit_subsd_xmm0_xmm1 EMIT d @@ -2027,11 +2064,15 @@ trace.c:2407 parse_value_p strtod PARSE g trace.c:2410 parse_value_p make_num PRODUCE g trace.c:2820 write_value_ptr VAL_NUM CASE g trace.c:2820 write_value_ptr VAL_NUM_RAW RAW g -trace.c:2837 write_slot SLOT_F64_RAW RAW g -trace.c:2837 write_slot slot_is_f64 TEST g -trace.c:2844 write_slot slot_is_smi TEST g -trace.c:2958 write_value_ptr_full VAL_NUM CASE g -trace.c:2958 write_value_ptr_full VAL_NUM_RAW RAW g +trace.c:2823 write_value_ptr VAL_I64_RAW RAW g +trace.c:2823 write_value_ptr VAL_INT CASE g +trace.c:2840 write_slot SLOT_F64_RAW RAW g +trace.c:2840 write_slot slot_is_f64 TEST g +trace.c:2847 write_slot slot_is_smi TEST g +trace.c:2961 write_value_ptr_full VAL_NUM CASE g +trace.c:2961 write_value_ptr_full VAL_NUM_RAW RAW g +trace.c:2962 write_value_ptr_full VAL_I64_RAW RAW g +trace.c:2962 write_value_ptr_full VAL_INT CASE g value_slot.h:106 slot_is_f64 slot_is_f64 TEST a value_slot.h:112 slot_is_smi slot_is_smi TEST a value_slot.h:123 #define SLOT_F64_RAW SLOT_F64_RAW RAW b @@ -2059,292 +2100,295 @@ vm.c:119 obs_dump_value slot_is_smi TEST i vm.c:119 obs_dump_value slot_smi_val RAW i vm.c:125 obs_dump_value VAL_NUM CASE i vm.c:125 obs_dump_value VAL_NUM_RAW RAW i -vm.c:214 obs_dump_scope slot_is_f64 TEST i -vm.c:215 obs_dump_scope SLOT_F64_RAW RAW i -vm.c:216 obs_dump_scope slot_is_smi TEST i -vm.c:217 obs_dump_scope slot_smi_val RAW i -vm.c:708 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c -vm.c:788 slot_bridge_unwrap slot_is_f64 TEST a -vm.c:790 slot_bridge_unwrap SLOT_F64_RAW RAW b -vm.c:790 slot_bridge_unwrap make_num PRODUCE c -vm.c:799 slot_bridge_unwrap slot_is_smi TEST a -vm.c:835 vm_slot_lift SLOT_F64_RAW RAW b -vm.c:835 vm_slot_lift make_num PRODUCE c -vm.c:835 vm_slot_lift slot_is_f64 TEST a -vm.c:840 vm_slot_lift slot_is_smi TEST a -vm.c:872 slot_truthy SLOT_F64_RAW RAW b -vm.c:872 slot_truthy slot_is_f64 TEST a -vm.c:876 slot_truthy slot_is_smi TEST a -vm.c:876 slot_truthy slot_smi_val RAW b -vm.c:933 make_iter_state make_num PRODUCE c -vm.c:946 make_iter_state make_num PRODUCE c -vm.c:1165 vm_store_local_slot slot_is_f64 TEST a -vm.c:1169 vm_store_local_slot VAL_NUM TEST a -vm.c:1171 vm_store_local_slot SLOT_F64_RAW RAW b -vm.c:1171 vm_store_local_slot VAL_NUM_RAW WRITE c -vm.c:1362 jit_helper_local_idx_get buffer_read_num READ b -vm.c:1362 jit_helper_local_idx_get slot_from_f64 PRODUCE c -vm.c:1523 jit_helper_dot_set slot_is_f64 TEST a -vm.c:1526 jit_helper_dot_set SLOT_F64_RAW RAW b -vm.c:1593 jit_helper_local_dot_set slot_is_f64 TEST a -vm.c:1594 jit_helper_local_dot_set SLOT_F64_RAW RAW b -vm.c:1644 obs_slot_observable slot_is_f64 TEST i -vm.c:1651 obs_slot_num SLOT_F64_RAW RAW i -vm.c:1651 obs_slot_num slot_is_f64 TEST i -vm.c:1652 obs_slot_num slot_is_smi TEST i -vm.c:1652 obs_slot_num slot_smi_val RAW i -vm.c:1799 jit_helper_iter_next VAL_NUM TEST a -vm.c:1800 jit_helper_iter_next eigs_slot_num READ b -vm.c:1810 jit_helper_iter_next VAL_NUM TEST a -vm.c:1811 jit_helper_iter_next VAL_NUM_RAW RAW b -vm.c:1818 jit_helper_iter_next buffer_read_num READ b -vm.c:1818 jit_helper_iter_next num_guard GUARD c -vm.c:1818 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1824 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1894 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b -vm.c:1894 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1898 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1901 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1940 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1954 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1954 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:1965 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:126 obs_dump_value VAL_I64_RAW RAW i +vm.c:126 obs_dump_value VAL_INT CASE i +vm.c:215 obs_dump_scope slot_is_f64 TEST i +vm.c:216 obs_dump_scope SLOT_F64_RAW RAW i +vm.c:217 obs_dump_scope slot_is_smi TEST i +vm.c:218 obs_dump_scope slot_smi_val RAW i +vm.c:709 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c +vm.c:789 slot_bridge_unwrap slot_is_f64 TEST a +vm.c:791 slot_bridge_unwrap SLOT_F64_RAW RAW b +vm.c:791 slot_bridge_unwrap make_num PRODUCE c +vm.c:800 slot_bridge_unwrap slot_is_smi TEST a +vm.c:836 vm_slot_lift SLOT_F64_RAW RAW b +vm.c:836 vm_slot_lift make_num PRODUCE c +vm.c:836 vm_slot_lift slot_is_f64 TEST a +vm.c:841 vm_slot_lift slot_is_smi TEST a +vm.c:873 slot_truthy SLOT_F64_RAW RAW b +vm.c:873 slot_truthy slot_is_f64 TEST a +vm.c:877 slot_truthy slot_is_smi TEST a +vm.c:877 slot_truthy slot_smi_val RAW b +vm.c:934 make_iter_state make_num PRODUCE c +vm.c:947 make_iter_state make_num PRODUCE c +vm.c:1166 vm_store_local_slot slot_is_f64 TEST a +vm.c:1170 vm_store_local_slot VAL_NUM TEST a +vm.c:1172 vm_store_local_slot SLOT_F64_RAW RAW b +vm.c:1172 vm_store_local_slot VAL_NUM_RAW WRITE c +vm.c:1363 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1363 jit_helper_local_idx_get slot_from_f64 PRODUCE c +vm.c:1524 jit_helper_dot_set slot_is_f64 TEST a +vm.c:1527 jit_helper_dot_set SLOT_F64_RAW RAW b +vm.c:1594 jit_helper_local_dot_set slot_is_f64 TEST a +vm.c:1595 jit_helper_local_dot_set SLOT_F64_RAW RAW b +vm.c:1645 obs_slot_observable slot_is_f64 TEST i +vm.c:1652 obs_slot_num SLOT_F64_RAW RAW i +vm.c:1652 obs_slot_num slot_is_f64 TEST i +vm.c:1653 obs_slot_num slot_is_smi TEST i +vm.c:1653 obs_slot_num slot_smi_val RAW i +vm.c:1800 jit_helper_iter_next VAL_NUM TEST a +vm.c:1801 jit_helper_iter_next eigs_slot_num READ b +vm.c:1811 jit_helper_iter_next VAL_NUM TEST a +vm.c:1812 jit_helper_iter_next VAL_NUM_RAW RAW b +vm.c:1819 jit_helper_iter_next buffer_read_num READ b +vm.c:1819 jit_helper_iter_next num_guard GUARD c +vm.c:1819 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1825 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1895 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b +vm.c:1895 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1899 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1902 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1941 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:1955 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1955 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c vm.c:1966 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1984 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:1984 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2067 loop_iter_store make_num PRODUCE c -vm.c:2074 loop_iter_store slot_is_f64 TEST a -vm.c:2075 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2080 loop_iter_store make_num PRODUCE c -vm.c:2202 jit_helper_index_set slot_is_f64 TEST a -vm.c:2207 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2208 jit_helper_index_set slot_is_f64 TEST a -vm.c:2210 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2212 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2222 jit_helper_index_set slot_is_f64 TEST a -vm.c:2224 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2225 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2227 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2239 jit_helper_index_set VAL_NUM TEST a -vm.c:2241 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:1967 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1985 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:1985 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2068 loop_iter_store make_num PRODUCE c +vm.c:2075 loop_iter_store slot_is_f64 TEST a +vm.c:2076 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2081 loop_iter_store make_num PRODUCE c +vm.c:2203 jit_helper_index_set slot_is_f64 TEST a +vm.c:2208 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2209 jit_helper_index_set slot_is_f64 TEST a +vm.c:2211 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2213 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2223 jit_helper_index_set slot_is_f64 TEST a +vm.c:2225 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2226 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2228 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2240 jit_helper_index_set VAL_NUM TEST a vm.c:2242 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2249 jit_helper_index_set VAL_NUM TEST a -vm.c:2251 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2243 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2250 jit_helper_index_set VAL_NUM TEST a vm.c:2252 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2255 jit_helper_index_set VAL_NUM TEST a -vm.c:2256 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2275 jit_helper_index_get slot_is_f64 TEST a -vm.c:2277 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2284 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2295 jit_helper_index_get buffer_read_num READ b -vm.c:2297 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2299 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2315 jit_helper_index_get VAL_NUM TEST a -vm.c:2317 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2253 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2256 jit_helper_index_set VAL_NUM TEST a +vm.c:2257 jit_helper_index_set VAL_NUM_RAW RAW b +vm.c:2276 jit_helper_index_get slot_is_f64 TEST a +vm.c:2278 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2285 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2296 jit_helper_index_get buffer_read_num READ b +vm.c:2298 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2300 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2316 jit_helper_index_get VAL_NUM TEST a vm.c:2318 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2330 jit_helper_index_get VAL_NUM TEST a -vm.c:2332 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2319 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2331 jit_helper_index_get VAL_NUM TEST a vm.c:2333 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2342 jit_helper_index_get VAL_NUM TEST a -vm.c:2344 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2334 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2343 jit_helper_index_get VAL_NUM TEST a vm.c:2345 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2347 jit_helper_index_get buffer_read_num READ b -vm.c:2347 jit_helper_index_get make_num PRODUCE c -vm.c:2933 vm_take_error_value make_num PRODUCE c -vm.c:3037 slot_type_name slot_is_f64 TEST e -vm.c:3038 slot_type_name slot_is_smi TEST e -vm.c:3278 vm_run_ex/CASE(CONST) VAL_NUM TEST a -vm.c:3279 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b -vm.c:3279 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3293 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3298 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3318 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3318 #define NUM_REUSE VAL_NUM TEST a -vm.c:3329 #define ARITH_FAST slot_f64_value READ b -vm.c:3329 #define ARITH_FAST slot_f64_value READ b -vm.c:3330 #define ARITH_FAST num_guard GUARD c -vm.c:3335 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3336 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3344 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3345 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3353 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3363 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3364 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3365 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3365 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:2346 jit_helper_index_get VAL_NUM_RAW RAW b +vm.c:2348 jit_helper_index_get buffer_read_num READ b +vm.c:2348 jit_helper_index_get make_num PRODUCE c +vm.c:2934 vm_take_error_value make_num PRODUCE c +vm.c:3038 slot_type_name slot_is_f64 TEST e +vm.c:3039 slot_type_name slot_is_smi TEST e +vm.c:3279 vm_run_ex/CASE(CONST) VAL_NUM TEST a +vm.c:3280 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b +vm.c:3280 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3294 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3299 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3319 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3319 #define NUM_REUSE VAL_NUM TEST a +vm.c:3330 #define ARITH_FAST slot_f64_value READ b +vm.c:3330 #define ARITH_FAST slot_f64_value READ b +vm.c:3331 #define ARITH_FAST num_guard GUARD c +vm.c:3336 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3337 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3345 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3346 #define ARITH_FAST VAL_NUM_RAW WRITE c +vm.c:3354 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM TEST a +vm.c:3365 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3365 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b +vm.c:3365 vm_run_ex/CASE(ADD) num_guard GUARD c vm.c:3366 vm_run_ex/CASE(ADD) NUM_REUSE TEST a vm.c:3366 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3367 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3416 #define NUM_BINOP VAL_NUM TEST a -vm.c:3416 #define NUM_BINOP VAL_NUM TEST a -vm.c:3417 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3417 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3417 #define NUM_BINOP num_guard GUARD c +vm.c:3367 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3367 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c +vm.c:3368 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3417 #define NUM_BINOP VAL_NUM TEST a +vm.c:3417 #define NUM_BINOP VAL_NUM TEST a vm.c:3418 #define NUM_BINOP VAL_NUM_RAW RAW b vm.c:3418 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3420 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3420 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3418 #define NUM_BINOP num_guard GUARD c +vm.c:3419 #define NUM_BINOP VAL_NUM_RAW RAW b +vm.c:3419 #define NUM_BINOP VAL_NUM_RAW RAW b vm.c:3421 #define NUM_BINOP NUM_REUSE TEST a vm.c:3421 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3422 #define NUM_BINOP make_num PRODUCE c -vm.c:3426 #define NUM_BINOP make_num PRODUCE c -vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3444 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3445 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3447 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3449 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3449 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3449 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3452 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3454 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3454 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3422 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3422 #define NUM_BINOP VAL_NUM_RAW WRITE c +vm.c:3423 #define NUM_BINOP make_num PRODUCE c +vm.c:3427 #define NUM_BINOP make_num PRODUCE c +vm.c:3445 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3445 vm_run_ex/CASE(DIV) VAL_NUM TEST a +vm.c:3446 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3448 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3450 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3450 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b +vm.c:3450 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3453 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b vm.c:3455 vm_run_ex/CASE(DIV) NUM_REUSE TEST a vm.c:3455 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3456 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3461 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3469 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3456 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3456 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c +vm.c:3457 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3462 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3470 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3471 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3471 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3471 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3471 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b +vm.c:3471 vm_run_ex/CASE(MOD) num_guard GUARD c vm.c:3472 vm_run_ex/CASE(MOD) NUM_REUSE TEST a vm.c:3472 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3473 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3475 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3475 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3480 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3503 #define INT_BINOP_R slot_f64_value READ b -vm.c:3503 #define INT_BINOP_R slot_f64_value READ b -vm.c:3505 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3473 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3473 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c +vm.c:3474 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3476 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3476 vm_run_ex/CASE(MOD) VAL_NUM TEST a +vm.c:3481 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3504 #define INT_BINOP_R slot_f64_value READ b +vm.c:3504 #define INT_BINOP_R slot_f64_value READ b vm.c:3506 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3509 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3510 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3517 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3517 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3521 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3521 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3524 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3532 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3532 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3507 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3510 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3511 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3518 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3518 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3522 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3522 #define INT_BINOP_R VAL_NUM_RAW WRITE c +vm.c:3525 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3533 #define INT_BINOP_R slot_is_smi TEST a vm.c:3533 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3543 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3570 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3573 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3573 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c -vm.c:3576 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3581 vm_run_ex/CASE(NEG) slot_is_smi TEST a -vm.c:3584 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3599 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3601 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b -vm.c:3604 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3610 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a -vm.c:3610 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c -vm.c:3613 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3618 vm_run_ex/CASE(BNOT) slot_is_smi TEST a -vm.c:3624 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3634 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3634 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3655 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3655 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3677 #define NUM_CMP slot_f64_value READ f -vm.c:3677 #define NUM_CMP slot_f64_value READ f -vm.c:3700 #define NUM_CMP slot_is_smi TEST f -vm.c:3700 #define NUM_CMP slot_is_smi TEST f +vm.c:3534 #define INT_BINOP_R slot_is_smi TEST a +vm.c:3544 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3571 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3574 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3574 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c +vm.c:3577 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3582 vm_run_ex/CASE(NEG) slot_is_smi TEST a +vm.c:3585 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3600 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3602 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b +vm.c:3605 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3611 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a +vm.c:3611 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c +vm.c:3614 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3619 vm_run_ex/CASE(BNOT) slot_is_smi TEST a +vm.c:3625 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3635 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3635 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3656 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3656 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3678 #define NUM_CMP slot_f64_value READ f +vm.c:3678 #define NUM_CMP slot_f64_value READ f +vm.c:3701 #define NUM_CMP slot_is_smi TEST f vm.c:3701 #define NUM_CMP slot_is_smi TEST f -vm.c:4617 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4619 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4626 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4636 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4638 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4640 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4655 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4657 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:3702 #define NUM_CMP slot_is_smi TEST f +vm.c:4618 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4620 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4627 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4637 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4639 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4641 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4656 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a vm.c:4658 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4668 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4670 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4659 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4669 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a vm.c:4671 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4678 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4680 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4672 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4679 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a vm.c:4681 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4683 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4683 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c -vm.c:4700 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4702 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4703 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4705 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4707 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4717 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4719 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4719 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4721 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4733 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4735 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4682 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b +vm.c:4684 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4684 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c +vm.c:4701 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4703 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4704 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4706 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4708 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4718 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4720 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4720 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4722 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4734 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a vm.c:4736 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4743 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4745 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4737 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4744 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a vm.c:4746 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4749 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4750 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4806 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4809 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4870 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4871 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4897 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4897 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5003 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5004 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5049 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5055 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5063 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5064 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5077 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5081 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5081 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5421 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:4747 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4750 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a +vm.c:4751 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b +vm.c:4807 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4810 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4871 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4872 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4898 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4898 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5004 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5005 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5050 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5056 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5064 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:5065 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5078 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5082 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5082 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c vm.c:5422 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i vm.c:5423 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5457 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5424 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i vm.c:5458 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i vm.c:5459 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5523 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5523 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i -vm.c:5523 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5527 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5460 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5524 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i +vm.c:5524 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i +vm.c:5524 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5528 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5529 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5530 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5534 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5548 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5531 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5535 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i vm.c:5549 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5571 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5597 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5600 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5552 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5572 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5598 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5601 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5604 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5620 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i -vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i -vm.c:5647 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i -vm.c:5648 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i -vm.c:5778 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a -vm.c:5795 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5796 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5798 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5805 #define READ_SLICE_BOUND VAL_NUM TEST a -vm.c:5806 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5809 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5820 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5823 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6417 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6418 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6419 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6422 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6432 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a -vm.c:6433 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b +vm.c:5602 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5605 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5621 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i +vm.c:5628 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i +vm.c:5648 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i +vm.c:5649 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i +vm.c:5779 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5779 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a +vm.c:5796 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5797 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5799 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5806 #define READ_SLICE_BOUND VAL_NUM TEST a +vm.c:5807 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5810 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b +vm.c:5821 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5824 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6418 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6419 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6420 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6423 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6433 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a +vm.c:6434 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b diff --git a/src/builtins.c b/src/builtins.c index 1684634de..bbaeac8fd 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -865,6 +865,7 @@ Value* builtin_type(Value *arg) { if (!arg) return make_str("none"); switch (arg->type) { case VAL_NUM: return make_str("num"); + case VAL_INT: return make_str("num"); /* #1758 (B): one number type at the surface */ case VAL_STR: return make_str("str"); case VAL_LIST: return make_str("list"); case VAL_FN: return make_str("fn"); @@ -923,6 +924,12 @@ static int eigs_json_encode_value(Value *v, strbuf *out, int depth) { strbuf_append(out, nb); break; } + case VAL_INT: { /* #1758 R1.2a: an int encodes as its exact digits */ + char nb[24]; + eigs_int_text(nb, sizeof(nb), VAL_I64_RAW(v)); + strbuf_append(out, nb); + break; + } case VAL_STR: { strbuf_append_char(out, '"'); for (const char *c = v->data.str; *c; c++) { @@ -989,7 +996,15 @@ static int eigs_json_encode_value(Value *v, strbuf *out, int depth) { strbuf_append_char(out, '}'); break; } - default: + /* #1758 R1.2a: the `default:` that answered "null" is gone, so a new + * ValType is a build error here (-Werror=switch) instead of a silent + * null. These are the types it covered, unchanged: null, fn and + * builtin (also caught above), raw JSON and a buffer. */ + case VAL_NULL: + case VAL_FN: + case VAL_BUILTIN: + case VAL_JSON_RAW: + case VAL_BUFFER: strbuf_append(out, "null"); break; } @@ -2902,6 +2917,7 @@ static Value *desc_isolate_const(DescVerify *ctx, Value *v) { if (!v || !desc_spend(ctx, 1)) return NULL; switch (v->type) { case VAL_NUM: + case VAL_INT: /* #1758 R1.2a: an immutable scalar, like a float */ case VAL_STR: case VAL_NULL: case VAL_JSON_RAW: diff --git a/src/eigenscript.c b/src/eigenscript.c index 7f571a802..ae0a01c61 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -306,7 +306,8 @@ const char* eigs_interrogative_word(int kind) { const char* val_type_name(ValType t) { switch (t) { - case VAL_NUM: return "num"; + case VAL_FLOAT: return "num"; + case VAL_INT: return "num"; /* #1758 (B): one number type at the surface */ case VAL_STR: return "str"; case VAL_LIST: return "list"; case VAL_FN: return "fn"; @@ -439,6 +440,9 @@ static double compute_entropy_impl(Value *v) { switch (v->type) { case VAL_NULL: return 0.0; case VAL_NUM: return entropy_of_num(VAL_NUM_RAW(v)); + /* #1758 R1.2a (design 7): an int's entropy is its double's; it joins + * the numeric channel when ints exist (R1.3). */ + case VAL_INT: return entropy_of_num((double)VAL_I64_RAW(v)); case VAL_STR: return entropy_of_cstr(v->data.str); case VAL_JSON_RAW: return entropy_of_cstr(v->data.str); case VAL_LIST: { @@ -1723,6 +1727,7 @@ void free_value(Value *v) { * that -Werror=switch (Makefile CFLAGS) makes a new ValType a build * error here instead of a silent leak. */ case VAL_NUM: + case VAL_INT: /* #1758 R1.2a: an int box owns nothing */ case VAL_BUILTIN: case VAL_NULL: case VAL_BOOL: @@ -2655,6 +2660,9 @@ static Value *chan_clone_rec(Value *v, int depth) { v->type != VAL_BOOL && v->type != VAL_STR) { val_incref(v); return v; } switch (v->type) { case VAL_NUM: return make_num(VAL_NUM_RAW(v)); + /* #1758 R1.2a: a channel gets a fresh int box, which needs make_int + * (R1.3); no int exists before then. */ + case VAL_INT: eigs_int_unwired("chan_clone_rec", (uint64_t)VAL_I64_RAW(v)); case VAL_NULL: return make_null(); case VAL_BOOL: return make_bool(v->data.boolean); case VAL_STR: return make_str(v->data.str); @@ -2843,6 +2851,7 @@ int is_truthy(Value *v) { switch (v->type) { case VAL_NULL: return 0; case VAL_NUM: return VAL_NUM_RAW(v) != 0.0; + case VAL_INT: return VAL_I64_RAW(v) != 0; /* #1758 R1.2a */ case VAL_STR: return v->data.str && v->data.str[0] != '\0'; case VAL_LIST: return v->data.list.count > 0; case VAL_FN: return 1; @@ -2894,6 +2903,7 @@ static int values_equal_impl(Value *a, Value *b, int depth, const char *op) { if (depth > 64 && (a->type == VAL_LIST || a->type == VAL_DICT)) return a == b; switch (a->type) { case VAL_NUM: return VAL_NUM_RAW(a) == VAL_NUM_RAW(b); + case VAL_INT: return VAL_I64_RAW(a) == VAL_I64_RAW(b); /* #1758 R1.2a: both ints */ case VAL_STR: return strcmp(a->data.str, b->data.str) == 0; case VAL_NULL: return 1; case VAL_BOOL: return a->data.boolean == b->data.boolean; @@ -2961,6 +2971,11 @@ int values_equal_op(Value *a, Value *b, const char *op) { return values_equal_im * * Every producer of number text now calls this, so a fourth copy cannot * appear with a fourth rule. Writes at most 32 bytes. */ +/* #1758 R1.2a: THE int->text rule: exact decimal digits, every int64. */ +void eigs_int_text(char *buf, size_t nbuf, int64_t i) { + snprintf(buf, nbuf, "%lld", (long long)i); +} + void eigs_num_text(char *buf, size_t nbuf, double n) { /* Exact integers up to 2^53 (the largest integer all doubles represent * exactly) print without a decimal point or exponent. The magnitude test @@ -2990,6 +3005,10 @@ char* value_to_string(Value *v) { eigs_num_text(buf, sizeof(buf), VAL_NUM_RAW(v)); return xstrdup(buf); } + case VAL_INT: { /* #1758 R1.2a: an int prints its exact digits */ + eigs_int_text(buf, sizeof(buf), VAL_I64_RAW(v)); + return xstrdup(buf); + } case VAL_STR: return xstrdup(v->data.str); case VAL_LIST: { strbuf out; @@ -4210,6 +4229,7 @@ static int gc_value_is_node(Value *v) { return 1; /* Leaves: no owned edges out, so no rows and never a cycle member. */ case VAL_NUM: + case VAL_INT: case VAL_STR: case VAL_NULL: case VAL_JSON_RAW: diff --git a/src/eigenscript.h b/src/eigenscript.h index 98a583541..3b74903be 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -266,22 +266,43 @@ struct ASTNode { /* ---- Value types ---- */ +/* #1758 R1.2: deprecated spellings, kept only while R1.2b-n migrate their + * sites (the compiler's warnings are the progress meter); R1.2z deletes them, + * so a straggler stops compiling. */ +#if defined(__GNUC__) || defined(__clang__) +#define EIGS_R12_DEPRECATED(msg) __attribute__((deprecated(msg))) +#else +#define EIGS_R12_DEPRECATED(msg) +#endif + typedef enum { - VAL_NUM, VAL_STR, VAL_LIST, VAL_FN, VAL_BUILTIN, VAL_NULL, VAL_JSON_RAW, VAL_DICT, VAL_BUFFER, VAL_TEXT_BUILDER, + /* #1758 R1.2a: a double (was VAL_NUM). A number Value is a VAL_FLOAT or a + * VAL_INT; `type of` says "num" for both (decision (B)). */ + VAL_FLOAT, VAL_STR, VAL_LIST, VAL_FN, VAL_BUILTIN, VAL_NULL, VAL_JSON_RAW, VAL_DICT, VAL_BUFFER, VAL_TEXT_BUILDER, /* #1637: a distinct boolean. Two immortal singletons (make_bool); the * slot layer carries it as the TAG_BOOL immediate. Arithmetic on it and * `==` against a number raise. */ - VAL_BOOL + VAL_BOOL, + /* #1758 R1.2a: an exact int64, boxed only outside the SMI range (design + * 2.1). Nothing produces one before R1.3 (make_int does not exist yet): + * every arm that handles it is dead code until then. */ + VAL_INT, + VAL_NUM EIGS_R12_DEPRECATED("#1758 R1.2: VAL_FLOAT, with an explicit VAL_INT arm") = VAL_FLOAT } ValType; typedef struct Value Value; typedef Value* (*BuiltinFn)(Value* arg); /* #1637 round 4: the ONE raw way into a Value's number (an lvalue: also the - * write). Only for a Value whose type is proven VAL_NUM, in a function listed - * in tools/num_read_allowlist.txt with its use count. Everything else uses - * eigs_num_arg / eigs_list_num / eigs_opt_num. VAL_NUM_OFFSET is the same - * member for JIT-emitted loads and stores. */ + * write). Only for a Value whose type is proven (VAL_FLOAT for the double, + * VAL_INT for the int64), in a function listed in tools/num_read_allowlist.txt + * with its use count. Everything else uses eigs_num_arg / eigs_list_num / + * eigs_opt_num. VAL_F64_OFFSET is the double member for JIT-emitted loads and + * stores (#1758 R1.2a: were VAL_NUM_RAW, VAL_NUM_OFFSET and the member num_). */ +#define VAL_F64_RAW(v) ((v)->data.f64_) +#define VAL_I64_RAW(v) ((v)->data.i64_) +#define VAL_F64_OFFSET ((int32_t)offsetof(Value, data.f64_)) +/* Deprecated until R1.2z: both spell the deprecated member, so every use warns. */ #define VAL_NUM_RAW(v) ((v)->data.num_) #define VAL_NUM_OFFSET ((int32_t)offsetof(Value, data.num_)) @@ -422,7 +443,9 @@ struct Value { * proven -- and every VAL_NUM_RAW use sits in a function on the * reviewed list tools/num_read_allowlist.txt, pinned by count * (tools/num_read_check.sh). */ - double num_; + double f64_; /* VAL_FLOAT (#1758 R1.2a: was num_) */ + double num_ EIGS_R12_DEPRECATED("#1758 R1.2: f64_ through VAL_F64_RAW"); + int64_t i64_; /* VAL_INT (#1758 R1.2a; no producer before R1.3) */ int boolean; /* VAL_BOOL: 0 or 1 (only the two singletons exist) */ /* VAL_STR / VAL_JSON_RAW payload: NUL-terminated bytes. * @@ -2249,6 +2272,7 @@ char* value_to_string(Value *v); * `str of`, all three JSON encoders, the SIGUSR1 observer dump — so a copy * with a different precision cannot reappear. Needs 32 bytes. */ void eigs_num_text(char *buf, size_t nbuf, double n); +void eigs_int_text(char *buf, size_t nbuf, int64_t i); /* #1758 R1.2a: exact digits */ void observer_ensure_fresh(Value *v); void eigs_json_escape_string(strbuf *out, const char *s); /* #880: decode a JSON string body (s[*pos] = first byte after the opening diff --git a/src/eigs_embed.c b/src/eigs_embed.c index c1c472639..45efa0201 100644 --- a/src/eigs_embed.c +++ b/src/eigs_embed.c @@ -312,6 +312,7 @@ EigsValueType eigs_value_type(EigsValue *v) { if (!v) return EIGS_TYPE_NULL; switch (v->type) { case VAL_NUM: return EIGS_TYPE_NUM; + case VAL_INT: return EIGS_TYPE_NUM; /* #1758 (Q3): one embed number type */ case VAL_STR: return EIGS_TYPE_STR; case VAL_LIST: return EIGS_TYPE_LIST; case VAL_DICT: return EIGS_TYPE_DICT; diff --git a/src/ext_store.c b/src/ext_store.c index 813027191..11ad82833 100644 --- a/src/ext_store.c +++ b/src/ext_store.c @@ -206,6 +206,12 @@ static void store_json_encode(Value *v, strbuf *out) { strbuf_append_fmt(out, "%.15g", n); break; } + case VAL_INT: { /* #1758 R1.2a: an int encodes as its exact digits */ + char nb[24]; + eigs_int_text(nb, sizeof(nb), VAL_I64_RAW(v)); + strbuf_append(out, nb); + break; + } case VAL_STR: { eigs_json_escape_string(out, v->data.str); break; diff --git a/src/trace.c b/src/trace.c index ba9b1cdf3..b818f2272 100644 --- a/src/trace.c +++ b/src/trace.c @@ -2818,6 +2818,9 @@ static void write_value_ptr(Value *v) { if (!v) { tp_puts("null"); return; } switch (v->type) { case VAL_NUM: tp_printf("%.17g", VAL_NUM_RAW(v)); break; + /* #1758 R1.2a: an int is written as digits by tape v7 (R1.3); a v6 + * tape cannot tell it from a float, so it is refused until then. */ + case VAL_INT: eigs_int_unwired("write_value_ptr", (uint64_t)VAL_I64_RAW(v)); case VAL_NULL: tp_puts("null"); break; case VAL_STR: write_string(v->data.str); break; case VAL_LIST: tp_printf("", v->data.list.count); break; @@ -2956,6 +2959,7 @@ static void write_value_ptr_full(Value *v, int *budget) { if (!v) { wf_puts("null", budget); return; } switch (v->type) { case VAL_NUM: wf_printf(budget, "%.17g", VAL_NUM_RAW(v)); break; + case VAL_INT: eigs_int_unwired("write_value_ptr_full", (uint64_t)VAL_I64_RAW(v)); /* #1758: tape v7, R1.3 */ case VAL_NULL: wf_puts("null", budget); break; case VAL_BOOL: wf_puts(v->data.boolean ? "true" : "false", budget); break; case VAL_STR: write_string_full(v->data.str, budget); break; diff --git a/src/vm.c b/src/vm.c index 2b02314cb..ebf8584ea 100644 --- a/src/vm.c +++ b/src/vm.c @@ -123,6 +123,7 @@ static void obs_dump_value(EigsSlot s, char *buf, size_t nbuf) { Value *v = slot_as_ptr(s); switch (v->type) { case VAL_NUM: obs_dump_num(VAL_NUM_RAW(v), buf, nbuf); break; + case VAL_INT: eigs_int_text(buf, nbuf, VAL_I64_RAW(v)); break; /* #1758 R1.2a */ case VAL_STR: { size_t o = 0, i; buf[o++] = '"'; @@ -5775,7 +5776,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, case VAL_BUFFER: len = target->data.buffer.count; break; /* Not sliceable. Enumerated rather than covered by a `default:` * so -Werror=switch forces a new ValType to choose here. */ - case VAL_NUM: case VAL_FN: case VAL_BUILTIN: case VAL_NULL: + case VAL_NUM: case VAL_INT: case VAL_FN: case VAL_BUILTIN: case VAL_NULL: case VAL_JSON_RAW: case VAL_DICT: case VAL_TEXT_BUILDER: case VAL_BOOL: rt_error(EK_TYPE, g_vm.current_line, "cannot slice %s", val_type_name(target->type)); diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 013776684..94817697b 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -6,6 +6,7 @@ # Builtins never belong here: they read through eigs_num_arg / eigs_list_num / # eigs_opt_num / eigs_elem_num, which raise on a bool. builtins_tensor.c|builtin_tensor_matmul|1|writes the NaN-boxed null sentinel into a result buffer cell (EIGS_STRICT=0 path); a write, no Value is read +builtins.c|eigs_json_encode_value|1|JSON encoder: case VAL_INT writes the int's exact digits (#1758 R1.2a) container.h|dict_value_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) container.h|dict_value_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 container.h|eigs_container_slot|1|Value-to-slot encoder reads a box only after type == VAL_NUM, then num_guards it @@ -21,11 +22,11 @@ container.h|slot_view|2|numeric view copies a proven immediate into caller stora chunk.c|chunk_disassemble|1|debug disassembly prints a constant behind its own type == VAL_NUM test chunk.c|const_equal|2|constant-pool dedup compares two constants after testing both are VAL_NUM chunk.c|const_hash_value|1|constant-pool hash of a constant inside its type == VAL_NUM branch -eigenscript.c|chan_clone_rec|1|channel deep-copy, switch case VAL_NUM -eigenscript.c|compute_entropy_impl|1|observer entropy, switch case VAL_NUM +eigenscript.c|chan_clone_rec|2|channel deep-copy, switch case VAL_NUM; case VAL_INT names the int it refuses (unwired, R1.3) +eigenscript.c|compute_entropy_impl|2|observer entropy, switch case VAL_NUM, and case VAL_INT (an int's entropy is its double's, design 7) eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_f64 eigenscript.c|eigs_num_arg_slow|1|checking accessor itself: reads only after type == VAL_NUM, raises otherwise -eigenscript.c|is_truthy|1|truthiness, switch case VAL_NUM (a bool has its own case) +eigenscript.c|is_truthy|2|truthiness, switch case VAL_NUM and case VAL_INT (a bool has its own case) eigenscript.c|make_num|1|constructor: writes the number of a Value it just typed VAL_NUM eigenscript.c|make_num_permanent|1|constructor: writes the number of a Value it just typed VAL_NUM eigenscript.c|module_ns_project|1|mirror refresh: reads the binding slot after slot_is_f64 and stores it over a numeric mirror slot @@ -35,13 +36,17 @@ eigenscript.c|observer_slot_sample_gated|1|observer sample after newval->type == eigenscript.c|observer_slot_update|1|observer update after newval->type == VAL_NUM eigenscript.c|slot_from_value|1|NaN-boxing boundary, inside its VAL_NUM branch eigenscript.c|slot_to_value|1|NaN-boxing boundary after slot_is_f64 -eigenscript.c|values_equal_impl|2|equality, switch case VAL_NUM after the bool/num pair raised -eigenscript.c|value_to_string|1|printing, switch case VAL_NUM +eigenscript.c|values_equal_impl|4|equality, switch case VAL_NUM after the bool/num pair raised, and case VAL_INT (both ints) +eigenscript.c|value_to_string|2|printing, switch case VAL_NUM and case VAL_INT (exact digits) eigenscript.h|#define VAL_NUM_OFFSET|1|the raw member offset definition (JIT) +eigenscript.h|#define VAL_F64_OFFSET|1|the raw double member offset definition (JIT; #1758 R1.2a: was VAL_NUM_OFFSET) eigenscript.h|#define VAL_NUM_RAW|1|the raw read definition +eigenscript.h|#define VAL_F64_RAW|1|the raw double read definition (#1758 R1.2a: was VAL_NUM_RAW) +eigenscript.h|#define VAL_I64_RAW|1|the raw int64 read definition (#1758 R1.2a) eigenscript.h|eigs_num_arg|1|inline fast path of the checking accessor: reads only after type == VAL_NUM eigs_embed.c|eigs_value_as_num|1|embedding API: reads only after type == VAL_NUM; a bool answers NaN and other non-numbers 0.0 (docs/EMBEDDING.md) embed_smoke.c|main|7|C test program: builds and inspects slots it constructed as numbers +ext_store.c|store_json_encode|1|store record encoder: case VAL_INT writes the int's exact digits (#1758 R1.2a) jit.c|emit_load_numeric_operand|2|emits the load of data.num_ after the emitted type == VAL_NUM / refcount guard jit.c|jit_compile_to_thunk|2|emits loads/stores of data.num_ behind emitted immediate-number checks; reads a VAL_NUM constant jit_smoke.c|jit_helper_index_get|2|JIT smoke test program (stubbed helpers over slots it built as numbers) @@ -52,8 +57,8 @@ jit_smoke.c|run_index_bail_cases|2|JIT smoke test program (stubbed helpers over jit_smoke.c|run_reader_bail_cases|8|JIT smoke test program (stubbed helpers over slots it built as numbers) jit_smoke.c|run_store_cases|4|JIT smoke test program (stubbed helpers over slots it built as numbers) trace.c|write_slot|1|tape writer after slot_is_f64 -trace.c|write_value_ptr|1|tape writer, switch case VAL_NUM -trace.c|write_value_ptr_full|1|tape writer, switch case VAL_NUM +trace.c|write_value_ptr|2|tape writer, switch case VAL_NUM; case VAL_INT names the int it refuses (tape v7, R1.3) +trace.c|write_value_ptr_full|2|tape writer, switch case VAL_NUM; case VAL_INT names the int it refuses (tape v7, R1.3) value_slot.h|#define SLOT_F64_RAW|1|the raw slot read definition (#1758: was SLOT_NUM_RAW) value_slot.h|slot_f64_value|2|float reader (#1758: was vm.c slot_as_double): an immediate after slot_is_f64, a box after type == VAL_NUM; 0 for an int value_slot.h|slot_from_f64|1|constructor: writes a double into a fresh slot (#1758: was slot_from_num) @@ -68,7 +73,7 @@ vm.c|jit_helper_iter_next|1|JIT helper: loop state list [iterable, idx, snap] bu vm.c|jit_helper_local_dot_set|1|JIT helper: number store after slot_is_f64 vm.c|loop_iter_store|1|writes the loop counter slot after slot_is_f64 vm.c|obs_dump_scope|1|SIGUSR1 observer dump after slot_is_f64 -vm.c|obs_dump_value|2|SIGUSR1 observer dump after slot_is_f64 / case VAL_NUM +vm.c|obs_dump_value|3|SIGUSR1 observer dump after slot_is_f64 / case VAL_NUM / case VAL_INT (exact digits) vm.c|obs_slot_num|1|observer numeric channel (#1758): reads an immediate after slot_is_f64; an int converts exactly vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 vm.c|slot_truthy|1|truthiness after slot_is_f64 diff --git a/tools/num_read_check.sh b/tools/num_read_check.sh index 23b85189a..67e98d85c 100644 --- a/tools/num_read_check.sh +++ b/tools/num_read_check.sh @@ -2,13 +2,16 @@ # num_read_check.sh -- #1637 round 4: raw number reads are TOKENS, and every # token is reviewed. # -# The Value union's number member is `num_` and the EigsSlot union's double is -# `d_`, so no unreviewed spelling compiles. Code reaches a number in exactly -# two ways: +# The Value union's number members are `f64_` (a VAL_FLOAT) and `i64_` (a +# VAL_INT), and the EigsSlot union's double is `d_`, so no unreviewed spelling +# compiles. (#1758 R1.2 renamed `num_`/VAL_NUM_RAW/VAL_NUM_OFFSET; until R1.2z +# deletes them, the old spellings are counted too.) Code reaches a number in +# exactly two ways: # - the checking accessors eigs_num_arg / eigs_list_num / eigs_opt_num, # which raise a type error on a bool or any other non-number; -# - the raw macros VAL_NUM_RAW(v) / SLOT_F64_RAW(s) (and VAL_NUM_OFFSET for -# JIT-emitted loads), for a value whose type is already proven. +# - the raw macros VAL_F64_RAW(v) / VAL_I64_RAW(v) / SLOT_F64_RAW(s) (and +# VAL_F64_OFFSET for JIT-emitted loads), for a value whose type is +# already proven. # This gate enumerates every raw token in src/*.c and src/*.h. It attributes # each one to its enclosing function, or to its #define for a macro. Then it # requires each (file, function) to appear in tools/num_read_allowlist.txt as @@ -56,12 +59,12 @@ for f in "$SRC_DIR"/*.c "$SRC_DIR"/*.h; do { linemac = inmac } { s = line - while (match(s, /(VAL_NUM_RAW|SLOT_F64_RAW)[ \t]*\(|VAL_NUM_OFFSET/)) { + while (match(s, /(VAL_NUM_RAW|VAL_F64_RAW|VAL_I64_RAW|SLOT_F64_RAW)[ \t]*\(|VAL_NUM_OFFSET|VAL_F64_OFFSET/)) { tok = substr(s, RSTART, RLENGTH); sub(/[ \t]*\($/, "", tok) printf "%s|%s|%s|%d\n", FILE, (scope == "" ? "" : scope), tok, NR s = substr(s, RSTART + RLENGTH) } - if (line ~ /data\.num_|[A-Za-z0-9_)\]]\.d_([^A-Za-z0-9_]|$)/ && scope !~ /^#define (VAL_NUM_RAW|SLOT_F64_RAW|VAL_NUM_OFFSET)$/) + if (line ~ /data\.(num_|f64_|i64_)|[A-Za-z0-9_)\]]\.d_([^A-Za-z0-9_]|$)/ && scope !~ /^#define (VAL_NUM_RAW|VAL_F64_RAW|VAL_I64_RAW|SLOT_F64_RAW|VAL_NUM_OFFSET|VAL_F64_OFFSET)$/) printf "%s:%d: %s\n", FILE, NR, $0 >> BYPASS if (line ~ /->data\.builtin[ \t]*\(/) printf "%s:%d: ungated builtin call: %s\n", FILE, NR, $0 >> BYPASS incont = ($0 ~ /\\$/) diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index bd68b8f87..ac97a37b8 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -57,15 +57,21 @@ VOCAB = { # (a) type tests and type derivations 'VAL_NUM': 'TAG', # position decides: TEST/CASE/TAGSET/YIELD/EMIT + # (#1758 R1.2a: deprecated; R1.2z deletes it) + 'VAL_FLOAT': 'TAG', # R1.2a: was VAL_NUM + 'VAL_INT': 'TAG', # R1.2a: the int ValType (no producer before R1.3) 'slot_is_f64': 'TEST', # R1.1: was slot_is_num (slot_is_numeric deleted) 'slot_is_smi': 'TEST', # R1.1: the SMI tag test 'NUM_REUSE': 'TEST', 'AST_NUM': 'TAG', # (b) payload reads - 'VAL_NUM_RAW': 'RAW', # an lvalue: `VAL_NUM_RAW(v) = x` is a WRITE + 'VAL_NUM_RAW': 'RAW', # an lvalue: `VAL_NUM_RAW(v) = x` is a WRITE (deprecated, R1.2z) + 'VAL_F64_RAW': 'RAW', # R1.2a: was VAL_NUM_RAW + 'VAL_I64_RAW': 'RAW', # R1.2a: a VAL_INT's int64 'SLOT_F64_RAW': 'RAW', # R1.1: was SLOT_NUM_RAW 'slot_smi_val': 'RAW', # R1.1: an SMI's int (no int Value exists before R1.3) - 'VAL_NUM_OFFSET': 'RAW', + 'VAL_NUM_OFFSET': 'RAW', # deprecated, R1.2z + 'VAL_F64_OFFSET': 'RAW', # R1.2a: was VAL_NUM_OFFSET 'slot_f64_value': 'READ', # R1.1: replaces vm.c's slot_as_double (floats only) 'slot_int_value': 'READ', # R1.1: an int's value (SMI; R1.2a adds the VAL_INT box) 'eigs_num_arg': 'READ', @@ -186,8 +192,9 @@ TOKEN_RE = re.compile(r'\b(' + '|'.join(sorted(VOCAB, key=len, reverse=True)) + r')\b') # Raw union members: the Value's double (`num_`) and the slot's (`d_`). Only # the accessor macros may name them; anywhere else is a bypass. -RAW_MEMBER = re.compile(r'(?:\.|->)(d_|num_)\b') -RAW_MEMBER_HOMES = {'#define VAL_NUM_RAW', '#define SLOT_F64_RAW', '#define VAL_NUM_OFFSET'} +RAW_MEMBER = re.compile(r'(?:\.|->)(d_|num_|f64_|i64_)\b') +RAW_MEMBER_HOMES = {'#define VAL_NUM_RAW', '#define SLOT_F64_RAW', '#define VAL_NUM_OFFSET', + '#define VAL_F64_RAW', '#define VAL_I64_RAW', '#define VAL_F64_OFFSET'} C_KEYWORDS = {'if', 'while', 'for', 'switch', 'return', 'sizeof', 'do', 'else', 'case', 'defined', '__attribute__', '__typeof__', '_Generic'} @@ -354,6 +361,8 @@ def val_num_kind(line, start, end, token): return 'EMIT' # JIT immediate operand of a type compare if (re.search(r'[({,]\s*$', before) or not before) and re.match(r'[)},]', after): return 'DATA' # the tag as data: enumerator, kind table, argument + if not before and re.match(r'EIGS_R12_DEPRECATED\(', after): + return 'DATA' # #1758 R1.2a-z: the deprecated alias enumerator itself return 'UNKNOWN' @@ -390,7 +399,7 @@ def scan_file(path, rel): kind = VOCAB[tok] if kind == 'TAG': kind = val_num_kind(line, m.start(), m.end(), tok) - elif tok in ('VAL_NUM_RAW', 'SLOT_F64_RAW'): + elif tok in ('VAL_NUM_RAW', 'VAL_F64_RAW', 'VAL_I64_RAW', 'SLOT_F64_RAW'): kind = raw_kind(line, m.end()) sites.append((rel, ln, scope[ln], tok, kind)) if JIT_FILES.match(rel): @@ -420,9 +429,9 @@ def classify(site): # ---- derived accessor check ---------------------------------------------- -READ_IN_BODY = re.compile(r'\b(VAL_NUM_RAW|SLOT_F64_RAW|eigs_num_arg|eigs_list_num|' +READ_IN_BODY = re.compile(r'\b(VAL_NUM_RAW|VAL_F64_RAW|VAL_I64_RAW|SLOT_F64_RAW|eigs_num_arg|eigs_list_num|' r'eigs_slot_num|list_get_num|dict_value_get_num|slot_f64_value)\b|' - r'(?:\.|->)(?:d_|num_)\b') + r'(?:\.|->)(?:d_|num_|f64_|i64_)\b') def derived_accessors(stripped_by_file, scope_by_file, sigs_by_file): @@ -693,7 +702,7 @@ def read_marked_table(doc, tag, row_re): # A LOSS row claims the body computes through a double; it must have one. DOUBLE_PATH = {'eigs_num_arg', 'eigs_list_num', 'eigs_slot_num', 'eigs_opt_num', 'eigs_slot_opt_num', 'eigs_slot_elem_num', 'eigs_elem_num', 'buffer_read_num', 'make_num', 'slot_f64_value', - 'VAL_NUM_RAW', 'SLOT_F64_RAW', 'strtod', 'atof', 'num_guard', 'list_set_num'} + 'VAL_NUM_RAW', 'VAL_F64_RAW', 'SLOT_F64_RAW', 'strtod', 'atof', 'num_guard', 'list_set_num'} def read_table(doc): @@ -762,7 +771,7 @@ def main(): classified, unclassified = [], [] rule_hits = [0] * len(ROLE_RULES) token_hits = {t: 0 for t in VOCAB} - token_hits.update({'d_': 0, 'num_': 0}) + token_hits.update({'d_': 0, 'num_': 0, 'f64_': 0, 'i64_': 0}) for site in sites: cat, rule = classify(site) if site[3] in token_hits: From 6e38d7e4dc8db90be561d43ec4c526fa132b5e26 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 10:47:02 -0500 Subject: [PATCH 019/188] phase2 tools: the inventory scans only tracked sources; unexpected calibration cases say why (#1758) R1.1's CI (gate self-tests, job 116494830237): the calibration case "inventory gate on an unchanged copy passes" was UNEXPECTED (want True, got False) and printed nothing more; it passes locally. Cause, reproduced on a fresh export of f404a608 (git archive, the file set of a fresh clone): `phase2_inventory.py --check` FAILS there, the committed inventory differing in one line, `files=65` against `files=64`. The inventory scanned every src/*.c and src/*.h present, and this box had the ignored, generated src/lsp_stdlib_index.h (written by `make lsp`, which the suite's LSP section runs), so the committed file depended on the machine that generated it. The calibration's copy of src/ then held 64 files on CI. Python's hash order is not involved: PYTHONHASHSEED 0, 1, 2 and 777 give byte-identical output. - phase2_inventory.py scans the TRACKED sources: `git ls-files` inside a work tree; outside one (a `git archive` export, the calibration's copy) every file present, which is tracked by construction. The int-source check uses the same list, and the calibration's copies of src/ hold only the tracked files, so a copy looks like a fresh clone. - The inventory is regenerated (files=64); on a fresh export with this commit's files, `--check` passes. - Every UNEXPECTED calibration case now prints the failing gate's own output (its last 40 lines, the elision counted), so a failure on another machine says why. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 2 +- tools/phase2_check.py | 99 +++++++++++++++++++------------- tools/phase2_inventory.py | 26 ++++++++- 3 files changed, 85 insertions(+), 42 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 8f1e8bdc7..36e9f966f 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,7 +1,7 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. examined=1863 classified=1863 unclassified=0 -files=65 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 +files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category (a) type tests 409 CASE=60 DATA=5 TEST=342 YIELD=2 diff --git a/tools/phase2_check.py b/tools/phase2_check.py index a2eaa90b2..ae54f0abd 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -500,7 +500,7 @@ def int_source(src, out, through='R1.1'): tag's own definitions names TAG_SMI or spells its bits. The dynamic half is the smi-trap build (value_slot.h EIGS_SMI_TRAP).""" allowed = INT_SOURCE_ALLOWED[through] - files = sorted(os.path.join(src, f) for f in os.listdir(src) if f.endswith(('.c', '.h'))) + files = inv.source_files(src) # the tracked sources (a generated header is not one) defs = {'slot_from_int': 0, 'make_int': 0} calls, bad, tags, homes = [], [], [], set() for p in files: @@ -688,10 +688,22 @@ def calibrate(args, out): map_rows, bad = parse_map(os.path.join(cal, 'MAP.md')) results = [] - def case(name, got, want): + def case(name, got, want, detail=None): + """One calibration case. An UNEXPECTED case prints the gate's own + output (`detail`, its last 40 lines with the elision counted), so a + failure on another machine says why (the R1.1 CI lane printed only + `got False`).""" ok = got == want results.append(ok) out('CAL %-58s want %-28s got %-28s %s' % (name, want, got, 'ok' if ok else 'UNEXPECTED')) + if not ok: + shown = [l for l in (detail or []) if l.strip()] + if len(shown) > 40: + out(' | ... %d earlier line(s) of the gate\'s output' % (len(shown) - 40)) + for l in shown[-40:]: + out(' | ' + l) + if not shown: + out(' | (this case runs no gate with output of its own)') def quiet(_): pass @@ -714,16 +726,16 @@ def sub(rows, ids, mutate=None, tag=None, branch=None, log=quiet): honest = [r['id'] for r in map_rows if not r['id'].endswith('-plant')] out('calibration fixtures: %d rows (%d honest) in %s' % (len(map_rows), len(honest), cal)) - case('fixture MAP parses', not bad and len(map_rows) > 0, True) - (pop, rows_ok, _, n, cnt, wit), _ = sub(map_rows, honest, log=out) - case('honest rows: every tier tag_fail == branch_pass == examined', rows_ok, True) + case('fixture MAP parses', not bad and len(map_rows) > 0, True, detail=bad) + (pop, rows_ok, _, n, cnt, wit), lines = sub(map_rows, honest, log=out) + case('honest rows: every tier tag_fail == branch_pass == examined', rows_ok, True, detail=lines) case('honest rows: every witness holds', wit, sum(r['witness']['kind'] != 'none' - for r in map_rows if r['id'] in honest)) - (pop, rows_ok, _, n, cnt, _), _ = sub(map_rows, honest, tag=args.branch) - case('the branch passed as the tag too: branch_pass=0?', cnt['default']['tag_fail'], 0) - case('... and the check fails', rows_ok, False) - (pop, rows_ok, _, n, cnt, _), _ = sub(map_rows, honest, branch=args.tag) - case('the tag passed as the branch: branch_pass', cnt['default']['branch_pass'], 0) + for r in map_rows if r['id'] in honest), detail=lines) + (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, tag=args.branch) + case('the branch passed as the tag too: branch_pass=0?', cnt['default']['tag_fail'], 0, detail=lines) + case('... and the check fails', rows_ok, False, detail=lines) + (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, branch=args.tag) + case('the tag passed as the branch: branch_pass', cnt['default']['branch_pass'], 0, detail=lines) victim = honest[0] def corrupt(rd): @@ -731,42 +743,42 @@ def corrupt(rd): f.write('corrupted\n') (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, mutate=corrupt) case('a corrupted .out fails, naming the row', (rows_ok, any( - ('BRANCH-FAIL %s ' % victim) in l for l in lines)), (False, True)) + ('BRANCH-FAIL %s ' % victim) in l for l in lines)), (False, True), detail=lines) (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, []) - case('an empty rows directory: examined=0 fails', (rows_ok, cnt['default']['examined']), (False, 0)) + case('an empty rows directory: examined=0 fails', (rows_ok, cnt['default']['examined']), (False, 0), detail=lines) def drop(rd): os.remove(os.path.join(rd, victim + '.eigs')) (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, mutate=drop) - case('a MAP id with no file fails', (pop, any('has no file' in l for l in lines)), (False, True)) + case('a MAP id with no file fails', (pop, any('has no file' in l for l in lines)), (False, True), detail=lines) def stray(rd): shutil.copy(os.path.join(rd, victim + '.eigs'), os.path.join(rd, 'stray.row.eigs')) (pop, rows_ok, _, n, cnt, _), lines = sub(map_rows, honest, mutate=stray) case('a file with no MAP id fails', (pop, any('stray.row.eigs has no MAP id' in l for l in lines)), - (False, True)) + (False, True), detail=lines) for r in map_rows: if r['id'].endswith('-plant'): (pop, rows_ok, _, n, cnt, wit), lines = sub(map_rows, [r['id']]) case('plant %s: vacuous, named' % r['id'], (cnt['default']['vacuous'], any( - ('VACUOUS %s ' % r['id']) in l for l in lines)), (1, True)) + ('VACUOUS %s ' % r['id']) in l for l in lines)), (1, True), detail=lines) # the plan-level checks against a mutated copy of the real MAP real, rbad = parse_map(os.path.join(ROOT, 'tests/phase2/MAP.md')) lines = [] plan_checks(real, list(rbad), lines.append) pb = [] plan_checks(real, pb, quiet) - case('plan checks on the real MAP pass', (rbad, pb), ([], [])) + case('plan checks on the real MAP pass', (rbad, pb), ([], []), detail=pb) pb = [] plan_checks([r for r in real if r['item'] != 'N4b'], pb, quiet) - case('a MAP with no N4b row fails, naming N4b', any('item N4b' in b for b in pb), True) + case('a MAP with no N4b row fails, naming N4b', any('item N4b' in b for b in pb), True, detail=pb) pb = [] n_arms = plan_checks([dict(r, ops=[]) for r in real], pb, quiet) case('a MAP whose rows exercise no arm fails per arm (%d arms)' % n_arms, - sum('numeric arm' in b for b in pb) == n_arms > 0, True) + sum('numeric arm' in b for b in pb) == n_arms > 0, True, detail=pb) pb = [] plan_checks([r for r in real if r['round'] != 'R2.3'], pb, quiet) - case('a round with neither rows nor gates fails', any('round R2.3' in b for b in pb), True) + case('a round with neither rows nor gates fails', any('round R2.3' in b for b in pb), True, detail=pb) # the int-source check against a planted production call with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src'), ignore=c_sources_only) @@ -779,9 +791,9 @@ def stray(rd): ok = int_source(os.path.join(d, 'src'), lines.append) case('int-source plant (slot_from_int(count) in trace.c) applied once', n_anchor, 1) case('int-source plant: the check fails, naming the caller', (ok, any( - 'trace.c' in l and 'calls slot_from_int' in l for l in lines)), (False, True)) + 'trace.c' in l and 'calls slot_from_int' in l for l in lines)), (False, True), detail=lines) lines = [] - case('int-source on the real tree passes', int_source(os.path.join(ROOT, 'src'), lines.append), True) + case('int-source on the real tree passes', int_source(os.path.join(ROOT, 'src'), lines.append), True, detail=lines) # the token gate against a reintroduced deleted token with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: os.mkdir(os.path.join(d, 'src')) @@ -793,7 +805,7 @@ def stray(rd): f.write('\nstatic int stray_reader(EigsSlot s) { return slot_is_num(s); }\n') lines = [] case('token plant (slot_is_num reintroduced): the gate fails', - (token_gate(d, 'R1.1', lines.append), any('slot_is_num' in l for l in lines)), (False, True)) + (token_gate(d, 'R1.1', lines.append), any('slot_is_num' in l for l in lines)), (False, True), detail=lines) # the int-source plants of the R1.1 critic, both halves for name, edits in INTSRC_PLANTS: with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: @@ -814,7 +826,7 @@ def stray(rd): case('%s, static half at %s: %s' % (name, through, 'fails, naming it' if want else 'passes (the dynamic half owns it)'), (not ok, any('INT-SOURCE' in l for l in lines)) if want else ok, - (True, True) if want else True) + (True, True) if want else True, detail=lines) # the corpus differential's plants: A and B are wrapper branches, D a build base = args.branch files = ['tests/test_dispatch.eigs', 'tests/test_bool.eigs'] @@ -825,7 +837,7 @@ def stray(rd): rc, text, v = diff_restricted(base, a, files) case('differential plant A (a deterministic file prints one more line): DIFF, control same', (rc, v.get('tests/test_dispatch.eigs'), v.get('tests/test_bool.eigs'), v.get('')), - (3, 'DIFF', 'same', None)) + (3, 'DIFF', 'same', None), detail=text.splitlines()) for phase in (0, 1): bdir = os.path.join(d, 'B%d' % phase) bw = wrapper_tree(bdir, args.branch, files, @@ -834,7 +846,7 @@ def stray(rd): rc, text, v = diff_restricted(base, bw, files) case('differential plant B, phase %d (wrong on alternate runs): DIFF, never NONDET' % phase, (rc, v.get('tests/test_dispatch.eigs'), v.get('tests/test_bool.eigs'), v.get('')), - (3, 'DIFF', 'same', None)) + (3, 'DIFF', 'same', None), detail=text.splitlines()) # the run conditions and the nonzero ledger (the second R1.1 critic): # fake trees that run the real branch binary with one input changed with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: @@ -843,27 +855,27 @@ def stray(rd): case('unplanted branch, conditioned files included: all same, nothing undeclared', (rc,) + tuple(v.get(f) for f in files) + (v.get(''), bool(re.search(r' incomplete=0 undeclared=0 stale=0 ledger_refused=0 ', text))), - (3, 'same', 'same', 'same', None, True)) + (3, 'same', 'same', 'same', None, True), detail=text.splitlines()) cut = wrapper_tree(os.path.join(d, 'cut'), args.branch, files[:1] + files[2:], 'exec "$REAL" "$@"', {'tests/suite_program_env.txt': lambda t: re.sub(r'(?m)^test_numeric_guard\.eigs .*\n', '', t)}) rc, text, v = diff_restricted(base, cut, files[:1] + files[2:]) case('a policy row removed: its file exits early on both, UNDECLARED-NONZERO', (rc, 'UNDECLARED-NONZERO tests/test_numeric_guard.eigs rc=1' in text, - ' undeclared=1 ' in text, v.get('')), (3, True, True, None)) + ' undeclared=1 ' in text, v.get('')), (3, True, True, None), detail=text.splitlines()) stale = wrapper_tree(os.path.join(d, 'stale'), args.branch, files[2:], 'exec "$REAL" "$@"', {'tests/phase2/corpus_nonzero.txt': lambda t: t + 'tests/test_bool.eigs 1 planted: test_bool completes\n'}) rc, text, v = diff_restricted(base, stale, files[2:]) case('a ledger row for a file that completes: STALE', - (rc, 'STALE tests/test_bool.eigs:' in text, ' stale=1 ' in text), (3, True, True)) + (rc, 'STALE tests/test_bool.eigs:' in text, ' stale=1 ' in text), (3, True, True), detail=text.splitlines()) inc = wrapper_tree(os.path.join(d, 'inc'), args.branch, ['tests/test_assert_fail.eigs'], 'exec "$REAL" "$@"', {'tests/suite_program_env.txt': lambda t: t + 'test_assert_fail.eigs EIGS_STRICT=0\n', 'tests/phase2/corpus_nonzero.txt': lambda t: re.sub(r'(?m)^tests/test_assert_fail\.eigs .*\n', '', t)}) rc, text, v = diff_restricted(base, inc, ['tests/test_assert_fail.eigs']) case('a conditioned file that does not complete: INCOMPLETE, never compared', - (rc, v.get('tests/test_assert_fail.eigs'), ' incomplete=1 ' in text), (3, 'INCOMPLETE', True)) + (rc, v.get('tests/test_assert_fail.eigs'), ' incomplete=1 ' in text), (3, 'INCOMPLETE', True), detail=text.splitlines()) # the inventory gate (#1804): a classifier with no reviewed disposition, # and a committed inventory that is not the generated one with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: @@ -874,13 +886,13 @@ def stray(rd): inv_args = ['--src', os.path.join(d, 'src'), '--doc', os.path.join(d, 'docs/design/phase2-numbers.md'), '--out', os.path.join(d, 'docs/design/phase2-inventory.txt')] lines = [] - case('inventory gate on an unchanged copy passes', inventory_gate(lines.append, inv_args), True) + case('inventory gate on an unchanged copy passes', inventory_gate(lines.append, inv_args), True, detail=lines) inv_path = os.path.join(d, 'docs/design/phase2-inventory.txt') committed = read_text(inv_path) write_text(inv_path, committed.replace('dispositions=', 'dispositions=0', 1)) lines = [] case('a committed inventory that is not the generated one: the gate fails, saying stale', - (inventory_gate(lines.append, inv_args), any('is stale' in l for l in lines)), (False, True)) + (inventory_gate(lines.append, inv_args), any('is stale' in l for l in lines)), (False, True), detail=lines) write_text(inv_path, committed) with open(os.path.join(d, 'src', 'vm.c'), 'a') as f: f.write('\nint critic_new_reader(Value *v) {\n EigsSlot s = slot_from_heap(v);\n' @@ -888,7 +900,7 @@ def stray(rd): lines = [] case('an unreviewed slot classifier (critic_new_reader): the gate fails, naming it', (inventory_gate(lines.append, inv_args), - any('`vm.c:critic_new_reader` has no disposition row' in l for l in lines)), (False, True)) + any('`vm.c:critic_new_reader` has no disposition row' in l for l in lines)), (False, True), detail=lines) if args.build_plants: args.planted_leaf_scan = build_plant('leaf-scan', out) args.planted_leaf_mul = build_plant('leaf-mul', out) @@ -908,7 +920,7 @@ def stray(rd): continue rc, text, v = diff_restricted(base, b, files) case('differential %s: DIFF where its conditioned file reaches it' % label, - (rc,) + tuple(v.get(f) for f in files) + (v.get(''),), (3,) + want + (None,)) + (rc,) + tuple(v.get(f) for f in files) + (v.get(''),), (3,) + want + (None,), detail=text.splitlines()) if args.planted_random_int: # test_system.eigs asserts random_int's bounds over 300 draws, so it # sees the plant whatever the seed; test_optimize.eigs prints a search @@ -918,7 +930,7 @@ def stray(rd): files = ['tests/test_system.eigs', 'tests/test_optimize.eigs', 'tests/test_bool.eigs'] rc, text, v = diff_restricted(base, args.planted_random_int, files) case('differential plant D (random_int answers lo+1..hi+1): both files DIFF live', - (rc,) + tuple(v.get(f) for f in files) + (v.get(''),), (3, 'DIFF', 'DIFF', 'same', None)) + (rc,) + tuple(v.get(f) for f in files) + (v.get(''),), (3, 'DIFF', 'DIFF', 'same', None), detail=text.splitlines()) else: out('CAL %-58s NOT RUN (no --planted-random-int binary; --build-plants builds it)' % 'plant D') results.append(False) @@ -929,7 +941,7 @@ def stray(rd): rc, text, v = diff_restricted(base, args.planted_p4_trap, files) case('P4 on the smi-trap build (the dynamic half): each file DIFF, aborting at the int', (rc,) + tuple(v.get(f) for f in files) + (v.get(''), 'slot_from_int under EIGS_SMI_TRAP' in text), - (3, 'DIFF', 'DIFF', None, True)) + (3, 'DIFF', 'DIFF', None, True), detail=text.splitlines()) else: out('CAL %-58s NOT RUN (no --planted-p4-trap binary; --build-plants builds it)' % 'P4 dynamic') results.append(False) @@ -943,10 +955,10 @@ def stray(rd): (pop, rows_ok, _, n, cnt, wit), lines = sub(map_rows, leaf, branch=b) if label == 'leaf-scanner-early-return': case('leaf row vs a scratch build whose leaf scanner returns early', - (cnt['default']['vacuous'] > 0, rows_ok), (True, False)) + (cnt['default']['vacuous'] > 0, rows_ok), (True, False), detail=lines) else: case('L row vs a scratch build whose leaf MUL adds 1: trace differs', - (cnt['trace']['branch_pass'], cnt['default']['branch_pass'] > 0, rows_ok), (len(leaf), False, False)) + (cnt['trace']['branch_pass'], cnt['default']['branch_pass'] > 0, rows_ok), (len(leaf), False, False), detail=lines) n_ok = sum(results) out('calibration: cases=%d as-expected=%d unexpected=%d' % (len(results), n_ok, len(results) - n_ok)) return 0 if results and n_ok == len(results) else 1 @@ -1024,8 +1036,15 @@ def build_plant(name, out): def c_sources_only(d, names): """copytree ignore: keep directories and C sources (the int-source check - reads nothing else), skip binaries and objects.""" - return [n for n in names if not n.endswith(('.c', '.h')) and not os.path.isdir(os.path.join(d, n))] + reads nothing else), skip binaries and objects. In src/ itself, only the + TRACKED sources (inv.source_files): a copy must look like a fresh clone, + or a generated header such as src/lsp_stdlib_index.h makes the copy's + inventory differ from the committed one (the R1.1 CI lane).""" + keep = None + if os.path.realpath(d) == os.path.realpath(os.path.join(ROOT, 'src')): + keep = {os.path.basename(f) for f in inv.source_files(d)} + return [n for n in names if not os.path.isdir(os.path.join(d, n)) and + (not n.endswith(('.c', '.h')) or (keep is not None and n not in keep))] def diff_restricted(base, branch, files): diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index ac97a37b8..a353d8512 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -48,6 +48,7 @@ import glob import os import re +import subprocess import sys ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -199,6 +200,29 @@ 'case', 'defined', '__attribute__', '__typeof__', '_Generic'} +def source_files(src): + """The files the inventory scans: the TRACKED *.c and *.h directly in + `src`, sorted. Inside a git work tree the list comes from `git ls-files`: + an ignored, generated header (src/lsp_stdlib_index.h, which `make lsp` + writes) is not a source, and a fresh clone does not have it -- scanning + it made the committed inventory say `files=65` on a box that had run + `make lsp` and fail `--check` everywhere else (CI, the R1.1 fix round). + Outside a work tree (a `git archive` export, or a calibration copy that + holds only tracked files) every file present is tracked by construction. + A file listed but missing from disk is skipped (a deletion not yet + staged).""" + git = ['git', '-c', 'safe.directory=*', '-C', src] + inside = subprocess.run(git + ['rev-parse', '--is-inside-work-tree'], capture_output=True) + if inside.returncode == 0 and inside.stdout.strip() == b'true': + ls = subprocess.run(git + ['ls-files', '-z', '--', '*.c', '*.h'], capture_output=True) + if ls.returncode != 0: + raise SystemExit('phase2-inventory: FAIL: git ls-files in %s: %s' + % (src, ls.stderr.decode('utf-8', 'replace').strip())) + names = [n for n in ls.stdout.decode('utf-8').split('\0') if n and '/' not in n] + return sorted(os.path.join(src, n) for n in names if os.path.isfile(os.path.join(src, n))) + return sorted(glob.glob(os.path.join(src, '*.c')) + glob.glob(os.path.join(src, '*.h'))) + + def strip_c(text, keep_strings=False): """Blank comments and (unless keep_strings) string/char literals, keeping every newline (so line numbers survive) and every other column.""" @@ -757,7 +781,7 @@ def main(): help='print the C slot test population (design 2.5) and exit') args = ap.parse_args() - files = sorted(glob.glob(os.path.join(args.src, '*.c')) + glob.glob(os.path.join(args.src, '*.h'))) + files = source_files(args.src) sites, stripped_by_file, scope_by_file, sigs_by_file = [], {}, {}, {} for path in files: rel = os.path.basename(path) From 5d8de708dcfc5e59a19beb8ed9abfdbd4c9e3418 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 10:47:57 -0500 Subject: [PATCH 020/188] replay_diff: the ledger carries reasons; ledger test_audio.eigs (#1803) (#1758) R1.1's CI (replay differential, job 116494830590): `LEDGER CHANGED ... > test_audio.eigs`. Since the run-condition loader gives test_audio its EIGS_STRICT=0, replay_diff reaches its audio path, and on CI the replay diverges from the recording: audio is not fully taped (#1803, a product bug with its own PR to main, not fixed here). - tests/replay_diff_expected.txt ledgers test_audio.eigs with the reason "#1803: audio_noise is not taped". - The ledger can carry that reason: replay_diff now strips '#' and blank lines before the comparison and the count (jit_diff's ledger rule), and --record keeps them. On the 4 GB dev box test_audio does not diverge: ten record/replay pairs, across a one-second boundary and with the real, the dummy, the disk and no audio driver, gave identical output (the test prints no noise-derived value). So a dev-box run reports this row as '<' (ledgered and now identical); the row is the CI environment's. `replay_diff.sh --selftest`: "SELFTEST: all planted faults caught". Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/replay_diff_expected.txt | 8 ++++++++ tools/replay_diff.sh | 10 +++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/replay_diff_expected.txt b/tests/replay_diff_expected.txt index 3bc0596d9..851fff17e 100644 --- a/tests/replay_diff_expected.txt +++ b/tests/replay_diff_expected.txt @@ -1 +1,9 @@ +# tests/replay_diff_expected.txt -- the programs whose record-vs-replay output +# diverges reproducibly (tools/replay_diff.sh). A ledger to work down: a row +# is a fidelity hole, with its issue on the line above it. +# +# test_audio.eigs -- #1803: audio_noise is not taped. Reached since the run +# conditions (EIGS_STRICT=0) carried test_audio past its first strict raise; +# it diverges on CI (job 116494830590) and not on the 4 GB dev box. +test_audio.eigs test_store_corruption.eigs diff --git a/tools/replay_diff.sh b/tools/replay_diff.sh index c8f4542bf..562b74dbc 100755 --- a/tools/replay_diff.sh +++ b/tools/replay_diff.sh @@ -53,9 +53,13 @@ export EIGS_TEST_DIR="$ROOT/tests" corpus_dir() { printf '%s' "${REPLAY_DIFF_CORPUS:-$ROOT/tests}"; } eig_bin() { printf '%s' "${REPLAY_DIFF_EIG:-./eigenscript}"; } norm() { sed -E 's/0x[0-9a-f]+/0xADDR/g' "$1"; } +# The ledger's DATA rows. A '#' line or a blank line is a reason, never a +# row (jit_diff's ledger rule): both are stripped before the comparison and +# the count, so a row can carry the issue that explains it. +ledger_data() { awk 'NF && substr($0, 1, 1) != "#" { print }' "$1" | sort; } ledger_count() { local count - count=$(wc -l < "$1") || return 1 + count=$(ledger_data "$1" | wc -l) || return 1 count=${count//[[:space:]]/} case "$count" in ''|*[!0-9]*) return 1;; esac printf '%s' "$count" @@ -238,9 +242,9 @@ if [ "$crash" -gt 0 ]; then echo "replay_diff: FAIL: $crash signal exit(s) -- a crash is never a boundary, whatever the arm printed (#1112); $n programs, $boundary at the documented boundary, $nondet nondeterministic" exit 1 fi -if [ "${1:-}" = "--record" ]; then cp "$got" "$BASE"; count=$(ledger_count "$BASE") || { echo "replay_diff: FAIL: invalid ledger count"; exit 1; }; echo "replay_diff: baseline recorded ($count rows, $n programs, $boundary at the documented boundary, $nondet nondeterministic)"; exit 0; fi +if [ "${1:-}" = "--record" ]; then { [ -f "$BASE" ] && awk '/^#/ { print }' "$BASE"; cat "$got"; } > "$T/ledger.new"; cp "$T/ledger.new" "$BASE"; count=$(ledger_count "$BASE") || { echo "replay_diff: FAIL: invalid ledger count"; exit 1; }; echo "replay_diff: baseline recorded ($count rows, $n programs, $boundary at the documented boundary, $nondet nondeterministic)"; exit 0; fi [ -f "$BASE" ] || { echo "replay_diff: no baseline at $BASE (run with --record)"; cat "$got"; exit 1; } -if diff <(sort "$BASE") "$got" > "$T/d"; then +if diff <(ledger_data "$BASE") "$got" > "$T/d"; then count=$(ledger_count "$BASE") || { echo "replay_diff: FAIL: invalid ledger count"; exit 1; } echo "replay_diff: OK ($n programs record+replay; $boundary at the documented boundary; $nondet nondeterministic; $count ledgered)"; exit 0 fi From 2fa1b7fb37b5433232b81dc81f3c4a7366b5457d Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 10:52:47 -0500 Subject: [PATCH 021/188] phase2 R1.2a follow-up: the C slot test's value renderer has its VAL_INT arm (#1758) R1.2a appended VAL_INT and the C slot test's r_v renderer switches over a Value's type without a `default:`, so -Werror=switch stopped the slot test's own build (tests/phase2/slot_layer.c:269). R1.2a's five- configuration compile check covered the runtime's translation units and not the test programs that include them; it now compiles every tests/*.c and the slot test too. r_v renders an int as `v:int:` and a float under VAL_FLOAT/VAL_F64_RAW. No other test program switches on a value's type. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/slot_layer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index 72401a249..474cb9584 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -267,7 +267,8 @@ static void r_v(char *b, size_t n, Value *v) { if (!v) { snprintf(b, n, "v:NULL"); return; } if (v == g_str) { snprintf(b, n, "v:H"); return; } switch (v->type) { - case VAL_NUM: snprintf(b, n, "v:num:%016llx", (unsigned long long)u64_of(VAL_NUM_RAW(v))); return; + case VAL_FLOAT: snprintf(b, n, "v:num:%016llx", (unsigned long long)u64_of(VAL_F64_RAW(v))); return; + case VAL_INT: snprintf(b, n, "v:int:%lld", (long long)VAL_I64_RAW(v)); return; /* #1758 R1.2a */ case VAL_NULL: snprintf(b, n, "v:null"); return; case VAL_BOOL: snprintf(b, n, "v:%s", v->data.boolean ? "true" : "false"); return; case VAL_STR: case VAL_LIST: case VAL_DICT: case VAL_FN: case VAL_BUILTIN: From 3275c91f27897606cad5aa1cd412a26be072084a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 10:53:32 -0500 Subject: [PATCH 022/188] phase2 slot test: a build warning fails it under gcc only (#1758) R1.1's CI (macOS suite, job 116494825622): `[0fk] slot-layer: FAIL: the slot test build printed 103 warning(s)` under clang -- clang-only warnings (-Wdefault-const-init-field-unsafe on EigsView) that the main clang build on macOS prints as well. The zero-warning rule (#1775) was established on gcc, the reference toolchain for that class (-Wreturn-type, -Wmaybe-uninitialized at -O0 and -O1), and now applies only there. The runner asks the compiler the Makefile uses (`make print-CC`) for its predefined macros, so macOS's `gcc`, which is clang, counts as clang: gcc defines __GNUC__ without __clang__. Under gcc a warning fails as before (and the binary is removed); under any other compiler the warnings print, marked "printed, not failing", and only the -Werror set fails, which stops the compile itself. The design doc states the rule (2.5). Checked both ways on the dev box: - gcc: the rule holds (the #1775 return-type plant is unchanged); - clang (`MAKEFLAGS=CC=clang`): 508 warnings printed, `slot-layer-test: examined=33 ... failures=0`, `slot-layer: PASS`. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 8 ++++++++ tests/phase2/slot_layer.sh | 30 ++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index a02764534..079f590ec 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -647,6 +647,14 @@ result).** flags at -O1 (`INT_BINOP_R`'s `_ad`/`_bd`, the `i` of `CASE(INDEX_SET)` and of `jit_helper_index_set`): against R1.1, -0.0001% on the JIT-off float loop, +0.0001% with the JIT, -0.08% on the DMG canary. +- **A build warning fails the slot test under gcc only.** gcc is the + reference toolchain for #1775's class (-Wreturn-type, + -Wmaybe-uninitialized at -O0/-O1). R1.1's macOS lane (clang) printed 103 + warnings the gcc build does not have (-Wdefault-const-init-field-unsafe + on `EigsView`), which the main clang build prints too. Under any compiler + other than gcc (asked through its predefined macros: `__GNUC__` without + `__clang__`) the slot test follows the main build's policy on that + platform: warnings print, and only the -Werror set fails. - **Its runner reads each tool on its own channel.** The scan and the test each have a grammar; a line outside it, or any stderr, is a FAIL that prints the line (the R1.1 critic: Python 3.13's DeprecationWarning on the diff --git a/tests/phase2/slot_layer.sh b/tests/phase2/slot_layer.sh index 559c44048..d487bbda1 100755 --- a/tests/phase2/slot_layer.sh +++ b/tests/phase2/slot_layer.sh @@ -6,7 +6,10 @@ # lists every slot classifier whose first parameter is an EigsSlot. # 2. Build tests/phase2/slot_layer.c against the amalgamation # (make phase2-slot-test; -O0 for release, -O1 for asan, both -Wall -# -Wextra) and run it. A build warning is a FAIL (#1775). +# -Wextra) and run it. Under gcc, the reference toolchain for #1775's +# class, a build warning is a FAIL. Under any other compiler (clang on +# macOS) the slot test follows the main build's policy there: warnings +# print, and only the -Werror set fails (the compile itself stops). # 3. The ENTRY lines (Part A) and the MATRIX lines (Part B) must each equal # the derived population, both ways; the examined count must equal its # size, which must be above zero; the test's own verdict must be PASS. @@ -64,12 +67,27 @@ if [ "$brc" -ne 0 ]; then fail "make phase2-slot-test exited $brc" fi # #1775: the amalgamation compiles warning-free at the slot test's level (-O0 -# for release, ASan's -O1 for asan, both with -Wall -Wextra). A warning fails, -# and the binary is removed so the next run compiles, and warns, again. +# for release, ASan's -O1 for asan, both with -Wall -Wextra). The rule was +# established on gcc, the reference toolchain for that class, and holds only +# there: R1.1's macOS lane failed it with 103 clang-only warnings +# (-Wdefault-const-init-field-unsafe on EigsView) that the main clang build +# prints too. The compiler is asked, not guessed: gcc defines __GNUC__ and +# not __clang__. Under gcc a warning fails and the binary is removed, so the +# next run compiles, and warns, again; under another compiler it prints. +SLOT_CC=$(make -s -C "$ROOT" --no-print-directory print-CC) +SLOT_CC_MACROS=$(printf '' | $SLOT_CC -dM -E -x c - 2> /dev/null) +case "$SLOT_CC_MACROS" in + *"#define __clang__"*) SLOT_CC_KIND=clang ;; + *"#define __GNUC__"*) SLOT_CC_KIND=gcc ;; + *) SLOT_CC_KIND=other ;; +esac if grep -q 'warning:' "$TMP/build.txt"; then - grep 'warning:' "$TMP/build.txt" | sed 's/^/ build warning: /' - rm -f "$BIN" - fail "the slot test build printed $(grep -c 'warning:' "$TMP/build.txt") warning(s) (#1775)" + if [ "$SLOT_CC_KIND" = gcc ]; then + grep 'warning:' "$TMP/build.txt" | sed 's/^/ build warning: /' + rm -f "$BIN" + fail "the slot test build printed $(grep -c 'warning:' "$TMP/build.txt") warning(s) (#1775)" + fi + grep 'warning:' "$TMP/build.txt" | sed "s/^/ build warning ($SLOT_CC_KIND: printed, not failing): /" fi [ -x "$BIN" ] || fail "no binary at $BIN after the build" From d2c0ed6a6a125a99594cadce319dc609b061c202 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 11:01:19 -0500 Subject: [PATCH 023/188] phase2 R1.2b: the bridge and the container helpers admit an int (#1758) Forced sites (deprecation warnings cleared): eigenscript.h 1, value_slot.h 1, container.h 10, and the bridge's slow path in eigenscript.c (12). - val_is_number(v): THE number test for a path where an int belongs with a float (a VAL_FLOAT or a VAL_INT). - The bridge (design 2.7) converts an int: eigs_num_arg keeps its float fast path, and eigs_num_arg_slow reads a VAL_INT as (double)i64, which is what every number already is on the tag. The container number readers (eigs_slot_num, eigs_slot_elem_num, eigs_slot_opt_num) send a heap VAL_INT box to it. - slot_f64_value reads a VAL_FLOAT box only; a VAL_INT box answers 0 and takes the caller's slow path (R1.1's decision, renamed). - Container storage is canonical (2.1): eigs_container_slot encodes a VAL_INT box as its SMI inside [-2^47, 2^47) and as the heap pointer outside; eigs_slot_store_owned re-encodes a heap VAL_INT box the same way (eigs_slot_adopt releases a box that became an SMI). - slot_type answers VAL_FLOAT for a double; slot_view returns a heap VAL_INT box as itself (a real Value), and eigs_view_check covers a VAL_INT facade for R1.3. eigs_container_slot now names SLOT_SMI_MIN/MAX, which makes it a derived slot classifier (D3): its disposition row is `not-a-classifier` (it reads a Value and writes bits). Its call of slot_from_int is the one int-source allowance R1.2 makes (design 8, the canonicalizing writers); the calibration's "the real tree passes" case now runs at R1.2. The num-read allowlist re-reviews eigs_container_slot and eigs_num_arg_slow. Builds: all five configurations, 0 errors (453 deprecation lines left in the release build). Callgrind for this commit (it changes code inlined into vm_run_ex) is in the round's COST table. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 383 ++++++++++++++++--------------- docs/design/phase2-numbers.md | 1 + src/container.h | 31 ++- src/eigenscript.c | 6 +- src/eigenscript.h | 8 +- src/value_slot.h | 4 +- tools/num_read_allowlist.txt | 4 +- tools/phase2_check.py | 5 +- 8 files changed, 234 insertions(+), 208 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 36e9f966f..c48a329c6 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,12 +1,12 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1863 classified=1863 unclassified=0 +examined=1869 classified=1869 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 409 CASE=60 DATA=5 TEST=342 YIELD=2 -(b) payload reads 542 RAW=127 READ=415 -(c) producers 470 GUARD=71 PARSE=3 PRODUCE=370 TAGSET=4 WRITE=22 +(a) type tests 412 CASE=60 DATA=5 TEST=345 YIELD=2 +(b) payload reads 544 RAW=129 READ=415 +(c) producers 471 GUARD=71 PARSE=3 PRODUCE=371 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 18 CASE=2 FORMAT=3 PARSE=1 RAW=3 READ=3 TEST=6 (f) equality, ordering and hashing 33 CASE=2 PRODUCE=4 RAW=7 READ=9 TEST=11 @@ -17,10 +17,10 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per token make_num 364 -VAL_NUM 328 +VAL_NUM 316 eigs_num_arg 145 eigs_list_num 130 -VAL_NUM_RAW 92 +VAL_NUM_RAW 87 SLOT_F64_RAW 83 num_guard 60 AST_NUM 52 @@ -30,19 +30,21 @@ eigs_value_as_num 48 slot_from_f64 41 buffer_read_num 38 slot_is_smi 37 +VAL_INT 23 buffer_read_byte 22 list_set_num 22 -VAL_INT 18 slot_smi_val 17 slot_f64_value 16 strtod 16 NUM_REUSE 15 -VAL_I64_RAW 12 +VAL_I64_RAW 14 +VAL_FLOAT 13 eigs_slot_opt_num 12 eigs_num_arg_slow 9 EIGS_NUM_MAX 8 finite_num_to_byte 8 eigs_num_text 7 +VAL_F64_RAW 6 eigs_opt_num 6 eigs_slot_elem_num 6 num_guard_named 6 @@ -51,22 +53,20 @@ num_val 5 VAL_NUM_OFFSET 4 buf_num_arg 4 dict_value_rewrite_num 4 -VAL_FLOAT 3 list_rewrite_num 3 eigs_elem_num 2 f64_ 2 list_append_num 2 make_num_permanent 2 num_ 2 +slot_from_int 2 VAL_F64_OFFSET 1 -VAL_F64_RAW 1 atof 1 d_ 1 dict_value_get_num 1 dict_value_set_num 1 i64_ 1 list_get_num 1 -slot_from_int 1 slot_int_value 1 data.num (AST) 7 @@ -75,14 +75,14 @@ builtins.c 323 a=76 b=94 c=111 e=6 f=8 h=17 i=11 vm.c 299 a=78 b=97 c=68 e=2 f=9 i=45 ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 184 a=39 b=59 c=86 -eigenscript.c 102 a=19 b=15 c=12 e=7 f=10 i=39 +eigenscript.c 104 a=20 b=16 c=12 e=7 f=10 i=39 builtins_buf.c 97 a=21 b=37 c=39 jit.c 96 d=96 -container.h 89 a=35 b=29 c=25 +container.h 91 a=35 b=30 c=26 ext_store.c 54 h=54 embed_smoke.c 50 j=50 builtins_host.c 47 a=11 b=24 c=12 -eigenscript.h 42 a=5 b=24 c=12 e=1 +eigenscript.h 44 a=7 b=24 c=12 e=1 jit_smoke.c 31 d=31 lint.c 29 a=29 compiler.c 21 a=13 b=5 c=1 i=2 @@ -191,7 +191,7 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=56 D2=19 D3=24 T=67 dispositions=99 missing=0 stale=0 +D1=56 D2=19 D3=25 T=67 dispositions=100 missing=0 stale=0 D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 @@ -267,6 +267,7 @@ D2 vm.c:vm_local_lift guarded slot_as_ptr=1 slo D2 vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK) guarded slot_as_ptr=2 slot_is_ptr=1 D2 vm.c:vm_run_ex/CASE(SLICE_GET) guarded slot_as_ptr=1 slot_is_ptr=1 D2 vm.c:vm_slot_value_opaque guarded slot_as_ptr=1 slot_is_ptr=1 +D3 container.h:eigs_container_slot not-a-classifier SLOT_SMI_MAX=1 SLOT_SMI_MIN=1 D3 container.h:eigs_slot_adopt guarded slot_is_heap=1 D3 jit.c:jit_compile_to_thunk/OP_EQ not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 D3 jit.c:jit_compile_to_thunk/OP_NEG not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 @@ -1212,95 +1213,97 @@ compiler.c:2986 compile_node_inner data.num RAW b compiler.c:3030 compile_node_inner AST_NUM TEST a compiler.c:3031 compile_node_inner data.num RAW b compiler.c:3844 obs_ast_scan_d AST_NUM CASE i -container.h:26 eigs_container_slot VAL_NUM TEST a -container.h:26 eigs_container_slot VAL_NUM_RAW RAW b +container.h:26 eigs_container_slot VAL_F64_RAW RAW b +container.h:26 eigs_container_slot VAL_FLOAT TEST a container.h:26 eigs_container_slot num_guard GUARD c container.h:26 eigs_container_slot slot_from_f64 PRODUCE c -container.h:43 eigs_slot_store_owned SLOT_F64_RAW RAW b -container.h:43 eigs_slot_store_owned num_guard GUARD c -container.h:43 eigs_slot_store_owned slot_from_f64 PRODUCE c -container.h:43 eigs_slot_store_owned slot_is_f64 TEST a -container.h:46 eigs_slot_store_owned VAL_NUM TEST a -container.h:52 eigs_slot_store_borrow SLOT_F64_RAW RAW b -container.h:52 eigs_slot_store_borrow num_guard GUARD c -container.h:52 eigs_slot_store_borrow slot_from_f64 PRODUCE c -container.h:52 eigs_slot_store_borrow slot_is_f64 TEST a -container.h:79 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c -container.h:81 dict_value_rewrite_num slot_from_f64 PRODUCE c -container.h:85 list_rewrite_num list_rewrite_num PRODUCE c -container.h:87 list_rewrite_num slot_from_f64 PRODUCE c -container.h:96 slot_type VAL_NUM YIELD a -container.h:96 slot_type slot_is_f64 TEST a -container.h:100 slot_type slot_is_smi TEST a -container.h:124 list_get_ref slot_is_f64 TEST a -container.h:124 list_get_ref slot_is_smi TEST a -container.h:128 dict_value_get_ref slot_is_f64 TEST a -container.h:128 dict_value_get_ref slot_is_smi TEST a -container.h:138 eigs_slot_num eigs_slot_num READ b -container.h:139 eigs_slot_num SLOT_F64_RAW RAW b -container.h:139 eigs_slot_num slot_is_f64 TEST a -container.h:140 eigs_slot_num slot_is_smi TEST a -container.h:140 eigs_slot_num slot_smi_val RAW b -container.h:141 eigs_slot_num VAL_NUM TEST a -container.h:142 eigs_slot_num eigs_num_arg READ b -container.h:143 eigs_slot_num eigs_num_arg_slow READ b -container.h:145 eigs_slot_elem_num eigs_slot_elem_num READ b -container.h:146 eigs_slot_elem_num SLOT_F64_RAW RAW b -container.h:146 eigs_slot_elem_num slot_is_f64 TEST a -container.h:147 eigs_slot_elem_num slot_is_smi TEST a -container.h:147 eigs_slot_elem_num slot_smi_val RAW b -container.h:149 eigs_slot_elem_num VAL_NUM TEST a -container.h:149 eigs_slot_elem_num eigs_num_arg READ b -container.h:150 eigs_slot_elem_num eigs_num_arg_slow READ b -container.h:153 eigs_slot_opt_num eigs_slot_opt_num READ b -container.h:155 eigs_slot_opt_num SLOT_F64_RAW RAW b -container.h:155 eigs_slot_opt_num slot_is_f64 TEST a -container.h:156 eigs_slot_opt_num slot_is_smi TEST a -container.h:156 eigs_slot_opt_num slot_smi_val RAW b -container.h:157 eigs_slot_opt_num VAL_NUM TEST a -container.h:158 eigs_slot_opt_num eigs_num_arg READ b -container.h:160 eigs_slot_opt_num eigs_num_arg_slow READ b -container.h:169 slot_view slot_is_smi TEST a -container.h:170 slot_view VAL_NUM TEST a -container.h:170 slot_view slot_is_f64 TEST a -container.h:171 slot_view VAL_NUM TAGSET c -container.h:172 slot_view SLOT_F64_RAW RAW b -container.h:172 slot_view VAL_NUM_RAW WRITE c -container.h:172 slot_view slot_is_f64 TEST a -container.h:173 slot_view eigs_num_arg READ b -container.h:184 eigs_view_check VAL_NUM TEST a -container.h:211 list_get_return slot_is_smi TEST a -container.h:212 list_get_return SLOT_F64_RAW RAW b -container.h:212 list_get_return make_num PRODUCE c -container.h:212 list_get_return slot_is_f64 TEST a -container.h:219 dict_value_get_return slot_is_smi TEST a -container.h:220 dict_value_get_return SLOT_F64_RAW RAW b -container.h:220 dict_value_get_return make_num PRODUCE c -container.h:220 dict_value_get_return slot_is_f64 TEST a -container.h:250 eigs_slot_box SLOT_F64_RAW RAW b -container.h:250 eigs_slot_box make_num PRODUCE c -container.h:250 eigs_slot_box num_guard GUARD c -container.h:250 eigs_slot_box slot_is_f64 TEST a -container.h:251 eigs_slot_box slot_is_smi TEST a -container.h:273 list_set_num list_set_num PRODUCE c -container.h:274 list_set_num list_rewrite_num PRODUCE c -container.h:274 list_set_num num_guard GUARD c -container.h:276 list_append_num list_append_num PRODUCE c -container.h:277 list_append_num num_guard GUARD c -container.h:279 list_append_num slot_from_f64 PRODUCE c -container.h:281 dict_value_set_num dict_value_set_num PRODUCE c -container.h:282 dict_value_set_num dict_value_rewrite_num PRODUCE c -container.h:282 dict_value_set_num num_guard GUARD c -container.h:311 list_get_num list_get_num READ b -container.h:313 list_get_num slot_is_smi TEST a -container.h:313 list_get_num slot_smi_val RAW b -container.h:314 list_get_num slot_is_f64 TEST a -container.h:315 list_get_num SLOT_F64_RAW RAW b -container.h:318 dict_value_get_num dict_value_get_num READ b -container.h:320 dict_value_get_num slot_is_smi TEST a -container.h:320 dict_value_get_num slot_smi_val RAW b -container.h:321 dict_value_get_num slot_is_f64 TEST a -container.h:322 dict_value_get_num SLOT_F64_RAW RAW b +container.h:29 eigs_container_slot VAL_INT TEST a +container.h:30 eigs_container_slot VAL_I64_RAW RAW b +container.h:31 eigs_container_slot slot_from_int PRODUCE c +container.h:49 eigs_slot_store_owned SLOT_F64_RAW RAW b +container.h:49 eigs_slot_store_owned num_guard GUARD c +container.h:49 eigs_slot_store_owned slot_from_f64 PRODUCE c +container.h:49 eigs_slot_store_owned slot_is_f64 TEST a +container.h:52 eigs_slot_store_owned VAL_FLOAT TEST a +container.h:52 eigs_slot_store_owned VAL_INT TEST a +container.h:58 eigs_slot_store_borrow SLOT_F64_RAW RAW b +container.h:58 eigs_slot_store_borrow num_guard GUARD c +container.h:58 eigs_slot_store_borrow slot_from_f64 PRODUCE c +container.h:58 eigs_slot_store_borrow slot_is_f64 TEST a +container.h:85 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c +container.h:87 dict_value_rewrite_num slot_from_f64 PRODUCE c +container.h:91 list_rewrite_num list_rewrite_num PRODUCE c +container.h:93 list_rewrite_num slot_from_f64 PRODUCE c +container.h:102 slot_type VAL_FLOAT YIELD a +container.h:102 slot_type slot_is_f64 TEST a +container.h:106 slot_type slot_is_smi TEST a +container.h:130 list_get_ref slot_is_f64 TEST a +container.h:130 list_get_ref slot_is_smi TEST a +container.h:134 dict_value_get_ref slot_is_f64 TEST a +container.h:134 dict_value_get_ref slot_is_smi TEST a +container.h:144 eigs_slot_num eigs_slot_num READ b +container.h:145 eigs_slot_num SLOT_F64_RAW RAW b +container.h:145 eigs_slot_num slot_is_f64 TEST a +container.h:146 eigs_slot_num slot_is_smi TEST a +container.h:146 eigs_slot_num slot_smi_val RAW b +container.h:148 eigs_slot_num eigs_num_arg READ b +container.h:149 eigs_slot_num eigs_num_arg_slow READ b +container.h:151 eigs_slot_elem_num eigs_slot_elem_num READ b +container.h:152 eigs_slot_elem_num SLOT_F64_RAW RAW b +container.h:152 eigs_slot_elem_num slot_is_f64 TEST a +container.h:153 eigs_slot_elem_num slot_is_smi TEST a +container.h:153 eigs_slot_elem_num slot_smi_val RAW b +container.h:155 eigs_slot_elem_num eigs_num_arg READ b +container.h:156 eigs_slot_elem_num eigs_num_arg_slow READ b +container.h:159 eigs_slot_opt_num eigs_slot_opt_num READ b +container.h:161 eigs_slot_opt_num SLOT_F64_RAW RAW b +container.h:161 eigs_slot_opt_num slot_is_f64 TEST a +container.h:162 eigs_slot_opt_num slot_is_smi TEST a +container.h:162 eigs_slot_opt_num slot_smi_val RAW b +container.h:164 eigs_slot_opt_num eigs_num_arg READ b +container.h:166 eigs_slot_opt_num eigs_num_arg_slow READ b +container.h:175 slot_view slot_is_smi TEST a +container.h:177 slot_view VAL_FLOAT TEST a +container.h:177 slot_view slot_is_f64 TEST a +container.h:178 slot_view VAL_FLOAT TAGSET c +container.h:179 slot_view SLOT_F64_RAW RAW b +container.h:179 slot_view VAL_F64_RAW WRITE c +container.h:179 slot_view slot_is_f64 TEST a +container.h:180 slot_view eigs_num_arg READ b +container.h:191 eigs_view_check VAL_FLOAT TEST a +container.h:191 eigs_view_check VAL_INT TEST a +container.h:218 list_get_return slot_is_smi TEST a +container.h:219 list_get_return SLOT_F64_RAW RAW b +container.h:219 list_get_return make_num PRODUCE c +container.h:219 list_get_return slot_is_f64 TEST a +container.h:226 dict_value_get_return slot_is_smi TEST a +container.h:227 dict_value_get_return SLOT_F64_RAW RAW b +container.h:227 dict_value_get_return make_num PRODUCE c +container.h:227 dict_value_get_return slot_is_f64 TEST a +container.h:257 eigs_slot_box SLOT_F64_RAW RAW b +container.h:257 eigs_slot_box make_num PRODUCE c +container.h:257 eigs_slot_box num_guard GUARD c +container.h:257 eigs_slot_box slot_is_f64 TEST a +container.h:258 eigs_slot_box slot_is_smi TEST a +container.h:280 list_set_num list_set_num PRODUCE c +container.h:281 list_set_num list_rewrite_num PRODUCE c +container.h:281 list_set_num num_guard GUARD c +container.h:283 list_append_num list_append_num PRODUCE c +container.h:284 list_append_num num_guard GUARD c +container.h:286 list_append_num slot_from_f64 PRODUCE c +container.h:288 dict_value_set_num dict_value_set_num PRODUCE c +container.h:289 dict_value_set_num dict_value_rewrite_num PRODUCE c +container.h:289 dict_value_set_num num_guard GUARD c +container.h:318 list_get_num list_get_num READ b +container.h:320 list_get_num slot_is_smi TEST a +container.h:320 list_get_num slot_smi_val RAW b +container.h:321 list_get_num slot_is_f64 TEST a +container.h:322 list_get_num SLOT_F64_RAW RAW b +container.h:325 dict_value_get_num dict_value_get_num READ b +container.h:327 dict_value_get_num slot_is_smi TEST a +container.h:327 dict_value_get_num slot_smi_val RAW b +container.h:328 dict_value_get_num slot_is_f64 TEST a +container.h:329 dict_value_get_num SLOT_F64_RAW RAW b eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a eigenscript.c:309 val_type_name VAL_FLOAT CASE a @@ -1357,96 +1360,100 @@ eigenscript.c:1786 make_num_permanent num_guard GUARD c eigenscript.c:1788 make_num_permanent VAL_NUM TAGSET c eigenscript.c:1789 make_num_permanent VAL_NUM_RAW WRITE c eigenscript.c:1818 eigs_num_arg_slow eigs_num_arg_slow READ b -eigenscript.c:1819 eigs_num_arg_slow VAL_NUM TEST a -eigenscript.c:1819 eigs_num_arg_slow VAL_NUM_RAW RAW b -eigenscript.c:1826 eigs_list_num eigs_list_num READ b -eigenscript.c:1833 eigs_list_num eigs_slot_num READ b -eigenscript.c:1836 eigs_elem_num eigs_elem_num READ b -eigenscript.c:1837 eigs_elem_num eigs_slot_elem_num READ b -eigenscript.c:1840 eigs_opt_num eigs_opt_num READ b -eigenscript.c:1841 eigs_opt_num eigs_slot_opt_num READ b -eigenscript.c:1877 slot_from_value VAL_NUM TEST a -eigenscript.c:1881 slot_from_value VAL_NUM_RAW RAW b -eigenscript.c:1883 slot_from_value slot_from_f64 PRODUCE c -eigenscript.c:1902 slot_to_value SLOT_F64_RAW RAW b -eigenscript.c:1902 slot_to_value make_num PRODUCE c -eigenscript.c:1902 slot_to_value slot_is_f64 TEST a -eigenscript.c:1910 slot_to_value slot_is_smi TEST a -eigenscript.c:2409 module_ns_project slot_is_f64 TEST a -eigenscript.c:2409 module_ns_project slot_is_f64 TEST a -eigenscript.c:2414 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2414 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2659 chan_clone_rec VAL_NUM TEST a -eigenscript.c:2662 chan_clone_rec VAL_NUM CASE a -eigenscript.c:2662 chan_clone_rec VAL_NUM_RAW RAW b -eigenscript.c:2662 chan_clone_rec make_num PRODUCE c -eigenscript.c:2665 chan_clone_rec VAL_I64_RAW RAW b -eigenscript.c:2665 chan_clone_rec VAL_INT CASE a -eigenscript.c:2853 is_truthy VAL_NUM CASE a -eigenscript.c:2853 is_truthy VAL_NUM_RAW RAW b -eigenscript.c:2854 is_truthy VAL_I64_RAW RAW b -eigenscript.c:2854 is_truthy VAL_INT CASE a -eigenscript.c:2890 values_equal_impl VAL_NUM TEST f -eigenscript.c:2891 values_equal_impl VAL_NUM TEST f -eigenscript.c:2905 values_equal_impl VAL_NUM CASE f -eigenscript.c:2905 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2905 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2906 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2906 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2906 values_equal_impl VAL_INT CASE f -eigenscript.c:2936 values_equal_impl buffer_read_num READ f -eigenscript.c:2938 values_equal_impl buffer_read_num READ f -eigenscript.c:2979 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:2994 eigs_num_text strtod PARSE e -eigenscript.c:3004 value_to_string VAL_NUM CASE e -eigenscript.c:3005 value_to_string VAL_NUM_RAW RAW e -eigenscript.c:3005 value_to_string eigs_num_text FORMAT e -eigenscript.c:3008 value_to_string VAL_INT CASE e -eigenscript.c:3009 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4231 gc_value_is_node VAL_NUM CASE a -eigenscript.c:4232 gc_value_is_node VAL_INT CASE a +eigenscript.c:1819 eigs_num_arg_slow VAL_F64_RAW RAW b +eigenscript.c:1819 eigs_num_arg_slow VAL_FLOAT TEST a +eigenscript.c:1823 eigs_num_arg_slow VAL_I64_RAW RAW b +eigenscript.c:1823 eigs_num_arg_slow VAL_INT TEST a +eigenscript.c:1830 eigs_list_num eigs_list_num READ b +eigenscript.c:1837 eigs_list_num eigs_slot_num READ b +eigenscript.c:1840 eigs_elem_num eigs_elem_num READ b +eigenscript.c:1841 eigs_elem_num eigs_slot_elem_num READ b +eigenscript.c:1844 eigs_opt_num eigs_opt_num READ b +eigenscript.c:1845 eigs_opt_num eigs_slot_opt_num READ b +eigenscript.c:1881 slot_from_value VAL_NUM TEST a +eigenscript.c:1885 slot_from_value VAL_NUM_RAW RAW b +eigenscript.c:1887 slot_from_value slot_from_f64 PRODUCE c +eigenscript.c:1906 slot_to_value SLOT_F64_RAW RAW b +eigenscript.c:1906 slot_to_value make_num PRODUCE c +eigenscript.c:1906 slot_to_value slot_is_f64 TEST a +eigenscript.c:1914 slot_to_value slot_is_smi TEST a +eigenscript.c:2413 module_ns_project slot_is_f64 TEST a +eigenscript.c:2413 module_ns_project slot_is_f64 TEST a +eigenscript.c:2418 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2418 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2663 chan_clone_rec VAL_NUM TEST a +eigenscript.c:2666 chan_clone_rec VAL_NUM CASE a +eigenscript.c:2666 chan_clone_rec VAL_NUM_RAW RAW b +eigenscript.c:2666 chan_clone_rec make_num PRODUCE c +eigenscript.c:2669 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:2669 chan_clone_rec VAL_INT CASE a +eigenscript.c:2857 is_truthy VAL_NUM CASE a +eigenscript.c:2857 is_truthy VAL_NUM_RAW RAW b +eigenscript.c:2858 is_truthy VAL_I64_RAW RAW b +eigenscript.c:2858 is_truthy VAL_INT CASE a +eigenscript.c:2894 values_equal_impl VAL_NUM TEST f +eigenscript.c:2895 values_equal_impl VAL_NUM TEST f +eigenscript.c:2909 values_equal_impl VAL_NUM CASE f +eigenscript.c:2909 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2909 values_equal_impl VAL_NUM_RAW RAW f +eigenscript.c:2910 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2910 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2910 values_equal_impl VAL_INT CASE f +eigenscript.c:2940 values_equal_impl buffer_read_num READ f +eigenscript.c:2942 values_equal_impl buffer_read_num READ f +eigenscript.c:2983 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:2998 eigs_num_text strtod PARSE e +eigenscript.c:3008 value_to_string VAL_NUM CASE e +eigenscript.c:3009 value_to_string VAL_NUM_RAW RAW e +eigenscript.c:3009 value_to_string eigs_num_text FORMAT e +eigenscript.c:3012 value_to_string VAL_INT CASE e +eigenscript.c:3013 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4235 gc_value_is_node VAL_NUM CASE a +eigenscript.c:4236 gc_value_is_node VAL_INT CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a eigenscript.h:281 VAL_FLOAT DATA a eigenscript.h:289 VAL_INT DATA a eigenscript.h:290 VAL_FLOAT TAGSET c eigenscript.h:290 VAL_NUM DATA a -eigenscript.h:302 #define VAL_F64_RAW VAL_F64_RAW RAW b -eigenscript.h:302 #define VAL_F64_RAW f64_ RAW b -eigenscript.h:303 #define VAL_I64_RAW VAL_I64_RAW RAW b -eigenscript.h:303 #define VAL_I64_RAW i64_ RAW b -eigenscript.h:304 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b -eigenscript.h:304 #define VAL_F64_OFFSET f64_ RAW b -eigenscript.h:306 #define VAL_NUM_RAW VAL_NUM_RAW RAW b -eigenscript.h:306 #define VAL_NUM_RAW num_ RAW b -eigenscript.h:307 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b -eigenscript.h:307 #define VAL_NUM_OFFSET num_ RAW b -eigenscript.h:1413 eigs_num_arg_slow READ b -eigenscript.h:1414 eigs_num_arg eigs_num_arg READ b -eigenscript.h:1415 eigs_num_arg VAL_NUM TEST a -eigenscript.h:1415 eigs_num_arg VAL_NUM_RAW RAW b -eigenscript.h:1416 eigs_num_arg eigs_num_arg_slow READ b -eigenscript.h:1418 eigs_list_num READ b -eigenscript.h:1423 eigs_elem_num READ b -eigenscript.h:1424 eigs_opt_num READ b -eigenscript.h:1795 make_num PRODUCE c -eigenscript.h:1805 make_num_permanent PRODUCE c -eigenscript.h:1857 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1899 num_guard num_guard GUARD c -eigenscript.h:1907 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1907 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1908 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1908 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1917 buffer_read_num buffer_read_num READ b -eigenscript.h:1918 buffer_read_num num_guard GUARD c -eigenscript.h:1924 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1933 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1942 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1943 buffer_read_byte buffer_read_num READ b -eigenscript.h:1945 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1956 num_guard_named num_guard_named GUARD c -eigenscript.h:1962 num_guard_named num_guard GUARD c -eigenscript.h:2274 eigs_num_text FORMAT e +eigenscript.h:298 #define val_is_number VAL_FLOAT TEST a +eigenscript.h:298 #define val_is_number VAL_INT TEST a +eigenscript.h:306 #define VAL_F64_RAW VAL_F64_RAW RAW b +eigenscript.h:306 #define VAL_F64_RAW f64_ RAW b +eigenscript.h:307 #define VAL_I64_RAW VAL_I64_RAW RAW b +eigenscript.h:307 #define VAL_I64_RAW i64_ RAW b +eigenscript.h:308 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b +eigenscript.h:308 #define VAL_F64_OFFSET f64_ RAW b +eigenscript.h:310 #define VAL_NUM_RAW VAL_NUM_RAW RAW b +eigenscript.h:310 #define VAL_NUM_RAW num_ RAW b +eigenscript.h:311 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b +eigenscript.h:311 #define VAL_NUM_OFFSET num_ RAW b +eigenscript.h:1417 eigs_num_arg_slow READ b +eigenscript.h:1418 eigs_num_arg eigs_num_arg READ b +eigenscript.h:1419 eigs_num_arg VAL_F64_RAW RAW b +eigenscript.h:1419 eigs_num_arg VAL_FLOAT TEST a +eigenscript.h:1420 eigs_num_arg eigs_num_arg_slow READ b +eigenscript.h:1422 eigs_list_num READ b +eigenscript.h:1427 eigs_elem_num READ b +eigenscript.h:1428 eigs_opt_num READ b +eigenscript.h:1799 make_num PRODUCE c +eigenscript.h:1809 make_num_permanent PRODUCE c +eigenscript.h:1861 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1903 num_guard num_guard GUARD c +eigenscript.h:1911 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1911 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1912 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1912 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1921 buffer_read_num buffer_read_num READ b +eigenscript.h:1922 buffer_read_num num_guard GUARD c +eigenscript.h:1928 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1937 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1946 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1947 buffer_read_byte buffer_read_num READ b +eigenscript.h:1949 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1960 num_guard_named num_guard_named GUARD c +eigenscript.h:1966 num_guard_named num_guard GUARD c +eigenscript.h:2278 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_NUM CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j @@ -2088,8 +2095,8 @@ value_slot.h:230 slot_truthy_immediate slot_smi_val RAW b value_slot.h:244 slot_f64_value slot_f64_value READ b value_slot.h:245 slot_f64_value SLOT_F64_RAW RAW b value_slot.h:245 slot_f64_value slot_is_f64 TEST a -value_slot.h:248 slot_f64_value VAL_NUM TEST a -value_slot.h:248 slot_f64_value VAL_NUM_RAW RAW b +value_slot.h:248 slot_f64_value VAL_F64_RAW RAW b +value_slot.h:248 slot_f64_value VAL_FLOAT TEST a value_slot.h:254 slot_int_value slot_int_value READ b value_slot.h:255 slot_int_value slot_is_smi TEST a value_slot.h:255 slot_int_value slot_smi_val RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 079f590ec..fee241d84 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -673,6 +673,7 @@ result).** | `container.h:dict_value_get_num` | smi-arm | bridge reader (2.7): an int element converts to its double, exactly (|SMI| < 2^47), until R1.6 deletes the bridge (D1) | | `container.h:dict_value_get_ref` | smi-arm | NULL for a number by contract, an int included; the caller then types the element (D1) | | `container.h:dict_value_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value`, the one SMI boxer (unwired until R1.3) (D1) | +| `container.h:eigs_container_slot` | not-a-classifier | the canonicalizing Value-to-slot writer (R1.2): it reads a Value, not a slot, and writes the bits; a `VAL_INT` box becomes an SMI inside [-2^47, 2^47) and stays a heap slot outside it (2.1) (D3) | | `container.h:eigs_slot_adopt` | guarded | decides ownership from what `eigs_container_slot` returned (compile-forced); a small int comes back as an SMI and its box is released (D3) | | `container.h:eigs_slot_box` | smi-arm | boxes an int through `slot_to_value`, kind-preserving (unwired until R1.3) (D1) | | `container.h:eigs_slot_elem_num` | smi-arm | bridge reader: an int converts to its double (D1) | diff --git a/src/container.h b/src/container.h index 705292323..3b3b82a0c 100644 --- a/src/container.h +++ b/src/container.h @@ -23,7 +23,13 @@ typedef struct { Value v; } EigsView; * encodings, everything else is a heap pointer. C NULL encodes as null. */ static inline EigsSlot eigs_container_slot(Value *v) { if (!v || v->type == VAL_NULL) return slot_null(); - if (v->type == VAL_NUM) return slot_from_f64(num_guard(VAL_NUM_RAW(v))); + if (v->type == VAL_FLOAT) return slot_from_f64(num_guard(VAL_F64_RAW(v))); + /* #1758 (design 2.1): container storage is canonical -- a small int is + * an SMI, and only an int outside [-2^47, 2^47) stays its box. */ + if (v->type == VAL_INT) { + int64_t i = VAL_I64_RAW(v); + return (i >= SLOT_SMI_MIN && i <= SLOT_SMI_MAX) ? slot_from_int(i) : slot_from_heap(v); + } if (v->type == VAL_BOOL) return slot_from_bool(v->data.boolean); return slot_from_heap(v); } @@ -43,8 +49,8 @@ static inline EigsSlot eigs_slot_store_owned(EigsSlot s) { if (slot_is_f64(s)) return slot_from_f64(num_guard(SLOT_F64_RAW(s))); if (slot_is_heap(s)) { Value *v = slot_as_ptr(s); - if (v->type == VAL_NUM || v->type == VAL_NULL || v->type == VAL_BOOL) - return eigs_slot_adopt(v); + if (v->type == VAL_FLOAT || v->type == VAL_INT || v->type == VAL_NULL || v->type == VAL_BOOL) + return eigs_slot_adopt(v); /* #1758: a small-int box becomes its SMI */ } return s; } @@ -93,7 +99,7 @@ static inline int list_rewrite_num(const Value *list, int i, double d) { * SMI's type is the int ValType, which lands in R1.2a; until then it is * refused loudly rather than read as a pointer. */ static inline ValType slot_type(EigsSlot s) { - if (slot_is_f64(s)) return VAL_NUM; + if (slot_is_f64(s)) return VAL_FLOAT; if (slot_is_null(s)) return VAL_NULL; if (slot_is_bool(s)) return VAL_BOOL; if (slot_is_heap(s)) return slot_as_ptr(s)->type; @@ -138,15 +144,15 @@ static inline Value *dict_value_get_ref(const Value *dict, int i) { static inline double eigs_slot_num(EigsSlot s, const char *who) { if (slot_is_f64(s)) return SLOT_F64_RAW(s); if (slot_is_smi(s)) return (double)slot_smi_val(s); - if (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_NUM) - return eigs_num_arg(slot_as_ptr(s), who); + if (slot_is_heap(s) && val_is_number(slot_as_ptr(s))) + return eigs_num_arg(slot_as_ptr(s), who); /* #1758: an int box converts (the bridge) */ return eigs_num_arg_slow(eigs_slot_ref(s), who); } static inline double eigs_slot_elem_num(EigsSlot s, const char *who) { if (slot_is_f64(s)) return SLOT_F64_RAW(s); if (slot_is_smi(s)) return (double)slot_smi_val(s); Value *v = eigs_slot_ref(s); - if (v && v->type == VAL_NUM) return eigs_num_arg(v, who); + if (v && val_is_number(v)) return eigs_num_arg(v, who); if (g_strict || (v && v->type == VAL_BOOL)) return eigs_num_arg_slow(v, who); return 0.0; } @@ -154,7 +160,7 @@ static inline int eigs_slot_opt_num(EigsSlot s, double *out, const char *who) { if (slot_is_null(s) || (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_NULL)) return 0; if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } - if (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_NUM) { + if (slot_is_heap(s) && val_is_number(slot_as_ptr(s))) { *out = eigs_num_arg(slot_as_ptr(s), who); return 1; } (void)eigs_num_arg_slow(eigs_slot_ref(s), who); @@ -167,9 +173,10 @@ static inline int eigs_slot_opt_num(EigsSlot s, double *out, const char *who) { * #1758: an SMI's facade is a VAL_INT view (R1.2a); refused until then. */ static inline Value *slot_view(EigsSlot s, EigsView *view) { if (slot_is_smi(s)) eigs_int_unwired("slot_view", s.u); - if (!slot_is_f64(s) && slot_type(s) != VAL_NUM) return eigs_slot_ref(s); - view->v.type = VAL_NUM; - VAL_NUM_RAW(&view->v) = slot_is_f64(s) ? SLOT_F64_RAW(s) + /* a heap VAL_INT box is a real Value: it is returned as itself */ + if (!slot_is_f64(s) && slot_type(s) != VAL_FLOAT) return eigs_slot_ref(s); + view->v.type = VAL_FLOAT; + VAL_F64_RAW(&view->v) = slot_is_f64(s) ? SLOT_F64_RAW(s) : eigs_num_arg(slot_as_ptr(s), "slot_view"); view->v.refcount = EIGS_VIEW_RC; return &view->v; @@ -181,7 +188,7 @@ static inline Value *dict_value_get_view(const Value *dict, int i, EigsView *vie return slot_view(dict_value_slot(dict, i), view); } static inline void eigs_view_check(EigsView *view) { - if (view->v.type == VAL_NUM && view->v.refcount != 0 && + if ((view->v.type == VAL_FLOAT || view->v.type == VAL_INT) && view->v.refcount != 0 && view->v.refcount != EIGS_VIEW_RC) { fprintf(stderr, "%s:%d: EigenScript FATAL: numeric view refcount moved (%d)\n", __FILE__, __LINE__, view->v.refcount); diff --git a/src/eigenscript.c b/src/eigenscript.c index ae0a01c61..82c70483e 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -1816,7 +1816,11 @@ static const char *num_who(const char *who) { } double eigs_num_arg_slow(const Value *v, const char *who) { - if (v && v->type == VAL_NUM) return VAL_NUM_RAW(v); + if (v && v->type == VAL_FLOAT) return VAL_F64_RAW(v); + /* #1758 R1.2, the bridge (design 2.7): until R1.6 a number a builtin + * reads is a double, so an int converts (rounding beyond 2^53), as every + * number already is one on the tag. */ + if (v && v->type == VAL_INT) return (double)VAL_I64_RAW(v); if (!g_has_error) rt_error(EK_TYPE, 0, "%s: expected a number, got %s", num_who(who), v ? val_type_name(v->type) : "nothing"); diff --git a/src/eigenscript.h b/src/eigenscript.h index 3b74903be..c2a34e57e 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -292,6 +292,10 @@ typedef enum { typedef struct Value Value; typedef Value* (*BuiltinFn)(Value* arg); +/* #1758 R1.2: a number Value is a VAL_FLOAT or a VAL_INT. THE test a number + * test uses when an int belongs on the same path as a float (a builtin's + * number test admits an int and reads it through the bridge, design 2.7). */ +#define val_is_number(v) ((v)->type == VAL_FLOAT || (v)->type == VAL_INT) /* #1637 round 4: the ONE raw way into a Value's number (an lvalue: also the * write). Only for a Value whose type is proven (VAL_FLOAT for the double, @@ -1412,8 +1416,8 @@ int eigs_arg_has_bool(const Value *arg); * and returns 0 */ double eigs_num_arg_slow(const Value *v, const char *who); static inline double eigs_num_arg(const Value *v, const char *who) { - if (__builtin_expect(v && v->type == VAL_NUM, 1)) return VAL_NUM_RAW(v); - return eigs_num_arg_slow(v, who); + if (__builtin_expect(v && v->type == VAL_FLOAT, 1)) return VAL_F64_RAW(v); + return eigs_num_arg_slow(v, who); /* #1758: an int converts there */ } double eigs_list_num(const Value *list, int i, const char *who); /* #1637 round 4: an ELEMENT a builtin reads as a number (a tensor cell, a diff --git a/src/value_slot.h b/src/value_slot.h index 4667febcd..5769790f2 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -232,7 +232,7 @@ static inline int slot_truthy_immediate(EigsSlot s, int *out_decided) { return 0; } -/* #1758: a float's double, from an immediate or a VAL_NUM box (the VM boxes +/* #1758: a float's double, from an immediate or a VAL_FLOAT box (the VM boxes * numbers on purpose: the lifts, a for-in variable). 0 for anything else, * an int (an SMI, later a VAL_INT box) included: the caller sends it to its * slow path; *out is written only when the answer is 1. Replaces vm.c's @@ -245,7 +245,7 @@ static inline int slot_f64_value(EigsSlot s, double *out) { if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } if (slot_is_heap(s)) { Value *v = slot_as_ptr(s); - if (v->type == VAL_NUM) { *out = VAL_NUM_RAW(v); return 1; } + if (v->type == VAL_FLOAT) { *out = VAL_F64_RAW(v); return 1; } /* a VAL_INT box: 0 */ } return 0; } diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 94817697b..57caf0674 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -9,7 +9,7 @@ builtins_tensor.c|builtin_tensor_matmul|1|writes the NaN-boxed null sentinel int builtins.c|eigs_json_encode_value|1|JSON encoder: case VAL_INT writes the int's exact digits (#1758 R1.2a) container.h|dict_value_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) container.h|dict_value_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 -container.h|eigs_container_slot|1|Value-to-slot encoder reads a box only after type == VAL_NUM, then num_guards it +container.h|eigs_container_slot|2|Value-to-slot encoder reads a box only after type == VAL_FLOAT (then num_guards it) or type == VAL_INT (an SMI in range, design 2.1) container.h|eigs_slot_store_borrow|1|storage normaliser re-guards an immediate only after slot_is_f64 (#1665 arm D B10) container.h|eigs_slot_store_owned|1|storage normaliser re-guards an immediate only after slot_is_f64 (#1665 arm D B10) container.h|eigs_slot_box|1|borrowed slot write boxes a double only after slot_is_f64 @@ -25,7 +25,7 @@ chunk.c|const_hash_value|1|constant-pool hash of a constant inside its type == V eigenscript.c|chan_clone_rec|2|channel deep-copy, switch case VAL_NUM; case VAL_INT names the int it refuses (unwired, R1.3) eigenscript.c|compute_entropy_impl|2|observer entropy, switch case VAL_NUM, and case VAL_INT (an int's entropy is its double's, design 7) eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_f64 -eigenscript.c|eigs_num_arg_slow|1|checking accessor itself: reads only after type == VAL_NUM, raises otherwise +eigenscript.c|eigs_num_arg_slow|2|checked reader slow path: reads only after type == VAL_FLOAT, or VAL_INT (the bridge converts an int, design 2.7) eigenscript.c|is_truthy|2|truthiness, switch case VAL_NUM and case VAL_INT (a bool has its own case) eigenscript.c|make_num|1|constructor: writes the number of a Value it just typed VAL_NUM eigenscript.c|make_num_permanent|1|constructor: writes the number of a Value it just typed VAL_NUM diff --git a/tools/phase2_check.py b/tools/phase2_check.py index ae54f0abd..68d0c1d27 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -793,7 +793,10 @@ def stray(rd): case('int-source plant: the check fails, naming the caller', (ok, any( 'trace.c' in l and 'calls slot_from_int' in l for l in lines)), (False, True), detail=lines) lines = [] - case('int-source on the real tree passes', int_source(os.path.join(ROOT, 'src'), lines.append), True, detail=lines) + # at R1.2: from R1.2 the canonicalizing writers may convert a VAL_INT + # (design 8), and the branch is past R1.1 + case('int-source on the real tree passes (at R1.2)', + int_source(os.path.join(ROOT, 'src'), lines.append, 'R1.2'), True, detail=lines) # the token gate against a reintroduced deleted token with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: os.mkdir(os.path.join(d, 'src')) From 466174229ebcee3c938842d94411d48565fba13a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Thu, 15 Oct 2026 11:09:52 -0500 Subject: [PATCH 024/188] phase2 R1.2c: eigenscript.c's number sites, with their final int arms (#1758) Forced sites (deprecation warnings cleared): eigenscript.c 30 lines in 14 functions. The tokens are renamed (VAL_FLOAT, VAL_F64_RAW) and each site that an int can reach has its final arm, dead until R1.3: - values_equal_impl: N2 (design 7). An int and a float are equal exactly when their values are, through the new eigs_cmp_int_float (eigenscript.h): NaN is unordered; f >= 2^63 is above every int and f < -2^63 below; otherwise i against floor(f), with a fraction putting the float above. A bool met by an int raises exactly as one met by a float. - slot_from_value: a VAL_INT box becomes its SMI inside [-2^47, 2^47) (its box released) and stays a heap slot outside (2.1). It names the SMI range, so it is a derived D3 classifier: `not-a-classifier` in 2.5, and one of the R1.2 int-source writers. - The observer (design 7): observer_slot_update and observer_slot_sample_gated route a boxed int into the numeric channel as its double; observer_slot_from_trajectory accepts a number of either kind in a snapshot and reads it through the bridge. - make_num, make_num_permanent, free_value (the freelist keeps float boxes only; an int box owns nothing and is freed), recycle_intermediate, is_truthy, value_to_string, gc_value_is_node, compute_entropy_impl and chan_clone_rec: renamed; their VAL_INT arms landed in R1.2a. eigs_cmp_int_float checked against an exact oracle (x86-64 long double holds every int64 and double): 504 edge pairs plus 2,000,000 random pairs, `cmp-int-float: examined=2000504 bad=0`. Three plants, each caught: dropping the fraction step (bad=186), `>` for `>=` at 2^63 (bad=18), trunc for floor (bad=102). The harness is a scratch file, not committed: R1.3's N2 MAP rows are the permanent gate. The num-read allowlist re-reviews observer_slot_update, observer_slot_sample_gated, slot_from_value and values_equal_impl, and drops observer_slot_from_trajectory (it now reads through the bridge). Builds 0 errors; the observer, trajectory, channel and equality tests pass. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 302 ++++++++++++++++--------------- docs/design/phase2-numbers.md | 1 + src/eigenscript.c | 90 +++++---- src/eigenscript.h | 13 ++ tools/num_read_allowlist.txt | 9 +- 5 files changed, 232 insertions(+), 183 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index c48a329c6..376cdcf5b 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,27 +1,27 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1869 classified=1869 unclassified=0 +examined=1878 classified=1878 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 412 CASE=60 DATA=5 TEST=345 YIELD=2 -(b) payload reads 544 RAW=129 READ=415 -(c) producers 471 GUARD=71 PARSE=3 PRODUCE=371 TAGSET=4 WRITE=22 +(a) type tests 414 CASE=60 DATA=5 TEST=347 YIELD=2 +(b) payload reads 545 RAW=130 READ=415 +(c) producers 472 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 18 CASE=2 FORMAT=3 PARSE=1 RAW=3 READ=3 TEST=6 -(f) equality, ordering and hashing 33 CASE=2 PRODUCE=4 RAW=7 READ=9 TEST=11 +(f) equality, ordering and hashing 39 CASE=2 PRODUCE=4 RAW=11 READ=9 TEST=13 (g) tape encode and decode 25 CASE=4 DATA=2 PARSE=7 PRODUCE=5 RAW=5 TEST=2 (h) JSON, store and db encoders 76 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=3 READ=24 TEST=18 -(i) observer numeric paths 98 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=25 READ=5 TEST=24 +(i) observer numeric paths 97 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=25 (j) embed API 65 CASE=2 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 ## Per token make_num 364 -VAL_NUM 316 -eigs_num_arg 145 +VAL_NUM 294 +eigs_num_arg 147 eigs_list_num 130 -VAL_NUM_RAW 87 SLOT_F64_RAW 83 +VAL_NUM_RAW 70 num_guard 60 AST_NUM 52 eigs_slot_num 52 @@ -30,21 +30,21 @@ eigs_value_as_num 48 slot_from_f64 41 buffer_read_num 38 slot_is_smi 37 -VAL_INT 23 +VAL_INT 32 +VAL_FLOAT 31 buffer_read_byte 22 list_set_num 22 +VAL_F64_RAW 19 +VAL_I64_RAW 19 slot_smi_val 17 slot_f64_value 16 strtod 16 NUM_REUSE 15 -VAL_I64_RAW 14 -VAL_FLOAT 13 eigs_slot_opt_num 12 eigs_num_arg_slow 9 EIGS_NUM_MAX 8 finite_num_to_byte 8 eigs_num_text 7 -VAL_F64_RAW 6 eigs_opt_num 6 eigs_slot_elem_num 6 num_guard_named 6 @@ -54,12 +54,12 @@ VAL_NUM_OFFSET 4 buf_num_arg 4 dict_value_rewrite_num 4 list_rewrite_num 3 +slot_from_int 3 eigs_elem_num 2 f64_ 2 list_append_num 2 make_num_permanent 2 num_ 2 -slot_from_int 2 VAL_F64_OFFSET 1 atof 1 d_ 1 @@ -75,7 +75,7 @@ builtins.c 323 a=76 b=94 c=111 e=6 f=8 h=17 i=11 vm.c 299 a=78 b=97 c=68 e=2 f=9 i=45 ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 184 a=39 b=59 c=86 -eigenscript.c 104 a=20 b=16 c=12 e=7 f=10 i=39 +eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 builtins_buf.c 97 a=21 b=37 c=39 jit.c 96 d=96 container.h 91 a=35 b=30 c=26 @@ -191,7 +191,7 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=56 D2=19 D3=25 T=67 dispositions=100 missing=0 stale=0 +D1=56 D2=19 D3=26 T=67 dispositions=101 missing=0 stale=0 D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 @@ -269,6 +269,7 @@ D2 vm.c:vm_run_ex/CASE(SLICE_GET) guarded slot_as_ptr=1 slo D2 vm.c:vm_slot_value_opaque guarded slot_as_ptr=1 slot_is_ptr=1 D3 container.h:eigs_container_slot not-a-classifier SLOT_SMI_MAX=1 SLOT_SMI_MIN=1 D3 container.h:eigs_slot_adopt guarded slot_is_heap=1 +D3 eigenscript.c:slot_from_value not-a-classifier SLOT_SMI_MAX=1 SLOT_SMI_MIN=1 D3 jit.c:jit_compile_to_thunk/OP_EQ not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 D3 jit.c:jit_compile_to_thunk/OP_NEG not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 D3 jit.c:jit_compile_to_thunk/OP_NULL not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 @@ -1312,104 +1313,113 @@ eigenscript.c:432 ent_child_slot SLOT_F64_RAW RAW i eigenscript.c:432 ent_child_slot slot_is_f64 TEST i eigenscript.c:434 ent_child_slot slot_is_smi TEST i eigenscript.c:434 ent_child_slot slot_smi_val RAW i -eigenscript.c:442 compute_entropy_impl VAL_NUM CASE i -eigenscript.c:442 compute_entropy_impl VAL_NUM_RAW RAW i +eigenscript.c:442 compute_entropy_impl VAL_F64_RAW RAW i +eigenscript.c:442 compute_entropy_impl VAL_FLOAT CASE i eigenscript.c:445 compute_entropy_impl VAL_I64_RAW RAW i eigenscript.c:445 compute_entropy_impl VAL_INT CASE i -eigenscript.c:794 observer_slot_update VAL_NUM TEST i -eigenscript.c:796 observer_slot_update VAL_NUM_RAW RAW i -eigenscript.c:858 observer_slot_sample_gated VAL_NUM TEST i -eigenscript.c:859 observer_slot_sample_gated VAL_NUM_RAW RAW i -eigenscript.c:942 observer_slot_saturated EIGS_NUM_MAX GUARD i -eigenscript.c:1390 observer_entropy_now slot_is_f64 TEST i -eigenscript.c:1392 observer_entropy_now SLOT_F64_RAW RAW i -eigenscript.c:1393 observer_entropy_now slot_is_smi TEST i -eigenscript.c:1395 observer_entropy_now slot_smi_val RAW i -eigenscript.c:1440 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1441 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:798 observer_slot_update VAL_I64_RAW RAW i +eigenscript.c:798 observer_slot_update VAL_INT TEST i +eigenscript.c:799 observer_slot_update VAL_F64_RAW RAW i +eigenscript.c:862 observer_slot_sample_gated VAL_I64_RAW RAW i +eigenscript.c:862 observer_slot_sample_gated VAL_INT TEST i +eigenscript.c:863 observer_slot_sample_gated VAL_F64_RAW RAW i +eigenscript.c:946 observer_slot_saturated EIGS_NUM_MAX GUARD i +eigenscript.c:1394 observer_entropy_now slot_is_f64 TEST i +eigenscript.c:1396 observer_entropy_now SLOT_F64_RAW RAW i +eigenscript.c:1397 observer_entropy_now slot_is_smi TEST i +eigenscript.c:1399 observer_entropy_now slot_smi_val RAW i eigenscript.c:1444 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1445 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1448 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1449 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1450 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1451 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1457 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1489 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1489 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1490 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1490 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1490 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1492 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1506 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1506 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1511 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1512 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1521 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1526 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1539 observer_slot_from_trajectory VAL_NUM TEST i -eigenscript.c:1544 observer_slot_from_trajectory VAL_NUM_RAW RAW i -eigenscript.c:1647 free_value VAL_NUM TEST a -eigenscript.c:1729 free_value VAL_NUM CASE a -eigenscript.c:1730 free_value VAL_INT CASE a -eigenscript.c:1739 make_num make_num PRODUCE c -eigenscript.c:1740 make_num num_guard GUARD c -eigenscript.c:1756 make_num VAL_NUM TAGSET c -eigenscript.c:1757 make_num VAL_NUM_RAW WRITE c -eigenscript.c:1763 recycle_intermediate VAL_NUM TEST a -eigenscript.c:1785 make_num_permanent make_num_permanent PRODUCE c -eigenscript.c:1786 make_num_permanent num_guard GUARD c -eigenscript.c:1788 make_num_permanent VAL_NUM TAGSET c -eigenscript.c:1789 make_num_permanent VAL_NUM_RAW WRITE c -eigenscript.c:1818 eigs_num_arg_slow eigs_num_arg_slow READ b -eigenscript.c:1819 eigs_num_arg_slow VAL_F64_RAW RAW b -eigenscript.c:1819 eigs_num_arg_slow VAL_FLOAT TEST a -eigenscript.c:1823 eigs_num_arg_slow VAL_I64_RAW RAW b -eigenscript.c:1823 eigs_num_arg_slow VAL_INT TEST a -eigenscript.c:1830 eigs_list_num eigs_list_num READ b -eigenscript.c:1837 eigs_list_num eigs_slot_num READ b -eigenscript.c:1840 eigs_elem_num eigs_elem_num READ b -eigenscript.c:1841 eigs_elem_num eigs_slot_elem_num READ b -eigenscript.c:1844 eigs_opt_num eigs_opt_num READ b -eigenscript.c:1845 eigs_opt_num eigs_slot_opt_num READ b -eigenscript.c:1881 slot_from_value VAL_NUM TEST a -eigenscript.c:1885 slot_from_value VAL_NUM_RAW RAW b -eigenscript.c:1887 slot_from_value slot_from_f64 PRODUCE c -eigenscript.c:1906 slot_to_value SLOT_F64_RAW RAW b -eigenscript.c:1906 slot_to_value make_num PRODUCE c -eigenscript.c:1906 slot_to_value slot_is_f64 TEST a -eigenscript.c:1914 slot_to_value slot_is_smi TEST a -eigenscript.c:2413 module_ns_project slot_is_f64 TEST a -eigenscript.c:2413 module_ns_project slot_is_f64 TEST a -eigenscript.c:2418 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2418 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2663 chan_clone_rec VAL_NUM TEST a -eigenscript.c:2666 chan_clone_rec VAL_NUM CASE a -eigenscript.c:2666 chan_clone_rec VAL_NUM_RAW RAW b -eigenscript.c:2666 chan_clone_rec make_num PRODUCE c -eigenscript.c:2669 chan_clone_rec VAL_I64_RAW RAW b -eigenscript.c:2669 chan_clone_rec VAL_INT CASE a -eigenscript.c:2857 is_truthy VAL_NUM CASE a -eigenscript.c:2857 is_truthy VAL_NUM_RAW RAW b -eigenscript.c:2858 is_truthy VAL_I64_RAW RAW b -eigenscript.c:2858 is_truthy VAL_INT CASE a -eigenscript.c:2894 values_equal_impl VAL_NUM TEST f -eigenscript.c:2895 values_equal_impl VAL_NUM TEST f -eigenscript.c:2909 values_equal_impl VAL_NUM CASE f -eigenscript.c:2909 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2909 values_equal_impl VAL_NUM_RAW RAW f -eigenscript.c:2910 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2910 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2910 values_equal_impl VAL_INT CASE f -eigenscript.c:2940 values_equal_impl buffer_read_num READ f -eigenscript.c:2942 values_equal_impl buffer_read_num READ f -eigenscript.c:2983 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:2998 eigs_num_text strtod PARSE e -eigenscript.c:3008 value_to_string VAL_NUM CASE e -eigenscript.c:3009 value_to_string VAL_NUM_RAW RAW e -eigenscript.c:3009 value_to_string eigs_num_text FORMAT e -eigenscript.c:3012 value_to_string VAL_INT CASE e -eigenscript.c:3013 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4235 gc_value_is_node VAL_NUM CASE a -eigenscript.c:4236 gc_value_is_node VAL_INT CASE a +eigenscript.c:1452 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1453 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1454 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1455 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1461 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1494 observer_slot_from_trajectory eigs_num_arg READ i +eigenscript.c:1513 observer_slot_from_trajectory VAL_FLOAT TEST i +eigenscript.c:1513 observer_slot_from_trajectory VAL_FLOAT TEST i +eigenscript.c:1513 observer_slot_from_trajectory VAL_INT TEST i +eigenscript.c:1513 observer_slot_from_trajectory VAL_INT TEST i +eigenscript.c:1518 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1519 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1529 observer_slot_from_trajectory VAL_FLOAT TEST i +eigenscript.c:1529 observer_slot_from_trajectory VAL_INT TEST i +eigenscript.c:1534 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1552 observer_slot_from_trajectory eigs_num_arg READ i +eigenscript.c:1655 free_value VAL_FLOAT TEST a +eigenscript.c:1737 free_value VAL_FLOAT CASE a +eigenscript.c:1738 free_value VAL_INT CASE a +eigenscript.c:1747 make_num make_num PRODUCE c +eigenscript.c:1748 make_num num_guard GUARD c +eigenscript.c:1764 make_num VAL_FLOAT TAGSET c +eigenscript.c:1765 make_num VAL_F64_RAW WRITE c +eigenscript.c:1771 recycle_intermediate VAL_FLOAT TEST a +eigenscript.c:1793 make_num_permanent make_num_permanent PRODUCE c +eigenscript.c:1794 make_num_permanent num_guard GUARD c +eigenscript.c:1796 make_num_permanent VAL_FLOAT TAGSET c +eigenscript.c:1797 make_num_permanent VAL_F64_RAW WRITE c +eigenscript.c:1826 eigs_num_arg_slow eigs_num_arg_slow READ b +eigenscript.c:1827 eigs_num_arg_slow VAL_F64_RAW RAW b +eigenscript.c:1827 eigs_num_arg_slow VAL_FLOAT TEST a +eigenscript.c:1831 eigs_num_arg_slow VAL_I64_RAW RAW b +eigenscript.c:1831 eigs_num_arg_slow VAL_INT TEST a +eigenscript.c:1838 eigs_list_num eigs_list_num READ b +eigenscript.c:1845 eigs_list_num eigs_slot_num READ b +eigenscript.c:1848 eigs_elem_num eigs_elem_num READ b +eigenscript.c:1849 eigs_elem_num eigs_slot_elem_num READ b +eigenscript.c:1852 eigs_opt_num eigs_opt_num READ b +eigenscript.c:1853 eigs_opt_num eigs_slot_opt_num READ b +eigenscript.c:1889 slot_from_value VAL_FLOAT TEST a +eigenscript.c:1893 slot_from_value VAL_F64_RAW RAW b +eigenscript.c:1895 slot_from_value slot_from_f64 PRODUCE c +eigenscript.c:1899 slot_from_value VAL_INT TEST a +eigenscript.c:1900 slot_from_value VAL_I64_RAW RAW b +eigenscript.c:1903 slot_from_value slot_from_int PRODUCE c +eigenscript.c:1924 slot_to_value SLOT_F64_RAW RAW b +eigenscript.c:1924 slot_to_value make_num PRODUCE c +eigenscript.c:1924 slot_to_value slot_is_f64 TEST a +eigenscript.c:1932 slot_to_value slot_is_smi TEST a +eigenscript.c:2431 module_ns_project slot_is_f64 TEST a +eigenscript.c:2431 module_ns_project slot_is_f64 TEST a +eigenscript.c:2436 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2436 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2681 chan_clone_rec VAL_FLOAT TEST a +eigenscript.c:2681 chan_clone_rec VAL_INT TEST a +eigenscript.c:2684 chan_clone_rec VAL_F64_RAW RAW b +eigenscript.c:2684 chan_clone_rec VAL_FLOAT CASE a +eigenscript.c:2684 chan_clone_rec make_num PRODUCE c +eigenscript.c:2687 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:2687 chan_clone_rec VAL_INT CASE a +eigenscript.c:2875 is_truthy VAL_F64_RAW RAW b +eigenscript.c:2875 is_truthy VAL_FLOAT CASE a +eigenscript.c:2876 is_truthy VAL_I64_RAW RAW b +eigenscript.c:2876 is_truthy VAL_INT CASE a +eigenscript.c:2916 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2916 values_equal_impl VAL_INT TEST f +eigenscript.c:2917 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2917 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2918 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2918 values_equal_impl VAL_INT TEST f +eigenscript.c:2919 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2919 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2935 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2935 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2935 values_equal_impl VAL_FLOAT CASE f +eigenscript.c:2936 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2936 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2936 values_equal_impl VAL_INT CASE f +eigenscript.c:2966 values_equal_impl buffer_read_num READ f +eigenscript.c:2968 values_equal_impl buffer_read_num READ f +eigenscript.c:3009 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:3024 eigs_num_text strtod PARSE e +eigenscript.c:3034 value_to_string VAL_FLOAT CASE e +eigenscript.c:3035 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3035 value_to_string eigs_num_text FORMAT e +eigenscript.c:3038 value_to_string VAL_INT CASE e +eigenscript.c:3039 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4261 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4262 gc_value_is_node VAL_INT CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a eigenscript.h:281 VAL_FLOAT DATA a @@ -1418,42 +1428,42 @@ eigenscript.h:290 VAL_FLOAT TAGSET c eigenscript.h:290 VAL_NUM DATA a eigenscript.h:298 #define val_is_number VAL_FLOAT TEST a eigenscript.h:298 #define val_is_number VAL_INT TEST a -eigenscript.h:306 #define VAL_F64_RAW VAL_F64_RAW RAW b -eigenscript.h:306 #define VAL_F64_RAW f64_ RAW b -eigenscript.h:307 #define VAL_I64_RAW VAL_I64_RAW RAW b -eigenscript.h:307 #define VAL_I64_RAW i64_ RAW b -eigenscript.h:308 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b -eigenscript.h:308 #define VAL_F64_OFFSET f64_ RAW b -eigenscript.h:310 #define VAL_NUM_RAW VAL_NUM_RAW RAW b -eigenscript.h:310 #define VAL_NUM_RAW num_ RAW b -eigenscript.h:311 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b -eigenscript.h:311 #define VAL_NUM_OFFSET num_ RAW b -eigenscript.h:1417 eigs_num_arg_slow READ b -eigenscript.h:1418 eigs_num_arg eigs_num_arg READ b -eigenscript.h:1419 eigs_num_arg VAL_F64_RAW RAW b -eigenscript.h:1419 eigs_num_arg VAL_FLOAT TEST a -eigenscript.h:1420 eigs_num_arg eigs_num_arg_slow READ b -eigenscript.h:1422 eigs_list_num READ b -eigenscript.h:1427 eigs_elem_num READ b -eigenscript.h:1428 eigs_opt_num READ b -eigenscript.h:1799 make_num PRODUCE c -eigenscript.h:1809 make_num_permanent PRODUCE c -eigenscript.h:1861 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1903 num_guard num_guard GUARD c -eigenscript.h:1911 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1911 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1912 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1912 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1921 buffer_read_num buffer_read_num READ b -eigenscript.h:1922 buffer_read_num num_guard GUARD c -eigenscript.h:1928 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1937 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1946 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1947 buffer_read_byte buffer_read_num READ b -eigenscript.h:1949 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1960 num_guard_named num_guard_named GUARD c -eigenscript.h:1966 num_guard_named num_guard GUARD c -eigenscript.h:2278 eigs_num_text FORMAT e +eigenscript.h:319 #define VAL_F64_RAW VAL_F64_RAW RAW b +eigenscript.h:319 #define VAL_F64_RAW f64_ RAW b +eigenscript.h:320 #define VAL_I64_RAW VAL_I64_RAW RAW b +eigenscript.h:320 #define VAL_I64_RAW i64_ RAW b +eigenscript.h:321 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b +eigenscript.h:321 #define VAL_F64_OFFSET f64_ RAW b +eigenscript.h:323 #define VAL_NUM_RAW VAL_NUM_RAW RAW b +eigenscript.h:323 #define VAL_NUM_RAW num_ RAW b +eigenscript.h:324 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b +eigenscript.h:324 #define VAL_NUM_OFFSET num_ RAW b +eigenscript.h:1430 eigs_num_arg_slow READ b +eigenscript.h:1431 eigs_num_arg eigs_num_arg READ b +eigenscript.h:1432 eigs_num_arg VAL_F64_RAW RAW b +eigenscript.h:1432 eigs_num_arg VAL_FLOAT TEST a +eigenscript.h:1433 eigs_num_arg eigs_num_arg_slow READ b +eigenscript.h:1435 eigs_list_num READ b +eigenscript.h:1440 eigs_elem_num READ b +eigenscript.h:1441 eigs_opt_num READ b +eigenscript.h:1812 make_num PRODUCE c +eigenscript.h:1822 make_num_permanent PRODUCE c +eigenscript.h:1874 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1916 num_guard num_guard GUARD c +eigenscript.h:1924 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1924 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1925 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1925 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1934 buffer_read_num buffer_read_num READ b +eigenscript.h:1935 buffer_read_num num_guard GUARD c +eigenscript.h:1941 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1950 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1959 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1960 buffer_read_byte buffer_read_num READ b +eigenscript.h:1962 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1973 num_guard_named num_guard_named GUARD c +eigenscript.h:1979 num_guard_named num_guard GUARD c +eigenscript.h:2291 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_NUM CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index fee241d84..5ccaaa279 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -694,6 +694,7 @@ result).** | `eigenscript.c:gc_collect_at_exit` | guarded | skips every non-pointer slot (D2) | | `eigenscript.c:module_ns_project` | guarded | an int skips the float-over-float rewrite: `slot_to_value` boxes it and the dict store re-canonicalizes it (D1) | | `eigenscript.c:observer_entropy_now` | smi-arm | an int is the numeric kind, as its double (D1) | +| `eigenscript.c:slot_from_value` | not-a-classifier | the adopting Value-to-slot writer (R1.2): it reads a Value, not a slot, and writes the bits; a `VAL_INT` box becomes an SMI inside [-2^47, 2^47) (its box released) and stays a heap slot outside it (2.1) (D3) | | `eigenscript.c:slot_to_value` | unwired | the one SMI boxer: a fresh int Value needs `make_int` (R1.3). Any other unknown tag now refuses; it used to read back as null (D1) | | `ext_store.c:store_json_encode_slot` | smi-arm | an int is written as its exact digits (design 7) (D1) | | `jit.c:jit_compile_to_thunk/OP_EQ` | not-a-classifier | writes the bool result bits (D3) | diff --git a/src/eigenscript.c b/src/eigenscript.c index 82c70483e..eebfc545a 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -439,7 +439,7 @@ static double compute_entropy_impl(Value *v) { if (!v) return 0.0; switch (v->type) { case VAL_NULL: return 0.0; - case VAL_NUM: return entropy_of_num(VAL_NUM_RAW(v)); + case VAL_FLOAT: return entropy_of_num(VAL_F64_RAW(v)); /* #1758 R1.2a (design 7): an int's entropy is its double's; it joins * the numeric channel when ints exist (R1.3). */ case VAL_INT: return entropy_of_num((double)VAL_I64_RAW(v)); @@ -791,9 +791,12 @@ void observer_slot_update(Env *e, int idx, Value *newval) { observer_slot_update_e(e, idx, compute_entropy(newval)); /* #294 also fold the raw value into the value-signal channel (numbers only: * the relative-delta step is only defined for a scalar trajectory). */ - if (newval && newval->type == VAL_NUM) { + /* #1758 (design 7): a boxed int joins the numeric channel as its double + * until round 3. */ + if (newval && val_is_number(newval)) { ObserverSlot *s = env_obs_slot(e, idx); - if (s) observer_slot_record_value(s, VAL_NUM_RAW(newval)); + if (s) observer_slot_record_value(s, newval->type == VAL_INT ? (double)VAL_I64_RAW(newval) + : VAL_F64_RAW(newval)); } else { /* #861: a non-numeric assignment ends the numeric trajectory's claim * on this binding — predicates fall back to the entropy channel until @@ -855,8 +858,9 @@ void observer_slot_sample_num_gated(Env *e, int idx, double num) { } void observer_slot_sample_gated(Env *e, int idx, Value *newval) { - if (newval && newval->type == VAL_NUM) { - observer_slot_sample_num_gated(e, idx, VAL_NUM_RAW(newval)); + if (newval && val_is_number(newval)) { /* #1758: an int box as its double */ + observer_slot_sample_num_gated(e, idx, newval->type == VAL_INT ? (double)VAL_I64_RAW(newval) + : VAL_F64_RAW(newval)); return; } if (!e || idx < 0) return; @@ -1486,10 +1490,12 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { EIGS_VIEW(w_view); Value *w = dict_get_view_local(dict, "window", &w_view); if (w) { - if (w->type != VAL_NUM || VAL_NUM_RAW(w) < OBSERVER_WINDOW_MIN || - VAL_NUM_RAW(w) > OBSERVER_WINDOW_MAX || VAL_NUM_RAW(w) != (int)VAL_NUM_RAW(w)) + /* #1758: a number of either kind, read through the bridge */ + double wd = val_is_number(w) ? eigs_num_arg(w, __func__) : 0.0; + if (!val_is_number(w) || wd < OBSERVER_WINDOW_MIN || + wd > OBSERVER_WINDOW_MAX || wd != (int)wd) return 0; - out->win_override = (uint8_t)(int)VAL_NUM_RAW(w); + out->win_override = (uint8_t)(int)wd; } } const int N = observer_slot_window(out); @@ -1503,7 +1509,8 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { out->v_cap = out->dh_cap = (uint8_t)N; for (int i = vstart; i < vcnt; i++) { EigsSlot a = list_slot(rel, i), b = list_slot(raw, i); - if (slot_type(a) != VAL_NUM || slot_type(b) != VAL_NUM) { + ValType ta = slot_type(a), tb = slot_type(b); /* #1758: either number kind */ + if ((ta != VAL_FLOAT && ta != VAL_INT) || (tb != VAL_FLOAT && tb != VAL_INT)) { free(out->v_window); free(out->vr_window); memset(out, 0, sizeof *out); return 0; @@ -1518,7 +1525,8 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { out->dh_window = xcalloc((size_t)N, sizeof(double)); for (int i = dstart; i < dcnt; i++) { EigsSlot a = list_slot(dh, i); - if (slot_type(a) != VAL_NUM) { + ValType ta = slot_type(a); + if (ta != VAL_FLOAT && ta != VAL_INT) { free(out->v_window); free(out->vr_window); free(out->dh_window); memset(out, 0, sizeof *out); return 0; @@ -1536,12 +1544,12 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { EIGS_VIEW(v_view); Value *v = dict_get_view_local(dict, nums[k], &v_view); if (!v) continue; - if (v->type != VAL_NUM) { + if (!val_is_number(v)) { free(out->v_window); free(out->vr_window); free(out->dh_window); memset(out, 0, sizeof *out); return 0; } - *dsts[k] = VAL_NUM_RAW(v); + *dsts[k] = eigs_num_arg(v, __func__); /* #1758: an int converts (the bridge) */ } EIGS_VIEW(fo_view); EIGS_VIEW(fn_view); Value *fo = dict_get_view_local(dict, "observed", &fo_view); @@ -1644,7 +1652,7 @@ void env_retain_intern_table(Env *env, EnvInternTable *table) { void free_value(Value *v) { if (!v) return; env_intern_release_value(v); - if (v->type == VAL_NUM) { + if (v->type == VAL_FLOAT) { /* the freelist recycles float boxes; an int box is freed */ #ifndef EIGS_POOL_OFF_NUM /* Route freed NUMs to freelist for reuse by make_num */ if (g_num_freelist_count < NUM_FREELIST_CAP) { @@ -1726,7 +1734,7 @@ void free_value(Value *v) { /* No owned memory. Enumerated rather than covered by a `default:` so * that -Werror=switch (Makefile CFLAGS) makes a new ValType a build * error here instead of a silent leak. */ - case VAL_NUM: + case VAL_FLOAT: case VAL_INT: /* #1758 R1.2a: an int box owns nothing */ case VAL_BUILTIN: case VAL_NULL: @@ -1753,14 +1761,14 @@ Value* make_num(double n) { { v = xcalloc(1, sizeof(Value)); } - v->type = VAL_NUM; - VAL_NUM_RAW(v) = n; + v->type = VAL_FLOAT; + VAL_F64_RAW(v) = n; v->refcount = 1; return v; } void recycle_intermediate(Value *v) { - if (!v || v->type != VAL_NUM || v->refcount > 1) return; + if (!v || v->type != VAL_FLOAT || v->refcount > 1) return; #ifdef EIGS_POOL_OFF_NUM /* #1665: no freelist — a discarded intermediate NUM is freed outright * (the pooled path already free()s it when the cap is hit, so callers @@ -1785,8 +1793,8 @@ void recycle_intermediate(Value *v) { Value* make_num_permanent(double n) { n = num_guard(n); Value *v = xcalloc(1, sizeof(Value)); - v->type = VAL_NUM; - VAL_NUM_RAW(v) = n; + v->type = VAL_FLOAT; + VAL_F64_RAW(v) = n; v->refcount = 1; return v; } @@ -1878,14 +1886,24 @@ EigsSlot slot_from_value(Value *v) { if (v && v != &g_null_singleton) val_decref(v); return slot_null(); } - if (v->type == VAL_NUM) { + if (v->type == VAL_FLOAT) { /* #262 Step E: a number never carries observer state (it lives on the - * Env slot), so every VAL_NUM ships as an immediate double. TAG_TRACKED + * Env slot), so every VAL_FLOAT ships as an immediate double. TAG_TRACKED * is dead. */ - double n = VAL_NUM_RAW(v); + double n = VAL_F64_RAW(v); val_decref(v); return slot_from_f64(n); } + /* #1758 (design 2.1): a small int is stored as its SMI and its box is + * released; an int outside [-2^47, 2^47) keeps its box (a heap slot). */ + if (v->type == VAL_INT) { + int64_t i = VAL_I64_RAW(v); + if (i >= SLOT_SMI_MIN && i <= SLOT_SMI_MAX) { + val_decref(v); + return slot_from_int(i); + } + return slot_from_heap(v); + } if (v->type == VAL_BOOL) return slot_from_bool(v->data.boolean); /* singleton: borrowed */ return slot_from_heap(v); } @@ -2660,10 +2678,10 @@ static Value *chan_clone_rec(Value *v, int depth) { * behavior) rather than overflow the stack. */ /* #1665: scalars are copied at any depth: a number may be a stack view, * which must never be shared out of its frame. */ - if (depth > CHAN_CLONE_MAX_DEPTH && v->type != VAL_NUM && v->type != VAL_NULL && + if (depth > CHAN_CLONE_MAX_DEPTH && v->type != VAL_FLOAT && v->type != VAL_INT && v->type != VAL_NULL && v->type != VAL_BOOL && v->type != VAL_STR) { val_incref(v); return v; } switch (v->type) { - case VAL_NUM: return make_num(VAL_NUM_RAW(v)); + case VAL_FLOAT: return make_num(VAL_F64_RAW(v)); /* #1758 R1.2a: a channel gets a fresh int box, which needs make_int * (R1.3); no int exists before then. */ case VAL_INT: eigs_int_unwired("chan_clone_rec", (uint64_t)VAL_I64_RAW(v)); @@ -2854,7 +2872,7 @@ int is_truthy(Value *v) { if (!v) return 0; switch (v->type) { case VAL_NULL: return 0; - case VAL_NUM: return VAL_NUM_RAW(v) != 0.0; + case VAL_FLOAT: return VAL_F64_RAW(v) != 0.0; case VAL_INT: return VAL_I64_RAW(v) != 0; /* #1758 R1.2a */ case VAL_STR: return v->data.str && v->data.str[0] != '\0'; case VAL_LIST: return v->data.list.count > 0; @@ -2874,7 +2892,8 @@ int is_truthy(Value *v) { * recursively by structure (lists element-wise, dicts by key/value * order-independently, buffers/text-builders by contents). Functions, * builtins, and raw-JSON compare by identity. Mixed types are never equal - * (no coercion — consistent with the comparison operators). The depth + * (no coercion — consistent with the comparison operators), except an int + * and a float, which are one type, `num`, and compare by value (#1758 N2). The depth * guard prevents runaway recursion on self-referential containers; beyond * it we fall back to identity. */ /* #1637 item 6: a bool met by a number — at any depth of the two values — @@ -2891,8 +2910,15 @@ static int values_equal_impl(Value *a, Value *b, int depth, const char *op) { if (a == b && (!a || a->type != VAL_BUFFER)) return 1; if (!a || !b) return 0; if (a->type != b->type) { - if ((a->type == VAL_BOOL && b->type == VAL_NUM) || - (a->type == VAL_NUM && b->type == VAL_BOOL)) { + /* #1758 N2 (design 7): an int and a float are both numbers and are + * equal exactly when their values are; no conversion rounds either + * side. Dead until R1.3, when the first int Value exists. */ + if (a->type == VAL_INT && b->type == VAL_FLOAT) + return eigs_cmp_int_float(VAL_I64_RAW(a), VAL_F64_RAW(b)) == 0; + if (a->type == VAL_FLOAT && b->type == VAL_INT) + return eigs_cmp_int_float(VAL_I64_RAW(b), VAL_F64_RAW(a)) == 0; + if ((a->type == VAL_BOOL && val_is_number(b)) || + (val_is_number(a) && b->type == VAL_BOOL)) { if (op[0] == '=' || op[0] == '!') rt_error(EK_TYPE, 0, "cannot compare %s and %s with '%s'", val_type_name(a->type), val_type_name(b->type), op); @@ -2906,7 +2932,7 @@ static int values_equal_impl(Value *a, Value *b, int depth, const char *op) { * (a number may be a view, so pointer identity is meaningless). */ if (depth > 64 && (a->type == VAL_LIST || a->type == VAL_DICT)) return a == b; switch (a->type) { - case VAL_NUM: return VAL_NUM_RAW(a) == VAL_NUM_RAW(b); + case VAL_FLOAT: return VAL_F64_RAW(a) == VAL_F64_RAW(b); case VAL_INT: return VAL_I64_RAW(a) == VAL_I64_RAW(b); /* #1758 R1.2a: both ints */ case VAL_STR: return strcmp(a->data.str, b->data.str) == 0; case VAL_NULL: return 1; @@ -3005,8 +3031,8 @@ char* value_to_string(Value *v) { char buf[256]; switch (v->type) { case VAL_NULL: return xstrdup("null"); - case VAL_NUM: { - eigs_num_text(buf, sizeof(buf), VAL_NUM_RAW(v)); + case VAL_FLOAT: { + eigs_num_text(buf, sizeof(buf), VAL_F64_RAW(v)); return xstrdup(buf); } case VAL_INT: { /* #1758 R1.2a: an int prints its exact digits */ @@ -4232,7 +4258,7 @@ static int gc_value_is_node(Value *v) { case VAL_FN: return 1; /* Leaves: no owned edges out, so no rows and never a cycle member. */ - case VAL_NUM: + case VAL_FLOAT: case VAL_INT: case VAL_STR: case VAL_NULL: diff --git a/src/eigenscript.h b/src/eigenscript.h index c2a34e57e..8666a608b 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -296,6 +296,19 @@ typedef Value* (*BuiltinFn)(Value* arg); * test uses when an int belongs on the same path as a float (a builtin's * number test admits an int and reads it through the bridge, design 2.7). */ #define val_is_number(v) ((v)->type == VAL_FLOAT || (v)->type == VAL_INT) +/* #1758 N2 (design 7): an int and a float compare exactly, by value. Returns + * -1, 0 or 1 for i < f, i == f, i > f, and 2 when f is NaN (unordered: every + * comparison is false except !=). Lua's LTintfloat/EQintfloat give the same + * answers. Pure; no int Value exists before R1.3. */ +static inline int eigs_cmp_int_float(int64_t i, double f) { + if (f != f) return 2; + if (f >= 9223372036854775808.0) return -1; /* f above every int64 */ + if (f < -9223372036854775808.0) return 1; /* f below every int64 */ + double fl = floor(f); /* in [-2^63, 2^63): the cast is exact */ + int64_t il = (int64_t)fl; + if (i != il) return i < il ? -1 : 1; + return f != fl ? -1 : 0; /* i == floor(f) < f when f has a fraction */ +} /* #1637 round 4: the ONE raw way into a Value's number (an lvalue: also the * write). Only for a Value whose type is proven (VAL_FLOAT for the double, diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 57caf0674..e79957ce2 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -31,12 +31,11 @@ eigenscript.c|make_num|1|constructor: writes the number of a Value it just typed eigenscript.c|make_num_permanent|1|constructor: writes the number of a Value it just typed VAL_NUM eigenscript.c|module_ns_project|1|mirror refresh: reads the binding slot after slot_is_f64 and stores it over a numeric mirror slot eigenscript.c|observer_entropy_now|1|observer entropy of a slot after slot_is_f64 -eigenscript.c|observer_slot_from_trajectory|6|trajectory snapshot fields each read right after its own type != VAL_NUM refusal -eigenscript.c|observer_slot_sample_gated|1|observer sample after newval->type == VAL_NUM -eigenscript.c|observer_slot_update|1|observer update after newval->type == VAL_NUM -eigenscript.c|slot_from_value|1|NaN-boxing boundary, inside its VAL_NUM branch +eigenscript.c|observer_slot_sample_gated|2|observer sample inside val_is_number: the VAL_INT box as its double, else the VAL_FLOAT (design 7) +eigenscript.c|observer_slot_update|2|observer update inside val_is_number: the VAL_INT box as its double, else the VAL_FLOAT (design 7) +eigenscript.c|slot_from_value|2|NaN-boxing boundary, inside its VAL_FLOAT branch and its VAL_INT branch (an SMI in range, design 2.1) eigenscript.c|slot_to_value|1|NaN-boxing boundary after slot_is_f64 -eigenscript.c|values_equal_impl|4|equality, switch case VAL_NUM after the bool/num pair raised, and case VAL_INT (both ints) +eigenscript.c|values_equal_impl|8|equality: the int/float pair by eigs_cmp_int_float (N2), each read inside its own type test; switch case VAL_FLOAT and case VAL_INT (both ints) eigenscript.c|value_to_string|2|printing, switch case VAL_NUM and case VAL_INT (exact digits) eigenscript.h|#define VAL_NUM_OFFSET|1|the raw member offset definition (JIT) eigenscript.h|#define VAL_F64_OFFSET|1|the raw double member offset definition (JIT; #1758 R1.2a: was VAL_NUM_OFFSET) From 40ef2d8455477dc0f96553cfca720ce3b9727bd5 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 05:48:37 -0500 Subject: [PATCH 025/188] phase2 R1.2d: migrate the core builtin Value number sites (#1758) Migrate 85 deprecated code-token sites (78 matching lines). Number guards admit VAL_INT through the unchanged double bridge. Exact int JSON text and sort keys are ready; dispatch argument boxing refuses until R1.3. Validation: make built; inventory examined=1822 classified=1822 unclassified=0, dispositions missing=0 stale=0; num-read examined=206 functions=80 allowlisted=80 violations=0 stale=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- .../internal/1758-phase2-value-builtins.md | 1 + docs/design/phase2-inventory.txt | 602 ++++++++---------- src/builtins.c | 205 +++--- tools/num_read_allowlist.txt | 5 + 4 files changed, 395 insertions(+), 418 deletions(-) create mode 100644 changes/internal/1758-phase2-value-builtins.md diff --git a/changes/internal/1758-phase2-value-builtins.md b/changes/internal/1758-phase2-value-builtins.md new file mode 100644 index 000000000..02c899951 --- /dev/null +++ b/changes/internal/1758-phase2-value-builtins.md @@ -0,0 +1 @@ +Prepare builtin number guards for both Value kinds while retaining the double bridge; preserve exact integer text and numeric sort keys for the future int producer. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 376cdcf5b..4e27c9756 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,41 +1,41 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1878 classified=1878 unclassified=0 +examined=1822 classified=1822 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 414 CASE=60 DATA=5 TEST=347 YIELD=2 -(b) payload reads 545 RAW=130 READ=415 +(a) type tests 349 CASE=60 DATA=5 TEST=282 YIELD=2 +(b) payload reads 554 RAW=137 READ=417 (c) producers 472 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 -(e) number formatting 18 CASE=2 FORMAT=3 PARSE=1 RAW=3 READ=3 TEST=6 -(f) equality, ordering and hashing 39 CASE=2 PRODUCE=4 RAW=11 READ=9 TEST=13 +(e) number formatting 15 CASE=2 FORMAT=3 PARSE=1 RAW=3 READ=3 TEST=3 +(f) equality, ordering and hashing 42 CASE=2 PRODUCE=4 RAW=12 READ=9 TEST=15 (g) tape encode and decode 25 CASE=4 DATA=2 PARSE=7 PRODUCE=5 RAW=5 TEST=2 -(h) JSON, store and db encoders 76 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=3 READ=24 TEST=18 -(i) observer numeric paths 97 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=25 +(h) JSON, store and db encoders 78 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=5 READ=24 TEST=18 +(i) observer numeric paths 95 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=23 (j) embed API 65 CASE=2 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 ## Per token make_num 364 -VAL_NUM 294 -eigs_num_arg 147 +VAL_NUM 209 +eigs_num_arg 151 eigs_list_num 130 SLOT_F64_RAW 83 VAL_NUM_RAW 70 num_guard 60 AST_NUM 52 -eigs_slot_num 52 +eigs_slot_num 50 slot_is_f64 50 eigs_value_as_num 48 +VAL_INT 42 slot_from_f64 41 +VAL_FLOAT 38 buffer_read_num 38 slot_is_smi 37 -VAL_INT 32 -VAL_FLOAT 31 +VAL_I64_RAW 29 buffer_read_byte 22 list_set_num 22 VAL_F64_RAW 19 -VAL_I64_RAW 19 slot_smi_val 17 slot_f64_value 16 strtod 16 @@ -71,8 +71,8 @@ slot_int_value 1 data.num (AST) 7 ## Per file (category counts) -builtins.c 323 a=76 b=94 c=111 e=6 f=8 h=17 i=11 vm.c 299 a=78 b=97 c=68 e=2 f=9 i=45 +builtins.c 267 a=11 b=103 c=111 e=3 f=11 h=19 i=9 ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 184 a=39 b=59 c=86 eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 @@ -299,14 +299,14 @@ registered=311 numeric=230 classified=230 unclassified=0 stale=0 classes: float-producing=57 int-preserving=37 int-requiring=85 other=51 LOSS (42): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_execute db_query_json db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed Q7: geometry=9 bounded=13 magnitude=13 -abs builtin_abs int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num -acos builtin_acos float-producing - - VAL_NUM,eigs_num_arg,make_num +abs builtin_abs int-preserving LOSS - eigs_num_arg,make_num +acos builtin_acos float-producing - - eigs_num_arg,make_num add builtin_tensor_add int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard -append builtin_append other - - VAL_NUM -asin builtin_asin float-producing - - VAL_NUM,eigs_num_arg,make_num +append builtin_append other - - VAL_FLOAT +asin builtin_asin float-producing - - eigs_num_arg,make_num assert builtin_assert other - - eigs_num_text -atan builtin_atan float-producing - - VAL_NUM,eigs_num_arg,make_num -atan2 builtin_atan2 float-producing - - VAL_NUM,eigs_num_arg,make_num +atan builtin_atan float-producing - - eigs_num_arg,make_num +atan2 builtin_atan2 float-producing - - eigs_num_arg,make_num audio_capture_open builtin_audio_capture_open int-requiring - - VAL_NUM,eigs_list_num,make_num audio_envelope builtin_audio_envelope float-producing - magnitude VAL_NUM,eigs_list_num,eigs_slot_num,make_num audio_gain builtin_audio_gain float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num @@ -328,12 +328,12 @@ audio_stream_push builtin_audio_stream_push other audio_stream_queued builtin_audio_stream_queued int-preserving - - make_num audio_sweep builtin_audio_sweep float-producing - magnitude VAL_NUM,eigs_list_num,make_num audio_volume builtin_audio_volume int-requiring - bounded VAL_NUM,eigs_slot_num,make_num -bit_and builtin_bit_and int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_not builtin_bit_not int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_or builtin_bit_or int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_shl builtin_bit_shift_left int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_shr builtin_bit_shift_right int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact -bit_xor builtin_bit_xor int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,num_to_i64_exact +bit_and builtin_bit_and int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact +bit_not builtin_bit_not int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact +bit_or builtin_bit_or int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact +bit_shl builtin_bit_shift_left int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact +bit_shr builtin_bit_shift_right int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact +bit_xor builtin_bit_xor int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact buf_copy builtin_buf_copy int-requiring - - VAL_NUM,eigs_slot_num buf_deinterleave builtin_buf_deinterleave int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num buf_dot builtin_buf_dot float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,make_num,num_guard @@ -350,33 +350,33 @@ buf_set builtin_buf_set int-requiring buf_to_pcm16le builtin_buf_to_pcm16le other - bounded VAL_NUM,buffer_read_num,eigs_slot_num,num_guard buffer builtin_buffer int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg build_corpus builtin_build_corpus int-requiring - - VAL_NUM,eigs_num_arg,eigs_opt_num,make_num,num_val -ceil builtin_ceil int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +ceil builtin_ceil int-preserving LOSS - eigs_num_arg,make_num channel builtin_channel int-preserving - - make_num -channel_closed builtin_channel_closed int-requiring - - VAL_NUM,eigs_num_arg -char_at builtin_char_at int-requiring - - VAL_NUM,eigs_num_arg -chr builtin_chr int-requiring - - VAL_NUM,eigs_num_arg +channel_closed builtin_channel_closed int-requiring - - eigs_num_arg +char_at builtin_char_at int-requiring - - eigs_num_arg +chr builtin_chr int-requiring - - eigs_num_arg clock_unix builtin_clock_unix float-producing - - make_num -close_channel builtin_close_channel int-requiring - - VAL_NUM,eigs_num_arg -copy_into builtin_copy_into int-requiring - - VAL_NUM,eigs_num_arg -cos builtin_cos float-producing - - VAL_NUM,eigs_num_arg,make_num +close_channel builtin_close_channel int-requiring - - eigs_num_arg +copy_into builtin_copy_into int-requiring - - eigs_num_arg +cos builtin_cos float-producing - - eigs_num_arg,make_num db_execute builtin_db_execute other LOSS - VAL_NUM,eigs_num_arg db_query_json builtin_db_query_json other LOSS - VAL_NUM,eigs_num_arg db_query_value builtin_db_query_value other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod -dispatch builtin_dispatch int-requiring - - VAL_NUM,eigs_num_arg,make_num +dispatch builtin_dispatch int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num divide builtin_tensor_divide float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard dot builtin_dot float-producing - - buffer_read_num,make_num,num_guard eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num eigen_generate builtin_eigen_generate int-requiring - - eigs_slot_num,eigs_slot_opt_num,make_num eigen_model_load builtin_eigen_model_load other - - strtod exec_capture builtin_exec_capture other - magnitude VAL_NUM,eigs_list_num,list_append_num -exit builtin_exit int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg +exit builtin_exit int-requiring - - eigs_list_num,eigs_num_arg exp builtin_tensor_exp float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard f64_from_bytes builtin_f64_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named f64_to_bytes builtin_f64_to_bytes other - - VAL_NUM,eigs_num_arg,make_num fill builtin_fill int-requiring - - eigs_list_num -floor builtin_floor int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +floor builtin_floor int-preserving LOSS - eigs_num_arg,make_num gather builtin_tensor_gather int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num -get_at builtin_get_at int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num +get_at builtin_get_at int-requiring - - buffer_read_num,eigs_num_arg,make_num get_observer_thresholds builtin_get_observer_thresholds float-producing - - make_num gfx_circle builtin_gfx_circle other - geometry,bounded VAL_NUM,eigs_list_num gfx_clear builtin_gfx_clear other - bounded VAL_NUM,eigs_list_num @@ -394,7 +394,7 @@ gfx_text builtin_gfx_text other gfx_text_height builtin_gfx_text_height int-preserving - magnitude VAL_NUM,eigs_list_num,eigs_num_arg,make_num gfx_text_width builtin_gfx_text_width int-preserving - magnitude VAL_NUM,eigs_list_num,make_num gfx_ticks builtin_gfx_ticks int-preserving - - make_num -hex builtin_hex int-requiring LOSS - VAL_NUM,eigs_list_num,eigs_num_arg +hex builtin_hex int-requiring LOSS - eigs_list_num,eigs_num_arg http_early_bind builtin_http_early_bind int-requiring - - VAL_NUM,eigs_opt_num http_post builtin_http_post other - - eigs_num_text http_route builtin_http_route other - - eigs_num_text @@ -404,33 +404,33 @@ http_static builtin_http_static other index_of builtin_index_of int-preserving - - make_num inflate builtin_inflate int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num join builtin_join other - - eigs_num_text -json_build builtin_json_build other LOSS - VAL_NUM,eigs_num_arg,eigs_num_text +json_build builtin_json_build other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text json_decode builtin_json_decode other LOSS - make_num,strtod -json_encode builtin_json_encode other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_num_text -json_path builtin_json_path other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_num_text,make_num,strtod +json_encode builtin_json_encode other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text +json_path builtin_json_path other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text,make_num,strtod leaky_relu builtin_tensor_leaky_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num len builtin_len int-preserving - - make_num list_contains builtin_list_contains other - - values_equal list_index_of builtin_list_index_of int-preserving - - make_num,values_equal -list_insert_at builtin_list_insert_at int-requiring - - VAL_NUM,eigs_num_arg -list_remove_at builtin_list_remove_at int-requiring - - VAL_NUM,eigs_num_arg -list_slice builtin_list_slice int-requiring - - VAL_NUM,eigs_num_arg -list_truncate builtin_list_truncate int-requiring - - VAL_NUM,eigs_num_arg +list_insert_at builtin_list_insert_at int-requiring - - eigs_num_arg +list_remove_at builtin_list_remove_at int-requiring - - eigs_num_arg +list_slice builtin_list_slice int-requiring - - eigs_num_arg +list_truncate builtin_list_truncate int-requiring - - eigs_num_arg log builtin_tensor_log float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard log_softmax builtin_tensor_log_softmax float-producing - - VAL_NUM,eigs_slot_num,make_num matmul builtin_tensor_matmul float-producing - - SLOT_F64_RAW,VAL_NUM,eigs_slot_num,make_num,num_guard_named matmul_at builtin_tensor_matmul_at float-producing - - VAL_NUM,eigs_slot_num,make_num matmul_bt builtin_tensor_matmul_bt float-producing - - VAL_NUM,eigs_slot_num,make_num -max builtin_max int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +max builtin_max int-preserving LOSS - eigs_num_arg,make_num mean builtin_tensor_mean float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard -min builtin_min int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +min builtin_min int-preserving LOSS - eigs_num_arg,make_num model_load_weights builtin_eigen_model_load other - - strtod monotonic_ms builtin_monotonic_ms float-producing - - make_num monotonic_ns builtin_monotonic_ns int-preserving LOSS - make_num multiply builtin_tensor_multiply int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard native_train_step_builtin builtin_native_train_step int-requiring - - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod -nearest_in_range builtin_nearest_in_range float-producing - - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num -nearest_in_range_all builtin_nearest_in_range_all float-producing - - VAL_NUM,eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num +nearest_in_range builtin_nearest_in_range float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num +nearest_in_range_all builtin_nearest_in_range_all float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num negative builtin_tensor_negative int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num net_accept builtin_net_accept int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num,make_num net_close builtin_net_close int-requiring - - VAL_NUM,eigs_num_arg @@ -440,8 +440,8 @@ net_port builtin_net_port int-requiring net_recv builtin_net_recv int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num net_send builtin_net_send int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num norm builtin_tensor_norm float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard -num builtin_num other LOSS - VAL_NUM,make_num,num_guard_named,strtod -num_copy builtin_num_copy int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +num builtin_num other LOSS - make_num,num_guard_named,strtod +num_copy builtin_num_copy int-preserving LOSS - eigs_num_arg,make_num numerical_grad builtin_numerical_grad float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num numerical_grad_cols builtin_numerical_grad_cols float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num numerical_grad_rows builtin_numerical_grad_rows float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num @@ -454,24 +454,24 @@ print builtin_print other proc_read_buf builtin_proc_read_buf int-requiring - - VAL_NUM,eigs_num_arg random builtin_random float-producing - - make_num random_hex builtin_random_hex int-requiring - - VAL_NUM,eigs_num_arg -random_int builtin_random_int int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num +random_int builtin_random_int int-requiring LOSS - eigs_num_arg,make_num random_normal builtin_random_normal float-producing - - eigs_list_num,make_num -range builtin_range int-preserving - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num +range builtin_range int-preserving - - eigs_list_num,eigs_num_arg,make_num read_bytes builtin_read_bytes int-preserving - - make_num read_bytes_buf builtin_read_bytes_buf int-requiring - - VAL_NUM,eigs_num_arg,make_num -record_history builtin_record_history other - - VAL_NUM,eigs_num_arg,make_num -recv builtin_recv int-requiring - - VAL_NUM,eigs_num_arg -recv_timeout builtin_recv_timeout int-requiring - magnitude VAL_NUM,eigs_num_arg +record_history builtin_record_history other - - eigs_num_arg,make_num +recv builtin_recv int-requiring - - eigs_num_arg +recv_timeout builtin_recv_timeout int-requiring - magnitude eigs_num_arg relu builtin_tensor_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num reshape builtin_reshape int-requiring - - VAL_NUM,eigs_list_num -round builtin_round int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num -sandbox_run builtin_sandbox_run int-requiring - - VAL_INT,VAL_NUM,eigs_list_num,eigs_num_arg,make_num +round builtin_round int-preserving LOSS - eigs_num_arg,make_num +sandbox_run builtin_sandbox_run int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num scan_int_tokens builtin_scan_int_tokens int-preserving LOSS - make_num scan_ints builtin_scan_ints int-preserving LOSS - make_num scatter_add builtin_tensor_scatter_add float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard -seed_random builtin_seed_random int-requiring LOSS - VAL_NUM,eigs_num_arg -send builtin_send int-requiring - - VAL_NUM,eigs_num_arg -set_at builtin_set_at int-requiring - - VAL_NUM,eigs_num_arg +seed_random builtin_seed_random int-requiring LOSS - eigs_num_arg +send builtin_send int-requiring - - eigs_num_arg +set_at builtin_set_at int-requiring - - eigs_num_arg sgd_update builtin_sgd_update float-producing - - VAL_NUM,eigs_slot_num,eigs_slot_opt_num,list_set_num sgd_update_cols builtin_sgd_update_cols float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num sgd_update_rows builtin_sgd_update_rows float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num @@ -479,14 +479,14 @@ shape builtin_tensor_shape int-preserving shared_delete builtin_shared_delete int-preserving - - make_num shared_incr builtin_shared_incr int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num shared_size builtin_shared_size int-preserving - - make_num -sign_extend builtin_sign_extend int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num -sin builtin_sin float-producing - - VAL_NUM,eigs_num_arg,make_num +sign_extend builtin_sign_extend int-requiring LOSS - eigs_num_arg,make_num +sin builtin_sin float-producing - - eigs_num_arg,make_num softmax builtin_tensor_softmax float-producing - - VAL_NUM,eigs_slot_num,make_num -sort builtin_sort other LOSS - VAL_NUM,eigs_slot_num -sort_by builtin_sort_by other LOSS - VAL_NUM,eigs_num_arg +sort builtin_sort other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg +sort_by builtin_sort_by other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg spawn builtin_spawn int-preserving - - make_num sqrt builtin_tensor_sqrt float-producing - - VAL_NUM,eigs_num_arg,make_num -state_at builtin_state_at int-requiring - - VAL_NUM,eigs_num_arg +state_at builtin_state_at int-requiring - - eigs_num_arg store_close builtin_store_close int-requiring - - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val store_collections builtin_store_collections int-requiring - - VAL_NUM,eigs_num_arg store_count builtin_store_count int-requiring - - VAL_NUM,eigs_num_arg,make_num @@ -501,47 +501,43 @@ str builtin_str other str_from_bytes builtin_str_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte stream_open builtin_stream_open int-requiring - - VAL_NUM,eigs_num_arg stream_write builtin_stream_write float-producing - - VAL_NUM,eigs_num_arg -substr builtin_substr int-requiring - - VAL_NUM,eigs_num_arg +substr builtin_substr int-requiring - - eigs_num_arg subtract builtin_tensor_subtract int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard sum builtin_tensor_sum int-preserving LOSS - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard -tan builtin_tan float-producing - - VAL_NUM,eigs_num_arg,make_num -task_alive builtin_task_alive int-requiring - - VAL_NUM,eigs_num_arg -task_detach builtin_task_detach int-requiring - - VAL_NUM,eigs_num_arg,make_num -task_join builtin_task_join int-requiring - - VAL_NUM,eigs_num_arg -task_kill builtin_task_kill int-requiring - - VAL_NUM,eigs_num_arg -task_sched_seed builtin_task_sched_seed int-requiring LOSS - VAL_NUM,eigs_num_arg +tan builtin_tan float-producing - - eigs_num_arg,make_num +task_alive builtin_task_alive int-requiring - - eigs_num_arg +task_detach builtin_task_detach int-requiring - - eigs_num_arg,make_num +task_join builtin_task_join int-requiring - - eigs_num_arg +task_kill builtin_task_kill int-requiring - - eigs_num_arg +task_sched_seed builtin_task_sched_seed int-requiring LOSS - eigs_num_arg task_self builtin_task_self int-preserving - - make_num -task_send builtin_task_send int-requiring - - VAL_NUM,eigs_num_arg -task_sleep builtin_task_sleep other - - VAL_NUM,eigs_num_arg +task_send builtin_task_send int-requiring - - eigs_num_arg +task_sleep builtin_task_sleep other - - eigs_num_arg task_spawn builtin_task_spawn int-preserving - - make_num tensor_load builtin_tensor_load float-producing - - VAL_NUM,eigs_list_num,make_num,num_guard_named tensor_save builtin_tensor_save float-producing - - VAL_NUM,eigs_slot_num text_builder_append builtin_text_builder_append other - - eigs_num_text text_builder_append_line builtin_text_builder_append_line other - - eigs_num_text -thread_join builtin_thread_join int-requiring - - VAL_NUM,eigs_num_arg +thread_join builtin_thread_join int-requiring - - eigs_num_arg throw builtin_throw other - - eigs_num_text -token_name builtin_token_name int-requiring - - VAL_NUM,eigs_num_arg -try_recv builtin_try_recv int-requiring - - VAL_NUM,eigs_num_arg -type builtin_type other - - VAL_INT,VAL_NUM -usleep builtin_usleep other - magnitude VAL_NUM,eigs_num_arg -vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_INT,VAL_NUM,eigs_num_arg +token_name builtin_token_name int-requiring - - eigs_num_arg +try_recv builtin_try_recv int-requiring - - eigs_num_arg +type builtin_type other - - VAL_FLOAT,VAL_INT +usleep builtin_usleep other - magnitude eigs_num_arg +vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg write builtin_write other - - eigs_num_text write_bytes builtin_write_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num zeros builtin_tensor_zeros int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num zeros_like builtin_tensor_zeros_like float-producing - - VAL_NUM,make_num ## Sites (file:line scope token kind category) -builtins.c:164 builtin_usleep VAL_NUM TEST a builtins.c:165 builtin_usleep eigs_num_arg READ b builtins.c:350 bit_int num_to_i64_exact READ b -builtins.c:361 bit_pair VAL_NUM TEST a -builtins.c:361 bit_pair VAL_NUM TEST a builtins.c:362 bit_pair eigs_num_arg READ b builtins.c:363 bit_pair eigs_num_arg READ b builtins.c:372 builtin_bit_and make_num PRODUCE c builtins.c:380 builtin_bit_or make_num PRODUCE c builtins.c:388 builtin_bit_xor make_num PRODUCE c -builtins.c:392 builtin_bit_not VAL_NUM TEST a builtins.c:394 builtin_bit_not eigs_num_arg READ b builtins.c:395 builtin_bit_not make_num PRODUCE c builtins.c:403 builtin_bit_shift_left make_num PRODUCE c @@ -556,7 +552,6 @@ builtins.c:454 builtin_len make_num PRODUCE c builtins.c:456 builtin_len make_num PRODUCE c builtins.c:466 builtin_len make_num PRODUCE c builtins.c:495 builtin_num make_num PRODUCE c -builtins.c:496 builtin_num VAL_NUM TEST a builtins.c:503 builtin_num make_num PRODUCE c builtins.c:522 builtin_num make_num PRODUCE c builtins.c:530 builtin_num make_num PRODUCE c @@ -565,20 +560,18 @@ builtins.c:535 builtin_num num_guard_named GUARD c builtins.c:535 builtin_num strtod PARSE c builtins.c:537 builtin_num make_num PRODUCE c builtins.c:538 builtin_num make_num PRODUCE c -builtins.c:557 builtin_append VAL_NUM YIELD a +builtins.c:557 builtin_append VAL_FLOAT YIELD a builtins.c:591 builtin_get_observer_thresholds make_num PRODUCE i builtins.c:592 builtin_get_observer_thresholds make_num PRODUCE i builtins.c:593 builtin_get_observer_thresholds make_num PRODUCE i -builtins.c:643 builtin_exit VAL_NUM TEST a builtins.c:644 builtin_exit eigs_num_arg READ b -builtins.c:647 builtin_exit VAL_NUM TEST a builtins.c:648 builtin_exit eigs_list_num READ b builtins.c:783 builtin_observe make_num PRODUCE i builtins.c:784 builtin_observe make_num PRODUCE i builtins.c:785 builtin_observe make_num PRODUCE i -builtins.c:867 builtin_type VAL_NUM CASE a +builtins.c:867 builtin_type VAL_FLOAT CASE a builtins.c:868 builtin_type VAL_INT CASE a -builtins.c:916 eigs_json_encode_value VAL_NUM CASE h +builtins.c:916 eigs_json_encode_value VAL_FLOAT CASE h builtins.c:923 eigs_json_encode_value eigs_num_arg READ h builtins.c:923 eigs_json_encode_value eigs_num_text FORMAT h builtins.c:927 eigs_json_encode_value VAL_INT CASE h @@ -589,271 +582,222 @@ builtins.c:1309 eigs_json_parse_number make_num PRODUCE h builtins.c:1314 eigs_json_parse_number strtod PARSE h builtins.c:1324 eigs_json_parse_number strtod PARSE h builtins.c:1328 eigs_json_parse_number make_num PRODUCE h -builtins.c:1499 builtin_json_build VAL_NUM TEST h -builtins.c:1501 builtin_json_build eigs_num_arg READ h -builtins.c:1501 builtin_json_build eigs_num_text FORMAT h -builtins.c:1687 builtin_scan_ints make_num PRODUCE c -builtins.c:1801 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1501 builtin_json_build VAL_I64_RAW RAW h +builtins.c:1501 builtin_json_build VAL_INT TEST h +builtins.c:1502 builtin_json_build eigs_num_arg READ h +builtins.c:1502 builtin_json_build eigs_num_text FORMAT h +builtins.c:1688 builtin_scan_ints make_num PRODUCE c builtins.c:1802 builtin_scan_int_tokens make_num PRODUCE c builtins.c:1803 builtin_scan_int_tokens make_num PRODUCE c builtins.c:1804 builtin_scan_int_tokens make_num PRODUCE c builtins.c:1805 builtin_scan_int_tokens make_num PRODUCE c builtins.c:1806 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1909 builtin_char_at VAL_NUM TEST a -builtins.c:1911 builtin_char_at eigs_num_arg READ b -builtins.c:1945 builtin_substr VAL_NUM TEST a -builtins.c:1946 builtin_substr VAL_NUM TEST a -builtins.c:1948 builtin_substr eigs_num_arg READ b +builtins.c:1807 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1912 builtin_char_at eigs_num_arg READ b builtins.c:1949 builtin_substr eigs_num_arg READ b -builtins.c:1979 builtin_index_of make_num PRODUCE c -builtins.c:1986 builtin_index_of make_num PRODUCE c -builtins.c:1991 builtin_index_of make_num PRODUCE c +builtins.c:1950 builtin_substr eigs_num_arg READ b +builtins.c:1980 builtin_index_of make_num PRODUCE c +builtins.c:1987 builtin_index_of make_num PRODUCE c builtins.c:1992 builtin_index_of make_num PRODUCE c -builtins.c:2000 builtin_sin VAL_NUM TEST a -builtins.c:2000 builtin_sin make_num PRODUCE c -builtins.c:2001 builtin_sin eigs_num_arg READ b +builtins.c:1993 builtin_index_of make_num PRODUCE c builtins.c:2001 builtin_sin make_num PRODUCE c -builtins.c:2005 builtin_cos VAL_NUM TEST a -builtins.c:2005 builtin_cos make_num PRODUCE c -builtins.c:2006 builtin_cos eigs_num_arg READ b +builtins.c:2002 builtin_sin eigs_num_arg READ b +builtins.c:2002 builtin_sin make_num PRODUCE c builtins.c:2006 builtin_cos make_num PRODUCE c -builtins.c:2010 builtin_tan VAL_NUM TEST a -builtins.c:2010 builtin_tan make_num PRODUCE c -builtins.c:2011 builtin_tan eigs_num_arg READ b +builtins.c:2007 builtin_cos eigs_num_arg READ b +builtins.c:2007 builtin_cos make_num PRODUCE c builtins.c:2011 builtin_tan make_num PRODUCE c -builtins.c:2015 builtin_asin VAL_NUM TEST a -builtins.c:2015 builtin_asin make_num PRODUCE c -builtins.c:2016 builtin_asin eigs_num_arg READ b -builtins.c:2021 builtin_asin make_num PRODUCE c -builtins.c:2025 builtin_asin make_num PRODUCE c -builtins.c:2029 builtin_acos VAL_NUM TEST a -builtins.c:2029 builtin_acos make_num PRODUCE c -builtins.c:2030 builtin_acos eigs_num_arg READ b -builtins.c:2035 builtin_acos make_num PRODUCE c -builtins.c:2039 builtin_acos make_num PRODUCE c -builtins.c:2043 builtin_atan VAL_NUM TEST a -builtins.c:2043 builtin_atan make_num PRODUCE c -builtins.c:2044 builtin_atan eigs_num_arg READ b +builtins.c:2012 builtin_tan eigs_num_arg READ b +builtins.c:2012 builtin_tan make_num PRODUCE c +builtins.c:2016 builtin_asin make_num PRODUCE c +builtins.c:2017 builtin_asin eigs_num_arg READ b +builtins.c:2022 builtin_asin make_num PRODUCE c +builtins.c:2026 builtin_asin make_num PRODUCE c +builtins.c:2030 builtin_acos make_num PRODUCE c +builtins.c:2031 builtin_acos eigs_num_arg READ b +builtins.c:2036 builtin_acos make_num PRODUCE c +builtins.c:2040 builtin_acos make_num PRODUCE c builtins.c:2044 builtin_atan make_num PRODUCE c -builtins.c:2049 builtin_atan2 make_num PRODUCE c -builtins.c:2052 builtin_atan2 VAL_NUM TEST a -builtins.c:2052 builtin_atan2 VAL_NUM TEST a -builtins.c:2052 builtin_atan2 make_num PRODUCE c -builtins.c:2053 builtin_atan2 eigs_num_arg READ b -builtins.c:2053 builtin_atan2 eigs_num_arg READ b +builtins.c:2045 builtin_atan eigs_num_arg READ b +builtins.c:2045 builtin_atan make_num PRODUCE c +builtins.c:2050 builtin_atan2 make_num PRODUCE c builtins.c:2053 builtin_atan2 make_num PRODUCE c -builtins.c:2057 builtin_floor VAL_NUM TEST a -builtins.c:2057 builtin_floor make_num PRODUCE c -builtins.c:2058 builtin_floor eigs_num_arg READ b +builtins.c:2054 builtin_atan2 eigs_num_arg READ b +builtins.c:2054 builtin_atan2 eigs_num_arg READ b +builtins.c:2054 builtin_atan2 make_num PRODUCE c builtins.c:2058 builtin_floor make_num PRODUCE c -builtins.c:2062 builtin_ceil VAL_NUM TEST a -builtins.c:2062 builtin_ceil make_num PRODUCE c -builtins.c:2063 builtin_ceil eigs_num_arg READ b +builtins.c:2059 builtin_floor eigs_num_arg READ b +builtins.c:2059 builtin_floor make_num PRODUCE c builtins.c:2063 builtin_ceil make_num PRODUCE c -builtins.c:2067 builtin_round VAL_NUM TEST a -builtins.c:2067 builtin_round make_num PRODUCE c -builtins.c:2068 builtin_round eigs_num_arg READ b +builtins.c:2064 builtin_ceil eigs_num_arg READ b +builtins.c:2064 builtin_ceil make_num PRODUCE c builtins.c:2068 builtin_round make_num PRODUCE c -builtins.c:2072 builtin_abs VAL_NUM TEST a -builtins.c:2072 builtin_abs make_num PRODUCE c -builtins.c:2073 builtin_abs eigs_num_arg READ b +builtins.c:2069 builtin_round eigs_num_arg READ b +builtins.c:2069 builtin_round make_num PRODUCE c builtins.c:2073 builtin_abs make_num PRODUCE c -builtins.c:2082 minmax_reduce VAL_NUM TEST a -builtins.c:2082 minmax_reduce eigs_num_arg READ b -builtins.c:2082 minmax_reduce make_num PRODUCE c -builtins.c:2087 minmax_reduce make_num PRODUCE c -builtins.c:2090 minmax_reduce make_num PRODUCE c -builtins.c:2094 minmax_reduce VAL_NUM TEST a -builtins.c:2094 minmax_reduce make_num PRODUCE c -builtins.c:2095 minmax_reduce eigs_num_arg READ b -builtins.c:2095 minmax_reduce eigs_num_arg READ b +builtins.c:2074 builtin_abs eigs_num_arg READ b +builtins.c:2074 builtin_abs make_num PRODUCE c +builtins.c:2083 minmax_reduce eigs_num_arg READ b +builtins.c:2083 minmax_reduce make_num PRODUCE c +builtins.c:2088 minmax_reduce make_num PRODUCE c +builtins.c:2091 minmax_reduce make_num PRODUCE c +builtins.c:2095 minmax_reduce make_num PRODUCE c builtins.c:2096 minmax_reduce eigs_num_arg READ b -builtins.c:2098 minmax_reduce make_num PRODUCE c -builtins.c:2107 builtin_pi make_num PRODUCE c -builtins.c:2163 builtin_random make_num PRODUCE c -builtins.c:2172 builtin_random_int make_num PRODUCE c -builtins.c:2175 builtin_random_int VAL_NUM TEST a -builtins.c:2175 builtin_random_int VAL_NUM TEST a -builtins.c:2176 builtin_random_int make_num PRODUCE c -builtins.c:2180 builtin_random_int eigs_num_arg READ b +builtins.c:2096 minmax_reduce eigs_num_arg READ b +builtins.c:2097 minmax_reduce eigs_num_arg READ b +builtins.c:2099 minmax_reduce make_num PRODUCE c +builtins.c:2108 builtin_pi make_num PRODUCE c +builtins.c:2164 builtin_random make_num PRODUCE c +builtins.c:2173 builtin_random_int make_num PRODUCE c +builtins.c:2177 builtin_random_int make_num PRODUCE c builtins.c:2181 builtin_random_int eigs_num_arg READ b -builtins.c:2191 builtin_random_int make_num PRODUCE c -builtins.c:2203 builtin_random_int make_num PRODUCE c -builtins.c:2208 builtin_seed_random VAL_NUM TEST a -builtins.c:2210 builtin_seed_random eigs_num_arg READ b -builtins.c:2438 builtin_json_path VAL_NUM TEST h -builtins.c:2440 builtin_json_path eigs_num_arg READ h -builtins.c:2440 builtin_json_path eigs_num_text FORMAT h -builtins.c:2544 builtin_token_name VAL_NUM TEST a -builtins.c:2545 builtin_token_name eigs_num_arg READ b -builtins.c:2581 builtin_state_at VAL_NUM TEST i -builtins.c:2582 builtin_state_at eigs_num_arg READ i -builtins.c:2628 builtin_chr VAL_NUM TEST a -builtins.c:2632 builtin_chr eigs_num_arg READ b -builtins.c:2656 builtin_hex VAL_NUM TEST e -builtins.c:2657 builtin_hex eigs_num_arg READ e -builtins.c:2659 builtin_hex VAL_NUM TEST e -builtins.c:2660 builtin_hex VAL_NUM TEST e -builtins.c:2661 builtin_hex eigs_list_num READ e -builtins.c:2662 builtin_hex eigs_list_num READ e -builtins.c:2689 builtin_ord make_num PRODUCE c -builtins.c:2692 builtin_ord make_num PRODUCE c -builtins.c:2693 builtin_ord make_num PRODUCE c -builtins.c:2810 vm_desc_abi_error VAL_NUM TEST a -builtins.c:2818 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2823 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2919 desc_isolate_const VAL_NUM CASE a -builtins.c:2920 desc_isolate_const VAL_INT CASE a -builtins.c:3038 vm_build_chunk_desc_body VAL_NUM TEST a -builtins.c:3043 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3099 vm_build_chunk_desc_body VAL_NUM TEST a -builtins.c:3100 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3417 builtin_sandbox_run VAL_NUM TEST a -builtins.c:3418 builtin_sandbox_run eigs_list_num READ b -builtins.c:3424 builtin_sandbox_run VAL_NUM TEST a -builtins.c:3425 builtin_sandbox_run eigs_list_num READ b -builtins.c:3426 builtin_sandbox_run eigs_list_num READ b -builtins.c:3433 builtin_sandbox_run VAL_NUM TEST a -builtins.c:3434 builtin_sandbox_run eigs_list_num READ b -builtins.c:3476 builtin_sandbox_run make_num PRODUCE c -builtins.c:3657 builtin_sandbox_run make_num PRODUCE c -builtins.c:3669 builtin_sandbox_run make_num PRODUCE c -builtins.c:3683 builtin_sandbox_run make_num PRODUCE c -builtins.c:3717 builtin_sandbox_run make_num PRODUCE c -builtins.c:3743 builtin_record_history VAL_NUM TEST i -builtins.c:3749 builtin_record_history eigs_num_arg READ i -builtins.c:3754 builtin_record_history make_num PRODUCE i -builtins.c:3782 builtin_copy_into VAL_NUM TEST a -builtins.c:3787 builtin_copy_into eigs_num_arg READ b -builtins.c:3799 builtin_copy_into VAL_NUM TEST a -builtins.c:3804 builtin_copy_into eigs_num_arg READ b -builtins.c:3837 builtin_list_slice VAL_NUM TEST a -builtins.c:3837 builtin_list_slice VAL_NUM TEST a -builtins.c:3840 builtin_list_slice eigs_num_arg READ b -builtins.c:3841 builtin_list_slice eigs_num_arg READ b -builtins.c:3863 builtin_num_copy VAL_NUM TEST a -builtins.c:3864 builtin_num_copy eigs_num_arg READ b -builtins.c:3864 builtin_num_copy make_num PRODUCE c -builtins.c:3908 builtin_range VAL_NUM TEST a -builtins.c:3910 builtin_range eigs_num_arg READ b -builtins.c:3917 builtin_range VAL_NUM TEST a -builtins.c:3925 builtin_range eigs_list_num READ b -builtins.c:3928 builtin_range eigs_list_num READ b -builtins.c:3932 builtin_range eigs_list_num READ b -builtins.c:3976 builtin_range make_num PRODUCE c -builtins.c:3992 builtin_fill eigs_list_num READ b -builtins.c:4014 at_index VAL_NUM TEST a -builtins.c:4018 at_index eigs_num_arg READ b -builtins.c:4022 at_index eigs_num_arg READ b -builtins.c:4033 buf_at_index VAL_NUM TEST a -builtins.c:4038 buf_at_index eigs_num_arg READ b -builtins.c:4042 buf_at_index eigs_num_arg READ b -builtins.c:4083 builtin_set_at VAL_NUM TEST a -builtins.c:4088 builtin_set_at eigs_num_arg READ b -builtins.c:4149 builtin_get_at buffer_read_num READ b -builtins.c:4149 builtin_get_at make_num PRODUCE c -builtins.c:4157 builtin_get_at buffer_read_num READ b -builtins.c:4157 builtin_get_at make_num PRODUCE c -builtins.c:4519 builtin_spawn make_num PRODUCE c -builtins.c:4525 builtin_spawn make_num PRODUCE c -builtins.c:4526 builtin_spawn make_num PRODUCE c -builtins.c:4551 builtin_thread_join VAL_NUM TEST a -builtins.c:4555 builtin_thread_join eigs_num_arg READ b -builtins.c:4556 builtin_thread_join VAL_NUM TEST a -builtins.c:4556 builtin_thread_join eigs_num_arg READ b -builtins.c:4636 get_channel_why VAL_NUM TEST a -builtins.c:4637 get_channel_why eigs_num_arg READ b -builtins.c:4639 get_channel_why VAL_NUM TEST a +builtins.c:2182 builtin_random_int eigs_num_arg READ b +builtins.c:2192 builtin_random_int make_num PRODUCE c +builtins.c:2204 builtin_random_int make_num PRODUCE c +builtins.c:2211 builtin_seed_random eigs_num_arg READ b +builtins.c:2441 builtin_json_path VAL_I64_RAW RAW h +builtins.c:2441 builtin_json_path VAL_INT TEST h +builtins.c:2442 builtin_json_path eigs_num_arg READ h +builtins.c:2442 builtin_json_path eigs_num_text FORMAT h +builtins.c:2547 builtin_token_name eigs_num_arg READ b +builtins.c:2584 builtin_state_at eigs_num_arg READ i +builtins.c:2634 builtin_chr eigs_num_arg READ b +builtins.c:2659 builtin_hex eigs_num_arg READ e +builtins.c:2663 builtin_hex eigs_list_num READ e +builtins.c:2664 builtin_hex eigs_list_num READ e +builtins.c:2691 builtin_ord make_num PRODUCE c +builtins.c:2694 builtin_ord make_num PRODUCE c +builtins.c:2695 builtin_ord make_num PRODUCE c +builtins.c:2820 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2825 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2921 desc_isolate_const VAL_FLOAT CASE a +builtins.c:2922 desc_isolate_const VAL_INT CASE a +builtins.c:3045 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3102 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3420 builtin_sandbox_run eigs_list_num READ b +builtins.c:3427 builtin_sandbox_run eigs_list_num READ b +builtins.c:3428 builtin_sandbox_run eigs_list_num READ b +builtins.c:3436 builtin_sandbox_run eigs_list_num READ b +builtins.c:3478 builtin_sandbox_run make_num PRODUCE c +builtins.c:3659 builtin_sandbox_run make_num PRODUCE c +builtins.c:3671 builtin_sandbox_run make_num PRODUCE c +builtins.c:3685 builtin_sandbox_run make_num PRODUCE c +builtins.c:3719 builtin_sandbox_run make_num PRODUCE c +builtins.c:3751 builtin_record_history eigs_num_arg READ i +builtins.c:3756 builtin_record_history make_num PRODUCE i +builtins.c:3789 builtin_copy_into eigs_num_arg READ b +builtins.c:3806 builtin_copy_into eigs_num_arg READ b +builtins.c:3842 builtin_list_slice eigs_num_arg READ b +builtins.c:3843 builtin_list_slice eigs_num_arg READ b +builtins.c:3866 builtin_num_copy eigs_num_arg READ b +builtins.c:3866 builtin_num_copy make_num PRODUCE c +builtins.c:3912 builtin_range eigs_num_arg READ b +builtins.c:3927 builtin_range eigs_list_num READ b +builtins.c:3930 builtin_range eigs_list_num READ b +builtins.c:3934 builtin_range eigs_list_num READ b +builtins.c:3978 builtin_range make_num PRODUCE c +builtins.c:3994 builtin_fill eigs_list_num READ b +builtins.c:4020 at_index eigs_num_arg READ b +builtins.c:4024 at_index eigs_num_arg READ b +builtins.c:4040 buf_at_index eigs_num_arg READ b +builtins.c:4044 buf_at_index eigs_num_arg READ b +builtins.c:4090 builtin_set_at eigs_num_arg READ b +builtins.c:4151 builtin_get_at buffer_read_num READ b +builtins.c:4151 builtin_get_at make_num PRODUCE c +builtins.c:4159 builtin_get_at buffer_read_num READ b +builtins.c:4159 builtin_get_at make_num PRODUCE c +builtins.c:4521 builtin_spawn make_num PRODUCE c +builtins.c:4527 builtin_spawn make_num PRODUCE c +builtins.c:4528 builtin_spawn make_num PRODUCE c +builtins.c:4557 builtin_thread_join eigs_num_arg READ b +builtins.c:4558 builtin_thread_join eigs_num_arg READ b builtins.c:4639 get_channel_why eigs_num_arg READ b -builtins.c:4704 builtin_channel make_num PRODUCE c -builtins.c:4705 builtin_channel make_num PRODUCE c -builtins.c:4807 builtin_recv_timeout VAL_NUM TEST a -builtins.c:4811 builtin_recv_timeout eigs_num_arg READ b -builtins.c:4993 builtin_task_spawn make_num PRODUCE c -builtins.c:5003 task_handle_resolve VAL_NUM TEST a -builtins.c:5004 task_handle_resolve eigs_num_arg READ b -builtins.c:5055 builtin_task_join VAL_NUM TEST a -builtins.c:5097 builtin_task_send VAL_NUM TEST a -builtins.c:5105 builtin_task_send eigs_num_arg READ b -builtins.c:5128 builtin_task_kill VAL_NUM TEST a -builtins.c:5140 builtin_task_alive VAL_NUM TEST a -builtins.c:5162 builtin_task_sleep VAL_NUM TEST a -builtins.c:5168 builtin_task_sleep eigs_num_arg READ b -builtins.c:5200 builtin_task_self make_num PRODUCE c -builtins.c:5212 builtin_task_detach VAL_NUM TEST a -builtins.c:5217 builtin_task_detach make_num PRODUCE c -builtins.c:5218 builtin_task_detach make_num PRODUCE c -builtins.c:5229 builtin_task_sched_seed VAL_NUM TEST a -builtins.c:5233 builtin_task_sched_seed eigs_num_arg READ b -builtins.c:5382 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5383 builtin_nearest_in_range eigs_list_num READ b +builtins.c:4641 get_channel_why eigs_num_arg READ b +builtins.c:4706 builtin_channel make_num PRODUCE c +builtins.c:4707 builtin_channel make_num PRODUCE c +builtins.c:4813 builtin_recv_timeout eigs_num_arg READ b +builtins.c:4995 builtin_task_spawn make_num PRODUCE c +builtins.c:5006 task_handle_resolve eigs_num_arg READ b +builtins.c:5107 builtin_task_send eigs_num_arg READ b +builtins.c:5170 builtin_task_sleep eigs_num_arg READ b +builtins.c:5202 builtin_task_self make_num PRODUCE c +builtins.c:5219 builtin_task_detach make_num PRODUCE c +builtins.c:5220 builtin_task_detach make_num PRODUCE c +builtins.c:5235 builtin_task_sched_seed eigs_num_arg READ b builtins.c:5384 builtin_nearest_in_range eigs_list_num READ b builtins.c:5385 builtin_nearest_in_range eigs_list_num READ b builtins.c:5386 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5442 builtin_nearest_in_range VAL_NUM TEST a -builtins.c:5442 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5466 builtin_nearest_in_range eigs_num_arg_slow READ b -builtins.c:5469 builtin_nearest_in_range VAL_NUM TEST a -builtins.c:5469 builtin_nearest_in_range VAL_NUM TEST a -builtins.c:5471 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5472 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5486 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5487 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5387 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5388 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5444 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5468 builtin_nearest_in_range eigs_num_arg_slow READ b +builtins.c:5473 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5474 builtin_nearest_in_range eigs_num_arg READ b builtins.c:5488 builtin_nearest_in_range make_num PRODUCE c builtins.c:5489 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5514 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5515 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5490 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5491 builtin_nearest_in_range make_num PRODUCE c builtins.c:5516 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5571 builtin_nearest_in_range_all VAL_NUM TEST a -builtins.c:5571 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5591 builtin_nearest_in_range_all eigs_num_arg_slow READ b -builtins.c:5594 builtin_nearest_in_range_all VAL_NUM TEST a -builtins.c:5594 builtin_nearest_in_range_all VAL_NUM TEST a -builtins.c:5598 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5599 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5640 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5641 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5517 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5518 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5573 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5593 builtin_nearest_in_range_all eigs_num_arg_slow READ b +builtins.c:5600 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5601 builtin_nearest_in_range_all eigs_num_arg READ b builtins.c:5642 builtin_nearest_in_range_all make_num PRODUCE c builtins.c:5643 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5666 builtin_sign_extend make_num PRODUCE c -builtins.c:5676 builtin_sign_extend VAL_NUM TEST a -builtins.c:5676 builtin_sign_extend VAL_NUM TEST a -builtins.c:5676 builtin_sign_extend make_num PRODUCE c -builtins.c:5677 builtin_sign_extend eigs_num_arg READ b -builtins.c:5678 builtin_sign_extend eigs_num_arg READ b -builtins.c:5679 builtin_sign_extend make_num PRODUCE c -builtins.c:5682 builtin_sign_extend make_num PRODUCE c -builtins.c:5683 builtin_sign_extend make_num PRODUCE c -builtins.c:5700 builtin_list_truncate VAL_NUM TEST a -builtins.c:5704 builtin_list_truncate eigs_num_arg READ b -builtins.c:5730 builtin_list_remove_at VAL_NUM TEST a -builtins.c:5731 builtin_list_remove_at eigs_num_arg READ b -builtins.c:5752 builtin_list_insert_at VAL_NUM TEST a -builtins.c:5753 builtin_list_insert_at eigs_num_arg READ b -builtins.c:5780 builtin_list_index_of make_num PRODUCE f -builtins.c:5784 builtin_list_index_of make_num PRODUCE f -builtins.c:5790 builtin_list_index_of make_num PRODUCE f -builtins.c:5794 builtin_list_index_of make_num PRODUCE f -builtins.c:5857 builtin_sort_by VAL_NUM TEST f -builtins.c:5866 builtin_sort_by eigs_num_arg READ f -builtins.c:5885 sort_cmp_num eigs_slot_num READ b -builtins.c:5886 sort_cmp_num eigs_slot_num READ b -builtins.c:5904 builtin_sort VAL_NUM TEST f -builtins.c:5911 builtin_sort VAL_NUM TEST f -builtins.c:5932 builtin_dispatch VAL_NUM TEST a -builtins.c:5936 builtin_dispatch eigs_num_arg READ b -builtins.c:5937 builtin_dispatch eigs_num_arg READ b -builtins.c:5939 builtin_dispatch eigs_num_arg READ b -builtins.c:5962 builtin_dispatch VAL_NUM TEST a -builtins.c:5963 builtin_dispatch eigs_num_arg READ b -builtins.c:5963 builtin_dispatch make_num PRODUCE c -builtins.c:6039 builtin_dot make_num PRODUCE c -builtins.c:6042 builtin_dot make_num PRODUCE c -builtins.c:6047 builtin_dot buffer_read_num READ b -builtins.c:6049 builtin_dot buffer_read_num READ b -builtins.c:6051 builtin_dot num_guard GUARD c -builtins.c:6051 builtin_dot num_guard GUARD c -builtins.c:6053 builtin_dot make_num PRODUCE c +builtins.c:5644 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5645 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5668 builtin_sign_extend make_num PRODUCE c +builtins.c:5678 builtin_sign_extend make_num PRODUCE c +builtins.c:5679 builtin_sign_extend eigs_num_arg READ b +builtins.c:5680 builtin_sign_extend eigs_num_arg READ b +builtins.c:5681 builtin_sign_extend make_num PRODUCE c +builtins.c:5684 builtin_sign_extend make_num PRODUCE c +builtins.c:5685 builtin_sign_extend make_num PRODUCE c +builtins.c:5706 builtin_list_truncate eigs_num_arg READ b +builtins.c:5733 builtin_list_remove_at eigs_num_arg READ b +builtins.c:5755 builtin_list_insert_at eigs_num_arg READ b +builtins.c:5782 builtin_list_index_of make_num PRODUCE f +builtins.c:5786 builtin_list_index_of make_num PRODUCE f +builtins.c:5792 builtin_list_index_of make_num PRODUCE f +builtins.c:5796 builtin_list_index_of make_num PRODUCE f +builtins.c:5876 builtin_sort_by VAL_INT TEST f +builtins.c:5877 builtin_sort_by VAL_I64_RAW RAW f +builtins.c:5878 builtin_sort_by eigs_num_arg READ f +builtins.c:5900 sort_cmp_num VAL_INT TEST a +builtins.c:5900 sort_cmp_num VAL_INT TEST a +builtins.c:5901 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5901 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5901 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5901 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5902 sort_cmp_num VAL_INT TEST a +builtins.c:5903 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5903 sort_cmp_num eigs_num_arg READ b +builtins.c:5906 sort_cmp_num VAL_INT TEST a +builtins.c:5907 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5907 sort_cmp_num eigs_num_arg READ b +builtins.c:5910 sort_cmp_num eigs_num_arg READ b +builtins.c:5910 sort_cmp_num eigs_num_arg READ b +builtins.c:5928 builtin_sort VAL_FLOAT TEST f +builtins.c:5928 builtin_sort VAL_INT TEST f +builtins.c:5936 builtin_sort VAL_FLOAT TEST f +builtins.c:5936 builtin_sort VAL_INT TEST f +builtins.c:5961 builtin_dispatch eigs_num_arg READ b +builtins.c:5962 builtin_dispatch eigs_num_arg READ b +builtins.c:5964 builtin_dispatch eigs_num_arg READ b +builtins.c:5987 builtin_dispatch VAL_INT TEST a +builtins.c:5988 builtin_dispatch VAL_I64_RAW RAW b +builtins.c:5989 builtin_dispatch VAL_FLOAT TEST a +builtins.c:5990 builtin_dispatch eigs_num_arg READ b +builtins.c:5990 builtin_dispatch make_num PRODUCE c +builtins.c:6066 builtin_dot make_num PRODUCE c +builtins.c:6069 builtin_dot make_num PRODUCE c +builtins.c:6074 builtin_dot buffer_read_num READ b +builtins.c:6076 builtin_dot buffer_read_num READ b +builtins.c:6078 builtin_dot num_guard GUARD c +builtins.c:6078 builtin_dot num_guard GUARD c +builtins.c:6080 builtin_dot make_num PRODUCE c builtins_buf.c:35 builtin_buffer VAL_NUM TEST a builtins_buf.c:36 builtin_buffer VAL_NUM TEST a builtins_buf.c:37 builtin_buffer eigs_list_num READ b diff --git a/src/builtins.c b/src/builtins.c index bbaeac8fd..d79136b2b 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -161,7 +161,7 @@ Value* builtin_flush(Value *arg) { /* usleep of microseconds — pause execution */ Value* builtin_usleep(Value *arg) { BOOL_REFUSE(arg, "usleep"); - if (!arg || arg->type != VAL_NUM) return make_null(); + if (!arg || !val_is_number(arg)) return make_null(); int us = (int)eigs_num_arg(arg, __func__); if (us > 0) { struct timespec deadline; @@ -358,7 +358,7 @@ static int bit_pair(Value *arg, int64_t *a_out, int64_t *b_out, const char *name if (!arg || arg->type != VAL_LIST || arg->data.list.count < 2) return 0; Value *va = BUILTIN_LIST_VIEW(arg, 0); Value *vb = BUILTIN_LIST_VIEW(arg, 1); - if (!va || va->type != VAL_NUM || !vb || vb->type != VAL_NUM) return 0; + if (!va || !val_is_number(va) || !vb || !val_is_number(vb)) return 0; if (!bit_int(eigs_num_arg(va, __func__), a_out, name) || !bit_int(eigs_num_arg(vb, __func__), b_out, name)) return -1; return 1; @@ -389,7 +389,7 @@ Value* builtin_bit_xor(Value *arg) { } Value* builtin_bit_not(Value *arg) { - if (!arg || arg->type != VAL_NUM) { rt_error(EK_TYPE, 0, "bit_not expects a number"); return make_null(); } + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "bit_not expects a number"); return make_null(); } int64_t a; if (!bit_int(eigs_num_arg(arg, __func__), &a, "bit_not")) return make_null(); return make_num((double)(~a)); @@ -493,7 +493,7 @@ Value* builtin_str(Value *arg) { * of scope here and belongs in its own issue if wanted. */ Value* builtin_num(Value *arg) { if (!arg) return make_num(0); /* fs:ANSWER coercion contract, see above */ - if (arg->type == VAL_NUM) return arg; + if (val_is_number(arg)) return arg; /* #1637: a bool is not a number, and the coercion contract's 0 for a * non-string would make `num of true` answer 0 -- a silent wrong value. * Whether `num of b` should convert is open (#1637 leaves it undecided), @@ -554,7 +554,7 @@ Value* builtin_append(Value *arg) { EigsSlot item = list_slot(arg, 1); if (!target || target->type != VAL_LIST) { rt_error(EK_TYPE, 0, "append: target must be a list (got %s)", - val_type_name(target ? target->type : VAL_NUM)); + val_type_name(target ? target->type : VAL_FLOAT)); return make_null(); } list_append_slot(target, item); @@ -640,11 +640,11 @@ Value* builtin_get_observer_thresholds(Value *arg) { Value* builtin_exit(Value *arg) { STRICT_LIST_MAX(arg, 1, "exit"); int code = 0; - if (arg && arg->type == VAL_NUM) { + if (arg && val_is_number(arg)) { code = (int)eigs_num_arg(arg, __func__); } else if (arg && arg->type == VAL_LIST && arg->data.list.count >= 1 && BUILTIN_LIST_VIEW(arg, 0) && - BUILTIN_LIST_VIEW(arg, 0)->type == VAL_NUM) { + val_is_number(BUILTIN_LIST_VIEW(arg, 0))) { code = (int)eigs_list_num(arg, 0, __func__); } g_exit_code = code; @@ -864,7 +864,7 @@ Value* builtin_math_flags(Value *arg) { Value* builtin_type(Value *arg) { if (!arg) return make_str("none"); switch (arg->type) { - case VAL_NUM: return make_str("num"); + case VAL_FLOAT: return make_str("num"); case VAL_INT: return make_str("num"); /* #1758 (B): one number type at the surface */ case VAL_STR: return make_str("str"); case VAL_LIST: return make_str("list"); @@ -913,7 +913,7 @@ static int eigs_json_encode_value(Value *v, strbuf *out, int depth) { if ((v->type == VAL_LIST || v->type == VAL_DICT) && depth >= JSON_ENCODE_MAX_DEPTH) return -1; switch (v->type) { - case VAL_NUM: { + case VAL_FLOAT: { /* #875: one shared rule with `str of` — exact integers to 2^53 * bare, otherwise the shortest round-tripping form. The local * %d fast path stopped at 2^31 and handed everything above it @@ -1496,9 +1496,10 @@ Value* builtin_json_build(Value *arg) { free(key); strbuf_append_n(&out, ": ", 2); Value *val = BUILTIN_LIST_VIEW(arg, i + 1); - if (val->type == VAL_NUM) { + if (val_is_number(val)) { char nb[32]; /* #875: the shared rule */ - eigs_num_text(nb, sizeof(nb), eigs_num_arg(val, __func__)); + if (val->type == VAL_INT) eigs_int_text(nb, sizeof(nb), VAL_I64_RAW(val)); + else eigs_num_text(nb, sizeof(nb), eigs_num_arg(val, __func__)); strbuf_append(&out, nb); } else if (val->type == VAL_NULL) { strbuf_append(&out, "null"); @@ -1906,7 +1907,7 @@ Value* builtin_char_at(Value *arg) { ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2, "char_at", "[string, index]", make_str("")); Value *str_val = BUILTIN_LIST_VIEW(arg, 0); Value *idx_val = BUILTIN_LIST_VIEW(arg, 1); - ARG_GUARD(!str_val || str_val->type != VAL_STR || !idx_val || idx_val->type != VAL_NUM, + ARG_GUARD(!str_val || str_val->type != VAL_STR || !idx_val || !val_is_number(idx_val), "char_at", "[string, number]", make_str("")); int idx = (int)eigs_num_arg(idx_val, __func__); int len = val_str_len(str_val); @@ -1942,8 +1943,8 @@ Value* builtin_substr(Value *arg) { Value *start_val = BUILTIN_LIST_VIEW(arg, 1); Value *len_val = BUILTIN_LIST_VIEW(arg, 2); ARG_GUARD(!str_val || str_val->type != VAL_STR, "substr", "a string as its first argument", make_str("")); - ARG_GUARD(!start_val || start_val->type != VAL_NUM, "substr", "a number as its start", make_str("")); - ARG_GUARD(!len_val || len_val->type != VAL_NUM, "substr", "a number as its length", make_str("")); + ARG_GUARD(!start_val || !val_is_number(start_val), "substr", "a number as its start", make_str("")); + ARG_GUARD(!len_val || !val_is_number(len_val), "substr", "a number as its length", make_str("")); int slen = val_str_len(str_val); int start = (int)eigs_num_arg(start_val, __func__); int rlen = (int)eigs_num_arg(len_val, __func__); @@ -1997,22 +1998,22 @@ Value* builtin_index_of(Value *arg) { * ================================================================ */ Value* builtin_sin(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "sin", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "sin", "a number", make_num(0)); return make_num(sin(eigs_num_arg(arg, __func__))); } Value* builtin_cos(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "cos", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "cos", "a number", make_num(0)); return make_num(cos(eigs_num_arg(arg, __func__))); } Value* builtin_tan(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "tan", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "tan", "a number", make_num(0)); return make_num(tan(eigs_num_arg(arg, __func__))); } Value* builtin_asin(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "asin", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "asin", "a number", make_num(0)); double x = eigs_num_arg(arg, __func__); /* #865/#971: an out-of-domain argument is clamped (invalid bit records it), * unless strict math is on, in which case it raises. */ @@ -2026,7 +2027,7 @@ Value* builtin_asin(Value *arg) { } Value* builtin_acos(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "acos", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "acos", "a number", make_num(0)); double x = eigs_num_arg(arg, __func__); /* #865/#971: an out-of-domain argument is clamped (invalid bit records it), * unless strict math is on, in which case it raises. */ @@ -2040,7 +2041,7 @@ Value* builtin_acos(Value *arg) { } Value* builtin_atan(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "atan", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "atan", "a number", make_num(0)); return make_num(atan(eigs_num_arg(arg, __func__))); } @@ -2049,27 +2050,27 @@ Value* builtin_atan2(Value *arg) { ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2, "atan2", "[y, x]", make_num(0)); Value *y = BUILTIN_LIST_VIEW(arg, 0); Value *x = BUILTIN_LIST_VIEW(arg, 1); - ARG_GUARD(!y || y->type != VAL_NUM || !x || x->type != VAL_NUM, "atan2", "two numbers", make_num(0)); + ARG_GUARD(!y || !val_is_number(y) || !x || !val_is_number(x), "atan2", "two numbers", make_num(0)); return make_num(atan2(eigs_num_arg(y, __func__), eigs_num_arg(x, __func__))); } Value* builtin_floor(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "floor", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "floor", "a number", make_num(0)); return make_num(floor(eigs_num_arg(arg, __func__))); } Value* builtin_ceil(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "ceil", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "ceil", "a number", make_num(0)); return make_num(ceil(eigs_num_arg(arg, __func__))); } Value* builtin_round(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "round", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "round", "a number", make_num(0)); return make_num(round(eigs_num_arg(arg, __func__))); } Value* builtin_abs(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "abs", "a number", make_num(0)); + ARG_GUARD(!arg || !val_is_number(arg), "abs", "a number", make_num(0)); return make_num(fabs(eigs_num_arg(arg, __func__))); } @@ -2079,7 +2080,7 @@ Value* builtin_abs(Value *arg) { * an empty list or any non-number element keeps the old 0 fallback rather * than inventing a partial answer. */ static Value* minmax_reduce(Value *arg, int want_max) { - if (arg && arg->type == VAL_NUM) return make_num(eigs_num_arg(arg, __func__)); + if (arg && val_is_number(arg)) return make_num(eigs_num_arg(arg, __func__)); /* Split from the empty-list case below: #317 chose the 0 fallback for BOTH * a wrong type and an empty list in one condition, and only the first half * is a type mistake. Splitting keeps the non-strict answer identical while @@ -2091,7 +2092,7 @@ static Value* minmax_reduce(Value *arg, int want_max) { double best = 0.0; for (int i = 0; i < arg->data.list.count; i++) { Value *v = BUILTIN_LIST_VIEW(arg, i); - ARG_GUARD(!v || v->type != VAL_NUM, want_max ? "max" : "min", "every element to be a number", make_num(0)); + ARG_GUARD(!v || !val_is_number(v), want_max ? "max" : "min", "every element to be a number", make_num(0)); if (i == 0 || (want_max ? eigs_num_arg(v, __func__) > best : eigs_num_arg(v, __func__) < best)) best = eigs_num_arg(v, __func__); } @@ -2172,7 +2173,7 @@ Value* builtin_random_int(Value *arg) { "random_int", "[lo, hi]", make_num(0)); Value *lo = BUILTIN_LIST_VIEW(arg, 0); Value *hi = BUILTIN_LIST_VIEW(arg, 1); - ARG_GUARD_TAPED(!lo || lo->type != VAL_NUM || !hi || hi->type != VAL_NUM, + ARG_GUARD_TAPED(!lo || !val_is_number(lo) || !hi || !val_is_number(hi), "random_int", "numeric bounds", make_num(0)); /* Range-check as doubles before any integer cast — a double outside the * int64_t range (or non-finite) makes the cast itself UB (#698 fixed the @@ -2205,7 +2206,7 @@ Value* builtin_random_int(Value *arg) { /* seed_random of n → seeds the RNG, returns 1 */ Value* builtin_seed_random(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "seed_random", "a number", make_bool(0)); + ARG_GUARD(!arg || !val_is_number(arg), "seed_random", "a number", make_bool(0)); pthread_mutex_lock(&g_random_lock); srand48((long)eigs_num_arg(arg, __func__)); __atomic_store_n(&g_random_seeded, 1, __ATOMIC_RELEASE); @@ -2435,9 +2436,10 @@ Value* builtin_json_path(Value *arg) { val_decref(root); return r; } - if (current->type == VAL_NUM) { + if (val_is_number(current)) { char buf[64]; - eigs_num_text(buf, sizeof(buf), eigs_num_arg(current, __func__)); /* #875 */ + if (current->type == VAL_INT) eigs_int_text(buf, sizeof(buf), VAL_I64_RAW(current)); + else eigs_num_text(buf, sizeof(buf), eigs_num_arg(current, __func__)); /* #875 */ val_decref(root); return make_str(buf); } @@ -2541,7 +2543,7 @@ void tokenlist_user_spelling(TokenList *tl) { Value* builtin_token_name(Value *arg) { /* #971 Phase D: "?" is the documented answer for an UNKNOWN id (below); * for a non-number it was laundering a type mistake into that answer. */ - ARG_GUARD(!arg || arg->type != VAL_NUM, "token_name", "a token id", make_str("?")); + ARG_GUARD(!arg || !val_is_number(arg), "token_name", "a token id", make_str("?")); int id = (int)eigs_num_arg(arg, __func__); static const char *names[] = { "NUM", "STR", "IDENT", @@ -2578,7 +2580,7 @@ Value* builtin_token_name(Value *arg) { * the dict snapshot it returns is independent of subsequent program state. */ Value* builtin_state_at(Value *arg) { BOOL_REFUSE(arg, "state_at"); - if (!arg || arg->type != VAL_NUM) return make_null(); + if (!arg || !val_is_number(arg)) return make_null(); Value *d = trace_state_at((int)eigs_num_arg(arg, __func__)); return d ? d : make_null(); } @@ -2625,7 +2627,7 @@ Value* builtin_secure_equals(Value *arg) { * else raises too — the old silent empty-string return for >127 hid every * high-byte construction bug (#435). */ Value* builtin_chr(Value *arg) { - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "chr requires a number"); return make_null(); } @@ -2653,11 +2655,11 @@ Value* builtin_hex(Value *arg) { STRICT_LIST_MAX(arg, 2, "hex"); double num; long long width = 0; - if (arg && arg->type == VAL_NUM) { + if (arg && val_is_number(arg)) { num = eigs_num_arg(arg, __func__); } else if (arg && arg->type == VAL_LIST && arg->data.list.count >= 2 && - BUILTIN_LIST_VIEW(arg, 0) && BUILTIN_LIST_VIEW(arg, 0)->type == VAL_NUM && - BUILTIN_LIST_VIEW(arg, 1) && BUILTIN_LIST_VIEW(arg, 1)->type == VAL_NUM) { + BUILTIN_LIST_VIEW(arg, 0) && val_is_number(BUILTIN_LIST_VIEW(arg, 0)) && + BUILTIN_LIST_VIEW(arg, 1) && val_is_number(BUILTIN_LIST_VIEW(arg, 1))) { num = eigs_list_num(arg, 0, __func__); width = (long long)eigs_list_num(arg, 1, __func__); if (g_has_error) return make_null(); @@ -2807,7 +2809,7 @@ static const char *vm_desc_abi_error(Value *desc, char *buf, size_t buflen) { if (!desc || desc->type != VAL_LIST || desc->data.list.count < 1) return "chunk descriptor must be a list"; Value *rev = BUILTIN_LIST_VIEW(desc, 0); - if (!rev || rev->type != VAL_NUM) { + if (!rev || !val_is_number(rev)) { snprintf(buf, buflen, "chunk descriptor carries no bytecode ABI revision (element 0 " "must be the number %d, found %s) — this producer predates the " @@ -2916,7 +2918,7 @@ static void desc_leave(DescVerify *ctx) { static Value *desc_isolate_const(DescVerify *ctx, Value *v) { if (!v || !desc_spend(ctx, 1)) return NULL; switch (v->type) { - case VAL_NUM: + case VAL_FLOAT: case VAL_INT: /* #1758 R1.2a: an immutable scalar, like a float */ case VAL_STR: case VAL_NULL: @@ -3035,7 +3037,7 @@ static EigsChunk *vm_build_chunk_desc_body(Value *desc, int off, int sandbox_mod Value *b = BUILTIN_LIST_VIEW(code, i); /* #1637: a non-number code element (a bool) is refused, never * emitted as byte 0 (OP_CONST's opcode). */ - if (!b || b->type != VAL_NUM) { + if (!b || !val_is_number(b)) { chunk_free(chunk); vm_desc_error(why, whyn, "descriptor code must be a list of byte numbers"); return NULL; @@ -3096,7 +3098,7 @@ static EigsChunk *vm_build_chunk_desc_body(Value *desc, int off, int sandbox_mod vm_desc_error(why, whyn, "descriptor param_count must be a number"); return NULL; } - int param_count = (n >= 4 && d[3] && d[3]->type == VAL_NUM) + int param_count = (n >= 4 && d[3] && val_is_number(d[3])) ? (int)eigs_num_arg(d[3], __func__) : 0; chunk->param_count = param_count; chunk->first_default = param_count; /* no defaults */ @@ -3414,14 +3416,14 @@ Value* builtin_sandbox_run(Value *arg) { ? BUILTIN_LIST_VIEW(arg, 0) : arg; int max_iter = 1000000; if (arg && arg->type == VAL_LIST && arg->data.list.count >= 2 && - BUILTIN_LIST_VIEW(arg, 1) && BUILTIN_LIST_VIEW(arg, 1)->type == VAL_NUM) + BUILTIN_LIST_VIEW(arg, 1) && val_is_number(BUILTIN_LIST_VIEW(arg, 1))) max_iter = (int)eigs_list_num(arg, 1, __func__); /* #292: optional max_bytes (3rd element) — the allocation budget for this * run. Default 256 MiB: ample for the short generated snippets grade() * runs, small enough that even a few of them can't thrash a 4 GB box. */ size_t max_bytes = (size_t)256 * 1024 * 1024; if (arg && arg->type == VAL_LIST && arg->data.list.count >= 3 && - BUILTIN_LIST_VIEW(arg, 2) && BUILTIN_LIST_VIEW(arg, 2)->type == VAL_NUM && + BUILTIN_LIST_VIEW(arg, 2) && val_is_number(BUILTIN_LIST_VIEW(arg, 2)) && eigs_list_num(arg, 2, __func__) > 0) max_bytes = (size_t)eigs_list_num(arg, 2, __func__); /* VM instructions, cumulative across callback re-entry and function @@ -3430,7 +3432,7 @@ Value* builtin_sandbox_run(Value *arg) { * placing a finite ceiling on straight-line/call-heavy computation. */ uint64_t max_work = UINT64_C(10000000); if (arg && arg->type == VAL_LIST && arg->data.list.count >= 4 && - BUILTIN_LIST_VIEW(arg, 3) && BUILTIN_LIST_VIEW(arg, 3)->type == VAL_NUM) { + BUILTIN_LIST_VIEW(arg, 3) && val_is_number(BUILTIN_LIST_VIEW(arg, 3))) { double requested = eigs_list_num(arg, 3, __func__); /* A double rounds UINT64_MAX up to 2^64, so use a strict bound; * accepting equality and casting it would itself be undefined. */ @@ -3740,7 +3742,7 @@ Value* builtin_sandbox_run(Value *arg) { * compiles a temporal query; a self-hosted compiler (whose output runs via * vm_run_bytecode) calls this to do the same. Returns the previous setting. */ Value* builtin_record_history(Value *arg) { - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "record_history requires a number flag (nonzero=on, 0=off), got %s", arg ? val_type_name(arg->type) : "null"); return make_null(); @@ -3779,7 +3781,7 @@ Value* builtin_copy_into(Value *arg) { Value *dest = list_get_ref(arg, 0); Value *offv = BUILTIN_LIST_VIEW(arg, 1); Value *src = BUILTIN_LIST_VIEW(arg, 2); - if (!offv || offv->type != VAL_NUM) { + if (!offv || !val_is_number(offv)) { rt_error(EK_TYPE, 0, "copy_into: offset must be a number, got %s (the order is [dest, offset, src])", offv ? val_type_name(offv->type) : "null"); return make_null(); @@ -3796,7 +3798,7 @@ Value* builtin_copy_into(Value *arg) { if (src && src->type == VAL_LIST) { for (int i = 0; i < src->data.list.count && offset + i < dest->data.buffer.count; i++) { Value *it = BUILTIN_LIST_VIEW(src, i); - if (!it || it->type != VAL_NUM) { + if (!it || !val_is_number(it)) { rt_error(EK_TYPE, 0, "cannot store %s in a buffer (copy_into element %d; buffers hold numbers)", it ? val_type_name(it->type) : "null", i); return make_null(); @@ -3834,7 +3836,7 @@ Value* builtin_list_slice(Value *arg) { Value *end_v = BUILTIN_LIST_VIEW(arg, 2); BOOL_REFUSE(start_v, "list_slice"); BOOL_REFUSE(end_v, "list_slice"); - if (!start_v || start_v->type != VAL_NUM || !end_v || end_v->type != VAL_NUM) + if (!start_v || !val_is_number(start_v) || !end_v || !val_is_number(end_v)) return make_null(); int n = list->data.list.count; int start = (int)eigs_num_arg(start_v, __func__); @@ -3860,7 +3862,7 @@ Value* builtin_list_slice(Value *arg) { */ Value* builtin_num_copy(Value *arg) { BOOL_REFUSE(arg, "num_copy"); - if (!arg || arg->type != VAL_NUM) return make_null(); + if (!arg || !val_is_number(arg)) return make_null(); return make_num(eigs_num_arg(arg, __func__)); } @@ -3905,7 +3907,7 @@ Value* builtin_range(Value *arg) { if (!arg) return make_list(0); - if (arg->type == VAL_NUM) { + if (val_is_number(arg)) { /* range of n */ if (!range_bound(eigs_num_arg(arg, __func__), &end)) return make_list(0); } else if (arg->type == VAL_LIST) { @@ -3914,7 +3916,7 @@ Value* builtin_range(Value *arg) { * be silently treated as 0 (or fold the whole call to []) — a * silent-wrong loop count. */ for (int i = 0; i < argc && i < 3; i++) { - if (BUILTIN_LIST_VIEW(arg, i)->type != VAL_NUM) { + if (!val_is_number(BUILTIN_LIST_VIEW(arg, i))) { rt_error(EK_TYPE, 0, "range: argument %d must be a number, got %s", i, val_type_name(BUILTIN_LIST_VIEW(arg, i)->type)); @@ -4011,7 +4013,7 @@ Value* builtin_fill(Value *arg) { * operator, which raises index_range. These helpers raise the same kinds. */ static int at_index(Value *idx_val, int count, const char *what, int *out) { - if (!idx_val || idx_val->type != VAL_NUM) { + if (!idx_val || !val_is_number(idx_val)) { rt_error(EK_VALUE, 0, "%s index must be an integer", what); return 0; } @@ -4030,7 +4032,7 @@ static int at_index(Value *idx_val, int count, const char *what, * the diagnostic `b[i]` and `buf_get` already use for a buffer, so `set_at of * [buf, 9, v]` and `buf[9]` do not report the same fault two different ways. */ static int buf_at_index(Value *idx_val, int count, int *out) { - if (!idx_val || idx_val->type != VAL_NUM) { + if (!idx_val || !val_is_number(idx_val)) { rt_error(EK_VALUE, 0, "buffer index must be a number, got %s", val_type_name(idx_val ? idx_val->type : VAL_NULL)); return 0; @@ -4080,7 +4082,7 @@ Value* builtin_set_at(Value *arg) { "shaped buffer (see reshape)"); return make_null(); } - if (!val || val->type != VAL_NUM) { + if (!val || !val_is_number(val)) { rt_error(EK_TYPE, 0, "cannot store %s in a buffer (buffers hold numbers)", val_type_name(val ? val->type : VAL_NULL)); return make_null(); @@ -4548,12 +4550,12 @@ Value* builtin_thread_join(Value *arg) { } Value *hv = BUILTIN_DICT_VIEW(arg, "_handle_id"); Value *gv = BUILTIN_DICT_VIEW(arg, "_handle_gen"); - if (!hv || hv->type != VAL_NUM) { + if (!hv || !val_is_number(hv)) { rt_error(EK_TYPE, 0, "thread_join requires a thread handle"); return make_null(); } int hid = (int)eigs_num_arg(hv, __func__); - uint32_t hgen = (gv && gv->type == VAL_NUM) ? (uint32_t)eigs_num_arg(gv, __func__) : 0; + uint32_t hgen = (gv && val_is_number(gv)) ? (uint32_t)eigs_num_arg(gv, __func__) : 0; int why = HANDLE_CLAIM_GONE; ThreadHandle *h = (ThreadHandle*)handle_claim(hid, hgen, HANDLE_THREAD, &why); if (!h) { @@ -4633,10 +4635,10 @@ static Channel* get_channel_why(Value *v, int *why, int *out_id) { *out_id = 0; if (!v || v->type != VAL_DICT) return NULL; Value *cv = BUILTIN_DICT_VIEW(v, "_channel_id"); - if (!cv || cv->type != VAL_NUM) return NULL; + if (!cv || !val_is_number(cv)) return NULL; *out_id = (int)eigs_num_arg(cv, __func__); Value *gv = BUILTIN_DICT_VIEW(v, "_channel_gen"); - uint32_t gen = (gv && gv->type == VAL_NUM) ? (uint32_t)eigs_num_arg(gv, __func__) : 0; + uint32_t gen = (gv && val_is_number(gv)) ? (uint32_t)eigs_num_arg(gv, __func__) : 0; return (Channel*)handle_lookup(*out_id, gen, HANDLE_CHANNEL, why); } @@ -4804,7 +4806,7 @@ Value* builtin_recv_timeout(Value *arg) { if (!ch) return make_null(); if (replay_blocks("recv_timeout")) return make_null(); /* #1072: after validation */ Value *ms_v = BUILTIN_LIST_VIEW(arg, 1); - if (ms_v->type != VAL_NUM) { + if (!val_is_number(ms_v)) { rt_error(EK_TYPE, 0, "recv_timeout: ms must be a number"); return make_null(); } @@ -5000,7 +5002,7 @@ Value* builtin_task_spawn(Value *arg) { static Task *task_handle_resolve(Value *arg, const char *who, int *out_id) { int id = 0; uint32_t gen = 0; - if (!arg || arg->type != VAL_NUM || + if (!arg || !val_is_number(arg) || !task_handle_unpack(eigs_num_arg(arg, __func__), &id, &gen)) return NULL; int why = HANDLE_CLAIM_GONE; Task *t = (Task *)handle_lookup(id, gen, HANDLE_TASK, &why); @@ -5052,7 +5054,7 @@ Value* builtin_task_yield(Value *arg) { * returns immediately. Joining an unknown id, self, or with no scheduler * returns null. Same nesting restriction as task_yield. */ Value* builtin_task_join(Value *arg) { - if (!arg || arg->type != VAL_NUM || !g_task_sched) return make_null(); + if (!arg || !val_is_number(arg) || !g_task_sched) return make_null(); int target = 0; Task *t = task_handle_resolve(arg, "task_join", &target); if (!t) return make_null(); @@ -5094,7 +5096,7 @@ Value* builtin_task_send(Value *arg) { * trigger, and the differential's probe (which spawns a task first) could * not see it. `task_kill` and `stream_write` already order it this way. * Non-strict is unchanged: both halves answer 0. */ - ARG_GUARD(!idv || idv->type != VAL_NUM, "task_send", "a task id (number)", make_bool(0)); + ARG_GUARD(!idv || !val_is_number(idv), "task_send", "a task id (number)", make_bool(0)); /* fs:ANSWER no scheduler means there is no task to deliver to, which is * the dead-letter drop this function's contract documents ("0 if * dropped") — split out of the arity guard above, which is a mistake. */ @@ -5125,7 +5127,7 @@ Value* builtin_task_recv(Value *arg) { * and suspended slice, wake any joiner with an `interrupt` error, mark it * dead. Returns 1 if killed, 0 for a bad/self/finished target. */ Value* builtin_task_kill(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "task_kill", "a task id (number)", make_bool(0)); + ARG_GUARD(!arg || !val_is_number(arg), "task_kill", "a task id (number)", make_bool(0)); /* fs:ANSWER no scheduler means no such target; 0 is the documented * "bad/self/finished target" answer, split from the type guard above. */ if (!g_task_sched) return make_bool(0); @@ -5137,7 +5139,7 @@ Value* builtin_task_kill(Value *arg) { /* task_alive of id → 1 while the task is READY/RUNNING/SUSPENDED, else 0 * (DONE, DEAD, or an unknown id). */ Value* builtin_task_alive(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "task_alive", "a task id (number)", make_bool(0)); + ARG_GUARD(!arg || !val_is_number(arg), "task_alive", "a task id (number)", make_bool(0)); Task *t = task_handle_resolve(arg, "task_alive", NULL); /* fs:ANSWER an unknown id is NOT alive; 0 is this function's documented * answer. Four lines above, an identical `return make_bool(0)` is a type @@ -5159,7 +5161,7 @@ Value* builtin_task_alive(Value *arg) { Value* builtin_task_sleep(Value *arg) { /* #1637: the type check comes before the no-scheduler short-circuit, so * `task_sleep of true` raises with or without a scheduler. */ - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "task_sleep requires a number of ticks"); return make_null(); } @@ -5209,7 +5211,7 @@ Value* builtin_task_self(Value *arg) { * Joining a reaped id returns null, like any unknown id. Deterministic; no * tape participation. */ Value* builtin_task_detach(Value *arg) { - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "task_detach requires a task id (a number)"); return make_null(); } @@ -5226,7 +5228,7 @@ Value* builtin_task_detach(Value *arg) { * simulation tester uses to search interleavings. Typically called once at * program start. Returns null. */ Value* builtin_task_sched_seed(Value *arg) { - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "task_sched_seed requires a number (the seed)"); return make_null(); } @@ -5439,7 +5441,7 @@ Value* builtin_nearest_in_range(Value *arg) { } /* #1637: "active" is a bool (false skips); the older 1/0 number * still reads as before. */ - if (av && ((av->type == VAL_NUM && eigs_num_arg(av, __func__) != 1.0) + if (av && ((val_is_number(av) && eigs_num_arg(av, __func__) != 1.0) || (av->type == VAL_BOOL && !av->data.boolean))) continue; Value *ex; @@ -5466,7 +5468,7 @@ Value* builtin_nearest_in_range(Value *arg) { eigs_num_arg_slow((ex && ex->type == VAL_BOOL) ? ex : ey, "nearest_in_range"); return make_null(); } - if (!ex || !ey || ex->type != VAL_NUM || ey->type != VAL_NUM) continue; + if (!ex || !ey || !val_is_number(ex) || !val_is_number(ey)) continue; double dx = eigs_num_arg(ex, __func__) - px; double dy = eigs_num_arg(ey, __func__) - py; @@ -5568,7 +5570,7 @@ Value* builtin_nearest_in_range_all(Value *arg) { } /* active default: 1 (matches single-call behavior where missing/non-num * is treated as active). Explicit 0/non-1 value flips to inactive. */ - active_arr[i] = (av && ((av->type == VAL_NUM && eigs_num_arg(av, __func__) != 1.0) + active_arr[i] = (av && ((val_is_number(av) && eigs_num_arg(av, __func__) != 1.0) || (av->type == VAL_BOOL && !av->data.boolean))) ? 0 : 1; /* #1637 */ Value *ex; @@ -5591,7 +5593,7 @@ Value* builtin_nearest_in_range_all(Value *arg) { eigs_num_arg_slow((ex && ex->type == VAL_BOOL) ? ex : ey, "nearest_in_range_all"); break; } - if (!ex || !ey || ex->type != VAL_NUM || ey->type != VAL_NUM) { + if (!ex || !ey || !val_is_number(ex) || !val_is_number(ey)) { valid_arr[i] = 0; continue; } @@ -5673,7 +5675,7 @@ Value* builtin_sign_extend(Value *arg) { * to preserve, because the previous behaviour was undefined; 0 is the * same stand-in every sibling here uses. Filed as its own issue. */ Value *v0 = BUILTIN_LIST_VIEW(arg, 0), *v1 = BUILTIN_LIST_VIEW(arg, 1); - ARG_GUARD(!v0 || v0->type != VAL_NUM || !v1 || v1->type != VAL_NUM, "sign_extend", "two numbers", make_num(0)); + ARG_GUARD(!v0 || !val_is_number(v0) || !v1 || !val_is_number(v1), "sign_extend", "two numbers", make_num(0)); double val = eigs_num_arg(v0, __func__); int bits = (int)eigs_num_arg(v1, __func__); if (bits <= 0 || bits > 32) return make_num(val); @@ -5697,7 +5699,7 @@ Value* builtin_list_truncate(Value *arg) { rt_error(EK_TYPE, 0, "list_truncate: first argument must be a list"); return make_null(); } - if (!len_val || len_val->type != VAL_NUM) { + if (!len_val || !val_is_number(len_val)) { rt_error(EK_TYPE, 0, "list_truncate: new_len must be a number"); return make_null(); } @@ -5727,7 +5729,7 @@ Value* builtin_list_remove_at(Value *arg) { if (!list || list->type != VAL_LIST) return make_null(); /* #1637: a non-number index raises under EIGS_STRICT (a bool in every * mode) instead of silently doing nothing. */ - ARG_GUARD(!idx_val || idx_val->type != VAL_NUM, "list_remove_at", "a number index", list); + ARG_GUARD(!idx_val || !val_is_number(idx_val), "list_remove_at", "a number index", list); int idx = (int)eigs_num_arg(idx_val, __func__); if (idx < 0 || idx >= list->data.list.count) return list; slot_decref(list_slot(list, idx)); @@ -5749,7 +5751,7 @@ Value* builtin_list_insert_at(Value *arg) { if (!list || list->type != VAL_LIST) return make_null(); /* #1637: a non-number index raises under EIGS_STRICT (a bool in every * mode) instead of silently doing nothing. */ - ARG_GUARD(!idx_val || idx_val->type != VAL_NUM, "list_insert_at", "a number index", list); + ARG_GUARD(!idx_val || !val_is_number(idx_val), "list_insert_at", "a number index", list); int idx = (int)eigs_num_arg(idx_val, __func__); int count = list->data.list.count; if (idx < 0 || idx > count) return list; @@ -5818,14 +5820,22 @@ Value* builtin_list_contains(Value *arg) { /* sort_by of [list, key_fn] — sort list by numeric keys from key_fn. * Evaluates key_fn once per element, then qsorts by key (ascending). * Stable tiebreak by original index. Returns a NEW sorted list. */ -typedef struct { double key; int index; } SortByPair; +typedef struct { double key; int64_t int_key; int is_int; int index; } SortByPair; static int sort_by_pair_cmp(const void *a, const void *b) { - double da = ((const SortByPair *)a)->key; - double db = ((const SortByPair *)b)->key; - if (da < db) return -1; - if (da > db) return 1; - return ((const SortByPair *)a)->index - ((const SortByPair *)b)->index; + const SortByPair *pa = a, *pb = b; + int cmp; + if (pa->is_int && pb->is_int) + cmp = (pa->int_key > pb->int_key) - (pa->int_key < pb->int_key); + else if (pa->is_int) + cmp = eigs_cmp_int_float(pa->int_key, pb->key); + else if (pb->is_int) { + cmp = eigs_cmp_int_float(pb->int_key, pa->key); + if (cmp != 2) cmp = -cmp; + } else + cmp = (pa->key > pb->key) - (pa->key < pb->key); + if (cmp != 0 && cmp != 2) return cmp; + return pa->index - pb->index; } Value* builtin_sort_by(Value *arg) { @@ -5854,7 +5864,7 @@ Value* builtin_sort_by(Value *arg) { } /* #501: a non-numeric key used to coerce to 0.0 — a silent wrong * order. Raise instead (mirrors `sort` #368). */ - if (!kv || kv->type != VAL_NUM) { + if (!kv || !val_is_number(kv)) { const char *kt = kv ? val_type_name(kv->type) : "null"; if (kv) val_decref(kv); free(pairs); @@ -5863,7 +5873,9 @@ Value* builtin_sort_by(Value *arg) { "gave %s)", i, kt); return make_null(); } - pairs[i].key = eigs_num_arg(kv, __func__); + pairs[i].is_int = kv->type == VAL_INT; + if (pairs[i].is_int) pairs[i].int_key = VAL_I64_RAW(kv); + else pairs[i].key = eigs_num_arg(kv, __func__); pairs[i].index = i; val_decref(kv); } @@ -5882,8 +5894,20 @@ Value* builtin_sort_by(Value *arg) { * with libc-dependent element order on top (qsort gives no stability * guarantee for all-equal elements). Record sorting is sort_by's job. */ static int sort_cmp_num(const void *a, const void *b) { - double da = eigs_slot_num(*(const EigsSlot *)a, __func__); - double db = eigs_slot_num(*(const EigsSlot *)b, __func__); + EIGS_VIEW(av); EIGS_VIEW(bv); + Value *va = slot_view(*(const EigsSlot *)a, &av); + Value *vb = slot_view(*(const EigsSlot *)b, &bv); + if (va->type == VAL_INT && vb->type == VAL_INT) + return (VAL_I64_RAW(va) > VAL_I64_RAW(vb)) - (VAL_I64_RAW(va) < VAL_I64_RAW(vb)); + if (va->type == VAL_INT) { + int cmp = eigs_cmp_int_float(VAL_I64_RAW(va), eigs_num_arg(vb, __func__)); + return cmp == 2 ? 0 : cmp; + } + if (vb->type == VAL_INT) { + int cmp = eigs_cmp_int_float(VAL_I64_RAW(vb), eigs_num_arg(va, __func__)); + return cmp == 2 ? 0 : -cmp; + } + double da = eigs_num_arg(va, __func__), db = eigs_num_arg(vb, __func__); return (da > db) - (da < db); } @@ -5901,14 +5925,15 @@ Value* builtin_sort(Value *arg) { : VAL_NULL; for (int i = 0; i < arg->data.list.count; i++) { Value *v = BUILTIN_LIST_VIEW(arg, i); - if (!v || v->type != t || (t != VAL_NUM && t != VAL_STR)) { + int numeric = (t == VAL_FLOAT || t == VAL_INT); + if (!v || (numeric ? !val_is_number(v) : t != VAL_STR || v->type != VAL_STR)) { rt_error(EK_TYPE, 0, "sort requires all numbers or all strings " "(element %d is %s); use sort_by for records", i, v ? val_type_name(v->type) : "null"); return make_null(); } } - list_sort(arg, t == VAL_NUM ? sort_cmp_num : sort_cmp_str); + list_sort(arg, (t == VAL_FLOAT || t == VAL_INT) ? sort_cmp_num : sort_cmp_str); return arg; } @@ -5929,7 +5954,7 @@ Value* builtin_dispatch(Value *arg) { /* Key validation mirrors OP_DISPATCH (#353): a non-number key used to * reinterpret whatever union member the value carried as a double. */ - if (!key_v || key_v->type != VAL_NUM) { + if (!key_v || !val_is_number(key_v)) { rt_error(EK_TYPE, 0, "dispatch: key must be a number"); return make_null(); } @@ -5959,7 +5984,9 @@ Value* builtin_dispatch(Value *arg) { /* #1665: a numeric fn_arg is a stack view in THIS frame. A builtin * that returns its argument (`num`) would hand our caller a pointer * into a dead frame, so a number goes in as a fresh box we own. */ - if (fn_arg && fn_arg->type == VAL_NUM) { + if (fn_arg && fn_arg->type == VAL_INT) + eigs_int_unwired("builtin_dispatch argument box", (uint64_t)VAL_I64_RAW(fn_arg)); + if (fn_arg && fn_arg->type == VAL_FLOAT) { Value *boxed = make_num(eigs_num_arg(fn_arg, __func__)); Value *res = eigs_call_builtin(fn->data.builtin, boxed); if (res == boxed) return boxed; /* our ref transfers */ diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index e79957ce2..ac6cfc873 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -80,3 +80,8 @@ vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admi vm.c|vm_run_ex|49|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_NUM dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 +builtins.c|builtin_json_build|1|VAL_INT text is exact digits; float text retains the bridge (#1758 R1.2d) +builtins.c|builtin_json_path|1|VAL_INT scalar text is exact digits before releasing root (#1758 R1.2d) +builtins.c|builtin_dispatch|1|VAL_INT argument boxing refuses until make_int lands in R1.3 (#1758) +builtins.c|builtin_sort_by|1|numeric key kind retained for exact mixed sorting (#1758 N2) +builtins.c|sort_cmp_num|6|validated numeric slots viewed through slot_view; int comparisons are exact (#1758 N2) From 10849e6023b10db3b39ceb88e6fd53573d0093bd Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 05:49:36 -0500 Subject: [PATCH 026/188] phase2 R1.2e: admit int Values in the tensor bridge (#1758) Migrate 39 deprecated code-token sites in builtins_tensor.c. Numeric argument and element guards admit ints through the unchanged double bridge; no int producer. Validation: make built; inventory verdict PASS (see committed inventory). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2e.md | 1 + docs/design/phase2-inventory.txt | 147 ++++++++++++-------------- src/builtins_tensor.c | 78 +++++++------- 3 files changed, 110 insertions(+), 116 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2e.md diff --git a/changes/internal/1758-phase2-r1-2e.md b/changes/internal/1758-phase2-r1-2e.md new file mode 100644 index 000000000..d221ced8e --- /dev/null +++ b/changes/internal/1758-phase2-r1-2e.md @@ -0,0 +1 @@ +Admit int Values in the tensor bridge. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 4e27c9756..da71fb97d 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,10 +1,10 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1822 classified=1822 unclassified=0 +examined=1815 classified=1815 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 349 CASE=60 DATA=5 TEST=282 YIELD=2 +(a) type tests 342 CASE=60 DATA=5 TEST=275 YIELD=2 (b) payload reads 554 RAW=137 READ=417 (c) producers 472 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 @@ -17,19 +17,19 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per token make_num 364 -VAL_NUM 209 +VAL_NUM 170 eigs_num_arg 151 eigs_list_num 130 SLOT_F64_RAW 83 VAL_NUM_RAW 70 num_guard 60 +VAL_INT 58 +VAL_FLOAT 54 AST_NUM 52 eigs_slot_num 50 slot_is_f64 50 eigs_value_as_num 48 -VAL_INT 42 slot_from_f64 41 -VAL_FLOAT 38 buffer_read_num 38 slot_is_smi 37 VAL_I64_RAW 29 @@ -74,7 +74,7 @@ data.num (AST) 7 vm.c 299 a=78 b=97 c=68 e=2 f=9 i=45 builtins.c 267 a=11 b=103 c=111 e=3 f=11 h=19 i=9 ext_gfx.c 250 a=56 b=124 c=70 -builtins_tensor.c 184 a=39 b=59 c=86 +builtins_tensor.c 177 a=32 b=59 c=86 eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 builtins_buf.c 97 a=21 b=37 c=39 jit.c 96 d=96 @@ -301,7 +301,7 @@ LOSS (42): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_execut Q7: geometry=9 bounded=13 magnitude=13 abs builtin_abs int-preserving LOSS - eigs_num_arg,make_num acos builtin_acos float-producing - - eigs_num_arg,make_num -add builtin_tensor_add int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard +add builtin_tensor_add int-preserving LOSS - eigs_num_arg,make_num,num_guard append builtin_append other - - VAL_FLOAT asin builtin_asin float-producing - - eigs_num_arg,make_num assert builtin_assert other - - eigs_num_text @@ -363,19 +363,19 @@ db_execute builtin_db_execute other db_query_json builtin_db_query_json other LOSS - VAL_NUM,eigs_num_arg db_query_value builtin_db_query_value other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod dispatch builtin_dispatch int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num -divide builtin_tensor_divide float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard +divide builtin_tensor_divide float-producing - - eigs_num_arg,make_num,num_guard dot builtin_dot float-producing - - buffer_read_num,make_num,num_guard eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num eigen_generate builtin_eigen_generate int-requiring - - eigs_slot_num,eigs_slot_opt_num,make_num eigen_model_load builtin_eigen_model_load other - - strtod exec_capture builtin_exec_capture other - magnitude VAL_NUM,eigs_list_num,list_append_num exit builtin_exit int-requiring - - eigs_list_num,eigs_num_arg -exp builtin_tensor_exp float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard +exp builtin_tensor_exp float-producing - - eigs_num_arg,make_num,num_guard f64_from_bytes builtin_f64_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named f64_to_bytes builtin_f64_to_bytes other - - VAL_NUM,eigs_num_arg,make_num fill builtin_fill int-requiring - - eigs_list_num floor builtin_floor int-preserving LOSS - eigs_num_arg,make_num -gather builtin_tensor_gather int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num +gather builtin_tensor_gather int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num get_at builtin_get_at int-requiring - - buffer_read_num,eigs_num_arg,make_num get_observer_thresholds builtin_get_observer_thresholds float-producing - - make_num gfx_circle builtin_gfx_circle other - geometry,bounded VAL_NUM,eigs_list_num @@ -408,7 +408,7 @@ json_build builtin_json_build other json_decode builtin_json_decode other LOSS - make_num,strtod json_encode builtin_json_encode other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text json_path builtin_json_path other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text,make_num,strtod -leaky_relu builtin_tensor_leaky_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num +leaky_relu builtin_tensor_leaky_relu float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,make_num len builtin_len int-preserving - - make_num list_contains builtin_list_contains other - - values_equal list_index_of builtin_list_index_of int-preserving - - make_num,values_equal @@ -416,22 +416,22 @@ list_insert_at builtin_list_insert_at int-requiring list_remove_at builtin_list_remove_at int-requiring - - eigs_num_arg list_slice builtin_list_slice int-requiring - - eigs_num_arg list_truncate builtin_list_truncate int-requiring - - eigs_num_arg -log builtin_tensor_log float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard -log_softmax builtin_tensor_log_softmax float-producing - - VAL_NUM,eigs_slot_num,make_num -matmul builtin_tensor_matmul float-producing - - SLOT_F64_RAW,VAL_NUM,eigs_slot_num,make_num,num_guard_named -matmul_at builtin_tensor_matmul_at float-producing - - VAL_NUM,eigs_slot_num,make_num -matmul_bt builtin_tensor_matmul_bt float-producing - - VAL_NUM,eigs_slot_num,make_num +log builtin_tensor_log float-producing - - eigs_num_arg,make_num,num_guard +log_softmax builtin_tensor_log_softmax float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num +matmul builtin_tensor_matmul float-producing - - SLOT_F64_RAW,VAL_FLOAT,VAL_INT,eigs_slot_num,make_num,num_guard_named +matmul_at builtin_tensor_matmul_at float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num +matmul_bt builtin_tensor_matmul_bt float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num max builtin_max int-preserving LOSS - eigs_num_arg,make_num -mean builtin_tensor_mean float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +mean builtin_tensor_mean float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard min builtin_min int-preserving LOSS - eigs_num_arg,make_num model_load_weights builtin_eigen_model_load other - - strtod monotonic_ms builtin_monotonic_ms float-producing - - make_num monotonic_ns builtin_monotonic_ns int-preserving LOSS - make_num -multiply builtin_tensor_multiply int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard +multiply builtin_tensor_multiply int-preserving LOSS - eigs_num_arg,make_num,num_guard native_train_step_builtin builtin_native_train_step int-requiring - - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod nearest_in_range builtin_nearest_in_range float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num nearest_in_range_all builtin_nearest_in_range_all float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num -negative builtin_tensor_negative int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +negative builtin_tensor_negative int-preserving LOSS - eigs_num_arg,make_num net_accept builtin_net_accept int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num,make_num net_close builtin_net_close int-requiring - - VAL_NUM,eigs_num_arg net_dial builtin_net_dial int-requiring - - eigs_slot_opt_num,make_num @@ -439,16 +439,16 @@ net_listen builtin_net_listen int-requiring net_port builtin_net_port int-requiring - - VAL_NUM,eigs_num_arg,make_num net_recv builtin_net_recv int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num net_send builtin_net_send int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num -norm builtin_tensor_norm float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +norm builtin_tensor_norm float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard num builtin_num other LOSS - make_num,num_guard_named,strtod num_copy builtin_num_copy int-preserving LOSS - eigs_num_arg,make_num -numerical_grad builtin_numerical_grad float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num -numerical_grad_cols builtin_numerical_grad_cols float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num -numerical_grad_rows builtin_numerical_grad_rows float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +numerical_grad builtin_numerical_grad float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +numerical_grad_cols builtin_numerical_grad_cols float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +numerical_grad_rows builtin_numerical_grad_rows float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num observe builtin_observe other - - make_num ord builtin_ord int-preserving - - make_num pi builtin_pi float-producing - - make_num -pow builtin_tensor_pow float-producing - - VAL_NUM,eigs_num_arg,make_num,num_guard_named +pow builtin_tensor_pow float-producing - - eigs_num_arg,make_num,num_guard_named ppu_render_frame builtin_ppu_render_frame int-requiring - - buffer_read_byte print builtin_print other - - eigs_num_text proc_read_buf builtin_proc_read_buf int-requiring - - VAL_NUM,eigs_num_arg @@ -462,30 +462,30 @@ read_bytes_buf builtin_read_bytes_buf int-requiring record_history builtin_record_history other - - eigs_num_arg,make_num recv builtin_recv int-requiring - - eigs_num_arg recv_timeout builtin_recv_timeout int-requiring - magnitude eigs_num_arg -relu builtin_tensor_relu float-producing - - VAL_NUM,eigs_num_arg,eigs_slot_num,make_num +relu builtin_tensor_relu float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,make_num reshape builtin_reshape int-requiring - - VAL_NUM,eigs_list_num round builtin_round int-preserving LOSS - eigs_num_arg,make_num sandbox_run builtin_sandbox_run int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num scan_int_tokens builtin_scan_int_tokens int-preserving LOSS - make_num scan_ints builtin_scan_ints int-preserving LOSS - make_num -scatter_add builtin_tensor_scatter_add float-producing - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard +scatter_add builtin_tensor_scatter_add float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard seed_random builtin_seed_random int-requiring LOSS - eigs_num_arg send builtin_send int-requiring - - eigs_num_arg set_at builtin_set_at int-requiring - - eigs_num_arg -sgd_update builtin_sgd_update float-producing - - VAL_NUM,eigs_slot_num,eigs_slot_opt_num,list_set_num -sgd_update_cols builtin_sgd_update_cols float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num -sgd_update_rows builtin_sgd_update_rows float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num -shape builtin_tensor_shape int-preserving - - VAL_NUM,make_num +sgd_update builtin_sgd_update float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,eigs_slot_opt_num,list_set_num +sgd_update_cols builtin_sgd_update_cols float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num +sgd_update_rows builtin_sgd_update_rows float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num +shape builtin_tensor_shape int-preserving - - make_num shared_delete builtin_shared_delete int-preserving - - make_num shared_incr builtin_shared_incr int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num shared_size builtin_shared_size int-preserving - - make_num sign_extend builtin_sign_extend int-requiring LOSS - eigs_num_arg,make_num sin builtin_sin float-producing - - eigs_num_arg,make_num -softmax builtin_tensor_softmax float-producing - - VAL_NUM,eigs_slot_num,make_num +softmax builtin_tensor_softmax float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num sort builtin_sort other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg sort_by builtin_sort_by other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg spawn builtin_spawn int-preserving - - make_num -sqrt builtin_tensor_sqrt float-producing - - VAL_NUM,eigs_num_arg,make_num +sqrt builtin_tensor_sqrt float-producing - - eigs_num_arg,make_num state_at builtin_state_at int-requiring - - eigs_num_arg store_close builtin_store_close int-requiring - - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val store_collections builtin_store_collections int-requiring - - VAL_NUM,eigs_num_arg @@ -502,8 +502,8 @@ str_from_bytes builtin_str_from_bytes int-requiring stream_open builtin_stream_open int-requiring - - VAL_NUM,eigs_num_arg stream_write builtin_stream_write float-producing - - VAL_NUM,eigs_num_arg substr builtin_substr int-requiring - - eigs_num_arg -subtract builtin_tensor_subtract int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num,num_guard -sum builtin_tensor_sum int-preserving LOSS - VAL_NUM,buffer_read_num,eigs_num_arg,make_num,num_guard +subtract builtin_tensor_subtract int-preserving LOSS - eigs_num_arg,make_num,num_guard +sum builtin_tensor_sum int-preserving LOSS - buffer_read_num,eigs_num_arg,make_num,num_guard tan builtin_tan float-producing - - eigs_num_arg,make_num task_alive builtin_task_alive int-requiring - - eigs_num_arg task_detach builtin_task_detach int-requiring - - eigs_num_arg,make_num @@ -514,8 +514,8 @@ task_self builtin_task_self int-preserving task_send builtin_task_send int-requiring - - eigs_num_arg task_sleep builtin_task_sleep other - - eigs_num_arg task_spawn builtin_task_spawn int-preserving - - make_num -tensor_load builtin_tensor_load float-producing - - VAL_NUM,eigs_list_num,make_num,num_guard_named -tensor_save builtin_tensor_save float-producing - - VAL_NUM,eigs_slot_num +tensor_load builtin_tensor_load float-producing - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num,num_guard_named +tensor_save builtin_tensor_save float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num text_builder_append builtin_text_builder_append other - - eigs_num_text text_builder_append_line builtin_text_builder_append_line other - - eigs_num_text thread_join builtin_thread_join int-requiring - - eigs_num_arg @@ -527,8 +527,8 @@ usleep builtin_usleep other vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg write builtin_write other - - eigs_num_text write_bytes builtin_write_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num -zeros builtin_tensor_zeros int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg,make_num -zeros_like builtin_tensor_zeros_like float-producing - - VAL_NUM,make_num +zeros builtin_tensor_zeros int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num +zeros_like builtin_tensor_zeros_like float-producing - - make_num ## Sites (file:line scope token kind category) builtins.c:165 builtin_usleep eigs_num_arg READ b @@ -942,16 +942,18 @@ builtins_host.c:1548 builtin_write_bytes buffer_read_num READ b builtins_host.c:1550 builtin_write_bytes finite_num_to_byte READ b builtins_host.c:1556 builtin_write_bytes make_num PRODUCE c builtins_host.c:1560 builtin_write_bytes make_num PRODUCE c -builtins_tensor.c:229 tensor_dims VAL_NUM TEST a -builtins_tensor.c:257 #define FLAT_BAD VAL_NUM TEST a -builtins_tensor.c:292 tensor_to_flat VAL_NUM TEST a +builtins_tensor.c:229 tensor_dims VAL_FLOAT TEST a +builtins_tensor.c:229 tensor_dims VAL_INT TEST a +builtins_tensor.c:257 #define FLAT_BAD VAL_FLOAT TEST a +builtins_tensor.c:257 #define FLAT_BAD VAL_INT TEST a +builtins_tensor.c:292 tensor_to_flat VAL_FLOAT TEST a +builtins_tensor.c:292 tensor_to_flat VAL_INT TEST a builtins_tensor.c:292 tensor_to_flat eigs_slot_num READ b -builtins_tensor.c:299 tensor_to_flat VAL_NUM TEST a +builtins_tensor.c:299 tensor_to_flat VAL_FLOAT TEST a +builtins_tensor.c:299 tensor_to_flat VAL_INT TEST a builtins_tensor.c:299 tensor_to_flat eigs_slot_num READ b builtins_tensor.c:311 flat_to_tensor_2d make_num PRODUCE c builtins_tensor.c:327 flat_to_tensor_1d make_num PRODUCE c -builtins_tensor.c:359 tensor_total VAL_NUM TEST a -builtins_tensor.c:380 tensor_flatten_recursive VAL_NUM TEST a builtins_tensor.c:380 tensor_flatten_recursive eigs_num_arg READ b builtins_tensor.c:383 tensor_flatten_recursive buffer_read_num READ b builtins_tensor.c:399 op_add num_guard GUARD c @@ -960,19 +962,12 @@ builtins_tensor.c:401 op_mul num_guard GUARD c builtins_tensor.c:408 op_div num_guard GUARD c builtins_tensor.c:412 op_pow num_guard_named GUARD c builtins_tensor.c:488 tensor_elementwise make_num PRODUCE c -builtins_tensor.c:491 tensor_elementwise VAL_NUM TEST a -builtins_tensor.c:491 tensor_elementwise VAL_NUM TEST a builtins_tensor.c:492 tensor_elementwise eigs_num_arg READ b builtins_tensor.c:492 tensor_elementwise eigs_num_arg READ b builtins_tensor.c:492 tensor_elementwise make_num PRODUCE c -builtins_tensor.c:500 tensor_elementwise VAL_NUM TEST a builtins_tensor.c:501 tensor_elementwise eigs_num_arg READ b -builtins_tensor.c:502 tensor_elementwise VAL_NUM TEST a builtins_tensor.c:503 tensor_elementwise eigs_num_arg READ b -builtins_tensor.c:520 tensor_elementwise VAL_NUM TEST a -builtins_tensor.c:531 tensor_elementwise VAL_NUM TEST a builtins_tensor.c:629 tensor_elementwise make_num PRODUCE c -builtins_tensor.c:683 tensor_unary VAL_NUM TEST a builtins_tensor.c:683 tensor_unary eigs_num_arg READ b builtins_tensor.c:683 tensor_unary make_num PRODUCE c builtins_tensor.c:705 tensor_unary make_num PRODUCE c @@ -981,38 +976,34 @@ builtins_tensor.c:732 op_log_safe num_guard GUARD c builtins_tensor.c:734 op_log_safe num_guard GUARD c builtins_tensor.c:797 builtin_tensor_matmul SLOT_F64_RAW RAW b builtins_tensor.c:828 builtin_tensor_matmul num_guard_named GUARD c -builtins_tensor.c:995 builtin_tensor_scatter_add VAL_NUM TEST a -builtins_tensor.c:1026 builtin_tensor_scatter_add VAL_NUM TEST a +builtins_tensor.c:1026 builtin_tensor_scatter_add VAL_FLOAT TEST a +builtins_tensor.c:1026 builtin_tensor_scatter_add VAL_INT TEST a builtins_tensor.c:1030 builtin_tensor_scatter_add eigs_slot_num READ b builtins_tensor.c:1036 builtin_tensor_scatter_add buffer_read_num READ b -builtins_tensor.c:1041 builtin_tensor_scatter_add VAL_NUM TEST a +builtins_tensor.c:1041 builtin_tensor_scatter_add VAL_FLOAT TEST a +builtins_tensor.c:1041 builtin_tensor_scatter_add VAL_INT TEST a builtins_tensor.c:1045 builtin_tensor_scatter_add eigs_slot_num READ b builtins_tensor.c:1049 builtin_tensor_scatter_add eigs_num_arg READ b builtins_tensor.c:1077 builtin_tensor_scatter_add num_guard GUARD c builtins_tensor.c:1080 builtin_tensor_scatter_add num_guard GUARD c -builtins_tensor.c:1091 builtin_tensor_softmax VAL_NUM TEST a builtins_tensor.c:1091 builtin_tensor_softmax make_num PRODUCE c -builtins_tensor.c:1125 builtin_tensor_log_softmax VAL_NUM TEST a -builtins_tensor.c:1131 builtin_tensor_log_softmax VAL_NUM TEST a +builtins_tensor.c:1125 builtin_tensor_log_softmax VAL_FLOAT TEST a +builtins_tensor.c:1125 builtin_tensor_log_softmax VAL_INT TEST a builtins_tensor.c:1131 builtin_tensor_log_softmax make_num PRODUCE c -builtins_tensor.c:1165 builtin_tensor_relu VAL_NUM TEST a builtins_tensor.c:1166 builtin_tensor_relu eigs_num_arg READ b builtins_tensor.c:1167 builtin_tensor_relu make_num PRODUCE c -builtins_tensor.c:1186 builtin_tensor_leaky_relu VAL_NUM TEST a builtins_tensor.c:1187 builtin_tensor_leaky_relu eigs_num_arg READ b builtins_tensor.c:1188 builtin_tensor_leaky_relu make_num PRODUCE c builtins_tensor.c:1219 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1222 builtin_tensor_mean buffer_read_num READ b builtins_tensor.c:1224 builtin_tensor_mean num_guard GUARD c builtins_tensor.c:1226 builtin_tensor_mean make_num PRODUCE c -builtins_tensor.c:1236 builtin_tensor_mean VAL_NUM TEST a builtins_tensor.c:1238 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1243 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1253 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1265 builtin_tensor_sum buffer_read_num READ b builtins_tensor.c:1267 builtin_tensor_sum num_guard GUARD c builtins_tensor.c:1269 builtin_tensor_sum make_num PRODUCE c -builtins_tensor.c:1279 builtin_tensor_sum VAL_NUM TEST a builtins_tensor.c:1281 builtin_tensor_sum make_num PRODUCE c builtins_tensor.c:1286 builtin_tensor_sum make_num PRODUCE c builtins_tensor.c:1294 builtin_tensor_sum num_guard GUARD c @@ -1022,38 +1013,38 @@ builtins_tensor.c:1307 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1307 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1309 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1309 builtin_tensor_norm num_guard GUARD c -builtins_tensor.c:1319 builtin_tensor_norm VAL_NUM TEST a builtins_tensor.c:1321 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1325 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1333 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1333 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1335 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1335 builtin_tensor_norm num_guard GUARD c -builtins_tensor.c:1356 builtin_tensor_zeros VAL_NUM TEST a builtins_tensor.c:1357 builtin_tensor_zeros eigs_num_arg READ b -builtins_tensor.c:1365 builtin_tensor_zeros VAL_NUM TEST a -builtins_tensor.c:1366 builtin_tensor_zeros VAL_NUM TEST a +builtins_tensor.c:1365 builtin_tensor_zeros VAL_FLOAT TEST a +builtins_tensor.c:1365 builtin_tensor_zeros VAL_INT TEST a +builtins_tensor.c:1366 builtin_tensor_zeros VAL_FLOAT TEST a +builtins_tensor.c:1366 builtin_tensor_zeros VAL_INT TEST a builtins_tensor.c:1367 builtin_tensor_zeros eigs_list_num READ b builtins_tensor.c:1368 builtin_tensor_zeros eigs_list_num READ b builtins_tensor.c:1381 builtin_tensor_zeros make_num PRODUCE c -builtins_tensor.c:1396 builtin_tensor_zeros_like VAL_NUM TEST a builtins_tensor.c:1396 builtin_tensor_zeros_like make_num PRODUCE c builtins_tensor.c:1413 builtin_tensor_zeros_like make_num PRODUCE c -builtins_tensor.c:1430 flat_index_at VAL_NUM TEST a +builtins_tensor.c:1430 flat_index_at VAL_FLOAT TEST a +builtins_tensor.c:1430 flat_index_at VAL_INT TEST a builtins_tensor.c:1431 flat_index_at eigs_slot_num READ b builtins_tensor.c:1436 flat_index_at buffer_read_num READ b -builtins_tensor.c:1445 flat_index_is_num VAL_NUM TEST a -builtins_tensor.c:1488 builtin_tensor_gather VAL_NUM TEST a +builtins_tensor.c:1445 flat_index_is_num VAL_FLOAT TEST a +builtins_tensor.c:1445 flat_index_is_num VAL_INT TEST a builtins_tensor.c:1489 builtin_tensor_gather eigs_num_arg READ b builtins_tensor.c:1495 builtin_tensor_gather buffer_read_num READ b builtins_tensor.c:1495 builtin_tensor_gather make_num PRODUCE c builtins_tensor.c:1538 builtin_tensor_gather eigs_num_arg_slow READ b builtins_tensor.c:1541 builtin_tensor_gather make_num PRODUCE c -builtins_tensor.c:1545 builtin_tensor_gather VAL_NUM TEST a +builtins_tensor.c:1545 builtin_tensor_gather VAL_FLOAT TEST a +builtins_tensor.c:1545 builtin_tensor_gather VAL_INT TEST a builtins_tensor.c:1551 builtin_tensor_gather eigs_slot_num READ b builtins_tensor.c:1561 builtin_tensor_gather eigs_slot_elem_num READ b builtins_tensor.c:1563 builtin_tensor_gather make_num PRODUCE c -builtins_tensor.c:1568 builtin_tensor_gather VAL_NUM TEST a builtins_tensor.c:1569 builtin_tensor_gather eigs_num_arg READ b builtins_tensor.c:1575 builtin_tensor_gather eigs_slot_elem_num READ b builtins_tensor.c:1577 builtin_tensor_gather make_num PRODUCE c @@ -1065,7 +1056,6 @@ builtins_tensor.c:1700 builtin_random_normal make_num PRODUCE c builtins_tensor.c:1708 builtin_random_normal eigs_list_num READ b builtins_tensor.c:1709 builtin_random_normal eigs_list_num READ b builtins_tensor.c:1715 builtin_random_normal make_num PRODUCE c -builtins_tensor.c:1726 builtin_tensor_shape VAL_NUM TEST a builtins_tensor.c:1734 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1735 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1739 builtin_tensor_shape make_num PRODUCE c @@ -1073,11 +1063,12 @@ builtins_tensor.c:1745 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1753 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1754 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1759 builtin_tensor_shape make_num PRODUCE c -builtins_tensor.c:1768 numerical_loss VAL_NUM TEST a builtins_tensor.c:1769 numerical_loss eigs_num_arg READ b -builtins_tensor.c:1804 tensor_cells_numeric VAL_NUM TEST a +builtins_tensor.c:1804 tensor_cells_numeric VAL_FLOAT TEST a +builtins_tensor.c:1804 tensor_cells_numeric VAL_INT TEST a builtins_tensor.c:1805 tensor_cells_numeric eigs_slot_num READ b -builtins_tensor.c:1808 tensor_cells_numeric VAL_NUM TEST a +builtins_tensor.c:1808 tensor_cells_numeric VAL_FLOAT TEST a +builtins_tensor.c:1808 tensor_cells_numeric VAL_INT TEST a builtins_tensor.c:1809 tensor_cells_numeric eigs_slot_num READ b builtins_tensor.c:1826 builtin_numerical_grad eigs_slot_opt_num READ b builtins_tensor.c:1862 builtin_numerical_grad eigs_slot_num READ b @@ -1121,8 +1112,10 @@ builtins_tensor.c:2276 builtin_sgd_update_cols eigs_slot_num READ b builtins_tensor.c:2277 builtin_sgd_update_cols list_set_num PRODUCE c builtins_tensor.c:2387 tensor_load_record_verdict make_num PRODUCE c builtins_tensor.c:2388 tensor_load_record_verdict make_num PRODUCE c -builtins_tensor.c:2405 builtin_tensor_load VAL_NUM TEST a -builtins_tensor.c:2406 builtin_tensor_load VAL_NUM TEST a +builtins_tensor.c:2405 builtin_tensor_load VAL_FLOAT TEST a +builtins_tensor.c:2405 builtin_tensor_load VAL_INT TEST a +builtins_tensor.c:2406 builtin_tensor_load VAL_FLOAT TEST a +builtins_tensor.c:2406 builtin_tensor_load VAL_INT TEST a builtins_tensor.c:2407 builtin_tensor_load eigs_list_num READ b builtins_tensor.c:2408 builtin_tensor_load eigs_list_num READ b builtins_tensor.c:2485 builtin_tensor_load num_guard_named GUARD c diff --git a/src/builtins_tensor.c b/src/builtins_tensor.c index b4749c0e6..1888e4032 100644 --- a/src/builtins_tensor.c +++ b/src/builtins_tensor.c @@ -210,7 +210,7 @@ static Value* make_buffer_like(Value *a) { /* same count + shape as a */ /* ==================================================================== * TENSOR SUBSTRATE BUILTINS * Expose tensor operations so the .eigs standard library can run natively. - * Tensors are represented as nested VAL_LIST of VAL_NUM (1D or 2D). + * Tensors are represented as nested VAL_LIST of VAL_FLOAT (1D or 2D). * ==================================================================== */ /* --- Tensor helper: detect dimensions --- */ @@ -226,7 +226,7 @@ static int tensor_dims(Value *v, int *rows, int *cols) { *rows = 1; *cols = v->data.buffer.count; return 1; } if (!v || v->type != VAL_LIST || v->data.list.count == 0) return 0; - if (list_elem_type(v, 0) == VAL_NUM) { + if ((list_elem_type(v, 0) == VAL_FLOAT || list_elem_type(v, 0) == VAL_INT)) { /* 1D tensor */ *rows = 1; *cols = v->data.list.count; @@ -254,7 +254,7 @@ static double* tensor_to_flat(Value *v, int *rows, int *cols, * explicit EIGS_STRICT=0 path deliberately retains the old stand-in. * Check even when the first element or row gives no usable shape. */ /* #1637: a bool element is refused in every strict mode. */ -#define FLAT_BAD(t) ((t) != VAL_NUM && (g_strict || (t) == VAL_BOOL)) +#define FLAT_BAD(t) (((t) != VAL_FLOAT && (t) != VAL_INT) && (g_strict || (t) == VAL_BOOL)) if (v && v->type == VAL_LIST) { int bad = 0; if (ndim == 1) { @@ -289,14 +289,14 @@ static double* tensor_to_flat(Value *v, int *rows, int *cols, } if (ndim == 1) { for (int i = 0; i < *cols; i++) - out[i] = (list_elem_type(v, i) == VAL_NUM) ? eigs_slot_num(list_slot(v, i), __func__) : 0.0; + out[i] = ((list_elem_type(v, i) == VAL_FLOAT || list_elem_type(v, i) == VAL_INT)) ? eigs_slot_num(list_slot(v, i), __func__) : 0.0; } else { for (int r = 0; r < *rows; r++) { /* list_get_ref is NULL for a number: test the type first. */ Value *row = (list_elem_type(v, r) == VAL_LIST) ? list_get_ref(v, r) : NULL; int rc = row ? row->data.list.count : 0; for (int c = 0; c < *cols && c < rc; c++) - out[r * (*cols) + c] = (list_elem_type(row, c) == VAL_NUM) ? eigs_slot_num(list_slot(row, c), __func__) : 0.0; + out[r * (*cols) + c] = ((list_elem_type(row, c) == VAL_FLOAT || list_elem_type(row, c) == VAL_INT)) ? eigs_slot_num(list_slot(row, c), __func__) : 0.0; } } return out; @@ -356,7 +356,7 @@ static Value* flat_to_like(Value *src, double *data, int rows, int cols) { /* --- Tensor helper: count total elements recursively --- */ static int tensor_total(Value *v) { if (!v) return 0; - if (v->type == VAL_NUM) return 1; + if (val_is_number(v)) return 1; /* #1637: arithmetic on a bool raises. Other non-number elements keep * their old (counted-as-absent) reading; a bool is the one that used to * BE a number, so letting it vanish from `sum of [a < b, ...]` would turn @@ -377,7 +377,7 @@ static int tensor_total(Value *v) { * Return failure at the first raised read; callers own and free the workspace. */ static int tensor_flatten_recursive(Value *v, double *out, int *idx) { if (!v) return 1; - if (v->type == VAL_NUM) { out[(*idx)++] = eigs_num_arg(v, __func__); return 1; } + if (val_is_number(v)) { out[(*idx)++] = eigs_num_arg(v, __func__); return 1; } if (v->type == VAL_BUFFER) { /* #1093 */ for (int i = 0; i < v->data.buffer.count; i++) { double x = buffer_read_num(v, i); @@ -488,7 +488,7 @@ static Value* tensor_elementwise(Value *a, Value *b, BinOpFn fn) { "two tensor operands", make_num(0.0)); /* scalar op scalar */ - if (a->type == VAL_NUM && b->type == VAL_NUM) + if (val_is_number(a) && val_is_number(b)) return make_num(fn(eigs_num_arg(a, __func__), eigs_num_arg(b, __func__))); /* #1093 buffers are flat numeric tensors. Buffer-only operands compute on @@ -497,9 +497,9 @@ static Value* tensor_elementwise(Value *a, Value *b, BinOpFn fn) { * (the rule: a buffer out iff every tensor operand was a buffer). */ if (a->type == VAL_BUFFER && b->type == VAL_BUFFER) return buf_elementwise(a, b, fn); - if (a->type == VAL_BUFFER && b->type == VAL_NUM) + if (a->type == VAL_BUFFER && val_is_number(b)) return buf_scalar_elementwise(a, eigs_num_arg(b, __func__), fn, 1); - if (a->type == VAL_NUM && b->type == VAL_BUFFER) + if (val_is_number(a) && b->type == VAL_BUFFER) return buf_scalar_elementwise(b, eigs_num_arg(a, __func__), fn, 0); if (a->type == VAL_BUFFER && b->type == VAL_LIST) { Value *al = buf_as_tensor_list(a); @@ -517,7 +517,7 @@ static Value* tensor_elementwise(Value *a, Value *b, BinOpFn fn) { } /* scalar broadcast to list */ - if (a->type == VAL_NUM && b->type == VAL_LIST) { + if (val_is_number(a) && b->type == VAL_LIST) { Value *out = make_list(b->data.list.count); for (int i = 0; i < b->data.list.count; i++) { Value *item = tensor_elementwise_slots(slot_from_heap(a), list_slot(b, i), fn); @@ -528,7 +528,7 @@ static Value* tensor_elementwise(Value *a, Value *b, BinOpFn fn) { } return out; } - if (a->type == VAL_LIST && b->type == VAL_NUM) { + if (a->type == VAL_LIST && val_is_number(b)) { Value *out = make_list(a->data.list.count); for (int i = 0; i < a->data.list.count; i++) { Value *item = tensor_elementwise_slots(list_slot(a, i), slot_from_heap(b), fn); @@ -680,7 +680,7 @@ Value* builtin_tensor_pow(Value *arg) { typedef double (*UnaryOpFn)(double); static Value* tensor_unary(Value *v, UnaryOpFn fn) { Value *arg = v; /* what the guard macros test for a bool (#1637) */ - if (v->type == VAL_NUM) return make_num(fn(eigs_num_arg(v, __func__))); + if (val_is_number(v)) return make_num(fn(eigs_num_arg(v, __func__))); /* #1093: a buffer is a flat numeric tensor — same kernel, buffer out. */ if (v->type == VAL_BUFFER) { Value *out = make_buffer_like(v); @@ -992,7 +992,7 @@ Value* builtin_tensor_scatter_add(Value *arg) { rt_error(EK_TYPE, 0, "scatter_add: indices must be a list or buffer, got %s", val_type_name(indices->type)); return make_null(); } - if (values->type != VAL_LIST && values->type != VAL_BUFFER && values->type != VAL_NUM) { + if (values->type != VAL_LIST && values->type != VAL_BUFFER && !val_is_number(values)) { rt_error(EK_TYPE, 0, "scatter_add: values must be a buffer, a list of numbers, or a number, got %s", val_type_name(values->type)); return make_null(); } @@ -1023,7 +1023,7 @@ Value* builtin_tensor_scatter_add(Value *arg) { double di, v; if (indices->type == VAL_LIST) { ValType it = list_elem_type(indices, i); - if (it != VAL_NUM) { + if ((it != VAL_FLOAT && it != VAL_INT)) { rt_error(EK_TYPE, 0, "scatter_add: index %d is %s (expected a number)", i, val_type_name(it)); return make_null(); } @@ -1038,7 +1038,7 @@ Value* builtin_tensor_scatter_add(Value *arg) { } if (values->type == VAL_LIST) { ValType vt = list_elem_type(values, i); - if (vt != VAL_NUM) { + if ((vt != VAL_FLOAT && vt != VAL_INT)) { rt_error(EK_TYPE, 0, "scatter_add: value %d is %s (expected a number)", i, val_type_name(vt)); return make_null(); } @@ -1088,7 +1088,7 @@ Value* builtin_tensor_scatter_add(Value *arg) { Value* builtin_tensor_softmax(Value *arg) { BOOL_REFUSE(arg, "softmax"); /* #632: softmax of a single element normalizes to 1.0. */ - if (arg && arg->type == VAL_NUM) return make_num(1.0); + if (arg && val_is_number(arg)) return make_num(1.0); /* flat-buffer fast path (#973): row-wise on the shape, 1-D is one row; * same ne_softmax_buf kernel as the list path, so byte-identical. */ if (arg && arg->type == VAL_BUFFER) { @@ -1122,13 +1122,13 @@ Value* builtin_tensor_log_softmax(Value *arg) { Value *tensor = arg; if (arg && arg->type == VAL_LIST && arg->data.list.count == 2 && list_elem_type(arg, 0) == VAL_LIST && - list_elem_type(arg, 1) == VAL_NUM) + (list_elem_type(arg, 1) == VAL_FLOAT || list_elem_type(arg, 1) == VAL_INT)) tensor = list_get_ref(arg, 0); /* [tensor, dim] form */ /* #632: log(softmax(scalar)) = log(1) = 0. */ /* fs:ANSWER softmax of a single element is 1 and log(1) is 0, so 0.0 is * the arithmetic result for a scalar argument — a NUMBER is a valid * argument here, which is what makes this not a type guard (#632). */ - if (tensor && tensor->type == VAL_NUM) return make_num(0.0); + if (tensor && val_is_number(tensor)) return make_num(0.0); /* flat-buffer fast path (#973): same kernel + the same #865 clamp. */ if (tensor && tensor->type == VAL_BUFFER) { Value *res = make_buffer_like(tensor); @@ -1162,7 +1162,7 @@ Value* builtin_tensor_log_softmax(Value *arg) { Value* builtin_tensor_relu(Value *arg) { BOOL_REFUSE(arg, "relu"); /* #632: a scalar is the degenerate element-wise case, like sqrt/exp/log. */ - if (arg && arg->type == VAL_NUM) { + if (arg && val_is_number(arg)) { double x = eigs_num_arg(arg, __func__); return make_num(x < 0.0 ? 0.0 : x); } @@ -1183,7 +1183,7 @@ Value* builtin_tensor_relu(Value *arg) { Value* builtin_tensor_leaky_relu(Value *arg) { BOOL_REFUSE(arg, "leaky_relu"); /* #632: scalar is the degenerate element-wise case. */ - if (arg && arg->type == VAL_NUM) { + if (arg && val_is_number(arg)) { double x = eigs_num_arg(arg, __func__); return make_num(x < 0.0 ? 0.01 * x : x); } @@ -1233,7 +1233,7 @@ Value* builtin_tensor_mean(Value *arg) { * tagged fs:EMPTY, which would have blessed the laundering permanently), * so the type half is hoisted out. Non-strict is byte-identical: both * halves still answer 0.0. Closes the main half of #1008. */ - ARG_GUARD(arg && arg->type != VAL_NUM && arg->type != VAL_LIST + ARG_GUARD(arg && !val_is_number(arg) && arg->type != VAL_LIST && arg->type != VAL_BUFFER, /* #1093 */ "mean", "a number, a list of numbers or a buffer", make_num(0.0)); int total = tensor_total(arg); @@ -1276,7 +1276,7 @@ Value* builtin_tensor_sum(Value *arg) { * tagged fs:EMPTY, which would have blessed the laundering permanently), * so the type half is hoisted out. Non-strict is byte-identical: both * halves still answer 0.0. Closes the main half of #1008. */ - ARG_GUARD(arg && arg->type != VAL_NUM && arg->type != VAL_LIST + ARG_GUARD(arg && !val_is_number(arg) && arg->type != VAL_LIST && arg->type != VAL_BUFFER, /* #1093 */ "sum", "a number, a list of numbers or a buffer", make_num(0.0)); int total = tensor_total(arg); @@ -1316,7 +1316,7 @@ Value* builtin_tensor_norm(Value *arg) { * tagged fs:EMPTY, which would have blessed the laundering permanently), * so the type half is hoisted out. Non-strict is byte-identical: both * halves still answer 0.0. Closes the main half of #1008. */ - ARG_GUARD(arg && arg->type != VAL_NUM && arg->type != VAL_LIST + ARG_GUARD(arg && !val_is_number(arg) && arg->type != VAL_LIST && arg->type != VAL_BUFFER, /* #1093 */ "norm", "a number, a list of numbers or a buffer", make_num(0.0)); int total = tensor_total(arg); @@ -1353,7 +1353,7 @@ Value* builtin_tensor_zeros(Value *arg) { * the list cost a Value per element on the VM and 12.4x on the AOT * (ouroboros#170). make_shaped_buffer carries the sandbox charge, which * is now 8 bytes/element instead of TENSOR_LIST_ELEM_BYTES. */ - if (arg->type == VAL_NUM) { + if (val_is_number(arg)) { int64_t n64 = (int64_t)eigs_num_arg(arg, __func__); if (n64 < 0) n64 = 0; if (n64 > 10000000) n64 = 10000000; /* #292: cap like fill/buffer (was uncapped → x_oom/abort) */ @@ -1362,8 +1362,8 @@ Value* builtin_tensor_zeros(Value *arg) { } /* zeros of [rows, cols] → 2D */ if (arg->type == VAL_LIST && arg->data.list.count >= 2 - && list_elem_type(arg, 0) == VAL_NUM - && list_elem_type(arg, 1) == VAL_NUM) { + && (list_elem_type(arg, 0) == VAL_FLOAT || list_elem_type(arg, 0) == VAL_INT) + && (list_elem_type(arg, 1) == VAL_FLOAT || list_elem_type(arg, 1) == VAL_INT)) { int64_t rows64 = (int64_t)eigs_list_num(arg, 0, __func__); int64_t cols64 = (int64_t)eigs_list_num(arg, 1, __func__); if (rows64 < 0) rows64 = 0; @@ -1393,7 +1393,7 @@ Value* builtin_tensor_zeros_like(Value *arg) { /* fs:LITERAL a number is a valid argument and this IS the value being * constructed — the zero of the same shape, which for a scalar is 0.0. * It is the scalar leaf of the recursion below, not a guard. */ - if (arg->type == VAL_NUM) return make_num(0.0); + if (val_is_number(arg)) return make_num(0.0); if (arg->type == VAL_LIST) { Value *out = make_list(arg->data.list.count); for (int i = 0; i < arg->data.list.count; i++) { @@ -1427,7 +1427,7 @@ static int flat_is_vector(Value *v) { } static int flat_index_at(Value *v, int i) { if (v->type == VAL_LIST) - return (list_elem_type(v, i) == VAL_NUM) + return ((list_elem_type(v, i) == VAL_FLOAT || list_elem_type(v, i) == VAL_INT)) ? (int)eigs_slot_num(list_slot(v, i), __func__) : -1; /* #1417: normalize before conversion, and let every caller propagate a * raised read before using its index or touching an output. Saturated @@ -1442,7 +1442,7 @@ static int flat_index_at(Value *v, int i) { * as "index -1 out of range" would name the wrong fault. Buffers hold doubles, * so every element is a number by construction. */ static int flat_index_is_num(Value *v, int i) { - return v->type != VAL_LIST || list_elem_type(v, i) == VAL_NUM; + return v->type != VAL_LIST || (list_elem_type(v, i) == VAL_FLOAT || list_elem_type(v, i) == VAL_INT); } /* ==== BUILTIN: gather ==== */ @@ -1485,7 +1485,7 @@ Value* builtin_tensor_gather(Value *arg) { * row selects one element per row and yields a buffer; an unshaped (1-D) * buffer with a scalar index yields that element. */ if (tensor->type == VAL_BUFFER) { - if (indices->type == VAL_NUM && tensor->data.buffer.rows == 0) { + if (val_is_number(indices) && tensor->data.buffer.rows == 0) { int idx = (int)eigs_num_arg(indices, __func__); if (idx < 0 || idx >= tensor->data.buffer.count) { rt_error(EK_INDEX, 0, "gather: index %d out of range (length %d)", @@ -1542,7 +1542,7 @@ Value* builtin_tensor_gather(Value *arg) { continue; } Value *row = list_get_ref(tensor, i); - if (list_elem_type(indices, i) != VAL_NUM) { + if ((list_elem_type(indices, i) != VAL_FLOAT && list_elem_type(indices, i) != VAL_INT)) { val_decref(out); rt_error(EK_TYPE, 0, "gather: index %d is %s (expected a number)", i, val_type_name(list_elem_type(indices, i))); @@ -1565,7 +1565,7 @@ Value* builtin_tensor_gather(Value *arg) { return out; } /* 1D tensor, scalar index */ - if (tensor->type == VAL_LIST && indices->type == VAL_NUM) { + if (tensor->type == VAL_LIST && val_is_number(indices)) { int idx = (int)eigs_num_arg(indices, __func__); if (idx < 0 || idx >= tensor->data.list.count) { rt_error(EK_INDEX, 0, "gather: index %d out of range (length %d)", @@ -1723,7 +1723,7 @@ Value* builtin_random_normal(Value *arg) { /* shape of tensor → [rows, cols] for 2D, [len] for 1D */ Value* builtin_tensor_shape(Value *arg) { if (!arg) return make_null(); - if (arg->type == VAL_NUM) { + if (val_is_number(arg)) { Value *out = make_list(0); return out; /* scalar: empty shape */ } @@ -1765,7 +1765,7 @@ static double numerical_loss(Value *loss_fn, Value *arg, const char *who, int *loss_valid) { if (!*loss_valid) return 0.0; Value *loss = call_eigs_fn(loss_fn, arg); - if (loss && loss->type == VAL_NUM) { + if (loss && val_is_number(loss)) { double result = eigs_num_arg(loss, __func__); val_decref(loss); return result; @@ -1801,11 +1801,11 @@ static int tensor_cells_numeric(const Value *v, const char *who) { const Value *e = et == VAL_LIST ? list_get_ref(v, i) : NULL; if (et == VAL_LIST) { for (int c = 0; c < e->data.list.count; c++) - if (list_elem_type(e, c) != VAL_NUM) { + if ((list_elem_type(e, c) != VAL_FLOAT && list_elem_type(e, c) != VAL_INT)) { eigs_slot_num(list_slot(e, c), who); return 0; } - } else if (et != VAL_NUM) { + } else if ((et != VAL_FLOAT && et != VAL_INT)) { eigs_slot_num(list_slot(v, i), who); return 0; } @@ -2402,8 +2402,8 @@ Value* builtin_tensor_load(Value *arg) { replayed_verdict = 1; if (verdict && verdict->type == VAL_LIST && verdict->data.list.count == 2 && - list_elem_type(verdict, 0) == VAL_NUM && - list_elem_type(verdict, 1) == VAL_NUM) { + (list_elem_type(verdict, 0) == VAL_FLOAT || list_elem_type(verdict, 0) == VAL_INT) && + (list_elem_type(verdict, 1) == VAL_FLOAT || list_elem_type(verdict, 1) == VAL_INT)) { uint32_t rows = (uint32_t)eigs_list_num(verdict, 0, __func__); uint32_t cols = (uint32_t)eigs_list_num(verdict, 1, __func__); val_decref(verdict); From f28b94b0f3c7f184c30eec128385685c5a65e81f Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 05:49:45 -0500 Subject: [PATCH 027/188] phase2 R1.2f: admit int Values in the buffer bridge (#1758) Migrate 21 deprecated code-token sites in builtins_buf.c. Numeric argument and element guards admit ints through the unchanged double bridge; no int producer. Validation: make built; inventory verdict PASS (see committed inventory). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2f.md | 1 + docs/design/phase2-inventory.txt | 95 ++++++++++++++------------- src/builtins_buf.c | 40 +++++------ 3 files changed, 71 insertions(+), 65 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2f.md diff --git a/changes/internal/1758-phase2-r1-2f.md b/changes/internal/1758-phase2-r1-2f.md new file mode 100644 index 000000000..dcb1efa6e --- /dev/null +++ b/changes/internal/1758-phase2-r1-2f.md @@ -0,0 +1 @@ +Admit int Values in the buffer bridge. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index da71fb97d..5fb55c8b8 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,10 +1,10 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1815 classified=1815 unclassified=0 +examined=1820 classified=1820 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 342 CASE=60 DATA=5 TEST=275 YIELD=2 +(a) type tests 347 CASE=60 DATA=5 TEST=280 YIELD=2 (b) payload reads 554 RAW=137 READ=417 (c) producers 472 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 @@ -17,14 +17,14 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per token make_num 364 -VAL_NUM 170 eigs_num_arg 151 +VAL_NUM 149 eigs_list_num 130 SLOT_F64_RAW 83 +VAL_INT 71 VAL_NUM_RAW 70 +VAL_FLOAT 67 num_guard 60 -VAL_INT 58 -VAL_FLOAT 54 AST_NUM 52 eigs_slot_num 50 slot_is_f64 50 @@ -76,7 +76,7 @@ builtins.c 267 a=11 b=103 c=111 e=3 f=11 h=19 i=9 ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 177 a=32 b=59 c=86 eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 -builtins_buf.c 97 a=21 b=37 c=39 +builtins_buf.c 102 a=26 b=37 c=39 jit.c 96 d=96 container.h 91 a=35 b=30 c=26 ext_store.c 54 h=54 @@ -334,21 +334,21 @@ bit_or builtin_bit_or int-requiring bit_shl builtin_bit_shift_left int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact bit_shr builtin_bit_shift_right int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact bit_xor builtin_bit_xor int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact -buf_copy builtin_buf_copy int-requiring - - VAL_NUM,eigs_slot_num -buf_deinterleave builtin_buf_deinterleave int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_num -buf_dot builtin_buf_dot float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,make_num,num_guard -buf_fill builtin_buf_fill float-producing - - VAL_NUM,buf_num_arg,eigs_slot_num -buf_from_list builtin_buf_from_list float-producing - - VAL_NUM,eigs_slot_num -buf_from_pcm16le builtin_buf_from_pcm16le int-requiring - - VAL_NUM,buffer_read_num,eigs_slot_num,num_guard +buf_copy builtin_buf_copy int-requiring - - VAL_FLOAT,VAL_INT,eigs_slot_num +buf_deinterleave builtin_buf_deinterleave int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num +buf_dot builtin_buf_dot float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,make_num,num_guard +buf_fill builtin_buf_fill float-producing - - VAL_FLOAT,VAL_INT,buf_num_arg,eigs_slot_num +buf_from_list builtin_buf_from_list float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num +buf_from_pcm16le builtin_buf_from_pcm16le int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,num_guard buf_get builtin_buf_get int-requiring - - buffer_read_num,eigs_list_num,make_num buf_len builtin_buf_len int-preserving - - make_num -buf_mix builtin_buf_mix float-producing - - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard -buf_peak builtin_buf_peak float-producing - - VAL_NUM,buffer_read_num,eigs_slot_num,make_num -buf_resample_linear builtin_buf_resample_linear float-producing - - VAL_NUM,eigs_slot_num,num_guard -buf_scale_range builtin_buf_scale_range float-producing - - VAL_NUM,buf_num_arg,eigs_slot_num,num_guard -buf_set builtin_buf_set int-requiring - - VAL_NUM,eigs_list_num -buf_to_pcm16le builtin_buf_to_pcm16le other - bounded VAL_NUM,buffer_read_num,eigs_slot_num,num_guard -buffer builtin_buffer int-requiring - - VAL_NUM,eigs_list_num,eigs_num_arg +buf_mix builtin_buf_mix float-producing - - VAL_FLOAT,VAL_INT,buf_num_arg,eigs_slot_num,num_guard +buf_peak builtin_buf_peak float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,make_num +buf_resample_linear builtin_buf_resample_linear float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,num_guard +buf_scale_range builtin_buf_scale_range float-producing - - VAL_FLOAT,VAL_INT,buf_num_arg,eigs_slot_num,num_guard +buf_set builtin_buf_set int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num +buf_to_pcm16le builtin_buf_to_pcm16le other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,num_guard +buffer builtin_buffer int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg build_corpus builtin_build_corpus int-requiring - - VAL_NUM,eigs_num_arg,eigs_opt_num,make_num,num_val ceil builtin_ceil int-preserving LOSS - eigs_num_arg,make_num channel builtin_channel int-preserving - - make_num @@ -371,8 +371,8 @@ eigen_model_load builtin_eigen_model_load other exec_capture builtin_exec_capture other - magnitude VAL_NUM,eigs_list_num,list_append_num exit builtin_exit int-requiring - - eigs_list_num,eigs_num_arg exp builtin_tensor_exp float-producing - - eigs_num_arg,make_num,num_guard -f64_from_bytes builtin_f64_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named -f64_to_bytes builtin_f64_to_bytes other - - VAL_NUM,eigs_num_arg,make_num +f64_from_bytes builtin_f64_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named +f64_to_bytes builtin_f64_to_bytes other - - eigs_num_arg,make_num fill builtin_fill int-requiring - - eigs_list_num floor builtin_floor int-preserving LOSS - eigs_num_arg,make_num gather builtin_tensor_gather int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num @@ -402,7 +402,7 @@ http_route_authed builtin_http_route_authed other http_serve builtin_http_serve int-requiring - - eigs_num_text,eigs_opt_num http_static builtin_http_static other - - eigs_num_text index_of builtin_index_of int-preserving - - make_num -inflate builtin_inflate int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num +inflate builtin_inflate int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num join builtin_join other - - eigs_num_text json_build builtin_json_build other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text json_decode builtin_json_decode other LOSS - make_num,strtod @@ -463,7 +463,7 @@ record_history builtin_record_history other recv builtin_recv int-requiring - - eigs_num_arg recv_timeout builtin_recv_timeout int-requiring - magnitude eigs_num_arg relu builtin_tensor_relu float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,make_num -reshape builtin_reshape int-requiring - - VAL_NUM,eigs_list_num +reshape builtin_reshape int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num round builtin_round int-preserving LOSS - eigs_num_arg,make_num sandbox_run builtin_sandbox_run int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num scan_int_tokens builtin_scan_int_tokens int-preserving LOSS - make_num @@ -498,7 +498,7 @@ store_put builtin_store_put other store_query builtin_store_query other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod store_update builtin_store_update other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val str builtin_str other - - eigs_num_text -str_from_bytes builtin_str_from_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte +str_from_bytes builtin_str_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte stream_open builtin_stream_open int-requiring - - VAL_NUM,eigs_num_arg stream_write builtin_stream_write float-producing - - VAL_NUM,eigs_num_arg substr builtin_substr int-requiring - - eigs_num_arg @@ -798,15 +798,17 @@ builtins.c:6076 builtin_dot buffer_read_num READ b builtins.c:6078 builtin_dot num_guard GUARD c builtins.c:6078 builtin_dot num_guard GUARD c builtins.c:6080 builtin_dot make_num PRODUCE c -builtins_buf.c:35 builtin_buffer VAL_NUM TEST a -builtins_buf.c:36 builtin_buffer VAL_NUM TEST a +builtins_buf.c:35 builtin_buffer VAL_FLOAT TEST a +builtins_buf.c:35 builtin_buffer VAL_INT TEST a +builtins_buf.c:36 builtin_buffer VAL_FLOAT TEST a +builtins_buf.c:36 builtin_buffer VAL_INT TEST a builtins_buf.c:37 builtin_buffer eigs_list_num READ b builtins_buf.c:38 builtin_buffer eigs_list_num READ b -builtins_buf.c:56 builtin_buffer VAL_NUM TEST a -builtins_buf.c:57 builtin_buffer VAL_NUM TEST a builtins_buf.c:57 builtin_buffer eigs_num_arg READ b -builtins_buf.c:78 builtin_reshape VAL_NUM TEST a -builtins_buf.c:79 builtin_reshape VAL_NUM TEST a +builtins_buf.c:78 builtin_reshape VAL_FLOAT TEST a +builtins_buf.c:78 builtin_reshape VAL_INT TEST a +builtins_buf.c:79 builtin_reshape VAL_FLOAT TEST a +builtins_buf.c:79 builtin_reshape VAL_INT TEST a builtins_buf.c:80 builtin_reshape eigs_list_num READ b builtins_buf.c:81 builtin_reshape eigs_list_num READ b builtins_buf.c:105 builtin_buf_get make_num PRODUCE c @@ -816,44 +818,49 @@ builtins_buf.c:115 builtin_buf_get make_num PRODUCE c builtins_buf.c:120 builtin_buf_get make_num PRODUCE c builtins_buf.c:122 builtin_buf_get buffer_read_num READ b builtins_buf.c:122 builtin_buf_get make_num PRODUCE c -builtins_buf.c:141 builtin_buf_set VAL_NUM TEST a -builtins_buf.c:145 builtin_buf_set VAL_NUM TEST a +builtins_buf.c:141 builtin_buf_set VAL_FLOAT TEST a +builtins_buf.c:141 builtin_buf_set VAL_INT TEST a +builtins_buf.c:145 builtin_buf_set VAL_FLOAT TEST a +builtins_buf.c:145 builtin_buf_set VAL_INT TEST a builtins_buf.c:149 builtin_buf_set eigs_list_num READ b builtins_buf.c:150 builtin_buf_set eigs_list_num READ b builtins_buf.c:163 builtin_buf_len make_num PRODUCE c builtins_buf.c:164 builtin_buf_len make_num PRODUCE c -builtins_buf.c:184 builtin_buf_from_list VAL_NUM TEST a +builtins_buf.c:184 builtin_buf_from_list VAL_FLOAT TEST a +builtins_buf.c:184 builtin_buf_from_list VAL_INT TEST a builtins_buf.c:185 builtin_buf_from_list eigs_slot_num READ b -builtins_buf.c:206 strict_numeric_byte_list VAL_NUM TEST a -builtins_buf.c:213 strict_numeric_byte_list VAL_NUM TEST a builtins_buf.c:214 strict_numeric_byte_list eigs_num_arg READ b builtins_buf.c:214 strict_numeric_byte_list finite_num_to_byte READ b -builtins_buf.c:239 builtin_str_from_bytes VAL_NUM TEST a +builtins_buf.c:239 builtin_str_from_bytes VAL_FLOAT TEST a +builtins_buf.c:239 builtin_str_from_bytes VAL_INT TEST a builtins_buf.c:239 builtin_str_from_bytes eigs_slot_num READ b builtins_buf.c:240 builtin_str_from_bytes buffer_read_num READ b builtins_buf.c:242 builtin_str_from_bytes finite_num_to_byte READ b -builtins_buf.c:260 builtin_f64_to_bytes VAL_NUM TEST a -builtins_buf.c:261 builtin_f64_to_bytes VAL_NUM TEST a builtins_buf.c:261 builtin_f64_to_bytes eigs_num_arg READ b builtins_buf.c:267 builtin_f64_to_bytes make_num PRODUCE c -builtins_buf.c:279 builtin_f64_from_bytes VAL_NUM TEST a +builtins_buf.c:279 builtin_f64_from_bytes VAL_FLOAT TEST a +builtins_buf.c:279 builtin_f64_from_bytes VAL_INT TEST a builtins_buf.c:280 builtin_f64_from_bytes eigs_slot_num READ b builtins_buf.c:284 builtin_f64_from_bytes buffer_read_num READ b builtins_buf.c:288 builtin_f64_from_bytes make_num PRODUCE c builtins_buf.c:292 builtin_f64_from_bytes finite_num_to_byte READ b builtins_buf.c:297 builtin_f64_from_bytes make_num PRODUCE c builtins_buf.c:297 builtin_f64_from_bytes num_guard_named GUARD c -builtins_buf.c:350 zlib_bytes_arg VAL_NUM TEST a +builtins_buf.c:350 zlib_bytes_arg VAL_FLOAT TEST a +builtins_buf.c:350 zlib_bytes_arg VAL_INT TEST a builtins_buf.c:350 zlib_bytes_arg eigs_slot_num READ b builtins_buf.c:351 zlib_bytes_arg buffer_read_num READ b builtins_buf.c:353 zlib_bytes_arg finite_num_to_byte READ b builtins_buf.c:374 zlib_bytes_result make_num PRODUCE c -builtins_buf.c:493 buf_count_arg VAL_NUM TEST a +builtins_buf.c:493 buf_count_arg VAL_FLOAT TEST a +builtins_buf.c:493 buf_count_arg VAL_INT TEST a builtins_buf.c:497 buf_count_arg eigs_slot_num READ b builtins_buf.c:507 buf_num_arg READ b -builtins_buf.c:509 buf_num_arg VAL_NUM TEST a +builtins_buf.c:509 buf_num_arg VAL_FLOAT TEST a +builtins_buf.c:509 buf_num_arg VAL_INT TEST a builtins_buf.c:513 buf_num_arg eigs_slot_num READ b -builtins_buf.c:526 buf_window_arg VAL_NUM TEST a +builtins_buf.c:526 buf_window_arg VAL_FLOAT TEST a +builtins_buf.c:526 buf_window_arg VAL_INT TEST a builtins_buf.c:530 buf_window_arg eigs_slot_num READ b builtins_buf.c:590 builtin_buf_mix buf_num_arg READ b builtins_buf.c:595 builtin_buf_mix num_guard GUARD c @@ -884,8 +891,6 @@ builtins_buf.c:799 builtin_buf_to_pcm16le num_guard GUARD c builtins_buf.c:800 builtin_buf_to_pcm16le num_guard GUARD c builtins_buf.c:801 builtin_buf_to_pcm16le num_guard GUARD c builtins_buf.c:801 builtin_buf_to_pcm16le num_guard GUARD c -builtins_buf.c:827 builtin_buf_deinterleave VAL_NUM TEST a -builtins_buf.c:827 builtin_buf_deinterleave VAL_NUM TEST a builtins_buf.c:831 builtin_buf_deinterleave eigs_num_arg READ b builtins_buf.c:832 builtin_buf_deinterleave eigs_num_arg READ b builtins_buf.c:909 builtin_buf_resample_linear num_guard GUARD c diff --git a/src/builtins_buf.c b/src/builtins_buf.c index 61b82df88..29683a048 100644 --- a/src/builtins_buf.c +++ b/src/builtins_buf.c @@ -32,8 +32,8 @@ Value* builtin_buffer(Value *arg) { /* buffer of [rows, cols] -> shaped 2-D buffer (flat double[rows*cols]) */ if (arg && arg->type == VAL_LIST && arg->data.list.count == 2 && - list_elem_type(arg, 0) == VAL_NUM && - list_elem_type(arg, 1) == VAL_NUM) { + (list_elem_type(arg, 0) == VAL_FLOAT || list_elem_type(arg, 0) == VAL_INT) && + (list_elem_type(arg, 1) == VAL_FLOAT || list_elem_type(arg, 1) == VAL_INT)) { int r = (int)eigs_list_num(arg, 0, __func__); int c = (int)eigs_list_num(arg, 1, __func__); if (r < 0) r = 0; @@ -53,8 +53,8 @@ Value* builtin_buffer(Value *arg) { int count = 0; /* #971 Phase D: a non-number size (or a malformed [rows, cols]) made an * EMPTY buffer — a plausible object with nothing in it. */ - STRICT_REQUIRE(!arg || arg->type != VAL_NUM, "buffer", "a size or [rows, cols]"); - if (arg && arg->type == VAL_NUM) count = (int)eigs_num_arg(arg, __func__); + STRICT_REQUIRE(!arg || !val_is_number(arg), "buffer", "a size or [rows, cols]"); + if (arg && val_is_number(arg)) count = (int)eigs_num_arg(arg, __func__); if (count < 0) count = 0; if (count > 10000000) count = 10000000; if (!sandbox_charge((size_t)count * sizeof(double))) return make_null(); /* #292 */ @@ -75,8 +75,8 @@ Value* builtin_reshape(Value *arg) { Value *b = list_get_view(arg, 0, &b_view); if (b->type != VAL_BUFFER) return make_null(); BOOL_REFUSE(arg, "reshape"); /* rows/cols; the buffer is not a bool */ - if (list_elem_type(arg, 1) != VAL_NUM || - list_elem_type(arg, 2) != VAL_NUM) return make_null(); + if ((list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT) || + (list_elem_type(arg, 2) != VAL_FLOAT && list_elem_type(arg, 2) != VAL_INT)) return make_null(); int r = (int)eigs_list_num(arg, 1, __func__); int c = (int)eigs_list_num(arg, 2, __func__); if (r < 0 || c < 0 || (long)r * (long)c != (long)b->data.buffer.count) return make_null(); @@ -138,11 +138,11 @@ Value* builtin_buf_set(Value *arg) { /* #1061: both operands were read through the num union member unchecked * -- a string index or value read garbage bits (the #1007 type-pun class). * Loud, like the `b[i] is v` opcode path. */ - if (list_elem_type(arg, 1) != VAL_NUM) { + if ((list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT)) { rt_error(EK_TYPE, 0, "buf_set: index must be a number, got %s", val_type_name(list_elem_type(arg, 1))); return make_null(); } - if (list_elem_type(arg, 2) != VAL_NUM) { + if ((list_elem_type(arg, 2) != VAL_FLOAT && list_elem_type(arg, 2) != VAL_INT)) { rt_error(EK_TYPE, 0, "cannot store %s in a buffer (buffers hold numbers)", val_type_name(list_elem_type(arg, 2))); return make_null(); } @@ -181,7 +181,7 @@ Value* builtin_buf_from_list(Value *arg) { v->data.buffer.data = xcalloc(n > 0 ? n : 1, sizeof(double)); v->refcount = 1; for (int i = 0; i < n; i++) { - if (list_elem_type(arg, i) == VAL_NUM) { + if ((list_elem_type(arg, i) == VAL_FLOAT || list_elem_type(arg, i) == VAL_INT)) { v->data.buffer.data[i] = eigs_slot_num(list_slot(arg, i), __func__); } else { /* #1061: a non-number element silently stayed 0.0. */ @@ -203,14 +203,14 @@ static int strict_numeric_byte_list(Value *arg, const char *who, int nul_ends) { EIGS_VIEW(item_view); Value *item = list_get_view(arg, i, &item_view); /* #1637: a bool byte is refused in every strict mode. */ - if (!item || (item->type != VAL_NUM && (g_strict || item->type == VAL_BOOL))) { + if (!item || (!val_is_number(item) && (g_strict || item->type == VAL_BOOL))) { rt_error(EK_TYPE, 0, "%s: expected numeric byte values", who); return 0; } /* EIGS_STRICT=0 legacy: a non-number element (a bool never reaches * here) ends the string as a NUL would -- the documented truncation * the compatibility mode keeps. It is never read as a number. */ - if (nul_ends && (item->type != VAL_NUM + if (nul_ends && (!val_is_number(item) || finite_num_to_byte(eigs_num_arg(item, __func__)) == 0)) break; } return 1; @@ -236,7 +236,7 @@ Value* builtin_str_from_bytes(Value *arg) { int len = 0; for (int i = 0; i < n; i++) { double dv = arg->type == VAL_LIST - ? (list_elem_type(arg, i) == VAL_NUM ? eigs_slot_num(list_slot(arg, i), __func__) : 0.0) + ? ((list_elem_type(arg, i) == VAL_FLOAT || list_elem_type(arg, i) == VAL_INT) ? eigs_slot_num(list_slot(arg, i), __func__) : 0.0) : buffer_read_num(arg, i); if (g_has_error) { free(s); return make_null(); } int b = finite_num_to_byte(dv); @@ -257,8 +257,8 @@ Value* builtin_str_from_bytes(Value *arg) { * explicit shifts, yielding the standard IEEE-754 layout on any platform. */ Value* builtin_f64_to_bytes(Value *arg) { /* #971 Phase D: a non-number encoded as 0.0's eight bytes. */ - STRICT_REQUIRE(!arg || arg->type != VAL_NUM, "f64_to_bytes", "a number"); - double d = (arg && arg->type == VAL_NUM) ? eigs_num_arg(arg, __func__) : 0.0; + STRICT_REQUIRE(!arg || !val_is_number(arg), "f64_to_bytes", "a number"); + double d = (arg && val_is_number(arg)) ? eigs_num_arg(arg, __func__) : 0.0; uint64_t bits; memcpy(&bits, &d, sizeof(bits)); Value *list = make_list(8); @@ -276,7 +276,7 @@ Value* builtin_f64_from_bytes(Value *arg) { if (arg && arg->type == VAL_LIST) { int n = arg->data.list.count; for (int i = 0; i < 8 && i < n; i++) - if (list_elem_type(arg, i) == VAL_NUM) + if ((list_elem_type(arg, i) == VAL_FLOAT || list_elem_type(arg, i) == VAL_INT)) bytes_in[i] = eigs_slot_num(list_slot(arg, i), __func__); } else if (arg && arg->type == VAL_BUFFER) { int n = arg->data.buffer.count; @@ -347,7 +347,7 @@ static int zlib_bytes_arg(Value *arg, const char *who, unsigned char *b = xmalloc((size_t)(n > 0 ? n : 1)); for (int i = 0; i < n; i++) { double dv = arg->type == VAL_LIST - ? (list_elem_type(arg, i) == VAL_NUM ? eigs_slot_num(list_slot(arg, i), __func__) : 0.0) + ? ((list_elem_type(arg, i) == VAL_FLOAT || list_elem_type(arg, i) == VAL_INT) ? eigs_slot_num(list_slot(arg, i), __func__) : 0.0) : buffer_read_num(arg, i); if (g_has_error) { free(b); return 0; } b[i] = finite_num_to_byte(dv); @@ -490,7 +490,7 @@ Value* builtin_inflate(Value *arg) { (void)arg; return zlib_unavailable("in * #490-#512 direction (buf_get/buf_set/set_at) — no silent truncation: * a clamped audio mix is a silently wrong render. */ static int buf_count_arg(const char *who, EigsSlot cnt, long long *out) { - if (slot_type(cnt) != VAL_NUM) { + if ((slot_type(cnt) != VAL_FLOAT && slot_type(cnt) != VAL_INT)) { rt_error(EK_VALUE, 0, "%s: count must be a number", who); return 0; } @@ -506,7 +506,7 @@ static int buf_count_arg(const char *who, EigsSlot cnt, long long *out) { static int buf_num_arg(const char *who, const char *what, EigsSlot s, double *out) { - if (slot_type(s) != VAL_NUM) { + if ((slot_type(s) != VAL_FLOAT && slot_type(s) != VAL_INT)) { rt_error(EK_VALUE, 0, "%s: %s must be a number", who, what); return 0; } @@ -523,7 +523,7 @@ static int buf_window_arg(const char *who, Value *buf, EigsSlot off, rt_error(EK_TYPE, 0, "%s: expected a buffer", who); return 0; } - if (slot_type(off) != VAL_NUM) { + if ((slot_type(off) != VAL_FLOAT && slot_type(off) != VAL_INT)) { rt_error(EK_VALUE, 0, "%s: offset must be a number", who); return 0; } @@ -824,7 +824,7 @@ Value* builtin_buf_deinterleave(Value *arg) { Value *ch_v = list_get_view(arg, 1, &ch_v_view); EIGS_VIEW(nch_v_view); Value *nch_v = list_get_view(arg, 2, &nch_v_view); - if (!ch_v || ch_v->type != VAL_NUM || !nch_v || nch_v->type != VAL_NUM) { + if (!ch_v || !val_is_number(ch_v) || !nch_v || !val_is_number(nch_v)) { rt_error(EK_VALUE, 0, "buf_deinterleave: channel and nch must be numbers"); return make_null(); } From f9e711dfced8dec05f149023ebcb317882df4c10 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 05:49:54 -0500 Subject: [PATCH 028/188] phase2 R1.2g: admit int Values in the host bridge (#1758) Migrate 11 deprecated code-token sites in builtins_host.c. Numeric argument and element guards admit ints through the unchanged double bridge; no int producer. Validation: make built; inventory verdict PASS (see committed inventory). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2g.md | 1 + docs/design/phase2-inventory.txt | 43 +++++++++++---------------- src/builtins_host.c | 22 +++++++------- 3 files changed, 30 insertions(+), 36 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2g.md diff --git a/changes/internal/1758-phase2-r1-2g.md b/changes/internal/1758-phase2-r1-2g.md new file mode 100644 index 000000000..794a33863 --- /dev/null +++ b/changes/internal/1758-phase2-r1-2g.md @@ -0,0 +1 @@ +Admit int Values in the host bridge. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 5fb55c8b8..a16fc0213 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,10 +1,10 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1820 classified=1820 unclassified=0 +examined=1813 classified=1813 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 347 CASE=60 DATA=5 TEST=280 YIELD=2 +(a) type tests 340 CASE=60 DATA=5 TEST=273 YIELD=2 (b) payload reads 554 RAW=137 READ=417 (c) producers 472 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 @@ -18,12 +18,12 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per token make_num 364 eigs_num_arg 151 -VAL_NUM 149 +VAL_NUM 138 eigs_list_num 130 SLOT_F64_RAW 83 -VAL_INT 71 +VAL_INT 73 VAL_NUM_RAW 70 -VAL_FLOAT 67 +VAL_FLOAT 69 num_guard 60 AST_NUM 52 eigs_slot_num 50 @@ -81,8 +81,8 @@ jit.c 96 d=96 container.h 91 a=35 b=30 c=26 ext_store.c 54 h=54 embed_smoke.c 50 j=50 -builtins_host.c 47 a=11 b=24 c=12 eigenscript.h 44 a=7 b=24 c=12 e=1 +builtins_host.c 40 a=4 b=24 c=12 jit_smoke.c 31 d=31 lint.c 29 a=29 compiler.c 21 a=13 b=5 c=1 i=2 @@ -349,7 +349,7 @@ buf_scale_range builtin_buf_scale_range float-producing buf_set builtin_buf_set int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num buf_to_pcm16le builtin_buf_to_pcm16le other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,num_guard buffer builtin_buffer int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg -build_corpus builtin_build_corpus int-requiring - - VAL_NUM,eigs_num_arg,eigs_opt_num,make_num,num_val +build_corpus builtin_build_corpus int-requiring - - eigs_num_arg,eigs_opt_num,make_num,num_val ceil builtin_ceil int-preserving LOSS - eigs_num_arg,make_num channel builtin_channel int-preserving - - make_num channel_closed builtin_channel_closed int-requiring - - eigs_num_arg @@ -368,7 +368,7 @@ dot builtin_dot float-producing eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num eigen_generate builtin_eigen_generate int-requiring - - eigs_slot_num,eigs_slot_opt_num,make_num eigen_model_load builtin_eigen_model_load other - - strtod -exec_capture builtin_exec_capture other - magnitude VAL_NUM,eigs_list_num,list_append_num +exec_capture builtin_exec_capture other - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,list_append_num exit builtin_exit int-requiring - - eigs_list_num,eigs_num_arg exp builtin_tensor_exp float-producing - - eigs_num_arg,make_num,num_guard f64_from_bytes builtin_f64_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named @@ -451,14 +451,14 @@ pi builtin_pi float-producing pow builtin_tensor_pow float-producing - - eigs_num_arg,make_num,num_guard_named ppu_render_frame builtin_ppu_render_frame int-requiring - - buffer_read_byte print builtin_print other - - eigs_num_text -proc_read_buf builtin_proc_read_buf int-requiring - - VAL_NUM,eigs_num_arg +proc_read_buf builtin_proc_read_buf int-requiring - - eigs_num_arg random builtin_random float-producing - - make_num -random_hex builtin_random_hex int-requiring - - VAL_NUM,eigs_num_arg +random_hex builtin_random_hex int-requiring - - eigs_num_arg random_int builtin_random_int int-requiring LOSS - eigs_num_arg,make_num random_normal builtin_random_normal float-producing - - eigs_list_num,make_num range builtin_range int-preserving - - eigs_list_num,eigs_num_arg,make_num read_bytes builtin_read_bytes int-preserving - - make_num -read_bytes_buf builtin_read_bytes_buf int-requiring - - VAL_NUM,eigs_num_arg,make_num +read_bytes_buf builtin_read_bytes_buf int-requiring - - eigs_num_arg,make_num record_history builtin_record_history other - - eigs_num_arg,make_num recv builtin_recv int-requiring - - eigs_num_arg recv_timeout builtin_recv_timeout int-requiring - magnitude eigs_num_arg @@ -499,8 +499,8 @@ store_query builtin_store_query other store_update builtin_store_update other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val str builtin_str other - - eigs_num_text str_from_bytes builtin_str_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte -stream_open builtin_stream_open int-requiring - - VAL_NUM,eigs_num_arg -stream_write builtin_stream_write float-producing - - VAL_NUM,eigs_num_arg +stream_open builtin_stream_open int-requiring - - eigs_num_arg +stream_write builtin_stream_write float-producing - - eigs_num_arg substr builtin_substr int-requiring - - eigs_num_arg subtract builtin_tensor_subtract int-preserving LOSS - eigs_num_arg,make_num,num_guard sum builtin_tensor_sum int-preserving LOSS - buffer_read_num,eigs_num_arg,make_num,num_guard @@ -526,7 +526,7 @@ type builtin_type other usleep builtin_usleep other - magnitude eigs_num_arg vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg write builtin_write other - - eigs_num_text -write_bytes builtin_write_bytes int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +write_bytes builtin_write_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num zeros builtin_tensor_zeros int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num zeros_like builtin_tensor_zeros_like float-producing - - make_num @@ -900,16 +900,13 @@ builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c builtins_buf.c:925 builtin_buf_resample_linear num_guard GUARD c -builtins_host.c:218 builtin_stream_open VAL_NUM TEST a builtins_host.c:220 builtin_stream_open eigs_num_arg READ b builtins_host.c:221 builtin_stream_open eigs_num_arg READ b builtins_host.c:222 builtin_stream_open eigs_num_arg READ b builtins_host.c:222 builtin_stream_open eigs_num_arg READ b builtins_host.c:225 builtin_stream_open eigs_num_arg READ b builtins_host.c:236 builtin_stream_open eigs_num_arg READ b -builtins_host.c:255 builtin_stream_write VAL_NUM TEST a builtins_host.c:260 builtin_stream_write eigs_num_arg READ b -builtins_host.c:413 builtin_build_corpus VAL_NUM TEST a builtins_host.c:417 builtin_build_corpus eigs_num_arg READ b builtins_host.c:449 builtin_build_corpus eigs_opt_num READ b builtins_host.c:478 builtin_build_corpus eigs_opt_num READ b @@ -918,30 +915,26 @@ builtins_host.c:808 builtin_build_corpus make_num PRODUCE c builtins_host.c:809 builtin_build_corpus make_num PRODUCE c builtins_host.c:810 builtin_build_corpus make_num PRODUCE c builtins_host.c:1055 builtin_read_bytes make_num PRODUCE c -builtins_host.c:1106 builtin_read_bytes_buf VAL_NUM TEST a builtins_host.c:1110 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1111 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1114 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1117 builtin_read_bytes_buf eigs_num_arg READ b -builtins_host.c:1131 builtin_read_bytes_buf VAL_NUM TEST a builtins_host.c:1132 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1152 builtin_read_bytes_buf make_num PRODUCE c builtins_host.c:1263 exec_capture_result list_append_num PRODUCE c -builtins_host.c:1290 builtin_exec_capture VAL_NUM TEST a +builtins_host.c:1290 builtin_exec_capture VAL_FLOAT TEST a +builtins_host.c:1290 builtin_exec_capture VAL_INT TEST a builtins_host.c:1292 builtin_exec_capture eigs_list_num READ b -builtins_host.c:1441 builtin_proc_read_buf VAL_NUM TEST a -builtins_host.c:1441 builtin_proc_read_buf VAL_NUM TEST a builtins_host.c:1443 builtin_proc_read_buf eigs_num_arg READ b builtins_host.c:1444 builtin_proc_read_buf eigs_num_arg READ b -builtins_host.c:1475 builtin_random_hex VAL_NUM TEST a -builtins_host.c:1476 builtin_random_hex VAL_NUM TEST a builtins_host.c:1476 builtin_random_hex eigs_num_arg READ b builtins_host.c:1502 builtin_write_bytes make_num PRODUCE c builtins_host.c:1508 builtin_write_bytes make_num PRODUCE c builtins_host.c:1516 builtin_write_bytes eigs_num_arg READ b builtins_host.c:1517 builtin_write_bytes make_num PRODUCE c builtins_host.c:1530 builtin_write_bytes make_num PRODUCE c -builtins_host.c:1540 builtin_write_bytes VAL_NUM TEST a +builtins_host.c:1540 builtin_write_bytes VAL_FLOAT TEST a +builtins_host.c:1540 builtin_write_bytes VAL_INT TEST a builtins_host.c:1547 builtin_write_bytes eigs_slot_elem_num READ b builtins_host.c:1548 builtin_write_bytes buffer_read_num READ b builtins_host.c:1550 builtin_write_bytes finite_num_to_byte READ b diff --git a/src/builtins_host.c b/src/builtins_host.c index d4e2a9a38..42f942f39 100644 --- a/src/builtins_host.c +++ b/src/builtins_host.c @@ -215,7 +215,7 @@ Value* builtin_stream_open(Value *arg) { Value *path_val = list_get_view(arg, 0, &path_val_view); EIGS_VIEW(count_val_view); Value *count_val = list_get_view(arg, 1, &count_val_view); - ARG_GUARD(!path_val || path_val->type != VAL_STR || !count_val || count_val->type != VAL_NUM, + ARG_GUARD(!path_val || path_val->type != VAL_STR || !count_val || !val_is_number(count_val), "stream_open", "[a string path, a number count]", make_bool(0)); if (eigs_num_arg(count_val, __func__) < 1 || eigs_num_arg(count_val, __func__) > EIGS_TENSOR_MAX_ELEMENTS || @@ -252,7 +252,7 @@ Value* builtin_stream_write(Value *arg) { * state, and strict must not report it as a type error. Both halves still * answer make_bool(0) with strict off, in either order, so the non-strict * result is unchanged. */ - ARG_GUARD(!arg || arg->type != VAL_NUM, "stream_write", "a number", make_bool(0)); + ARG_GUARD(!arg || !val_is_number(arg), "stream_write", "a number", make_bool(0)); /* fs:ANSWER no stream is open — the state, not the argument (which the * guard above already accepted); 0 is the failure bit paired with the * make_bool(1) success value below. */ @@ -410,7 +410,7 @@ Value* builtin_build_corpus(Value *arg) { if (!file_list || file_list->type != VAL_LIST) return make_null(); BOOL_REFUSE(topn_val, "build_corpus"); - if (!topn_val || topn_val->type != VAL_NUM) return make_null(); + if (!topn_val || !val_is_number(topn_val)) return make_null(); if (!stream_path_val || stream_path_val->type != VAL_STR) return make_null(); if (!vocab_path_val || vocab_path_val->type != VAL_STR) return make_null(); @@ -1103,7 +1103,7 @@ Value* builtin_read_bytes_buf(Value *arg) { if (arg->data.list.count >= 2) { EIGS_VIEW(mv_view); Value *mv = list_get_view(arg, 1, &mv_view); - if (!mv || mv->type != VAL_NUM) { + if (!mv || !val_is_number(mv)) { rt_error(EK_VALUE, 0, "read_bytes_buf: max_bytes must be a number"); return make_null(); } @@ -1121,14 +1121,14 @@ Value* builtin_read_bytes_buf(Value *arg) { /* Tape boundary. Success records the VAL_BUFFER; unopenable file * records null; the over-cap raise records the observed SIZE as a - * VAL_NUM N record (unambiguous — no other path records a number) so + * VAL_FLOAT N record (unambiguous — no other path records a number) so * the identical raise is re-derived under EIGS_REPLAY without * touching the live filesystem. */ if (__builtin_expect(g_replay_enabled, 0)) { Value *tv; if (trace_replay_refuse_off_owner("read_bytes_buf")) return make_null(); if (trace_replay_take("read_bytes_buf", &tv)) { - if (tv && tv->type == VAL_NUM) { + if (tv && val_is_number(tv)) { long long len = (long long)eigs_num_arg(tv, __func__); val_decref(tv); read_bytes_buf_cap_raise(path->data.str, len, cap); @@ -1287,7 +1287,7 @@ Value* builtin_exec_capture(Value *arg) { Value *cmd_list = arg; if (arg->data.list.count == 2 && list_elem_type(arg, 0) == VAL_LIST - && list_elem_type(arg, 1) == VAL_NUM) { + && (list_elem_type(arg, 1) == VAL_FLOAT || list_elem_type(arg, 1) == VAL_INT)) { cmd_list = list_get_ref(arg, 0); timeout_sec = eigs_list_num(arg, 1, __func__); ARG_GUARD(cmd_list->data.list.count < 1, @@ -1438,7 +1438,7 @@ Value* builtin_proc_read_buf(Value *arg) { Value *fd_v = list_get_view(arg, 0, &fd_v_view); EIGS_VIEW(max_v_view); Value *max_v = list_get_view(arg, 1, &max_v_view); - if (!fd_v || fd_v->type != VAL_NUM || !max_v || max_v->type != VAL_NUM) + if (!fd_v || !val_is_number(fd_v) || !max_v || !val_is_number(max_v)) return make_null(); int fd = (int)eigs_num_arg(fd_v, __func__); int max = (int)eigs_num_arg(max_v, __func__); @@ -1472,8 +1472,8 @@ Value* builtin_proc_read_buf(Value *arg) { Value* builtin_random_hex(Value *arg) { /* #971 Phase D: a non-number length answered "" (as does a length of 0, * which stays the answer). Taped: the soft half records as before. */ - ARG_GUARD_TAPED(!arg || arg->type != VAL_NUM, "random_hex", "a number of hex digits", make_str("")); - int n = (arg && arg->type == VAL_NUM) ? (int)eigs_num_arg(arg, __func__) : 0; + ARG_GUARD_TAPED(!arg || !val_is_number(arg), "random_hex", "a number of hex digits", make_str("")); + int n = (arg && val_is_number(arg)) ? (int)eigs_num_arg(arg, __func__) : 0; if (n <= 0 || n > 256) TRACE_NONDET_RET("random_hex", make_str("")); int bytes_needed = (n + 1) / 2; unsigned char raw[128]; @@ -1537,7 +1537,7 @@ Value* builtin_write_bytes(Value *arg) { * two zero bytes and reported success. Same class as join/str_replace * — no stand-in return, so invisible to the classifier. The free() * matters: STRICT_REQUIRE returns, and `out` is already allocated. */ - if (data->type == VAL_LIST && list_elem_type(data, i) != VAL_NUM + if (data->type == VAL_LIST && (list_elem_type(data, i) != VAL_FLOAT && list_elem_type(data, i) != VAL_INT) && (g_strict || list_elem_type(data, i) == VAL_BOOL)) { /* #1637: a bool in every mode */ free(out); rt_error(EK_TYPE, 0, "write_bytes: expected every element to be a number"); From 2fb9b5e20832d5ab76777699592fe9bb6057bd56 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 05:52:19 -0500 Subject: [PATCH 029/188] phase2 R1.2h: migrate gfx and audio Value number sites (#1758) Migrate 56 deprecated code-token sites (59 matching lines). All numeric inputs keep the double bridge; Q7 semantics remain for R1.6. The audio test's shared run policy now pins SDL_AUDIODRIVER=dummy. Reproduced disk output with strace: test_audio.eigs opened sdlaudio.raw four times. The policy overrides inherited SDL_AUDIODRIVER=disk: 53/53 checks and mixer checks pass, with no source-tree output. Removed the untracked src/sdlaudio.raw artifact. Validation: make built; inventory PASS, unclassified=0 missing=0 stale=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-value-gfx.md | 1 + docs/design/phase2-inventory.txt | 230 +++++++++++++--------- src/ext_gfx.c | 118 +++++------ tests/suite_program_env.txt | 2 +- 4 files changed, 196 insertions(+), 155 deletions(-) create mode 100644 changes/internal/1758-phase2-value-gfx.md diff --git a/changes/internal/1758-phase2-value-gfx.md b/changes/internal/1758-phase2-value-gfx.md new file mode 100644 index 000000000..9f8cbb7b1 --- /dev/null +++ b/changes/internal/1758-phase2-value-gfx.md @@ -0,0 +1 @@ +Prepare graphics and audio numeric guards to admit ints through the unchanged bridge. Pin the audio corpus program to SDL's dummy driver so inherited disk audio settings cannot create sdlaudio.raw in the source tree. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index a16fc0213..419d12775 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,10 +1,10 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1813 classified=1813 unclassified=0 +examined=1853 classified=1853 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 340 CASE=60 DATA=5 TEST=273 YIELD=2 +(a) type tests 380 CASE=60 DATA=5 TEST=313 YIELD=2 (b) payload reads 554 RAW=137 READ=417 (c) producers 472 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=4 WRITE=22 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 @@ -18,12 +18,12 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per token make_num 364 eigs_num_arg 151 -VAL_NUM 138 eigs_list_num 130 +VAL_INT 121 +VAL_FLOAT 117 SLOT_F64_RAW 83 -VAL_INT 73 +VAL_NUM 82 VAL_NUM_RAW 70 -VAL_FLOAT 69 num_guard 60 AST_NUM 52 eigs_slot_num 50 @@ -72,8 +72,8 @@ data.num (AST) 7 ## Per file (category counts) vm.c 299 a=78 b=97 c=68 e=2 f=9 i=45 +ext_gfx.c 290 a=96 b=124 c=70 builtins.c 267 a=11 b=103 c=111 e=3 f=11 h=19 i=9 -ext_gfx.c 250 a=56 b=124 c=70 builtins_tensor.c 177 a=32 b=59 c=86 eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 builtins_buf.c 102 a=26 b=37 c=39 @@ -307,27 +307,27 @@ asin builtin_asin float-producing assert builtin_assert other - - eigs_num_text atan builtin_atan float-producing - - eigs_num_arg,make_num atan2 builtin_atan2 float-producing - - eigs_num_arg,make_num -audio_capture_open builtin_audio_capture_open int-requiring - - VAL_NUM,eigs_list_num,make_num -audio_envelope builtin_audio_envelope float-producing - magnitude VAL_NUM,eigs_list_num,eigs_slot_num,make_num -audio_gain builtin_audio_gain float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num -audio_mix builtin_audio_mix float-producing - - VAL_NUM,eigs_slot_num,make_num -audio_music_play builtin_audio_music_play int-requiring - - VAL_NUM,eigs_list_num -audio_music_volume builtin_audio_music_volume other - bounded VAL_NUM,eigs_list_num,eigs_num_arg -audio_noise builtin_audio_noise float-producing - magnitude VAL_NUM,eigs_list_num,make_num -audio_open builtin_audio_open int-requiring - - VAL_NUM,eigs_list_num,make_num -audio_pause builtin_audio_pause int-requiring - - VAL_NUM,eigs_num_arg -audio_play builtin_audio_play other - bounded VAL_NUM,buffer_read_num,eigs_slot_num,make_num -audio_play_loop builtin_audio_play_loop int-requiring - bounded VAL_NUM,buffer_read_num,eigs_list_num,eigs_slot_num,make_num +audio_capture_open builtin_audio_capture_open int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_envelope builtin_audio_envelope float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,eigs_slot_num,make_num +audio_gain builtin_audio_gain float-producing - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_slot_num,make_num +audio_mix builtin_audio_mix float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num +audio_music_play builtin_audio_music_play int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num +audio_music_volume builtin_audio_music_volume other - bounded VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg +audio_noise builtin_audio_noise float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_open builtin_audio_open int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_pause builtin_audio_pause int-requiring - - eigs_num_arg +audio_play builtin_audio_play other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,make_num +audio_play_loop builtin_audio_play_loop int-requiring - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_list_num,eigs_slot_num,make_num audio_queue_size builtin_audio_queue_size int-preserving - - make_num -audio_saw builtin_audio_saw float-producing - magnitude VAL_NUM,eigs_list_num,make_num -audio_sine builtin_audio_sine float-producing - magnitude VAL_NUM,eigs_list_num,make_num -audio_square builtin_audio_square float-producing - magnitude VAL_NUM,eigs_list_num,make_num -audio_stop builtin_audio_stop int-requiring - - VAL_NUM,eigs_num_arg,make_num -audio_stream_open builtin_audio_stream_open int-requiring - - VAL_NUM,eigs_list_num,make_num -audio_stream_push builtin_audio_stream_push other - bounded VAL_NUM,buffer_read_num,eigs_slot_num +audio_saw builtin_audio_saw float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_sine builtin_audio_sine float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_square builtin_audio_square float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_stop builtin_audio_stop int-requiring - - eigs_num_arg,make_num +audio_stream_open builtin_audio_stream_open int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_stream_push builtin_audio_stream_push other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num audio_stream_queued builtin_audio_stream_queued int-preserving - - make_num -audio_sweep builtin_audio_sweep float-producing - magnitude VAL_NUM,eigs_list_num,make_num -audio_volume builtin_audio_volume int-requiring - bounded VAL_NUM,eigs_slot_num,make_num +audio_sweep builtin_audio_sweep float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num +audio_volume builtin_audio_volume int-requiring - bounded VAL_FLOAT,VAL_INT,eigs_slot_num,make_num bit_and builtin_bit_and int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact bit_not builtin_bit_not int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact bit_or builtin_bit_or int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact @@ -378,21 +378,21 @@ floor builtin_floor int-preserving gather builtin_tensor_gather int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num get_at builtin_get_at int-requiring - - buffer_read_num,eigs_num_arg,make_num get_observer_thresholds builtin_get_observer_thresholds float-producing - - make_num -gfx_circle builtin_gfx_circle other - geometry,bounded VAL_NUM,eigs_list_num -gfx_clear builtin_gfx_clear other - bounded VAL_NUM,eigs_list_num -gfx_clip builtin_gfx_clip other - geometry VAL_NUM,eigs_list_num -gfx_delay builtin_gfx_delay other - magnitude VAL_NUM,eigs_num_arg -gfx_fb builtin_gfx_fb int-requiring - geometry VAL_NUM,buffer_read_byte,eigs_list_num -gfx_line builtin_gfx_line other - geometry,bounded VAL_NUM,eigs_list_num -gfx_open builtin_gfx_open other - magnitude VAL_NUM,eigs_list_num -gfx_point builtin_gfx_point other - geometry,bounded VAL_NUM,eigs_list_num +gfx_circle builtin_gfx_circle other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num +gfx_clear builtin_gfx_clear other - bounded VAL_FLOAT,VAL_INT,eigs_list_num +gfx_clip builtin_gfx_clip other - geometry VAL_FLOAT,VAL_INT,eigs_list_num +gfx_delay builtin_gfx_delay other - magnitude eigs_num_arg +gfx_fb builtin_gfx_fb int-requiring - geometry VAL_FLOAT,VAL_INT,buffer_read_byte,eigs_list_num +gfx_line builtin_gfx_line other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num +gfx_open builtin_gfx_open other - magnitude VAL_FLOAT,VAL_INT,eigs_list_num +gfx_point builtin_gfx_point other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num gfx_poll builtin_gfx_poll int-preserving - - make_num -gfx_read builtin_gfx_read other - geometry VAL_NUM,eigs_list_num,make_num -gfx_rect builtin_gfx_rect other - geometry,bounded VAL_NUM,eigs_list_num -gfx_rrect builtin_gfx_rrect other - geometry,bounded VAL_NUM,eigs_list_num -gfx_text builtin_gfx_text other - geometry,bounded VAL_NUM,eigs_list_num -gfx_text_height builtin_gfx_text_height int-preserving - magnitude VAL_NUM,eigs_list_num,eigs_num_arg,make_num -gfx_text_width builtin_gfx_text_width int-preserving - magnitude VAL_NUM,eigs_list_num,make_num +gfx_read builtin_gfx_read other - geometry VAL_FLOAT,VAL_INT,eigs_list_num,make_num +gfx_rect builtin_gfx_rect other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num +gfx_rrect builtin_gfx_rrect other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num +gfx_text builtin_gfx_text other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num +gfx_text_height builtin_gfx_text_height int-preserving - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num +gfx_text_width builtin_gfx_text_width int-preserving - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num gfx_ticks builtin_gfx_ticks int-preserving - - make_num hex builtin_hex int-requiring LOSS - eigs_list_num,eigs_num_arg http_early_bind builtin_http_early_bind int-requiring - - VAL_NUM,eigs_opt_num @@ -1468,10 +1468,14 @@ ext_db.c:57 db_build_query VAL_NUM TEST h ext_db.c:58 db_build_query eigs_num_arg READ h ext_db.c:310 builtin_db_query_value make_num PRODUCE h ext_db.c:310 builtin_db_query_value strtod PARSE h -ext_gfx.c:407 gfx_nums VAL_NUM TEST a -ext_gfx.c:420 gfx_list_all_num VAL_NUM TEST a -ext_gfx.c:455 builtin_gfx_open VAL_NUM TEST a -ext_gfx.c:456 builtin_gfx_open VAL_NUM TEST a +ext_gfx.c:407 gfx_nums VAL_FLOAT TEST a +ext_gfx.c:407 gfx_nums VAL_INT TEST a +ext_gfx.c:420 gfx_list_all_num VAL_FLOAT TEST a +ext_gfx.c:420 gfx_list_all_num VAL_INT TEST a +ext_gfx.c:455 builtin_gfx_open VAL_FLOAT TEST a +ext_gfx.c:455 builtin_gfx_open VAL_INT TEST a +ext_gfx.c:456 builtin_gfx_open VAL_FLOAT TEST a +ext_gfx.c:456 builtin_gfx_open VAL_INT TEST a ext_gfx.c:458 builtin_gfx_open eigs_list_num READ b ext_gfx.c:459 builtin_gfx_open eigs_list_num READ b ext_gfx.c:529 builtin_gfx_clear eigs_list_num READ b @@ -1539,7 +1543,6 @@ ext_gfx.c:819 builtin_gfx_poll make_num PRODUCE c ext_gfx.c:827 builtin_gfx_poll make_num PRODUCE c ext_gfx.c:828 builtin_gfx_poll make_num PRODUCE c ext_gfx.c:848 builtin_gfx_ticks make_num PRODUCE c -ext_gfx.c:853 builtin_gfx_delay VAL_NUM TEST a ext_gfx.c:855 builtin_gfx_delay eigs_num_arg READ b ext_gfx.c:1003 builtin_gfx_text eigs_list_num READ b ext_gfx.c:1004 builtin_gfx_text eigs_list_num READ b @@ -1547,24 +1550,28 @@ ext_gfx.c:1006 builtin_gfx_text eigs_list_num READ b ext_gfx.c:1007 builtin_gfx_text eigs_list_num READ b ext_gfx.c:1008 builtin_gfx_text eigs_list_num READ b ext_gfx.c:1009 builtin_gfx_text eigs_list_num READ b -ext_gfx.c:1075 builtin_gfx_text_width VAL_NUM TEST a +ext_gfx.c:1075 builtin_gfx_text_width VAL_FLOAT TEST a +ext_gfx.c:1075 builtin_gfx_text_width VAL_INT TEST a ext_gfx.c:1076 builtin_gfx_text_width eigs_list_num READ b ext_gfx.c:1084 builtin_gfx_text_width make_num PRODUCE c ext_gfx.c:1094 builtin_gfx_text_width make_num PRODUCE c ext_gfx.c:1096 builtin_gfx_text_width make_num PRODUCE c -ext_gfx.c:1109 builtin_gfx_text_height VAL_NUM TEST a -ext_gfx.c:1111 builtin_gfx_text_height VAL_NUM TEST a -ext_gfx.c:1113 builtin_gfx_text_height VAL_NUM TEST a +ext_gfx.c:1111 builtin_gfx_text_height VAL_FLOAT TEST a +ext_gfx.c:1111 builtin_gfx_text_height VAL_INT TEST a ext_gfx.c:1114 builtin_gfx_text_height eigs_num_arg READ b -ext_gfx.c:1116 builtin_gfx_text_height VAL_NUM TEST a +ext_gfx.c:1116 builtin_gfx_text_height VAL_FLOAT TEST a +ext_gfx.c:1116 builtin_gfx_text_height VAL_INT TEST a ext_gfx.c:1117 builtin_gfx_text_height eigs_list_num READ b ext_gfx.c:1122 builtin_gfx_text_height make_num PRODUCE c ext_gfx.c:1124 builtin_gfx_text_height make_num PRODUCE c ext_gfx.c:1189 audio_convert_samples buffer_read_num READ b -ext_gfx.c:1209 audio_convert_samples VAL_NUM TEST a +ext_gfx.c:1209 audio_convert_samples VAL_FLOAT TEST a +ext_gfx.c:1209 audio_convert_samples VAL_INT TEST a ext_gfx.c:1226 audio_convert_samples eigs_slot_num READ b -ext_gfx.c:1314 builtin_audio_open VAL_NUM TEST a -ext_gfx.c:1315 builtin_audio_open VAL_NUM TEST a +ext_gfx.c:1314 builtin_audio_open VAL_FLOAT TEST a +ext_gfx.c:1314 builtin_audio_open VAL_INT TEST a +ext_gfx.c:1315 builtin_audio_open VAL_FLOAT TEST a +ext_gfx.c:1315 builtin_audio_open VAL_INT TEST a ext_gfx.c:1316 builtin_audio_open make_num PRODUCE c ext_gfx.c:1318 builtin_audio_open make_num PRODUCE c ext_gfx.c:1321 builtin_audio_open make_num PRODUCE c @@ -1572,11 +1579,11 @@ ext_gfx.c:1334 builtin_audio_open eigs_list_num READ b ext_gfx.c:1335 builtin_audio_open eigs_list_num READ b ext_gfx.c:1339 builtin_audio_open make_num PRODUCE c ext_gfx.c:1343 builtin_audio_open make_num PRODUCE c -ext_gfx.c:1362 builtin_audio_pause VAL_NUM TEST a -ext_gfx.c:1365 builtin_audio_pause VAL_NUM TEST a ext_gfx.c:1365 builtin_audio_pause eigs_num_arg READ b -ext_gfx.c:1457 builtin_audio_capture_open VAL_NUM TEST a -ext_gfx.c:1458 builtin_audio_capture_open VAL_NUM TEST a +ext_gfx.c:1457 builtin_audio_capture_open VAL_FLOAT TEST a +ext_gfx.c:1457 builtin_audio_capture_open VAL_INT TEST a +ext_gfx.c:1458 builtin_audio_capture_open VAL_FLOAT TEST a +ext_gfx.c:1458 builtin_audio_capture_open VAL_INT TEST a ext_gfx.c:1459 builtin_audio_capture_open make_num PRODUCE c ext_gfx.c:1463 builtin_audio_capture_open make_num PRODUCE c ext_gfx.c:1467 builtin_audio_capture_open make_num PRODUCE c @@ -1584,33 +1591,40 @@ ext_gfx.c:1480 builtin_audio_capture_open eigs_list_num READ b ext_gfx.c:1481 builtin_audio_capture_open eigs_list_num READ b ext_gfx.c:1491 builtin_audio_capture_open make_num PRODUCE c ext_gfx.c:1494 builtin_audio_capture_open make_num PRODUCE c -ext_gfx.c:1586 builtin_audio_stream_open VAL_NUM TEST a -ext_gfx.c:1587 builtin_audio_stream_open VAL_NUM TEST a +ext_gfx.c:1586 builtin_audio_stream_open VAL_FLOAT TEST a +ext_gfx.c:1586 builtin_audio_stream_open VAL_INT TEST a +ext_gfx.c:1587 builtin_audio_stream_open VAL_FLOAT TEST a +ext_gfx.c:1587 builtin_audio_stream_open VAL_INT TEST a ext_gfx.c:1588 builtin_audio_stream_open make_num PRODUCE c ext_gfx.c:1590 builtin_audio_stream_open make_num PRODUCE c ext_gfx.c:1593 builtin_audio_stream_open make_num PRODUCE c -ext_gfx.c:1605 builtin_audio_stream_open VAL_NUM TEST a -ext_gfx.c:1606 builtin_audio_stream_open VAL_NUM TEST a +ext_gfx.c:1605 builtin_audio_stream_open VAL_FLOAT TEST a +ext_gfx.c:1605 builtin_audio_stream_open VAL_INT TEST a +ext_gfx.c:1606 builtin_audio_stream_open VAL_FLOAT TEST a +ext_gfx.c:1606 builtin_audio_stream_open VAL_INT TEST a ext_gfx.c:1607 builtin_audio_stream_open eigs_list_num READ b ext_gfx.c:1608 builtin_audio_stream_open eigs_list_num READ b ext_gfx.c:1616 builtin_audio_stream_open make_num PRODUCE c ext_gfx.c:1620 builtin_audio_stream_open make_num PRODUCE c ext_gfx.c:1664 builtin_audio_stream_queued make_num PRODUCE c ext_gfx.c:1667 builtin_audio_stream_queued make_num PRODUCE c -ext_gfx.c:1703 builtin_audio_music_play VAL_NUM TEST a -ext_gfx.c:1706 builtin_audio_music_play VAL_NUM TEST a +ext_gfx.c:1703 builtin_audio_music_play VAL_FLOAT TEST a +ext_gfx.c:1703 builtin_audio_music_play VAL_INT TEST a +ext_gfx.c:1706 builtin_audio_music_play VAL_FLOAT TEST a +ext_gfx.c:1706 builtin_audio_music_play VAL_INT TEST a ext_gfx.c:1707 builtin_audio_music_play eigs_list_num READ b -ext_gfx.c:1742 builtin_audio_music_volume VAL_NUM TEST a -ext_gfx.c:1744 builtin_audio_music_volume VAL_NUM TEST a -ext_gfx.c:1748 builtin_audio_music_volume VAL_NUM TEST a +ext_gfx.c:1744 builtin_audio_music_volume VAL_FLOAT TEST a +ext_gfx.c:1744 builtin_audio_music_volume VAL_INT TEST a ext_gfx.c:1748 builtin_audio_music_volume eigs_num_arg READ b -ext_gfx.c:1750 builtin_audio_music_volume VAL_NUM TEST a +ext_gfx.c:1750 builtin_audio_music_volume VAL_FLOAT TEST a +ext_gfx.c:1750 builtin_audio_music_volume VAL_INT TEST a ext_gfx.c:1751 builtin_audio_music_volume eigs_list_num READ b ext_gfx.c:1774 builtin_audio_play make_num PRODUCE c ext_gfx.c:1779 builtin_audio_play make_num PRODUCE c ext_gfx.c:1781 builtin_audio_play make_num PRODUCE c ext_gfx.c:1783 builtin_audio_play make_num PRODUCE c -ext_gfx.c:1797 builtin_audio_play_loop VAL_NUM TEST a +ext_gfx.c:1797 builtin_audio_play_loop VAL_FLOAT TEST a +ext_gfx.c:1797 builtin_audio_play_loop VAL_INT TEST a ext_gfx.c:1798 builtin_audio_play_loop make_num PRODUCE c ext_gfx.c:1800 builtin_audio_play_loop eigs_list_num READ b ext_gfx.c:1807 builtin_audio_play_loop make_num PRODUCE c @@ -1618,15 +1632,16 @@ ext_gfx.c:1820 builtin_audio_play_loop make_num PRODUCE c ext_gfx.c:1825 builtin_audio_play_loop make_num PRODUCE c ext_gfx.c:1827 builtin_audio_play_loop make_num PRODUCE c ext_gfx.c:1829 builtin_audio_play_loop make_num PRODUCE c -ext_gfx.c:1838 builtin_audio_volume VAL_NUM TEST a -ext_gfx.c:1839 builtin_audio_volume VAL_NUM TEST a +ext_gfx.c:1838 builtin_audio_volume VAL_FLOAT TEST a +ext_gfx.c:1838 builtin_audio_volume VAL_INT TEST a +ext_gfx.c:1839 builtin_audio_volume VAL_FLOAT TEST a +ext_gfx.c:1839 builtin_audio_volume VAL_INT TEST a ext_gfx.c:1840 builtin_audio_volume make_num PRODUCE c ext_gfx.c:1841 builtin_audio_volume make_num PRODUCE c ext_gfx.c:1842 builtin_audio_volume eigs_slot_num READ b ext_gfx.c:1843 builtin_audio_volume make_num PRODUCE c ext_gfx.c:1844 builtin_audio_volume eigs_slot_num READ b ext_gfx.c:1851 builtin_audio_volume make_num PRODUCE c -ext_gfx.c:1858 builtin_audio_stop VAL_NUM TEST a ext_gfx.c:1859 builtin_audio_stop make_num PRODUCE c ext_gfx.c:1860 builtin_audio_stop make_num PRODUCE c ext_gfx.c:1861 builtin_audio_stop eigs_num_arg READ b @@ -1634,62 +1649,87 @@ ext_gfx.c:1862 builtin_audio_stop make_num PRODUCE c ext_gfx.c:1867 builtin_audio_stop make_num PRODUCE c ext_gfx.c:1873 builtin_audio_queue_size make_num PRODUCE c ext_gfx.c:1887 builtin_audio_queue_size make_num PRODUCE c -ext_gfx.c:1920 builtin_audio_sine VAL_NUM TEST a -ext_gfx.c:1921 builtin_audio_sine VAL_NUM TEST a -ext_gfx.c:1922 builtin_audio_sine VAL_NUM TEST a +ext_gfx.c:1920 builtin_audio_sine VAL_FLOAT TEST a +ext_gfx.c:1920 builtin_audio_sine VAL_INT TEST a +ext_gfx.c:1921 builtin_audio_sine VAL_FLOAT TEST a +ext_gfx.c:1921 builtin_audio_sine VAL_INT TEST a +ext_gfx.c:1922 builtin_audio_sine VAL_FLOAT TEST a +ext_gfx.c:1922 builtin_audio_sine VAL_INT TEST a ext_gfx.c:1924 builtin_audio_sine eigs_list_num READ b ext_gfx.c:1925 builtin_audio_sine eigs_list_num READ b ext_gfx.c:1926 builtin_audio_sine eigs_list_num READ b ext_gfx.c:1935 builtin_audio_sine make_num PRODUCE c -ext_gfx.c:1955 builtin_audio_saw VAL_NUM TEST a -ext_gfx.c:1956 builtin_audio_saw VAL_NUM TEST a -ext_gfx.c:1957 builtin_audio_saw VAL_NUM TEST a +ext_gfx.c:1955 builtin_audio_saw VAL_FLOAT TEST a +ext_gfx.c:1955 builtin_audio_saw VAL_INT TEST a +ext_gfx.c:1956 builtin_audio_saw VAL_FLOAT TEST a +ext_gfx.c:1956 builtin_audio_saw VAL_INT TEST a +ext_gfx.c:1957 builtin_audio_saw VAL_FLOAT TEST a +ext_gfx.c:1957 builtin_audio_saw VAL_INT TEST a ext_gfx.c:1959 builtin_audio_saw eigs_list_num READ b ext_gfx.c:1960 builtin_audio_saw eigs_list_num READ b ext_gfx.c:1961 builtin_audio_saw eigs_list_num READ b ext_gfx.c:1970 builtin_audio_saw make_num PRODUCE c -ext_gfx.c:1990 builtin_audio_square VAL_NUM TEST a -ext_gfx.c:1991 builtin_audio_square VAL_NUM TEST a -ext_gfx.c:1992 builtin_audio_square VAL_NUM TEST a +ext_gfx.c:1990 builtin_audio_square VAL_FLOAT TEST a +ext_gfx.c:1990 builtin_audio_square VAL_INT TEST a +ext_gfx.c:1991 builtin_audio_square VAL_FLOAT TEST a +ext_gfx.c:1991 builtin_audio_square VAL_INT TEST a +ext_gfx.c:1992 builtin_audio_square VAL_FLOAT TEST a +ext_gfx.c:1992 builtin_audio_square VAL_INT TEST a ext_gfx.c:1994 builtin_audio_square eigs_list_num READ b ext_gfx.c:1995 builtin_audio_square eigs_list_num READ b ext_gfx.c:1996 builtin_audio_square eigs_list_num READ b ext_gfx.c:2005 builtin_audio_square make_num PRODUCE c -ext_gfx.c:2026 builtin_audio_sweep VAL_NUM TEST a -ext_gfx.c:2027 builtin_audio_sweep VAL_NUM TEST a -ext_gfx.c:2028 builtin_audio_sweep VAL_NUM TEST a -ext_gfx.c:2029 builtin_audio_sweep VAL_NUM TEST a -ext_gfx.c:2030 builtin_audio_sweep VAL_NUM TEST a +ext_gfx.c:2026 builtin_audio_sweep VAL_FLOAT TEST a +ext_gfx.c:2026 builtin_audio_sweep VAL_INT TEST a +ext_gfx.c:2027 builtin_audio_sweep VAL_FLOAT TEST a +ext_gfx.c:2027 builtin_audio_sweep VAL_INT TEST a +ext_gfx.c:2028 builtin_audio_sweep VAL_FLOAT TEST a +ext_gfx.c:2028 builtin_audio_sweep VAL_INT TEST a +ext_gfx.c:2029 builtin_audio_sweep VAL_FLOAT TEST a +ext_gfx.c:2029 builtin_audio_sweep VAL_INT TEST a +ext_gfx.c:2030 builtin_audio_sweep VAL_FLOAT TEST a +ext_gfx.c:2030 builtin_audio_sweep VAL_INT TEST a ext_gfx.c:2032 builtin_audio_sweep eigs_list_num READ b ext_gfx.c:2033 builtin_audio_sweep eigs_list_num READ b ext_gfx.c:2034 builtin_audio_sweep eigs_list_num READ b ext_gfx.c:2035 builtin_audio_sweep eigs_list_num READ b ext_gfx.c:2036 builtin_audio_sweep eigs_list_num READ b ext_gfx.c:2053 builtin_audio_sweep make_num PRODUCE c -ext_gfx.c:2073 builtin_audio_noise VAL_NUM TEST a -ext_gfx.c:2074 builtin_audio_noise VAL_NUM TEST a +ext_gfx.c:2073 builtin_audio_noise VAL_FLOAT TEST a +ext_gfx.c:2073 builtin_audio_noise VAL_INT TEST a +ext_gfx.c:2074 builtin_audio_noise VAL_FLOAT TEST a +ext_gfx.c:2074 builtin_audio_noise VAL_INT TEST a ext_gfx.c:2076 builtin_audio_noise eigs_list_num READ b ext_gfx.c:2077 builtin_audio_noise eigs_list_num READ b ext_gfx.c:2085 builtin_audio_noise make_num PRODUCE c -ext_gfx.c:2112 builtin_audio_mix VAL_NUM TEST a +ext_gfx.c:2112 builtin_audio_mix VAL_FLOAT TEST a +ext_gfx.c:2112 builtin_audio_mix VAL_INT TEST a ext_gfx.c:2112 builtin_audio_mix eigs_slot_num READ b -ext_gfx.c:2113 builtin_audio_mix VAL_NUM TEST a +ext_gfx.c:2113 builtin_audio_mix VAL_FLOAT TEST a +ext_gfx.c:2113 builtin_audio_mix VAL_INT TEST a ext_gfx.c:2113 builtin_audio_mix eigs_slot_num READ b ext_gfx.c:2117 builtin_audio_mix make_num PRODUCE c -ext_gfx.c:2143 builtin_audio_gain VAL_NUM TEST a +ext_gfx.c:2143 builtin_audio_gain VAL_FLOAT TEST a +ext_gfx.c:2143 builtin_audio_gain VAL_INT TEST a ext_gfx.c:2145 builtin_audio_gain eigs_list_num READ b -ext_gfx.c:2150 builtin_audio_gain VAL_NUM TEST a +ext_gfx.c:2150 builtin_audio_gain VAL_FLOAT TEST a +ext_gfx.c:2150 builtin_audio_gain VAL_INT TEST a ext_gfx.c:2150 builtin_audio_gain eigs_slot_num READ b ext_gfx.c:2154 builtin_audio_gain make_num PRODUCE c -ext_gfx.c:2174 builtin_audio_envelope VAL_NUM TEST a -ext_gfx.c:2175 builtin_audio_envelope VAL_NUM TEST a -ext_gfx.c:2176 builtin_audio_envelope VAL_NUM TEST a -ext_gfx.c:2177 builtin_audio_envelope VAL_NUM TEST a +ext_gfx.c:2174 builtin_audio_envelope VAL_FLOAT TEST a +ext_gfx.c:2174 builtin_audio_envelope VAL_INT TEST a +ext_gfx.c:2175 builtin_audio_envelope VAL_FLOAT TEST a +ext_gfx.c:2175 builtin_audio_envelope VAL_INT TEST a +ext_gfx.c:2176 builtin_audio_envelope VAL_FLOAT TEST a +ext_gfx.c:2176 builtin_audio_envelope VAL_INT TEST a +ext_gfx.c:2177 builtin_audio_envelope VAL_FLOAT TEST a +ext_gfx.c:2177 builtin_audio_envelope VAL_INT TEST a ext_gfx.c:2188 builtin_audio_envelope eigs_list_num READ b ext_gfx.c:2189 builtin_audio_envelope eigs_list_num READ b ext_gfx.c:2190 builtin_audio_envelope eigs_list_num READ b ext_gfx.c:2191 builtin_audio_envelope eigs_list_num READ b -ext_gfx.c:2220 builtin_audio_envelope VAL_NUM TEST a +ext_gfx.c:2220 builtin_audio_envelope VAL_FLOAT TEST a +ext_gfx.c:2220 builtin_audio_envelope VAL_INT TEST a ext_gfx.c:2220 builtin_audio_envelope eigs_slot_num READ b ext_gfx.c:2222 builtin_audio_envelope make_num PRODUCE c ext_gfx.c:2244 builtin_gfx_fb eigs_list_num READ b diff --git a/src/ext_gfx.c b/src/ext_gfx.c index ef7c936eb..d15c7a7dd 100644 --- a/src/ext_gfx.c +++ b/src/ext_gfx.c @@ -404,7 +404,7 @@ static int gfx_nums(Value *arg, int from, int to) { int cnt = arg->data.list.count; if (to > cnt) to = cnt; for (int i = from; i < to; i++) { - if (list_elem_type(arg, i) != VAL_NUM) return 0; + if ((list_elem_type(arg, i) != VAL_FLOAT && list_elem_type(arg, i) != VAL_INT)) return 0; } return 1; } @@ -417,7 +417,7 @@ static int gfx_nums(Value *arg, int from, int to) { static int gfx_list_all_num(Value *l) { if (!l || l->type != VAL_LIST) return 0; for (int i = 0; i < l->data.list.count; i++) { - if (list_elem_type(l, i) != VAL_NUM) return 0; + if ((list_elem_type(l, i) != VAL_FLOAT && list_elem_type(l, i) != VAL_INT)) return 0; } return 1; } @@ -452,8 +452,8 @@ Value* builtin_gfx_open(Value *arg) { * overlaps `double num` with `char *str`, so gfx_open of ["800","600",t] * reinterpreted a pointer as a double and int-cast it — in practice a * tiny denormal, so the window opened 0x0 and gfx_open answered 1. */ - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "gfx_open", "[number width, number height, title]", make_bool(0)); int w = (int)eigs_list_num(arg, 0, __func__); int h = (int)eigs_list_num(arg, 1, __func__); @@ -850,7 +850,7 @@ Value* builtin_gfx_ticks(Value *arg) { /* gfx_delay of ms */ Value* builtin_gfx_delay(Value *arg) { - ARG_GUARD(!arg || arg->type != VAL_NUM, "gfx_delay", "number milliseconds", + ARG_GUARD(!arg || !val_is_number(arg), "gfx_delay", "number milliseconds", make_null()); if (g_sdl_lib) p_SDL_Delay((Uint32)eigs_num_arg(arg, __func__)); return make_null(); /* fs:VOID gfx_delay answers null on every path -- this is the return value, not a stand-in for a rejected argument */ @@ -979,7 +979,7 @@ Value* builtin_gfx_text(Value *arg) { * * THE OPTIONAL SCALE (slot 6) IS IN THIS GUARD ON PURPOSE, and that is * why gfx_text and gfx_text_width answer a wrong-typed scale - * DIFFERENTLY. gfx_text_width's slot carried `items[1]->type == VAL_NUM` + * DIFFERENTLY. gfx_text_width's slot carried `val_is_number(items[1])` * before #1007, so its wrong-typed scale is a COERCION and keeps * measuring at scale 1 (STRICT_REQUIRE there, byte-identical off the * flag). This one did not: @@ -1072,7 +1072,7 @@ Value* builtin_gfx_text_width(Value *arg) { && list_elem_type(arg, 0) == VAL_STR) { text = list_get_ref(arg, 0)->data.str; if (arg->data.list.count >= 2) { - if (list_elem_type(arg, 1) == VAL_NUM) + if ((list_elem_type(arg, 1) == VAL_FLOAT || list_elem_type(arg, 1) == VAL_INT)) scale = (int)eigs_list_num(arg, 1, __func__); else bad_scale = 1; @@ -1106,14 +1106,14 @@ Value* builtin_gfx_text_height(Value *arg) { * 1 and the caller was told the height it did not ask for. There is no * stand-in to name (the height for scale 1 is still returned), so this * raises under strict and does nothing otherwise. */ - STRICT_REQUIRE(arg && arg->type != VAL_NULL && arg->type != VAL_NUM + STRICT_REQUIRE(arg && arg->type != VAL_NULL && !val_is_number(arg) && !(arg->type == VAL_LIST && arg->data.list.count >= 1 - && list_elem_type(arg, 0) == VAL_NUM), + && (list_elem_type(arg, 0) == VAL_FLOAT || list_elem_type(arg, 0) == VAL_INT)), "gfx_text_height", "number scale, [number scale] or null"); - if (arg && arg->type == VAL_NUM) { + if (arg && val_is_number(arg)) { scale = (int)eigs_num_arg(arg, __func__); } else if (arg && arg->type == VAL_LIST && arg->data.list.count >= 1 - && list_elem_type(arg, 0) == VAL_NUM) { + && (list_elem_type(arg, 0) == VAL_FLOAT || list_elem_type(arg, 0) == VAL_INT)) { scale = (int)eigs_list_num(arg, 0, __func__); } if (scale < 1) scale = 1; @@ -1176,7 +1176,7 @@ static void audio_mix_callback(void *ud, uint8_t *stream, int len) { /* Convert samples (floats -1..1) to an owned int16 buffer. Accepts a * VAL_LIST or a VAL_BUFFER (#578 — the buffer is the type the language * recommends for bulk samples and what a DAW render produces; forcing a - * buffer→list conversion per play meant millions of appends + VAL_NUM + * buffer→list conversion per play meant millions of appends + VAL_FLOAT * allocations just to feed the mixer). Returns NULL on bad shape or an * over-64MB clip. */ static int16_t* audio_convert_samples(Value *samples, int *out_n) { @@ -1206,7 +1206,7 @@ static int16_t* audio_convert_samples(Value *samples, int *out_n) { * `if (!buf)` guard never saw it — audio_play answered with a real * channel id and played nothing. Coercion is the one shape that * cannot be caught downstream, so it is rejected at the element. */ - if (slot_type(sample) != VAL_NUM) { + if ((slot_type(sample) != VAL_FLOAT && slot_type(sample) != VAL_INT)) { /* Raise only under strict, exactly as ARG_GUARD does — this macro * cannot be used here because the function answers int16_t*, not * Value*. An unconditional raise turned a call that used to answer @@ -1309,10 +1309,10 @@ Value* builtin_audio_open(Value *arg) { if (arg && arg->type == VAL_LIST && arg->data.list.count >= 2) { /* The same unchecked `eigs_num_arg(&(), __func__)` type-pun as gfx_open. That it is an * oversight rather than a convention is settled 180 lines down: - * audio_stream_open guards this identical pair with `type == VAL_NUM` + * audio_stream_open guards this identical pair with `(type == VAL_FLOAT || type == VAL_INT)` * before reading it. */ - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_open", "[number freq, number channels]", make_num(0)); } if (!g_sdl_lib) { if (!load_sdl2()) return make_num(0); } /* fs:ANSWER 0 is not a device id -- line 1095 returns the real one; libSDL2 unavailable is environment state, not an argument */ @@ -1359,10 +1359,10 @@ Value* builtin_audio_pause(Value *arg) { /* #1007, COERCION shape: a wrong-typed flag fell back to 1 (pause), so * `audio_pause of "off"` PAUSED the device and said nothing. Above the * device check, the [135] rule. */ - STRICT_REQUIRE(arg && arg->type != VAL_NULL && arg->type != VAL_NUM, + STRICT_REQUIRE(arg && arg->type != VAL_NULL && !val_is_number(arg), "audio_pause", "number flag (1 = pause, 0 = unpause) or null"); if (!g_audio_device) return make_null(); /* fs:VOID no device open: audio_pause answers null on every path -- the return value, not a rejected-argument stand-in */ - int pause = (arg && arg->type == VAL_NUM) ? (int)eigs_num_arg(arg, __func__) : 1; + int pause = (arg && val_is_number(arg)) ? (int)eigs_num_arg(arg, __func__) : 1; p_SDL_PauseAudioDevice(g_audio_device, pause); return make_null(); /* fs:VOID audio_pause answers null on every path -- this is the return value, not a stand-in for a rejected argument */ } @@ -1454,8 +1454,8 @@ Value* builtin_audio_capture_open(Value *arg) { && !(arg->type == VAL_LIST && arg->data.list.count >= 2), "audio_capture_open", "[number freq, number channels] or null"); if (arg && arg->type == VAL_LIST && arg->data.list.count >= 2) { - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_capture_open", "[number freq, number channels]", make_num(0)); } TRACE_NONDET_TAKE("audio_capture_open"); @@ -1583,8 +1583,8 @@ Value* builtin_audio_stream_open(Value *arg) { && !(arg->type == VAL_LIST && arg->data.list.count >= 2), "audio_stream_open", "[number freq, number channels] or null"); if (arg && arg->type == VAL_LIST && arg->data.list.count >= 2) { - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_stream_open", "[number freq, number channels]", make_num(0)); } if (!g_sdl_lib) { if (!load_sdl2()) return make_num(0); } /* fs:ANSWER BUILTINS.md audio_stream_open: "0 when SDL/audio is unavailable"; libSDL2 absent is environment state */ @@ -1602,8 +1602,8 @@ Value* builtin_audio_stream_open(Value *arg) { want.callback = NULL; /* queue mode: feed via SDL_QueueAudio */ if (arg && arg->type == VAL_LIST && arg->data.list.count >= 2 - && list_elem_type(arg, 0) == VAL_NUM - && list_elem_type(arg, 1) == VAL_NUM) { + && (list_elem_type(arg, 0) == VAL_FLOAT || list_elem_type(arg, 0) == VAL_INT) + && (list_elem_type(arg, 1) == VAL_FLOAT || list_elem_type(arg, 1) == VAL_INT)) { want.freq = (int)eigs_list_num(arg, 0, __func__); want.channels = (int)eigs_list_num(arg, 1, __func__); } @@ -1700,10 +1700,10 @@ Value* builtin_audio_music_play(Value *arg) { /* A wrong-typed `loops` is the COERCION shape: it fell back to -1 * (forever), so a typo made the track loop rather than play once. */ STRICT_REQUIRE(arg->data.list.count >= 2 - && list_elem_type(arg, 1) != VAL_NUM, + && (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_music_play", "[string path, number loops]"); const char *path = list_get_ref(arg, 0)->data.str; - int loops = (arg->data.list.count >= 2 && list_elem_type(arg, 1) == VAL_NUM) + int loops = (arg->data.list.count >= 2 && (list_elem_type(arg, 1) == VAL_FLOAT || list_elem_type(arg, 1) == VAL_INT)) ? (int)eigs_list_num(arg, 1, __func__) : -1; if (!load_sdl2()) return make_bool(0); /* fs:ANSWER the header's documented "0 on failure (missing mixer lib ...)" -- libSDL2 absent is environment state, not an argument */ p_SDL_Init(MY_SDL_INIT_AUDIO); /* ensure the audio subsystem is up */ @@ -1739,15 +1739,15 @@ Value* builtin_audio_music_volume(Value *arg) { STRICT_LIST_MAX(arg, 1, "audio_music_volume"); /* #1007, COERCION shape: a wrong-typed volume fell through to v = 0 and * MUTED the music. Above the mixer-state check, the [135] rule. */ - STRICT_REQUIRE(!(arg && arg->type == VAL_NUM) + STRICT_REQUIRE(!(arg && val_is_number(arg)) && !(arg && arg->type == VAL_LIST && arg->data.list.count >= 1 - && list_elem_type(arg, 0) == VAL_NUM), + && (list_elem_type(arg, 0) == VAL_FLOAT || list_elem_type(arg, 0) == VAL_INT)), "audio_music_volume", "number volume 0..128 or [number volume]"); if (!g_mixer_open || !p_Mix_VolumeMusic) return make_null(); /* fs:VOID no mixer open: audio_music_volume answers null on every path -- the return value, not a rejected-argument stand-in */ int v = 0; - if (arg && arg->type == VAL_NUM) v = (int)eigs_num_arg(arg, __func__); + if (arg && val_is_number(arg)) v = (int)eigs_num_arg(arg, __func__); else if (arg && arg->type == VAL_LIST && arg->data.list.count >= 1 - && list_elem_type(arg, 0) == VAL_NUM) + && (list_elem_type(arg, 0) == VAL_FLOAT || list_elem_type(arg, 0) == VAL_INT)) v = (int)eigs_list_num(arg, 0, __func__); if (v < 0) v = 0; if (v > MY_MIX_MAX_VOLUME) v = MY_MIX_MAX_VOLUME; @@ -1794,7 +1794,7 @@ Value* builtin_audio_play_loop(Value *arg) { * soft, and it moves BELOW the guard so the guard is reachable on a * machine with no audio device (the [135] rule). */ ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2 - || list_elem_type(arg, 1) != VAL_NUM, + || (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_play_loop", "[samples, number loops]", make_num(0)); /* #152: NaN/huge casts are UB; -1 is the one negative with meaning. */ double loops_d = eigs_list_num(arg, 1, __func__); @@ -1835,8 +1835,8 @@ Value* builtin_audio_volume(Value *arg) { STRICT_LIST_MAX(arg, 2, "audio_volume"); /* #1007: the mixed condition split, as its #971 deferral marker asked. */ ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 2 - || list_elem_type(arg, 0) != VAL_NUM - || list_elem_type(arg, 1) != VAL_NUM, + || (list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) + || (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_volume", "[number channel, number volume]", make_num(0)); if (!g_audio_device) return make_num(0); /* fs:ANSWER 0 means "that channel is not playing", and with no device open no channel is */ int c = (int)eigs_slot_num(list_slot(arg, 0), "audio_volume") - 1; @@ -1855,7 +1855,7 @@ Value* builtin_audio_volume(Value *arg) { * bad/inactive channel. */ Value* builtin_audio_stop(Value *arg) { /* #1007: the mixed condition split, as its #971 deferral marker asked. */ - ARG_GUARD(!arg || arg->type != VAL_NUM, "audio_stop", "number channel", + ARG_GUARD(!arg || !val_is_number(arg), "audio_stop", "number channel", make_num(0)); if (!g_audio_device) return make_num(0); /* fs:ANSWER 0 means "the channel was not active", and with no device open none is */ int c = (int)eigs_num_arg(arg, __func__) - 1; @@ -1917,9 +1917,9 @@ Value* builtin_audio_sine(Value *arg) { * Seven builtins share the shape; the list was derived by running each * candidate twice and diffing (a per-run difference IS the disclosure), * not by reading names — audio_gain was missed by the reading. */ - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM || - list_elem_type(arg, 2) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT) || + (list_elem_type(arg, 2) != VAL_FLOAT && list_elem_type(arg, 2) != VAL_INT), "audio_sine", "[number freq, number duration, number amplitude]", make_list(0)); double freq = eigs_list_num(arg, 0, __func__); double dur = eigs_list_num(arg, 1, __func__); @@ -1952,9 +1952,9 @@ Value* builtin_audio_saw(Value *arg) { * pointer value, disclosed into script-visible data and varying per run. * All six generators share the shape; guarding one would have left the * class open. */ - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM || - list_elem_type(arg, 2) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT) || + (list_elem_type(arg, 2) != VAL_FLOAT && list_elem_type(arg, 2) != VAL_INT), "audio_saw", "[number freq, number duration, number amplitude]", make_list(0)); double freq = eigs_list_num(arg, 0, __func__); double dur = eigs_list_num(arg, 1, __func__); @@ -1987,9 +1987,9 @@ Value* builtin_audio_square(Value *arg) { * pointer value, disclosed into script-visible data and varying per run. * All six generators share the shape; guarding one would have left the * class open. */ - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM || - list_elem_type(arg, 2) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT) || + (list_elem_type(arg, 2) != VAL_FLOAT && list_elem_type(arg, 2) != VAL_INT), "audio_square", "[number freq, number duration, number amplitude]", make_list(0)); double freq = eigs_list_num(arg, 0, __func__); double dur = eigs_list_num(arg, 1, __func__); @@ -2023,11 +2023,11 @@ Value* builtin_audio_sweep(Value *arg) { * pointer value, disclosed into script-visible data and varying per run. * All six generators share the shape; guarding one would have left the * class open. */ - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM || - list_elem_type(arg, 2) != VAL_NUM || - list_elem_type(arg, 3) != VAL_NUM || - list_elem_type(arg, 4) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT) || + (list_elem_type(arg, 2) != VAL_FLOAT && list_elem_type(arg, 2) != VAL_INT) || + (list_elem_type(arg, 3) != VAL_FLOAT && list_elem_type(arg, 3) != VAL_INT) || + (list_elem_type(arg, 4) != VAL_FLOAT && list_elem_type(arg, 4) != VAL_INT), "audio_sweep", "[number freq_start, number freq_end, number duration, number amplitude, number waveform]", make_list(0)); double f0 = eigs_list_num(arg, 0, __func__); double f1 = eigs_list_num(arg, 1, __func__); @@ -2070,8 +2070,8 @@ Value* builtin_audio_noise(Value *arg) { * pointer value, disclosed into script-visible data and varying per run. * All six generators share the shape; guarding one would have left the * class open. */ - ARG_GUARD(list_elem_type(arg, 0) != VAL_NUM || - list_elem_type(arg, 1) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 0) != VAL_FLOAT && list_elem_type(arg, 0) != VAL_INT) || + (list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_noise", "[number duration, number amplitude]", make_list(0)); double dur = eigs_list_num(arg, 0, __func__); double amp = eigs_list_num(arg, 1, __func__); @@ -2109,8 +2109,8 @@ Value* builtin_audio_mix(Value *arg) { Value *out = make_list(n); for (int i = 0; i < n; i++) { - double sa = (i < a->data.list.count && list_elem_type(a, i) == VAL_NUM) ? eigs_slot_num(list_slot(a, i), __func__) : 0; - double sb = (i < b->data.list.count && list_elem_type(b, i) == VAL_NUM) ? eigs_slot_num(list_slot(b, i), __func__) : 0; + double sa = (i < a->data.list.count && (list_elem_type(a, i) == VAL_FLOAT || list_elem_type(a, i) == VAL_INT)) ? eigs_slot_num(list_slot(a, i), __func__) : 0; + double sb = (i < b->data.list.count && (list_elem_type(b, i) == VAL_FLOAT || list_elem_type(b, i) == VAL_INT)) ? eigs_slot_num(list_slot(b, i), __func__) : 0; double mixed = sa + sb; if (mixed > 1.0) mixed = 1.0; if (mixed < -1.0) mixed = -1.0; @@ -2140,14 +2140,14 @@ Value* builtin_audio_gain(Value *arg) { * `char *` into script-visible data exactly as audio_sweep did. Note the * element read on the next line was ALREADY type-checked — the argument * beside it was not, which is the same next-line asymmetry as gfx_open. */ - ARG_GUARD(list_elem_type(arg, 1) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT), "audio_gain", "[samples, number volume]", make_list(0)); double vol = eigs_list_num(arg, 1, __func__); int n = samples->data.list.count; Value *out = make_list(n); for (int i = 0; i < n; i++) { - double s = (list_elem_type(samples, i) == VAL_NUM) ? eigs_slot_num(list_slot(samples, i), __func__) : 0; + double s = ((list_elem_type(samples, i) == VAL_FLOAT || list_elem_type(samples, i) == VAL_INT)) ? eigs_slot_num(list_slot(samples, i), __func__) : 0; s *= vol; if (s > 1.0) s = 1.0; if (s < -1.0) s = -1.0; @@ -2171,10 +2171,10 @@ Value* builtin_audio_envelope(Value *arg) { * pointer value, disclosed into script-visible data and varying per run. * All six generators share the shape; guarding one would have left the * class open. */ - ARG_GUARD(list_elem_type(arg, 1) != VAL_NUM || - list_elem_type(arg, 2) != VAL_NUM || - list_elem_type(arg, 3) != VAL_NUM || - list_elem_type(arg, 4) != VAL_NUM, + ARG_GUARD((list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT) || + (list_elem_type(arg, 2) != VAL_FLOAT && list_elem_type(arg, 2) != VAL_INT) || + (list_elem_type(arg, 3) != VAL_FLOAT && list_elem_type(arg, 3) != VAL_INT) || + (list_elem_type(arg, 4) != VAL_FLOAT && list_elem_type(arg, 4) != VAL_INT), "audio_envelope", "[samples, number attack, number decay, number sustain, number release]", make_list(0)); ARG_GUARD(list_elem_type(arg, 0) != VAL_LIST, "audio_envelope", "[list samples, number attack, number decay, number sustain, number release]", @@ -2217,7 +2217,7 @@ Value* builtin_audio_envelope(Value *arg) { double frac = (r_samples > 0) ? (double)(i - r_start) / r_samples : 1.0; env = sustain * (1.0 - frac); } - double s = (list_elem_type(samples, i) == VAL_NUM) ? eigs_slot_num(list_slot(samples, i), __func__) : 0; + double s = ((list_elem_type(samples, i) == VAL_FLOAT || list_elem_type(samples, i) == VAL_INT)) ? eigs_slot_num(list_slot(samples, i), __func__) : 0; s *= env; list_append_owned(out, make_num(s)); } diff --git a/tests/suite_program_env.txt b/tests/suite_program_env.txt index a2cf581ac..e43c21e2d 100644 --- a/tests/suite_program_env.txt +++ b/tests/suite_program_env.txt @@ -14,7 +14,7 @@ test_json_hard.eigs EIGS_STRICT=0 test_tensor_buffer_ops.eigs EIGS_STRICT=0 test_buffer_nonfinite_read.eigs EIGS_STRICT=0 test_coalesce_legacy.eigs EIGS_STRICT=0 -test_audio.eigs EIGS_STRICT=0 +test_audio.eigs EIGS_STRICT=0 SDL_AUDIODRIVER=dummy test_gfx_text.eigs EIGS_STRICT=0 SDL_VIDEODRIVER=dummy test_gfx_argtypes.eigs EIGS_STRICT=0 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy test_ui_containment_gfx.eigs SDL_VIDEODRIVER=dummy From 7038423ced85034e1f8c305146077f9ad2d3db56 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:15:01 -0500 Subject: [PATCH 030/188] phase2 R1.2i: finish the int reader arms scheduled at R1.2a (#1758) Finish three inherited reader arms: slot_type returns VAL_INT for an SMI, slot_view gives an exact allocation-free int facade, and slot_int_value reads a boxed int64. No int producer is added. Update the existing slot matrix, including boxed INT64_MIN/MAX and 2^53+1 extraction; the population and its matrix dimensions remain unchanged. Align the disposition table and R1.3 handoff with the R1.2a schedule in section 2.5. Validation: make built; num-read examined=208 functions=81 allowlisted=81 violations=0 stale=0. Migration-only C slot probe (expected deprecation warnings suppressed until R1.2z): examined=33 calls=165 matrix_cells=396 from_int_rows=11 arm_rows=32 failures=0, PASS. Final warning-free gate and one-time planted-fault proof run after the deprecated aliases are deleted. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-value-readers.md | 1 + docs/design/phase2-inventory.txt | 112 +++++++++--------- docs/design/phase2-numbers.md | 9 +- src/container.h | 15 ++- src/value_slot.h | 4 + tests/phase2/slot_layer.c | 33 ++++-- tools/num_read_allowlist.txt | 3 +- 7 files changed, 105 insertions(+), 72 deletions(-) create mode 100644 changes/internal/1758-phase2-value-readers.md diff --git a/changes/internal/1758-phase2-value-readers.md b/changes/internal/1758-phase2-value-readers.md new file mode 100644 index 000000000..5a3a9274d --- /dev/null +++ b/changes/internal/1758-phase2-value-readers.md @@ -0,0 +1 @@ +Complete the allocation-free int readers: SMI type and Value views preserve VAL_INT and exact digits, and slot_int_value extracts boxed int64 values without converting through double. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 419d12775..43764e7fb 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,12 +1,12 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1853 classified=1853 unclassified=0 +examined=1859 classified=1859 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 380 CASE=60 DATA=5 TEST=313 YIELD=2 -(b) payload reads 554 RAW=137 READ=417 -(c) producers 472 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=4 WRITE=22 +(a) type tests 382 CASE=60 DATA=5 TEST=314 YIELD=3 +(b) payload reads 556 RAW=139 READ=417 +(c) producers 474 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=5 WRITE=23 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 15 CASE=2 FORMAT=3 PARSE=1 RAW=3 READ=3 TEST=3 (f) equality, ordering and hashing 42 CASE=2 PRODUCE=4 RAW=12 READ=9 TEST=15 @@ -19,7 +19,7 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 make_num 364 eigs_num_arg 151 eigs_list_num 130 -VAL_INT 121 +VAL_INT 124 VAL_FLOAT 117 SLOT_F64_RAW 83 VAL_NUM 82 @@ -32,11 +32,11 @@ eigs_value_as_num 48 slot_from_f64 41 buffer_read_num 38 slot_is_smi 37 -VAL_I64_RAW 29 +VAL_I64_RAW 31 buffer_read_byte 22 list_set_num 22 VAL_F64_RAW 19 -slot_smi_val 17 +slot_smi_val 18 slot_f64_value 16 strtod 16 NUM_REUSE 15 @@ -78,16 +78,16 @@ builtins_tensor.c 177 a=32 b=59 c=86 eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 builtins_buf.c 102 a=26 b=37 c=39 jit.c 96 d=96 -container.h 91 a=35 b=30 c=26 +container.h 95 a=36 b=31 c=28 ext_store.c 54 h=54 embed_smoke.c 50 j=50 eigenscript.h 44 a=7 b=24 c=12 e=1 builtins_host.c 40 a=4 b=24 c=12 jit_smoke.c 31 d=31 lint.c 29 a=29 +value_slot.h 22 a=8 b=11 c=3 compiler.c 21 a=13 b=5 c=1 i=2 trace.c 20 g=20 -value_slot.h 20 a=7 b=10 c=3 ext_net.c 19 a=5 b=7 c=7 model_infer.c 16 a=1 b=6 c=9 ext_http.c 14 a=3 b=4 c=7 @@ -204,8 +204,8 @@ D1 container.h:eigs_slot_store_owned guarded slot_as_ptr=1 slo D1 container.h:list_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:list_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:list_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 -D1 container.h:slot_type unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_type=1 -D1 container.h:slot_view unwired eigs_slot_ref=1 slot_as_ptr=1 slot_is_f64=2 slot_is_smi=1 slot_type=1 +D1 container.h:slot_type smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_type=1 +D1 container.h:slot_view smi-arm eigs_slot_ref=1 slot_as_ptr=1 slot_is_f64=2 slot_is_smi=1 slot_smi_val=1 slot_type=1 D1 eigenscript.c:ent_child_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 eigenscript.c:module_ns_project guarded slot_is_f64=2 D1 eigenscript.c:observer_entropy_now smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 @@ -213,7 +213,7 @@ D1 eigenscript.c:slot_to_value unwired slot_as_ptr=1 slo D1 ext_store.c:store_json_encode_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 trace.c:write_slot unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 D1 value_slot.h:slot_f64_value guarded slot_as_ptr=1 slot_f64_value=1 slot_is_f64=1 slot_is_heap=1 -D1 value_slot.h:slot_int_value smi-arm slot_int_value=1 slot_is_smi=1 slot_smi_val=1 +D1 value_slot.h:slot_int_value smi-arm slot_as_ptr=1 slot_int_value=1 slot_is_heap=1 slot_is_smi=1 slot_smi_val=1 D1 value_slot.h:slot_is_f64 guarded SLOT_QNAN_MASK=2 slot_is_f64=1 D1 value_slot.h:slot_is_smi smi-arm SLOT_TAG_MASK=1 TAG_SMI=1 slot_is_smi=1 D1 value_slot.h:slot_smi_val smi-arm SLOT_PAYLOAD_MASK=1 SLOT_SMI_SIGN=2 slot_smi_val=1 @@ -1172,6 +1172,7 @@ container.h:91 list_rewrite_num list_rewrite_num PRODUCE c container.h:93 list_rewrite_num slot_from_f64 PRODUCE c container.h:102 slot_type VAL_FLOAT YIELD a container.h:102 slot_type slot_is_f64 TEST a +container.h:106 slot_type VAL_INT YIELD a container.h:106 slot_type slot_is_smi TEST a container.h:130 list_get_ref slot_is_f64 TEST a container.h:130 list_get_ref slot_is_smi TEST a @@ -1199,47 +1200,50 @@ container.h:162 eigs_slot_opt_num slot_smi_val RAW b container.h:164 eigs_slot_opt_num eigs_num_arg READ b container.h:166 eigs_slot_opt_num eigs_num_arg_slow READ b container.h:175 slot_view slot_is_smi TEST a -container.h:177 slot_view VAL_FLOAT TEST a -container.h:177 slot_view slot_is_f64 TEST a -container.h:178 slot_view VAL_FLOAT TAGSET c -container.h:179 slot_view SLOT_F64_RAW RAW b -container.h:179 slot_view VAL_F64_RAW WRITE c -container.h:179 slot_view slot_is_f64 TEST a -container.h:180 slot_view eigs_num_arg READ b -container.h:191 eigs_view_check VAL_FLOAT TEST a -container.h:191 eigs_view_check VAL_INT TEST a -container.h:218 list_get_return slot_is_smi TEST a -container.h:219 list_get_return SLOT_F64_RAW RAW b -container.h:219 list_get_return make_num PRODUCE c -container.h:219 list_get_return slot_is_f64 TEST a -container.h:226 dict_value_get_return slot_is_smi TEST a -container.h:227 dict_value_get_return SLOT_F64_RAW RAW b -container.h:227 dict_value_get_return make_num PRODUCE c -container.h:227 dict_value_get_return slot_is_f64 TEST a -container.h:257 eigs_slot_box SLOT_F64_RAW RAW b -container.h:257 eigs_slot_box make_num PRODUCE c -container.h:257 eigs_slot_box num_guard GUARD c -container.h:257 eigs_slot_box slot_is_f64 TEST a -container.h:258 eigs_slot_box slot_is_smi TEST a -container.h:280 list_set_num list_set_num PRODUCE c -container.h:281 list_set_num list_rewrite_num PRODUCE c -container.h:281 list_set_num num_guard GUARD c -container.h:283 list_append_num list_append_num PRODUCE c -container.h:284 list_append_num num_guard GUARD c -container.h:286 list_append_num slot_from_f64 PRODUCE c -container.h:288 dict_value_set_num dict_value_set_num PRODUCE c -container.h:289 dict_value_set_num dict_value_rewrite_num PRODUCE c -container.h:289 dict_value_set_num num_guard GUARD c -container.h:318 list_get_num list_get_num READ b -container.h:320 list_get_num slot_is_smi TEST a -container.h:320 list_get_num slot_smi_val RAW b -container.h:321 list_get_num slot_is_f64 TEST a -container.h:322 list_get_num SLOT_F64_RAW RAW b -container.h:325 dict_value_get_num dict_value_get_num READ b -container.h:327 dict_value_get_num slot_is_smi TEST a -container.h:327 dict_value_get_num slot_smi_val RAW b -container.h:328 dict_value_get_num slot_is_f64 TEST a -container.h:329 dict_value_get_num SLOT_F64_RAW RAW b +container.h:176 slot_view VAL_INT TAGSET c +container.h:177 slot_view VAL_I64_RAW WRITE c +container.h:177 slot_view slot_smi_val RAW b +container.h:182 slot_view VAL_FLOAT TEST a +container.h:182 slot_view slot_is_f64 TEST a +container.h:183 slot_view VAL_FLOAT TAGSET c +container.h:184 slot_view SLOT_F64_RAW RAW b +container.h:184 slot_view VAL_F64_RAW WRITE c +container.h:184 slot_view slot_is_f64 TEST a +container.h:185 slot_view eigs_num_arg READ b +container.h:196 eigs_view_check VAL_FLOAT TEST a +container.h:196 eigs_view_check VAL_INT TEST a +container.h:223 list_get_return slot_is_smi TEST a +container.h:224 list_get_return SLOT_F64_RAW RAW b +container.h:224 list_get_return make_num PRODUCE c +container.h:224 list_get_return slot_is_f64 TEST a +container.h:231 dict_value_get_return slot_is_smi TEST a +container.h:232 dict_value_get_return SLOT_F64_RAW RAW b +container.h:232 dict_value_get_return make_num PRODUCE c +container.h:232 dict_value_get_return slot_is_f64 TEST a +container.h:262 eigs_slot_box SLOT_F64_RAW RAW b +container.h:262 eigs_slot_box make_num PRODUCE c +container.h:262 eigs_slot_box num_guard GUARD c +container.h:262 eigs_slot_box slot_is_f64 TEST a +container.h:263 eigs_slot_box slot_is_smi TEST a +container.h:285 list_set_num list_set_num PRODUCE c +container.h:286 list_set_num list_rewrite_num PRODUCE c +container.h:286 list_set_num num_guard GUARD c +container.h:288 list_append_num list_append_num PRODUCE c +container.h:289 list_append_num num_guard GUARD c +container.h:291 list_append_num slot_from_f64 PRODUCE c +container.h:293 dict_value_set_num dict_value_set_num PRODUCE c +container.h:294 dict_value_set_num dict_value_rewrite_num PRODUCE c +container.h:294 dict_value_set_num num_guard GUARD c +container.h:323 list_get_num list_get_num READ b +container.h:325 list_get_num slot_is_smi TEST a +container.h:325 list_get_num slot_smi_val RAW b +container.h:326 list_get_num slot_is_f64 TEST a +container.h:327 list_get_num SLOT_F64_RAW RAW b +container.h:330 dict_value_get_num dict_value_get_num READ b +container.h:332 dict_value_get_num slot_is_smi TEST a +container.h:332 dict_value_get_num slot_smi_val RAW b +container.h:333 dict_value_get_num slot_is_f64 TEST a +container.h:334 dict_value_get_num SLOT_F64_RAW RAW b eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a eigenscript.c:309 val_type_name VAL_FLOAT CASE a @@ -2085,6 +2089,8 @@ value_slot.h:248 slot_f64_value VAL_FLOAT TEST a value_slot.h:254 slot_int_value slot_int_value READ b value_slot.h:255 slot_int_value slot_is_smi TEST a value_slot.h:255 slot_int_value slot_smi_val RAW b +value_slot.h:258 slot_int_value VAL_I64_RAW RAW b +value_slot.h:258 slot_int_value VAL_INT TEST a vm.c:107 obs_dump_num eigs_num_text FORMAT i vm.c:118 obs_dump_value SLOT_F64_RAW RAW i vm.c:118 obs_dump_value slot_is_f64 TEST i diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 5ccaaa279..179b56f70 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -685,8 +685,8 @@ result).** | `container.h:list_get_num` | smi-arm | bridge reader: an int element converts to its double (D1) | | `container.h:list_get_ref` | smi-arm | NULL for a number by contract, an int included (D1) | | `container.h:list_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value` (unwired until R1.3) (D1) | -| `container.h:slot_type` | unwired | an SMI's type is the int ValType, which lands in R1.2a; any other unknown tag refuses instead of being read as a pointer (D1) | -| `container.h:slot_view` | unwired | an SMI's facade is a `VAL_INT` view (R1.2a) (D1) | +| `container.h:slot_type` | smi-arm | an SMI's type is `VAL_INT` (R1.2); any other unknown tag refuses instead of being read as a pointer (D1) | +| `container.h:slot_view` | smi-arm | an SMI's facade is an exact `VAL_INT` view (R1.2) (D1) | | `eigenscript.c:#define GC_EDGE_TABLE` | guarded | a GC edge exists only for `slot_is_ptr`; an SMI has no edge (D2) | | `eigenscript.c:ent_child_slot` | smi-arm | an int's entropy is its double's: the numeric channel until round 3 (design 7) (D1) | | `eigenscript.c:env_get_hashed` | guarded | a non-pointer slot goes through `slot_to_value` (compile-forced) and comes back boxed: the lift boxes on purpose (§2.1) (D2) | @@ -713,7 +713,7 @@ result).** | `value_slot.h:slot_from_heap` | guarded | maps null and bool Values to their immediates and every other Value to a heap slot, so a `VAL_INT` box stays a box: the lifts depend on that (§2.1) (D3) | | `value_slot.h:slot_from_int` | not-a-classifier | the one int writer: an SMI inside [-2^47, 2^47); outside it the `VAL_INT` box is unwired until R1.3 (D3) | | `value_slot.h:slot_incref` | guarded | as `slot_decref` (D3) | -| `value_slot.h:slot_int_value` | smi-arm | an SMI's int; the `VAL_INT` box arm lands in R1.2a with the type it names (D1) | +| `value_slot.h:slot_int_value` | smi-arm | an SMI's int, or a heap `VAL_INT`'s exact int64 (R1.2) (D1) | | `value_slot.h:slot_is_bool` | guarded | exact tag test (D3) | | `value_slot.h:slot_is_f64` | guarded | the double test (was `slot_is_num`): an SMI answers 0 (D1) | | `value_slot.h:slot_is_heap` | guarded | exact tag test (D3) | @@ -1922,8 +1922,7 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: and replay would turn ints into floats. The float token marks its kind now (`3.0`); N6's repr replaces it in R1.7, still inside v7. - `eigs_int_unwired` is deleted: `slot_to_value` boxes an SMI with - `make_int`, `slot_type` answers `VAL_INT`, `slot_view` gives a - `VAL_INT` facade, `write_slot` writes v7 digits, and `slot_from_int` + `make_int`, `write_slot` writes v7 digits, and `slot_from_int` boxes an int outside the SMI range (each R1.1 placeholder, 2.5). - The observer routes an SMI and a boxed int into the numeric channel (§7). diff --git a/src/container.h b/src/container.h index 3b3b82a0c..32eb00143 100644 --- a/src/container.h +++ b/src/container.h @@ -96,14 +96,14 @@ static inline int list_rewrite_num(const Value *list, int i, double d) { } /* Return the logical type of a borrowed slot without allocating. #1758: an - * SMI's type is the int ValType, which lands in R1.2a; until then it is - * refused loudly rather than read as a pointer. */ + * SMI's type is VAL_INT; any reserved tag refuses instead of being read + * as a pointer. */ static inline ValType slot_type(EigsSlot s) { if (slot_is_f64(s)) return VAL_FLOAT; if (slot_is_null(s)) return VAL_NULL; if (slot_is_bool(s)) return VAL_BOOL; if (slot_is_heap(s)) return slot_as_ptr(s)->type; - if (slot_is_smi(s)) eigs_int_unwired("slot_type", s.u); + if (slot_is_smi(s)) return VAL_INT; eigs_slot_refuse("slot_type", s); } /* A slot's Value for a reader that wants a pointer: null and bool become @@ -170,9 +170,14 @@ static inline int eigs_slot_opt_num(EigsSlot s, double *out, const char *who) { /* A numeric view is a caller-owned, allocation-free Value facade. Reference * slots return their real pointer. The cleanup guard catches retaining or * decrefing a numeric facade: its sentinel refcount must be unchanged. - * #1758: an SMI's facade is a VAL_INT view (R1.2a); refused until then. */ + * #1758: an SMI's facade preserves its exact int Value kind. */ static inline Value *slot_view(EigsSlot s, EigsView *view) { - if (slot_is_smi(s)) eigs_int_unwired("slot_view", s.u); + if (slot_is_smi(s)) { + view->v.type = VAL_INT; + VAL_I64_RAW(&view->v) = slot_smi_val(s); + view->v.refcount = EIGS_VIEW_RC; + return &view->v; + } /* a heap VAL_INT box is a real Value: it is returned as itself */ if (!slot_is_f64(s) && slot_type(s) != VAL_FLOAT) return eigs_slot_ref(s); view->v.type = VAL_FLOAT; diff --git a/src/value_slot.h b/src/value_slot.h index 5769790f2..6c81b7ea1 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -253,6 +253,10 @@ static inline int slot_f64_value(EigsSlot s, double *out) { * arm with the type it names. */ static inline int slot_int_value(EigsSlot s, int64_t *out) { if (slot_is_smi(s)) { *out = slot_smi_val(s); return 1; } + if (slot_is_heap(s)) { + Value *v = slot_as_ptr(s); + if (v->type == VAL_INT) { *out = VAL_I64_RAW(v); return 1; } + } return 0; } diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index 474cb9584..c81993f8c 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -132,7 +132,26 @@ static int r_store_json_encode_slot(int64_t v) { return bad; } static int r_slot_f64_value(int64_t v) { double d = -7.25; return slot_f64_value(smi(v), &d) != 0 || d != -7.25; } -static int r_slot_int_value(int64_t v) { int64_t i = 7; return slot_int_value(smi(v), &i) != 1 || i != v; } +static int r_slot_int_value(int64_t v) { + int64_t i = 7; + if (slot_int_value(smi(v), &i) != 1 || i != v) return 1; + /* The box arm is independent of SMI range and must not narrow through double. */ + static const int64_t boxed[] = {INT64_MIN, INT64_MAX, INT64_C(9007199254740993)}; + for (size_t n = 0; n < sizeof boxed / sizeof boxed[0]; n++) { + Value box = {.type = VAL_INT}; + VAL_I64_RAW(&box) = boxed[n]; + i = 7; + if (!slot_int_value(slot_from_heap(&box), &i) || i != boxed[n]) return 1; + } + return 0; +} +static int r_slot_type(int64_t v) { return slot_type(smi(v)) != VAL_INT; } +static int r_slot_view(int64_t v) { + EIGS_VIEW(view); + Value *got = slot_view(smi(v), &view); + return got != &view.v || got->type != VAL_INT || VAL_I64_RAW(got) != v || + got->refcount != EIGS_VIEW_RC; +} static int r_slot_is_f64(int64_t v) { return slot_is_f64(smi(v)) != 0; } static int r_slot_is_smi(int64_t v) { return slot_is_smi(smi(v)) != 1; } static int r_slot_smi_val(int64_t v) { return slot_smi_val(smi(v)) != v; } @@ -160,8 +179,6 @@ static int r_slot_is_ptr(int64_t v) { return slot_is_ptr(smi(v)) != 0; } /* ---- Part A: ABORT calls ------------------------------------------------ */ static void a_eigs_slot_box(EigsSlot s) { (void)eigs_slot_box(s); } -static void a_slot_type(EigsSlot s) { (void)slot_type(s); } -static void a_slot_view(EigsSlot s) { EIGS_VIEW_NOCHECK(view); (void)slot_view(s, &view); } static void a_slot_to_value(EigsSlot s) { (void)slot_to_value(s); } static void a_write_slot(EigsSlot s) { write_slot(s); } static void a_obs_slot_observable(EigsSlot s) { (void)obs_slot_observable(s); } @@ -203,8 +220,8 @@ static const Entry ENTRIES[] = { {"value_slot.h:slot_is_null", r_slot_is_null, 0, 0, "0"}, {"value_slot.h:slot_is_ptr", r_slot_is_ptr, 0, 0, "0"}, {"container.h:eigs_slot_box", 0, a_eigs_slot_box, "slot_to_value", "unwired: an int Value (R1.3)"}, - {"container.h:slot_type", 0, a_slot_type, "slot_type", "unwired: the int ValType (R1.2a)"}, - {"container.h:slot_view", 0, a_slot_view, "slot_view", "unwired: a VAL_INT facade (R1.2a)"}, + {"container.h:slot_type", r_slot_type, 0, 0, "VAL_INT"}, + {"container.h:slot_view", r_slot_view, 0, 0, "exact VAL_INT facade"}, {"eigenscript.c:slot_to_value", 0, a_slot_to_value, "slot_to_value", "unwired: make_int (R1.3)"}, {"trace.c:write_slot", 0, a_write_slot, "write_slot", "unwired: tape v7 (R1.3)"}, {"vm.c:obs_slot_observable", 0, a_obs_slot_observable, "obs_slot_observable", "refuse"}, @@ -456,8 +473,8 @@ EXP(slot_box) { } } EXP(slot_type) { - static const char *names[] = {"t:num", "t:null", "t:bool", "", "t:str"}; - if (kclass(k) == C_SMI || kclass(k) == C_RES) ABORT("slot_type"); + static const char *names[] = {"t:num", "t:null", "t:bool", "t:num", "t:str"}; + if (kclass(k) == C_RES) ABORT("slot_type"); else snprintf(b, n, "%s", names[kclass(k)]); } EXP(slot_view) { @@ -466,7 +483,7 @@ EXP(slot_view) { case C_NULL: snprintf(b, n, "v:null"); break; case C_BOOL: e_bool(b, n, k); break; case C_HEAP: snprintf(b, n, "v:H"); break; - case C_SMI: ABORT("slot_view"); break; + case C_SMI: snprintf(b, n, "v:int:5"); break; default: ABORT("slot_type"); } } diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index ac6cfc873..d7d9522a6 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -18,7 +18,6 @@ container.h|eigs_slot_num|1|required numeric accessor reads only after slot_is_f container.h|eigs_slot_opt_num|1|optional numeric accessor reads only after slot_is_f64 container.h|list_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) container.h|list_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 -container.h|slot_view|2|numeric view copies a proven immediate into caller storage chunk.c|chunk_disassemble|1|debug disassembly prints a constant behind its own type == VAL_NUM test chunk.c|const_equal|2|constant-pool dedup compares two constants after testing both are VAL_NUM chunk.c|const_hash_value|1|constant-pool hash of a constant inside its type == VAL_NUM branch @@ -85,3 +84,5 @@ builtins.c|builtin_json_path|1|VAL_INT scalar text is exact digits before releas builtins.c|builtin_dispatch|1|VAL_INT argument boxing refuses until make_int lands in R1.3 (#1758) builtins.c|builtin_sort_by|1|numeric key kind retained for exact mixed sorting (#1758 N2) builtins.c|sort_cmp_num|6|validated numeric slots viewed through slot_view; int comparisons are exact (#1758 N2) +value_slot.h|slot_int_value|1|boxed VAL_INT payload after its type test (#1758 R1.2i) +container.h|slot_view|3|typed float or int facade, preserving exact payload and kind (#1758 R1.2i) From 3f1ff968bd5ad318839f9e70e72cf0b2631d637d Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:46:36 -0500 Subject: [PATCH 031/188] phase2 R1.2j: migrate the JIT float guards and standalone emitter stub (#1758) Migrate 10 deprecated code-token sites in jit.c, jit_smoke.c. Float behavior and the R1.6 bridge names stay unchanged; int consumers preserve their kind or refuse through the R1.3 unwired token. Validation: make all built; inventory PASS; num-read PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2j.md | 1 + docs/design/phase2-inventory.txt | 32 ++++++++++++------------- src/jit.c | 34 +++++++++++++-------------- src/jit_smoke.c | 4 ++-- 4 files changed, 36 insertions(+), 35 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2j.md diff --git a/changes/internal/1758-phase2-r1-2j.md b/changes/internal/1758-phase2-r1-2j.md new file mode 100644 index 000000000..acff4f0be --- /dev/null +++ b/changes/internal/1758-phase2-r1-2j.md @@ -0,0 +1 @@ +Migrate the JIT float guards and standalone emitter stub. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 43764e7fb..5b3c29937 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -20,10 +20,10 @@ make_num 364 eigs_num_arg 151 eigs_list_num 130 VAL_INT 124 -VAL_FLOAT 117 +VAL_FLOAT 122 SLOT_F64_RAW 83 -VAL_NUM 82 -VAL_NUM_RAW 70 +VAL_NUM 77 +VAL_NUM_RAW 68 num_guard 60 AST_NUM 52 eigs_slot_num 50 @@ -35,7 +35,7 @@ slot_is_smi 37 VAL_I64_RAW 31 buffer_read_byte 22 list_set_num 22 -VAL_F64_RAW 19 +VAL_F64_RAW 21 slot_smi_val 18 slot_f64_value 16 strtod 16 @@ -50,7 +50,7 @@ eigs_slot_elem_num 6 num_guard_named 6 num_to_i64_exact 6 num_val 5 -VAL_NUM_OFFSET 4 +VAL_F64_OFFSET 4 buf_num_arg 4 dict_value_rewrite_num 4 list_rewrite_num 3 @@ -60,7 +60,7 @@ f64_ 2 list_append_num 2 make_num_permanent 2 num_ 2 -VAL_F64_OFFSET 1 +VAL_NUM_OFFSET 1 atof 1 d_ 1 dict_value_get_num 1 @@ -1883,17 +1883,17 @@ jit.c:2343 emit_load_numeric_operand EMIT d jit.c:2348 emit_load_numeric_operand TAG-IMM 0xFFF8 EMIT d jit.c:2353 emit_load_numeric_operand TAG-IMM 0xFFFB EMIT d jit.c:2356 emit_load_numeric_operand TAG-IMM 0xFFFD EMIT d -jit.c:2363 emit_load_numeric_operand VAL_NUM EMIT d -jit.c:2367 emit_load_numeric_operand VAL_NUM_OFFSET RAW d -jit.c:2368 emit_load_numeric_operand VAL_NUM_OFFSET RAW d +jit.c:2363 emit_load_numeric_operand VAL_FLOAT EMIT d +jit.c:2367 emit_load_numeric_operand VAL_F64_OFFSET RAW d +jit.c:2368 emit_load_numeric_operand VAL_F64_OFFSET RAW d jit.c:2397 emit_decref_binop_operands TAG-IMM 0xFFFB EMIT d jit.c:2425 emit_commit_binop TAG-IMM 0xFFFB EMIT d jit.c:2633 jit_compile_to_thunk max_normal_bits EMIT d jit.c:2634 jit_compile_to_thunk EIGS_NUM_MAX GUARD d jit.c:2634 jit_compile_to_thunk max_normal_bits EMIT d jit.c:2801 jit_compile_to_thunk/OP_NULL TAG-IMM 0xFFF8 EMIT d -jit.c:2822 jit_compile_to_thunk/OP_CONST VAL_NUM TEST d -jit.c:2825 jit_compile_to_thunk/OP_CONST VAL_NUM_RAW RAW d +jit.c:2822 jit_compile_to_thunk/OP_CONST VAL_FLOAT TEST d +jit.c:2825 jit_compile_to_thunk/OP_CONST VAL_F64_RAW RAW d jit.c:2828 jit_compile_to_thunk/OP_CONST TAG-IMM 0xFFFB EMIT d jit.c:3024 jit_compile_to_thunk/OP_SET_NAME TAG-IMM 0xFFFB EMIT d jit.c:3145 jit_compile_to_thunk/OP_LOCAL_DOT_GET emit_immediate_num_check_rax EMIT d @@ -1902,8 +1902,8 @@ jit.c:3274 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rdx EM jit.c:3452 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFF8 EMIT d jit.c:3457 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFB EMIT d jit.c:3459 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFD EMIT d -jit.c:3465 jit_compile_to_thunk/OP_SET_LOCAL VAL_NUM EMIT d -jit.c:3471 jit_compile_to_thunk/OP_SET_LOCAL VAL_NUM_OFFSET RAW d +jit.c:3465 jit_compile_to_thunk/OP_SET_LOCAL VAL_FLOAT EMIT d +jit.c:3471 jit_compile_to_thunk/OP_SET_LOCAL VAL_F64_OFFSET RAW d jit.c:3530 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d jit.c:3534 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d jit.c:3544 jit_compile_to_thunk/OP_MOD emit_btr_63_rsi EMIT d @@ -1944,7 +1944,7 @@ jit.c:4107 jit_compile_to_thunk/OP_INDEX_SET emit_cvttsd2si_xmm0_r8d EMIT d jit.c:4108 jit_compile_to_thunk/OP_INDEX_SET emit_cvtsi2sd_r8d_xmm1 EMIT d jit.c:4109 jit_compile_to_thunk/OP_INDEX_SET emit_ucomisd_xmm0_xmm1 EMIT d jit.c:4117 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rax EMIT d -jit.c:4375 jit_compile_to_thunk/OP_POP VAL_NUM TEST d +jit.c:4375 jit_compile_to_thunk/OP_POP VAL_FLOAT TEST d jit_smoke.c:103 jit_helper_local_idx_get slot_from_f64 PRODUCE d jit_smoke.c:138 jit_helper_iter_next SLOT_F64_RAW RAW d jit_smoke.c:142 jit_helper_iter_next slot_from_f64 PRODUCE d @@ -1971,8 +1971,8 @@ jit_smoke.c:539 run_reader_bail_cases SLOT_F64_RAW RAW d jit_smoke.c:540 run_reader_bail_cases SLOT_F64_RAW RAW d jit_smoke.c:541 run_reader_bail_cases SLOT_F64_RAW RAW d jit_smoke.c:541 run_reader_bail_cases SLOT_F64_RAW RAW d -jit_smoke.c:601 run_exit_cases VAL_NUM TAGSET d -jit_smoke.c:602 run_exit_cases VAL_NUM_RAW WRITE d +jit_smoke.c:601 run_exit_cases VAL_FLOAT TAGSET d +jit_smoke.c:602 run_exit_cases VAL_F64_RAW WRITE d jit_smoke.c:628 run_exit_cases slot_from_f64 PRODUCE d jit_smoke.c:637 run_exit_cases SLOT_F64_RAW RAW d jit_smoke.c:642 run_exit_cases SLOT_F64_RAW RAW d diff --git a/src/jit.c b/src/jit.c index 5e710a398..4d77f6d1f 100644 --- a/src/jit.c +++ b/src/jit.c @@ -2331,7 +2331,7 @@ static uint8_t *emit_mov_disp32_rdi_to_rdx(uint8_t *w, int32_t disp) { * * Accepts what the interpreter's slot_f64_value accepts MINUS the * NUM_REUSE candidates: an immediate double, or a heap/tracked pointer - * to a VAL_NUM with refcount >= 2 (refcount 1 would make the + * to a VAL_FLOAT with refcount >= 2 (refcount 1 would make the * interpreter's NUM_REUSE in-place branch fire, so it routes to the * interpreter to keep observer-value identity semantics exact). * @@ -2355,17 +2355,17 @@ static uint8_t *emit_load_numeric_operand(uint8_t *w, int is_b, /* Tag 0xFFFD+ (reserved/sentinel): not a pointer we may chase. */ w = emit_cmp_imm32_esi(w, 0xFFFD); w = emit_jae_rel32(w, &lp[*lp_n]); (*lp_n)++; - /* Heap or tracked pointer: must be a non-REUSE VAL_NUM. */ + /* Heap or tracked pointer: must be a non-REUSE VAL_FLOAT. */ w = is_b ? emit_mov_rax_rdi(w) : emit_mov_rdx_rdi(w); w = emit_shl_16_rdi(w); w = emit_shr_16_rdi(w); w = emit_cmpl_imm32_disp32_rdi(w, (int32_t)offsetof(Value, type), - (uint32_t)VAL_NUM); + (uint32_t)VAL_FLOAT); w = emit_jne_rel32(w, &lp[*lp_n]); (*lp_n)++; w = emit_cmpl_imm32_disp32_rdi(w, (int32_t)offsetof(Value, refcount), 2); w = emit_jl_rel32(w, &lp[*lp_n]); (*lp_n)++; - w = is_b ? emit_mov_disp32_rdi_to_rax(w, (int32_t)VAL_NUM_OFFSET) - : emit_mov_disp32_rdi_to_rdx(w, (int32_t)VAL_NUM_OFFSET); + w = is_b ? emit_mov_disp32_rdi_to_rax(w, (int32_t)VAL_F64_OFFSET) + : emit_mov_disp32_rdi_to_rdx(w, (int32_t)VAL_F64_OFFSET); /* .imm: bits (immediate or loaded data.num) → xmm. */ { int rel = (int)(w - imm_after); @@ -2819,10 +2819,10 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, Value *v = chunk->constants[idx]; uint64_t bits; int needs_incref = 0; - if (v->type == VAL_NUM) { + if (v->type == VAL_FLOAT) { /* Immediate-num: same shape as NUM_ZERO. (#262 Step E: a * constant num never carries observer state.) */ - memcpy(&bits, &VAL_NUM_RAW(v), 8); + memcpy(&bits, &VAL_F64_RAW(v), 8); } else { /* Heap slot: TAG_HEAP | payload. */ bits = 0xFFFB000000000000ULL | @@ -3410,7 +3410,7 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, } else if (op == OP_SET_LOCAL) { /* Stage 5e: mirror CASE(SET_LOCAL) exactly, including its * in-place branch — writing an immediate into a slot whose - * existing Value is an exclusive non-observed VAL_NUM + * existing Value is an exclusive non-observed VAL_FLOAT * rewrites data.num instead of swapping pointers. This is * load-bearing beyond speed: the observer's g_last_observer * can point at that Value, and the swap path would free it @@ -3419,9 +3419,9 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, * tos imm? no → .swap * old slot ptr? no → .plain (imm/sentinel old: * incref+decref both no-op) - * old is VAL_NUM && rc==1 && obs_age==0? + * old is VAL_FLOAT && rc==1 && obs_age==0? * no → .swap - * in-place: VAL_NUM_RAW(old) = tos bits; → .done + * in-place: VAL_F64_RAW(old) = tos bits; → .done * .plain: values[slot] = tos; → .done * .swap: values[slot] = tos; incref tos; decref old * .done: */ @@ -3462,13 +3462,13 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, w = emit_shl_16_rdi(w); w = emit_shr_16_rdi(w); w = emit_cmpl_imm32_disp32_rdi(w, (int32_t)offsetof(Value, type), - (uint32_t)VAL_NUM); + (uint32_t)VAL_FLOAT); w = emit_jne_rel32(w, &swap_p[swap_n]); swap_n++; w = emit_cmpl_imm32_disp32_rdi(w, (int32_t)offsetof(Value, refcount), 1); w = emit_jne_rel32(w, &swap_p[swap_n]); swap_n++; /* #262 Step E: obs_age guard removed — nums are never tracked. */ - /* in-place: VAL_NUM_RAW(existing) = tos bits. */ - w = emit_mov_rax_to_disp32_rdi(w, (int32_t)VAL_NUM_OFFSET); + /* in-place: VAL_F64_RAW(existing) = tos bits. */ + w = emit_mov_rax_to_disp32_rdi(w, (int32_t)VAL_F64_OFFSET); w = emit_jmp_rel32(w, &done_p[done_n]); done_n++; /* .plain: store only (both refcount sides are no-ops). */ for (int k = 0; k < plain_n; k++) patch_rel32(plain_p[k], w); @@ -3535,7 +3535,7 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, if (ab) { JIT_BAIL_AND_RETURN(); } - /* Divisor zero check. The VM compares `VAL_NUM_RAW(b) != 0.0`, + /* Divisor zero check. The VM compares `VAL_F64_RAW(b) != 0.0`, * which under IEEE-754 treats +0.0 and -0.0 as equal — so * we must also bail when b == -0.0 (bits = 0x8000…0). * Strategy: copy b's bits to %rsi (dead scratch after the @@ -3586,7 +3586,7 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, } else if (op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV) { /* Stage 5e: operands may be immediates OR heap/tracked - * VAL_NUM pointers with refcount >= 2 (the loader bails + * VAL_FLOAT pointers with refcount >= 2 (the loader bails * the rc==1 case so the interpreter's NUM_REUSE branch * keeps its in-place semantics). All guard failures route * through one per-op trampoline so the epilogue patch @@ -3651,7 +3651,7 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, i += 1; } else if (op == OP_EQ || op == OP_NE || op == OP_LT || op == OP_GT || op == OP_LE || op == OP_GE) { - /* Stage 5e: tracked/heap VAL_NUM operands accepted via the + /* Stage 5e: tracked/heap VAL_FLOAT operands accepted via the * shared loader (rc==1 bails — NUM_CMP/EQ/NE all have the * same NUM_REUSE branch as ARITH_FAST). One trampoline * slot. NaN inputs would give incorrect comparison results @@ -4372,7 +4372,7 @@ static void jit_compile_to_thunk(struct EigsChunk *chunk, uint16_t idx = (uint16_t)(chunk->code[op_start + 1] | ((uint16_t)chunk->code[op_start + 2] << 8)); Value *v = chunk->constants[idx]; - last_imm = (v && v->type == VAL_NUM); + last_imm = (v && v->type == VAL_FLOAT); break; } case OP_LINE: diff --git a/src/jit_smoke.c b/src/jit_smoke.c index 91fa3fcc4..f6d07b1fc 100644 --- a/src/jit_smoke.c +++ b/src/jit_smoke.c @@ -598,8 +598,8 @@ static int run_exit_cases(void) { vm->owner = thread; eigs_current = thread; state->jit_entry_threshold = state->jit_iter_threshold = 1; - Value limit = {.type = VAL_NUM}; - VAL_NUM_RAW(&limit) = 4; + Value limit = {.type = VAL_FLOAT}; + VAL_F64_RAW(&limit) = 4; Value *constants[] = {&limit}; uint8_t code[] = {OP_NULL, OP_POP, OP_NULL, OP_POP, OP_NUM_ONE, OP_ADD, OP_DUP, OP_CONST, 0, 0, From a0f663875a3232ec63afb9db7ac105be2ebc696e Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:47:06 -0500 Subject: [PATCH 032/188] phase2 R1.2k: give constant deduplication and disassembly exact int arms (#1758) Migrate 11 deprecated code-token sites in chunk.c. Float behavior and the R1.6 bridge names stay unchanged; int consumers preserve their kind or refuse through the R1.3 unwired token. Validation: make all built; inventory PASS; num-read PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2k.md | 1 + docs/design/phase2-inventory.txt | 50 +++++++++++++++------------ src/chunk.c | 31 +++++++++++------ tools/num_read_allowlist.txt | 6 ++-- 4 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2k.md diff --git a/changes/internal/1758-phase2-r1-2k.md b/changes/internal/1758-phase2-r1-2k.md new file mode 100644 index 000000000..3a5e9c6f0 --- /dev/null +++ b/changes/internal/1758-phase2-r1-2k.md @@ -0,0 +1 @@ +Give constant deduplication and disassembly exact int arms. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 5b3c29937..86dcb89cc 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,15 +1,15 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1859 classified=1859 unclassified=0 +examined=1865 classified=1865 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 382 CASE=60 DATA=5 TEST=314 YIELD=3 +(a) type tests 380 CASE=60 DATA=5 TEST=312 YIELD=3 (b) payload reads 556 RAW=139 READ=417 (c) producers 474 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=5 WRITE=23 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 -(e) number formatting 15 CASE=2 FORMAT=3 PARSE=1 RAW=3 READ=3 TEST=3 -(f) equality, ordering and hashing 42 CASE=2 PRODUCE=4 RAW=12 READ=9 TEST=15 +(e) number formatting 17 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=4 +(f) equality, ordering and hashing 48 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=18 (g) tape encode and decode 25 CASE=4 DATA=2 PARSE=7 PRODUCE=5 RAW=5 TEST=2 (h) JSON, store and db encoders 78 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=5 READ=24 TEST=18 (i) observer numeric paths 95 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=23 @@ -19,11 +19,11 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 make_num 364 eigs_num_arg 151 eigs_list_num 130 -VAL_INT 124 -VAL_FLOAT 122 +VAL_INT 128 +VAL_FLOAT 127 SLOT_F64_RAW 83 -VAL_NUM 77 -VAL_NUM_RAW 68 +VAL_NUM 70 +VAL_NUM_RAW 64 num_guard 60 AST_NUM 52 eigs_slot_num 50 @@ -32,10 +32,10 @@ eigs_value_as_num 48 slot_from_f64 41 buffer_read_num 38 slot_is_smi 37 -VAL_I64_RAW 31 +VAL_I64_RAW 35 +VAL_F64_RAW 25 buffer_read_byte 22 list_set_num 22 -VAL_F64_RAW 21 slot_smi_val 18 slot_f64_value 16 strtod 16 @@ -89,9 +89,9 @@ value_slot.h 22 a=8 b=11 c=3 compiler.c 21 a=13 b=5 c=1 i=2 trace.c 20 g=20 ext_net.c 19 a=5 b=7 c=7 +chunk.c 17 a=1 e=4 f=12 model_infer.c 16 a=1 b=6 c=9 ext_http.c 14 a=3 b=4 c=7 -chunk.c 11 a=3 e=2 f=6 eigs_embed.c 8 j=8 model_train.c 7 a=1 b=4 c=1 i=1 embed_concurrent.c 6 j=6 @@ -1117,17 +1117,23 @@ builtins_tensor.c:2406 builtin_tensor_load VAL_INT TEST a builtins_tensor.c:2407 builtin_tensor_load eigs_list_num READ b builtins_tensor.c:2408 builtin_tensor_load eigs_list_num READ b builtins_tensor.c:2485 builtin_tensor_load num_guard_named GUARD c -chunk.c:194 const_hash_value VAL_NUM TEST f -chunk.c:195 const_hash_value VAL_NUM_RAW RAW f -chunk.c:213 const_equal VAL_NUM TEST f -chunk.c:213 const_equal VAL_NUM TEST f -chunk.c:214 const_equal VAL_NUM_RAW RAW f -chunk.c:214 const_equal VAL_NUM_RAW RAW f -chunk.c:234 const_dedup_grow VAL_NUM TEST a -chunk.c:243 chunk_add_constant_ex VAL_NUM TEST a -chunk.c:421 chunk_disassemble VAL_NUM TEST e -chunk.c:422 chunk_disassemble VAL_NUM_RAW RAW e -chunk.c:1090 chunk_scan_leaf_accessor/OP_CONST VAL_NUM TEST a +chunk.c:194 const_hash_value VAL_FLOAT TEST f +chunk.c:195 const_hash_value VAL_F64_RAW RAW f +chunk.c:204 const_hash_value VAL_INT TEST f +chunk.c:205 const_hash_value VAL_I64_RAW RAW f +chunk.c:220 const_equal VAL_FLOAT TEST f +chunk.c:220 const_equal VAL_FLOAT TEST f +chunk.c:221 const_equal VAL_F64_RAW RAW f +chunk.c:221 const_equal VAL_F64_RAW RAW f +chunk.c:222 const_equal VAL_INT TEST f +chunk.c:222 const_equal VAL_INT TEST f +chunk.c:223 const_equal VAL_I64_RAW RAW f +chunk.c:223 const_equal VAL_I64_RAW RAW f +chunk.c:430 chunk_disassemble VAL_FLOAT TEST e +chunk.c:431 chunk_disassemble VAL_F64_RAW RAW e +chunk.c:432 chunk_disassemble VAL_INT TEST e +chunk.c:433 chunk_disassemble VAL_I64_RAW RAW e +chunk.c:1101 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a compiler.c:582 add_num_constant make_num PRODUCE c compiler.c:791 collect_referenced_names_skip AST_NUM CASE a compiler.c:935 collect_referenced_names AST_NUM CASE a diff --git a/src/chunk.c b/src/chunk.c index e52e0f08b..531d2aa38 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -189,10 +189,10 @@ void chunk_patch_jump(EigsChunk *chunk, int offset) { * Equality is EXACTLY the old linear scan's tests, so pools stay * byte-identical (the AOT oracle depends on that): NaN never equals * itself (each NaN appends), and -0.0 merges with +0.0 (they hash the - * same and compare ==). Non-NUM/STR constants are never deduped. */ + * same and compare ==). Only numeric and string constants are deduped; numeric kinds stay distinct. */ static uint32_t const_hash_value(const Value *v) { - if (v->type == VAL_NUM) { - double d = VAL_NUM_RAW(v); + if (v->type == VAL_FLOAT) { + double d = VAL_F64_RAW(v); if (d == 0.0) d = 0.0; /* fold -0.0 into +0.0, matching == */ uint64_t bits; memcpy(&bits, &d, sizeof bits); @@ -201,6 +201,13 @@ static uint32_t const_hash_value(const Value *v) { bits ^= bits >> 33; return (uint32_t)bits; } + if (v->type == VAL_INT) { + uint64_t bits = (uint64_t)VAL_I64_RAW(v); + bits ^= bits >> 33; + bits *= 0xff51afd7ed558ccdULL; + bits ^= bits >> 33; + return (uint32_t)bits ^ 0x9e3779b9u; /* kind is part of a constant's key */ + } uint32_t h = 2166136261u; /* FNV-1a */ for (const char *p = v->data.str; *p; p++) { h ^= (unsigned char)*p; @@ -210,8 +217,10 @@ static uint32_t const_hash_value(const Value *v) { } static int const_equal(const Value *a, const Value *b) { - if (a->type == VAL_NUM && b->type == VAL_NUM) - return VAL_NUM_RAW(a) == VAL_NUM_RAW(b); + if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) + return VAL_F64_RAW(a) == VAL_F64_RAW(b); + if (a->type == VAL_INT && b->type == VAL_INT) + return VAL_I64_RAW(a) == VAL_I64_RAW(b); if (a->type == VAL_STR && b->type == VAL_STR) return strcmp(a->data.str, b->data.str) == 0; return 0; @@ -231,7 +240,7 @@ static void const_dedup_grow(EigsChunk *c) { c->const_dedup_cap = new_cap; for (int i = 0; i < c->const_count; i++) { Value *v = c->constants[i]; - if (v->type == VAL_NUM || v->type == VAL_STR) + if (val_is_number(v) || v->type == VAL_STR) const_dedup_insert(c, const_hash_value(v), i); } } @@ -240,7 +249,7 @@ static int chunk_add_constant_ex(EigsChunk *chunk, Value *val, int dedup) { /* Deduplicate numbers and strings via the hash index — the linear * scan here was O(pool) per add: 92% of compile time on a 12k-name * generated program (#341). */ - int hashable = (val->type == VAL_NUM || val->type == VAL_STR); + int hashable = (val_is_number(val) || val->type == VAL_STR); uint32_t h = 0; if (hashable) { if ((chunk->const_count + 1) * 2 > chunk->const_dedup_cap) @@ -418,8 +427,10 @@ void chunk_disassemble(EigsChunk *chunk, const char *label) { fprintf(stderr, " %d", arg); if (op == OP_CONST && arg < (uint16_t)chunk->const_count) { Value *v = chunk->constants[arg]; - if (v->type == VAL_NUM) - fprintf(stderr, " (%.6g)", VAL_NUM_RAW(v)); + if (v->type == VAL_FLOAT) + fprintf(stderr, " (%.6g)", VAL_F64_RAW(v)); + else if (v->type == VAL_INT) + fprintf(stderr, " (%lld)", (long long)VAL_I64_RAW(v)); else if (v->type == VAL_STR) fprintf(stderr, " (\"%s\")", v->data.str); } @@ -1087,7 +1098,7 @@ void chunk_scan_leaf_accessor(EigsChunk *c) { if (ip + 2 > end) return; uint16_t idx = (uint16_t)(ip[0] | (ip[1] << 8)); ip += 2; if (idx >= (uint16_t)c->const_count) return; - if (c->constants[idx]->type != VAL_NUM) return; + if (c->constants[idx]->type != VAL_FLOAT) return; depth++; break; } diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index d7d9522a6..6ef58c020 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -18,9 +18,9 @@ container.h|eigs_slot_num|1|required numeric accessor reads only after slot_is_f container.h|eigs_slot_opt_num|1|optional numeric accessor reads only after slot_is_f64 container.h|list_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) container.h|list_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 -chunk.c|chunk_disassemble|1|debug disassembly prints a constant behind its own type == VAL_NUM test -chunk.c|const_equal|2|constant-pool dedup compares two constants after testing both are VAL_NUM -chunk.c|const_hash_value|1|constant-pool hash of a constant inside its type == VAL_NUM branch +chunk.c|chunk_disassemble|2|debug disassembly prints a constant behind its own type == VAL_NUM test +chunk.c|const_equal|4|constant-pool dedup compares two constants after testing both are VAL_NUM +chunk.c|const_hash_value|2|constant-pool hash of a constant inside its type == VAL_NUM branch eigenscript.c|chan_clone_rec|2|channel deep-copy, switch case VAL_NUM; case VAL_INT names the int it refuses (unwired, R1.3) eigenscript.c|compute_entropy_impl|2|observer entropy, switch case VAL_NUM, and case VAL_INT (an int's entropy is its double's, design 7) eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_f64 From 6640b3d5c1ce1042f3f78efe2c8228545be2c777 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:47:18 -0500 Subject: [PATCH 033/188] phase2 R1.2l: migrate float tape tokens and retain the v7 int refusal (#1758) Migrate 6 deprecated code-token sites in trace.c. Float behavior and the R1.6 bridge names stay unchanged; int consumers preserve their kind or refuse through the R1.3 unwired token. Validation: make all built; inventory PASS; num-read PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2l.md | 1 + docs/design/phase2-inventory.txt | 51 ++++++++++++++------------- src/trace.c | 12 ++++--- 3 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2l.md diff --git a/changes/internal/1758-phase2-r1-2l.md b/changes/internal/1758-phase2-r1-2l.md new file mode 100644 index 000000000..6db0d0627 --- /dev/null +++ b/changes/internal/1758-phase2-r1-2l.md @@ -0,0 +1 @@ +Migrate float tape tokens and retain the v7 int refusal. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 86dcb89cc..0ddf1cdf9 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1865 classified=1865 unclassified=0 +examined=1868 classified=1868 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category @@ -10,7 +10,7 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 17 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=4 (f) equality, ordering and hashing 48 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=18 -(g) tape encode and decode 25 CASE=4 DATA=2 PARSE=7 PRODUCE=5 RAW=5 TEST=2 +(g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 (h) JSON, store and db encoders 78 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=5 READ=24 TEST=18 (i) observer numeric paths 95 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=23 (j) embed API 65 CASE=2 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 @@ -18,12 +18,12 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per token make_num 364 eigs_num_arg 151 +VAL_FLOAT 132 +VAL_INT 130 eigs_list_num 130 -VAL_INT 128 -VAL_FLOAT 127 SLOT_F64_RAW 83 -VAL_NUM 70 -VAL_NUM_RAW 64 +VAL_NUM 66 +VAL_NUM_RAW 62 num_guard 60 AST_NUM 52 eigs_slot_num 50 @@ -33,7 +33,7 @@ slot_from_f64 41 buffer_read_num 38 slot_is_smi 37 VAL_I64_RAW 35 -VAL_F64_RAW 25 +VAL_F64_RAW 27 buffer_read_byte 22 list_set_num 22 slot_smi_val 18 @@ -85,9 +85,9 @@ eigenscript.h 44 a=7 b=24 c=12 e=1 builtins_host.c 40 a=4 b=24 c=12 jit_smoke.c 31 d=31 lint.c 29 a=29 +trace.c 23 g=23 value_slot.h 22 a=8 b=11 c=3 compiler.c 21 a=13 b=5 c=1 i=2 -trace.c 20 g=20 ext_net.c 19 a=5 b=7 c=7 chunk.c 17 a=1 e=4 f=12 model_infer.c 16 a=1 b=6 c=9 @@ -2059,22 +2059,25 @@ trace.c:742 trace_query_at slot_from_f64 PRODUCE g trace.c:757 trace_query_at slot_from_f64 PRODUCE g trace.c:806 trace_query_when slot_from_f64 PRODUCE g trace.c:827 trace_query_when slot_from_f64 PRODUCE g -trace.c:1927 #define TK_NUM_ VAL_NUM DATA g -trace.c:2018 kinds_text VAL_NUM DATA g -trace.c:2324 parse_value_p strtod PARSE g -trace.c:2407 parse_value_p strtod PARSE g -trace.c:2410 parse_value_p make_num PRODUCE g -trace.c:2820 write_value_ptr VAL_NUM CASE g -trace.c:2820 write_value_ptr VAL_NUM_RAW RAW g -trace.c:2823 write_value_ptr VAL_I64_RAW RAW g -trace.c:2823 write_value_ptr VAL_INT CASE g -trace.c:2840 write_slot SLOT_F64_RAW RAW g -trace.c:2840 write_slot slot_is_f64 TEST g -trace.c:2847 write_slot slot_is_smi TEST g -trace.c:2961 write_value_ptr_full VAL_NUM CASE g -trace.c:2961 write_value_ptr_full VAL_NUM_RAW RAW g -trace.c:2962 write_value_ptr_full VAL_I64_RAW RAW g -trace.c:2962 write_value_ptr_full VAL_INT CASE g +trace.c:1927 #define TK_NUM_ VAL_FLOAT DATA g +trace.c:1927 #define TK_NUM_ VAL_INT DATA g +trace.c:2019 kinds_text VAL_FLOAT DATA g +trace.c:2019 kinds_text VAL_INT DATA g +trace.c:2020 kinds_text VAL_FLOAT DATA g +trace.c:2326 parse_value_p strtod PARSE g +trace.c:2409 parse_value_p strtod PARSE g +trace.c:2412 parse_value_p make_num PRODUCE g +trace.c:2822 write_value_ptr VAL_F64_RAW RAW g +trace.c:2822 write_value_ptr VAL_FLOAT CASE g +trace.c:2825 write_value_ptr VAL_I64_RAW RAW g +trace.c:2825 write_value_ptr VAL_INT CASE g +trace.c:2842 write_slot SLOT_F64_RAW RAW g +trace.c:2842 write_slot slot_is_f64 TEST g +trace.c:2849 write_slot slot_is_smi TEST g +trace.c:2963 write_value_ptr_full VAL_F64_RAW RAW g +trace.c:2963 write_value_ptr_full VAL_FLOAT CASE g +trace.c:2964 write_value_ptr_full VAL_I64_RAW RAW g +trace.c:2964 write_value_ptr_full VAL_INT CASE g value_slot.h:106 slot_is_f64 slot_is_f64 TEST a value_slot.h:112 slot_is_smi slot_is_smi TEST a value_slot.h:123 #define SLOT_F64_RAW SLOT_F64_RAW RAW b diff --git a/src/trace.c b/src/trace.c index b818f2272..6e29d0b90 100644 --- a/src/trace.c +++ b/src/trace.c @@ -13,7 +13,7 @@ * O win per-binding observer window override (v3) * * Value encoding: - * numeric (immediate, tracked, or heap VAL_NUM) + * numeric (immediate, tracked, or heap VAL_FLOAT) * null VAL_NULL / immediate null slot * true|false * "" heap string, content truncated at TRACE_STR_MAX @@ -1924,7 +1924,7 @@ static void replay_malformed_value(const char *value) { * API declare their kinds with eigs_trace_declare_kind; a name in neither * table is refused at replay. Bits are ValType (TK below). */ #define TK(t) (1u << (t)) -#define TK_NUM_ TK(VAL_NUM) +#define TK_NUM_ (TK(VAL_FLOAT) | TK(VAL_INT)) #define TK_STR_ TK(VAL_STR) #define TK_BOOL_ TK(VAL_BOOL) #define TK_NULL_ TK(VAL_NULL) @@ -2015,7 +2015,9 @@ static unsigned replay_expected_kinds(const char *fn) { /* "a bool", "a list or null" */ static void kinds_text(unsigned kinds, char *buf, size_t n) { - static const ValType order[] = {VAL_NUM, VAL_STR, VAL_BOOL, VAL_LIST, VAL_DICT, + /* Both numeric kinds have the one surface name, num. */ + if (kinds & TK(VAL_INT)) kinds |= TK(VAL_FLOAT); + static const ValType order[] = {VAL_FLOAT, VAL_STR, VAL_BOOL, VAL_LIST, VAL_DICT, VAL_BUFFER, VAL_NULL}; size_t used = 0; int first = 1; buf[0] = '\0'; @@ -2817,7 +2819,7 @@ static void write_string(const char *s) { static void write_value_ptr(Value *v) { if (!v) { tp_puts("null"); return; } switch (v->type) { - case VAL_NUM: tp_printf("%.17g", VAL_NUM_RAW(v)); break; + case VAL_FLOAT: tp_printf("%.17g", VAL_F64_RAW(v)); break; /* #1758 R1.2a: an int is written as digits by tape v7 (R1.3); a v6 * tape cannot tell it from a float, so it is refused until then. */ case VAL_INT: eigs_int_unwired("write_value_ptr", (uint64_t)VAL_I64_RAW(v)); @@ -2958,7 +2960,7 @@ static void write_value_ptr_full(Value *v, int *budget) { if (*budget <= 0) return; if (!v) { wf_puts("null", budget); return; } switch (v->type) { - case VAL_NUM: wf_printf(budget, "%.17g", VAL_NUM_RAW(v)); break; + case VAL_FLOAT: wf_printf(budget, "%.17g", VAL_F64_RAW(v)); break; case VAL_INT: eigs_int_unwired("write_value_ptr_full", (uint64_t)VAL_I64_RAW(v)); /* #1758: tape v7, R1.3 */ case VAL_NULL: wf_puts("null", budget); break; case VAL_BOOL: wf_puts(v->data.boolean ? "true" : "false", budget); break; From d5ff982cb3214a8e25ee75019559116d8acfc0cd Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:47:30 -0500 Subject: [PATCH 034/188] phase2 R1.2m: migrate the store encoder and numeric bridge (#1758) Migrate 14 deprecated code-token sites in ext_store.c. Float behavior and the R1.6 bridge names stay unchanged; int consumers preserve their kind or refuse through the R1.3 unwired token. Validation: make all built; inventory PASS; num-read PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2m.md | 1 + docs/design/phase2-inventory.txt | 45 ++++++++++----------------- src/ext_store.c | 26 ++++++++-------- 3 files changed, 30 insertions(+), 42 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2m.md diff --git a/changes/internal/1758-phase2-r1-2m.md b/changes/internal/1758-phase2-r1-2m.md new file mode 100644 index 000000000..236ba0e89 --- /dev/null +++ b/changes/internal/1758-phase2-r1-2m.md @@ -0,0 +1 @@ +Migrate the store encoder and numeric bridge. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 0ddf1cdf9..4db493686 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1868 classified=1868 unclassified=0 +examined=1855 classified=1855 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category @@ -11,21 +11,21 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 (e) number formatting 17 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=4 (f) equality, ordering and hashing 48 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=18 (g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 -(h) JSON, store and db encoders 78 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=5 READ=24 TEST=18 +(h) JSON, store and db encoders 65 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=5 READ=24 TEST=5 (i) observer numeric paths 95 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=23 (j) embed API 65 CASE=2 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 ## Per token make_num 364 eigs_num_arg 151 -VAL_FLOAT 132 +VAL_FLOAT 133 VAL_INT 130 eigs_list_num 130 SLOT_F64_RAW 83 -VAL_NUM 66 VAL_NUM_RAW 62 num_guard 60 AST_NUM 52 +VAL_NUM 52 eigs_slot_num 50 slot_is_f64 50 eigs_value_as_num 48 @@ -79,9 +79,9 @@ eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 builtins_buf.c 102 a=26 b=37 c=39 jit.c 96 d=96 container.h 95 a=36 b=31 c=28 -ext_store.c 54 h=54 embed_smoke.c 50 j=50 eigenscript.h 44 a=7 b=24 c=12 e=1 +ext_store.c 41 h=41 builtins_host.c 40 a=4 b=24 c=12 jit_smoke.c 31 d=31 lint.c 29 a=29 @@ -487,16 +487,16 @@ sort_by builtin_sort_by other spawn builtin_spawn int-preserving - - make_num sqrt builtin_tensor_sqrt float-producing - - eigs_num_arg,make_num state_at builtin_state_at int-requiring - - eigs_num_arg -store_close builtin_store_close int-requiring - - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val -store_collections builtin_store_collections int-requiring - - VAL_NUM,eigs_num_arg -store_count builtin_store_count int-requiring - - VAL_NUM,eigs_num_arg,make_num -store_delete builtin_store_delete int-requiring LOSS - VAL_NUM,eigs_num_arg -store_drop builtin_store_drop int-requiring - - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val -store_get builtin_store_get int-requiring LOSS - VAL_NUM,eigs_num_arg,make_num,strtod -store_open builtin_store_open int-preserving - - VAL_NUM,eigs_num_arg,make_num,strtod -store_put builtin_store_put other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val -store_query builtin_store_query other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod -store_update builtin_store_update other LOSS - VAL_I64_RAW,VAL_INT,VAL_NUM,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val +store_close builtin_store_close int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val +store_collections builtin_store_collections int-requiring - - eigs_num_arg +store_count builtin_store_count int-requiring - - eigs_num_arg,make_num +store_delete builtin_store_delete int-requiring LOSS - eigs_num_arg +store_drop builtin_store_drop int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val +store_get builtin_store_get int-requiring LOSS - eigs_num_arg,make_num,strtod +store_open builtin_store_open int-preserving - - eigs_num_arg,make_num,strtod +store_put builtin_store_put other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val +store_query builtin_store_query other LOSS - eigs_num_arg,make_num,strtod +store_update builtin_store_update other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val str builtin_str other - - eigs_num_text str_from_bytes builtin_str_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte stream_open builtin_stream_open int-requiring - - eigs_num_arg @@ -1805,42 +1805,30 @@ ext_store.c:173 store_json_encode_slot slot_is_f64 TEST h ext_store.c:174 store_json_encode_slot eigs_slot_num READ h ext_store.c:181 store_json_encode_slot slot_is_smi TEST h ext_store.c:183 store_json_encode_slot slot_smi_val RAW h -ext_store.c:195 store_json_encode VAL_NUM CASE h +ext_store.c:195 store_json_encode VAL_FLOAT CASE h ext_store.c:196 store_json_encode eigs_num_arg READ h ext_store.c:209 store_json_encode VAL_INT CASE h ext_store.c:211 store_json_encode VAL_I64_RAW RAW h ext_store.c:334 store_json_parse_number strtod PARSE h ext_store.c:337 store_json_parse_number make_num PRODUCE h -ext_store.c:373 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:373 store_buffer_from_tag VAL_NUM TEST h ext_store.c:383 store_buffer_from_tag eigs_num_arg READ h ext_store.c:383 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:403 store_buffer_from_tag VAL_NUM TEST h -ext_store.c:418 store_buffer_from_tag VAL_NUM TEST h ext_store.c:418 store_buffer_from_tag eigs_num_arg READ h -ext_store.c:756 store_load_catalog VAL_NUM TEST h -ext_store.c:756 store_load_catalog VAL_NUM TEST h ext_store.c:761 store_load_catalog eigs_num_arg READ h -ext_store.c:828 get_store_why VAL_NUM TEST h ext_store.c:829 get_store_why eigs_num_arg READ h -ext_store.c:831 get_store_why VAL_NUM TEST h ext_store.c:831 get_store_why eigs_num_arg READ h ext_store.c:979 builtin_store_open make_num PRODUCE h ext_store.c:980 builtin_store_open make_num PRODUCE h -ext_store.c:993 builtin_store_close VAL_NUM TEST h ext_store.c:993 builtin_store_close eigs_num_arg READ h -ext_store.c:995 builtin_store_close VAL_NUM TEST h ext_store.c:995 builtin_store_close eigs_num_arg READ h ext_store.c:1041 builtin_store_put make_num PRODUCE h ext_store.c:1042 builtin_store_put make_num PRODUCE h ext_store.c:1056 builtin_store_put eigs_num_arg READ h ext_store.c:1057 builtin_store_put eigs_num_arg READ h ext_store.c:1069 builtin_store_put make_num PRODUCE h -ext_store.c:1193 builtin_store_get VAL_NUM TEST h ext_store.c:1194 builtin_store_get eigs_num_arg READ h ext_store.c:1203 builtin_store_get eigs_num_arg READ h ext_store.c:1261 store_locate eigs_num_arg READ h -ext_store.c:1357 builtin_store_delete VAL_NUM TEST h ext_store.c:1358 builtin_store_delete eigs_num_arg READ h ext_store.c:1404 builtin_store_query eigs_num_arg READ h ext_store.c:1439 builtin_store_count make_num PRODUCE h @@ -1852,7 +1840,6 @@ ext_store.c:1461 builtin_store_count make_num PRODUCE h ext_store.c:1462 builtin_store_count eigs_num_arg READ h ext_store.c:1473 builtin_store_count make_num PRODUCE h ext_store.c:1479 builtin_store_count make_num PRODUCE h -ext_store.c:1513 builtin_store_update VAL_NUM TEST h ext_store.c:1514 builtin_store_update eigs_num_arg READ h ext_store.c:1655 builtin_store_drop eigs_num_arg READ h jit.c:1282 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d diff --git a/src/ext_store.c b/src/ext_store.c index 11ad82833..8052fd645 100644 --- a/src/ext_store.c +++ b/src/ext_store.c @@ -156,7 +156,7 @@ static int store_nonfinite_sentinel(const char *s, double *out) { /* Buffer elements use the 17-significant-digit form, as trace.c's buffer tape * encoding does: %.17g is the shortest width that round-trips a double * bit-exactly, and a buffer holding samples or weights would otherwise come - * back subtly altered. (VAL_NUM's own %d/%.15g encoding is untouched.) */ + * back subtly altered. (VAL_FLOAT's own %d/%.15g encoding is untouched.) */ static void store_json_encode_buf_elem(strbuf *out, double d) { if (isnan(d)) { strbuf_append(out, "\"nan\""); return; } if (isinf(d)) { strbuf_append(out, d < 0 ? "\"-inf\"" : "\"inf\""); return; } @@ -192,7 +192,7 @@ static void store_json_encode(Value *v, strbuf *out) { return; } switch (v->type) { - case VAL_NUM: { + case VAL_FLOAT: { double n = eigs_num_arg(v, __func__); /* #816: magnitude BEFORE the narrowing cast (same class as * #695) — converting a double beyond int's range is UB, and @@ -370,7 +370,7 @@ static Value* store_buffer_from_tag(Value *dict) { Value *rv = list_get_view(shape, 0, &(EigsView){{0}}); Value *cv = list_get_view(shape, 1, &(EigsView){{0}}); - if (!rv || rv->type != VAL_NUM || !cv || cv->type != VAL_NUM) return NULL; + if (!rv || !val_is_number(rv) || !cv || !val_is_number(cv)) return NULL; /* Range-gate BEFORE narrowing. A stored shape is whatever double the file * holds, and (int)d is undefined when d is outside int's range (C11 @@ -400,7 +400,7 @@ static Value* store_buffer_from_tag(Value *dict) { for (int i = 0; i < count; i++) { Value *e = list_get_view(body, i, &(EigsView){{0}}); if (!e) return NULL; - if (e->type == VAL_NUM) continue; + if (val_is_number(e)) continue; if (e->type == VAL_STR && store_nonfinite_sentinel(e->data.str, NULL)) continue; return NULL; } @@ -415,7 +415,7 @@ static Value* store_buffer_from_tag(Value *dict) { for (int i = 0; i < count; i++) { Value *e = list_get_view(body, i, &(EigsView){{0}}); double d = 0; - if (e->type == VAL_NUM) d = eigs_num_arg(e, __func__); + if (val_is_number(e)) d = eigs_num_arg(e, __func__); else store_nonfinite_sentinel(e->data.str, &d); buf->data.buffer.data[i] = d; } @@ -753,7 +753,7 @@ static int store_load_catalog(Store *store) { } Value *rv = store_dict_get_view(col, "root", &(EigsView){{0}}); Value *nv = store_dict_get_view(col, "next_id", &(EigsView){{0}}); - if (!rv || rv->type != VAL_NUM || !nv || nv->type != VAL_NUM) { + if (!rv || !val_is_number(rv) || !nv || !val_is_number(nv)) { fprintf(stderr, "store_open: collection '%s' missing root or next_id\n", name); free(visited); return -1; @@ -825,10 +825,10 @@ static Store* get_store_why(Value *v, int *why, int *out_id) { *out_id = 0; if (!v || v->type != VAL_DICT) return NULL; Value *sv = store_dict_get_view(v, "_store_id", &(EigsView){{0}}); - if (!sv || sv->type != VAL_NUM) return NULL; + if (!sv || !val_is_number(sv)) return NULL; *out_id = (int)eigs_num_arg(sv, __func__); Value *gv = store_dict_get_view(v, "_store_gen", &(EigsView){{0}}); - uint32_t gen = (gv && gv->type == VAL_NUM) ? (uint32_t)eigs_num_arg(gv, __func__) : 0; + uint32_t gen = (gv && val_is_number(gv)) ? (uint32_t)eigs_num_arg(gv, __func__) : 0; return (Store*)handle_lookup(*out_id, gen, HANDLE_STORE, why); } @@ -990,9 +990,9 @@ static Value* builtin_store_close(Value *arg) { /* Release handle BEFORE freeing memory to prevent use-after-free * if another thread calls get_store() concurrently. */ Value *id_val = (arg && arg->type == VAL_DICT) ? store_dict_get_view(arg, "_store_id", &(EigsView){{0}}) : NULL; - int hid = (id_val && id_val->type == VAL_NUM) ? (int)eigs_num_arg(id_val, __func__) : -1; + int hid = (id_val && val_is_number(id_val)) ? (int)eigs_num_arg(id_val, __func__) : -1; Value *g_val = (arg && arg->type == VAL_DICT) ? store_dict_get_view(arg, "_store_gen", &(EigsView){{0}}) : NULL; - uint32_t hgen = (g_val && g_val->type == VAL_NUM) ? (uint32_t)eigs_num_arg(g_val, __func__) : 0; + uint32_t hgen = (g_val && val_is_number(g_val)) ? (uint32_t)eigs_num_arg(g_val, __func__) : 0; handle_release(hid, hgen); store->dirty = 1; /* Force flush */ store_flush_catalog(store); @@ -1190,7 +1190,7 @@ static Value* builtin_store_get(Value *arg) { if (key_val->type == VAL_STR) { strncpy(key_buf, key_val->data.str, STORE_MAX_KEY_LEN - 1); key_buf[STORE_MAX_KEY_LEN - 1] = '\0'; - } else if (key_val->type == VAL_NUM) { + } else if (val_is_number(key_val)) { snprintf(key_buf, STORE_MAX_KEY_LEN, "%d", (int)eigs_num_arg(key_val, __func__)); } else { return make_null(); @@ -1354,7 +1354,7 @@ static Value* builtin_store_delete(Value *arg) { if (key_val->type == VAL_STR) { strncpy(key_buf, key_val->data.str, STORE_MAX_KEY_LEN - 1); key_buf[STORE_MAX_KEY_LEN - 1] = '\0'; - } else if (key_val->type == VAL_NUM) { + } else if (val_is_number(key_val)) { snprintf(key_buf, STORE_MAX_KEY_LEN, "%d", (int)eigs_num_arg(key_val, __func__)); } else { /* Reaching the else arm IS the rejection: the key is neither a string @@ -1510,7 +1510,7 @@ static Value* builtin_store_update(Value *arg) { if (key_val->type == VAL_STR) { strncpy(key_buf, key_val->data.str, STORE_MAX_KEY_LEN - 1); key_buf[STORE_MAX_KEY_LEN - 1] = '\0'; - } else if (key_val->type == VAL_NUM) { + } else if (val_is_number(key_val)) { snprintf(key_buf, STORE_MAX_KEY_LEN, "%d", (int)eigs_num_arg(key_val, __func__)); } else { /* Reaching the else arm IS the rejection: the key is neither a string From 23262614e1682aca3aad6d5ed84f2a1ac6cd8173 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:47:39 -0500 Subject: [PATCH 035/188] phase2 R1.2n: admit int Values in the embedding number bridge (#1758) Migrate 4 deprecated code-token sites in eigs_embed.c. Float behavior and the R1.6 bridge names stay unchanged; int consumers preserve their kind or refuse through the R1.3 unwired token. Validation: make all built; inventory PASS; num-read PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2n.md | 1 + docs/design/phase2-inventory.txt | 31 +++++++++++++++------------ src/eigs_embed.c | 7 +++--- tools/num_read_allowlist.txt | 2 +- 4 files changed, 23 insertions(+), 18 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2n.md diff --git a/changes/internal/1758-phase2-r1-2n.md b/changes/internal/1758-phase2-r1-2n.md new file mode 100644 index 000000000..e62a5f6a9 --- /dev/null +++ b/changes/internal/1758-phase2-r1-2n.md @@ -0,0 +1 @@ +Admit int Values in the embedding number bridge. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 4db493686..bd0f760f2 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1855 classified=1855 unclassified=0 +examined=1858 classified=1858 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category @@ -13,27 +13,27 @@ files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 (g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 (h) JSON, store and db encoders 65 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=5 READ=24 TEST=5 (i) observer numeric paths 95 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=23 -(j) embed API 65 CASE=2 DATA=1 GUARD=1 PRODUCE=1 RAW=5 READ=51 TEST=1 WRITE=3 +(j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token make_num 364 eigs_num_arg 151 -VAL_FLOAT 133 -VAL_INT 130 +VAL_FLOAT 136 +VAL_INT 132 eigs_list_num 130 SLOT_F64_RAW 83 -VAL_NUM_RAW 62 +VAL_NUM_RAW 61 num_guard 60 AST_NUM 52 -VAL_NUM 52 eigs_slot_num 50 slot_is_f64 50 +VAL_NUM 49 eigs_value_as_num 48 slot_from_f64 41 buffer_read_num 38 slot_is_smi 37 -VAL_I64_RAW 35 -VAL_F64_RAW 27 +VAL_I64_RAW 36 +VAL_F64_RAW 28 buffer_read_byte 22 list_set_num 22 slot_smi_val 18 @@ -92,7 +92,7 @@ ext_net.c 19 a=5 b=7 c=7 chunk.c 17 a=1 e=4 f=12 model_infer.c 16 a=1 b=6 c=9 ext_http.c 14 a=3 b=4 c=7 -eigs_embed.c 8 j=8 +eigs_embed.c 11 j=11 model_train.c 7 a=1 b=4 c=1 i=1 embed_concurrent.c 6 j=6 parser.c 5 a=2 b=1 c=2 @@ -1410,13 +1410,16 @@ eigenscript.h:1973 num_guard_named num_guard_named GUARD c eigenscript.h:1979 num_guard_named num_guard GUARD c eigenscript.h:2291 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j -eigs_embed.c:314 eigs_value_type VAL_NUM CASE j +eigs_embed.c:314 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j eigs_embed.c:340 eigs_value_as_num eigs_value_as_num READ j -eigs_embed.c:342 eigs_value_as_num VAL_NUM TEST j -eigs_embed.c:342 eigs_value_as_num VAL_NUM_RAW RAW j -eigs_embed.c:395 eigs_value_buffer_get buffer_read_num READ j -eigs_embed.c:434 eigs_trace_declare_kind VAL_NUM DATA j +eigs_embed.c:342 eigs_value_as_num VAL_I64_RAW RAW j +eigs_embed.c:342 eigs_value_as_num VAL_INT TEST j +eigs_embed.c:343 eigs_value_as_num VAL_F64_RAW RAW j +eigs_embed.c:343 eigs_value_as_num VAL_FLOAT TEST j +eigs_embed.c:396 eigs_value_buffer_get buffer_read_num READ j +eigs_embed.c:435 eigs_trace_declare_kind VAL_FLOAT DATA j +eigs_embed.c:435 eigs_trace_declare_kind VAL_INT DATA j eigs_embed.h:171 eigs_value_as_num READ j embed_concurrent.c:106 global_worker eigs_value_as_num READ j embed_concurrent.c:768 take_drain eigs_value_as_num READ j diff --git a/src/eigs_embed.c b/src/eigs_embed.c index 45efa0201..bba96860d 100644 --- a/src/eigs_embed.c +++ b/src/eigs_embed.c @@ -311,7 +311,7 @@ void eigs_value_release(EigsValue *v) { if (v) val_decref(v); } EigsValueType eigs_value_type(EigsValue *v) { if (!v) return EIGS_TYPE_NULL; switch (v->type) { - case VAL_NUM: return EIGS_TYPE_NUM; + case VAL_FLOAT: return EIGS_TYPE_NUM; case VAL_INT: return EIGS_TYPE_NUM; /* #1758 (Q3): one embed number type */ case VAL_STR: return EIGS_TYPE_STR; case VAL_LIST: return EIGS_TYPE_LIST; @@ -339,7 +339,8 @@ int eigs_value_as_bool(EigsValue *v) { * test eigs_value_type first, or read a bool with eigs_value_as_bool. */ double eigs_value_as_num(EigsValue *v) { if (v && v->type == VAL_BOOL) return NAN; - return (v && v->type == VAL_NUM) ? VAL_NUM_RAW(v) : 0.0; + if (v && v->type == VAL_INT) return (double)VAL_I64_RAW(v); /* Q3: converting accessor */ + return (v && v->type == VAL_FLOAT) ? VAL_F64_RAW(v) : 0.0; } const char *eigs_value_as_string(EigsValue *v) { @@ -431,7 +432,7 @@ void eigs_trace_record_nondet(const char *name, EigsValue *v) { /* #1637: EIGS_KIND(EIGS_TYPE_X) bits -> the runtime's ValType bits. */ int eigs_trace_declare_kind(const char *name, unsigned kinds) { static const struct { EigsValueType e; ValType v; } map[] = { - {EIGS_TYPE_NULL, VAL_NULL}, {EIGS_TYPE_NUM, VAL_NUM}, {EIGS_TYPE_STR, VAL_STR}, + {EIGS_TYPE_NULL, VAL_NULL}, {EIGS_TYPE_NUM, VAL_FLOAT}, {EIGS_TYPE_NUM, VAL_INT}, {EIGS_TYPE_STR, VAL_STR}, {EIGS_TYPE_LIST, VAL_LIST}, {EIGS_TYPE_DICT, VAL_DICT}, {EIGS_TYPE_BUFFER, VAL_BUFFER}, {EIGS_TYPE_BOOL, VAL_BOOL}, }; diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 6ef58c020..4b7d97823 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -42,7 +42,7 @@ eigenscript.h|#define VAL_NUM_RAW|1|the raw read definition eigenscript.h|#define VAL_F64_RAW|1|the raw double read definition (#1758 R1.2a: was VAL_NUM_RAW) eigenscript.h|#define VAL_I64_RAW|1|the raw int64 read definition (#1758 R1.2a) eigenscript.h|eigs_num_arg|1|inline fast path of the checking accessor: reads only after type == VAL_NUM -eigs_embed.c|eigs_value_as_num|1|embedding API: reads only after type == VAL_NUM; a bool answers NaN and other non-numbers 0.0 (docs/EMBEDDING.md) +eigs_embed.c|eigs_value_as_num|2|embedding API: reads only after type == VAL_NUM; a bool answers NaN and other non-numbers 0.0 (docs/EMBEDDING.md) embed_smoke.c|main|7|C test program: builds and inspects slots it constructed as numbers ext_store.c|store_json_encode|1|store record encoder: case VAL_INT writes the int's exact digits (#1758 R1.2a) jit.c|emit_load_numeric_operand|2|emits the load of data.num_ after the emitted type == VAL_NUM / refcount guard From 1a2c4e44804931f915ac609a5b149f12ab11ebb8 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:50:07 -0500 Subject: [PATCH 036/188] phase2 R1.2o: migrate extension numeric guards and exact database int encoding (#1758) Migrate 11 deprecated code-token sites in ext_net.c, ext_http.c, ext_db.c, model_infer.c, model_train.c. Float behavior and the R1.6 bridge names stay unchanged; int consumers preserve their kind or refuse through the R1.3 unwired token. Validation: make server-db built; inventory PASS; num-read PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2o.md | 1 + docs/design/phase2-inventory.txt | 74 +++++++++++++-------------- src/ext_db.c | 5 +- src/ext_http.c | 6 +-- src/ext_net.c | 10 ++-- src/model_infer.c | 2 +- src/model_train.c | 2 +- tools/num_read_allowlist.txt | 1 + 8 files changed, 51 insertions(+), 50 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2o.md diff --git a/changes/internal/1758-phase2-r1-2o.md b/changes/internal/1758-phase2-r1-2o.md new file mode 100644 index 000000000..9d6044561 --- /dev/null +++ b/changes/internal/1758-phase2-r1-2o.md @@ -0,0 +1 @@ +Migrate extension numeric guards and exact database int encoding. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index bd0f760f2..a82fe4b61 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,25 +1,25 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1858 classified=1858 unclassified=0 +examined=1854 classified=1854 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 380 CASE=60 DATA=5 TEST=312 YIELD=3 +(a) type tests 374 CASE=60 DATA=5 TEST=306 YIELD=3 (b) payload reads 556 RAW=139 READ=417 (c) producers 474 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=5 WRITE=23 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 17 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=4 (f) equality, ordering and hashing 48 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=18 (g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 -(h) JSON, store and db encoders 65 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=5 READ=24 TEST=5 +(h) JSON, store and db encoders 67 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=6 READ=24 TEST=6 (i) observer numeric paths 95 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=23 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token make_num 364 eigs_num_arg 151 -VAL_FLOAT 136 -VAL_INT 132 +VAL_FLOAT 139 +VAL_INT 135 eigs_list_num 130 SLOT_F64_RAW 83 VAL_NUM_RAW 61 @@ -27,12 +27,12 @@ num_guard 60 AST_NUM 52 eigs_slot_num 50 slot_is_f64 50 -VAL_NUM 49 eigs_value_as_num 48 slot_from_f64 41 +VAL_NUM 38 buffer_read_num 38 +VAL_I64_RAW 37 slot_is_smi 37 -VAL_I64_RAW 36 VAL_F64_RAW 28 buffer_read_byte 22 list_set_num 22 @@ -88,16 +88,16 @@ lint.c 29 a=29 trace.c 23 g=23 value_slot.h 22 a=8 b=11 c=3 compiler.c 21 a=13 b=5 c=1 i=2 -ext_net.c 19 a=5 b=7 c=7 chunk.c 17 a=1 e=4 f=12 -model_infer.c 16 a=1 b=6 c=9 -ext_http.c 14 a=3 b=4 c=7 +model_infer.c 17 a=2 b=6 c=9 +ext_net.c 14 b=7 c=7 eigs_embed.c 11 j=11 -model_train.c 7 a=1 b=4 c=1 i=1 +ext_http.c 11 b=4 c=7 +model_train.c 8 a=2 b=4 c=1 i=1 embed_concurrent.c 6 j=6 +ext_db.c 6 h=6 parser.c 5 a=2 b=1 c=2 tape_read.c 5 g=5 -ext_db.c 4 h=4 task.c 4 c=4 lexer.c 3 b=2 c=1 lint_host.c 3 a=3 @@ -359,13 +359,13 @@ clock_unix builtin_clock_unix float-producing close_channel builtin_close_channel int-requiring - - eigs_num_arg copy_into builtin_copy_into int-requiring - - eigs_num_arg cos builtin_cos float-producing - - eigs_num_arg,make_num -db_execute builtin_db_execute other LOSS - VAL_NUM,eigs_num_arg -db_query_json builtin_db_query_json other LOSS - VAL_NUM,eigs_num_arg -db_query_value builtin_db_query_value other LOSS - VAL_NUM,eigs_num_arg,make_num,strtod +db_execute builtin_db_execute other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg +db_query_json builtin_db_query_json other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg +db_query_value builtin_db_query_value other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,strtod dispatch builtin_dispatch int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num divide builtin_tensor_divide float-producing - - eigs_num_arg,make_num,num_guard dot builtin_dot float-producing - - buffer_read_num,make_num,num_guard -eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_NUM,eigs_list_num,eigs_slot_num,make_num +eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_slot_num,make_num eigen_generate builtin_eigen_generate int-requiring - - eigs_slot_num,eigs_slot_opt_num,make_num eigen_model_load builtin_eigen_model_load other - - strtod exec_capture builtin_exec_capture other - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,list_append_num @@ -395,7 +395,7 @@ gfx_text_height builtin_gfx_text_height int-preserving gfx_text_width builtin_gfx_text_width int-preserving - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num gfx_ticks builtin_gfx_ticks int-preserving - - make_num hex builtin_hex int-requiring LOSS - eigs_list_num,eigs_num_arg -http_early_bind builtin_http_early_bind int-requiring - - VAL_NUM,eigs_opt_num +http_early_bind builtin_http_early_bind int-requiring - - eigs_opt_num http_post builtin_http_post other - - eigs_num_text http_route builtin_http_route other - - eigs_num_text http_route_authed builtin_http_route_authed other - - eigs_num_text @@ -428,17 +428,17 @@ model_load_weights builtin_eigen_model_load other monotonic_ms builtin_monotonic_ms float-producing - - make_num monotonic_ns builtin_monotonic_ns int-preserving LOSS - make_num multiply builtin_tensor_multiply int-preserving LOSS - eigs_num_arg,make_num,num_guard -native_train_step_builtin builtin_native_train_step int-requiring - - VAL_NUM,atof,eigs_list_num,eigs_slot_num,strtod +native_train_step_builtin builtin_native_train_step int-requiring - - VAL_FLOAT,VAL_INT,atof,eigs_list_num,eigs_slot_num,strtod nearest_in_range builtin_nearest_in_range float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num nearest_in_range_all builtin_nearest_in_range_all float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num negative builtin_tensor_negative int-preserving LOSS - eigs_num_arg,make_num -net_accept builtin_net_accept int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num,make_num -net_close builtin_net_close int-requiring - - VAL_NUM,eigs_num_arg +net_accept builtin_net_accept int-requiring - - eigs_num_arg,eigs_slot_opt_num,make_num +net_close builtin_net_close int-requiring - - eigs_num_arg net_dial builtin_net_dial int-requiring - - eigs_slot_opt_num,make_num -net_listen builtin_net_listen int-requiring - - VAL_NUM,eigs_num_arg,make_num -net_port builtin_net_port int-requiring - - VAL_NUM,eigs_num_arg,make_num -net_recv builtin_net_recv int-requiring - - VAL_NUM,eigs_num_arg,eigs_slot_opt_num -net_send builtin_net_send int-requiring - - VAL_NUM,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num +net_listen builtin_net_listen int-requiring - - eigs_num_arg,make_num +net_port builtin_net_port int-requiring - - eigs_num_arg,make_num +net_recv builtin_net_recv int-requiring - - eigs_num_arg,eigs_slot_opt_num +net_send builtin_net_send int-requiring - - buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num norm builtin_tensor_norm float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard num builtin_num other LOSS - make_num,num_guard_named,strtod num_copy builtin_num_copy int-preserving LOSS - eigs_num_arg,make_num @@ -477,7 +477,7 @@ sgd_update_cols builtin_sgd_update_cols float-producing sgd_update_rows builtin_sgd_update_rows float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num shape builtin_tensor_shape int-preserving - - make_num shared_delete builtin_shared_delete int-preserving - - make_num -shared_incr builtin_shared_incr int-preserving LOSS - VAL_NUM,eigs_num_arg,make_num +shared_incr builtin_shared_incr int-preserving LOSS - eigs_num_arg,make_num shared_size builtin_shared_size int-preserving - - make_num sign_extend builtin_sign_extend int-requiring LOSS - eigs_num_arg,make_num sin builtin_sin float-producing - - eigs_num_arg,make_num @@ -1477,10 +1477,12 @@ embed_smoke.c:1065 main eigs_value_as_num READ j embed_smoke.c:1121 main eigs_value_as_num READ j embed_smoke.c:1145 main eigs_value_as_num READ j embed_smoke.c:1172 main eigs_value_as_num READ j -ext_db.c:57 db_build_query VAL_NUM TEST h -ext_db.c:58 db_build_query eigs_num_arg READ h -ext_db.c:310 builtin_db_query_value make_num PRODUCE h -ext_db.c:310 builtin_db_query_value strtod PARSE h +ext_db.c:57 db_build_query VAL_INT TEST h +ext_db.c:58 db_build_query VAL_I64_RAW RAW h +ext_db.c:60 db_build_query VAL_FLOAT TEST h +ext_db.c:61 db_build_query eigs_num_arg READ h +ext_db.c:313 builtin_db_query_value make_num PRODUCE h +ext_db.c:313 builtin_db_query_value strtod PARSE h ext_gfx.c:407 gfx_nums VAL_FLOAT TEST a ext_gfx.c:407 gfx_nums VAL_INT TEST a ext_gfx.c:420 gfx_list_all_num VAL_FLOAT TEST a @@ -1771,12 +1773,9 @@ ext_gfx.c:2467 builtin_ppu_render_frame buffer_read_byte READ b ext_gfx.c:2469 builtin_ppu_render_frame buffer_read_byte READ b ext_gfx.c:2506 builtin_ppu_render_frame buffer_read_byte READ b ext_gfx.c:2508 builtin_ppu_render_frame buffer_read_byte READ b -ext_http.c:584 builtin_http_early_bind VAL_NUM TEST a ext_http.c:594 builtin_http_early_bind eigs_opt_num READ b ext_http.c:662 builtin_http_serve eigs_opt_num READ b -ext_http.c:948 builtin_shared_incr VAL_NUM TEST a ext_http.c:952 builtin_shared_incr eigs_num_arg READ b -ext_http.c:964 builtin_shared_incr VAL_NUM TEST a ext_http.c:965 builtin_shared_incr eigs_num_arg READ b ext_http.c:975 builtin_shared_incr make_num PRODUCE c ext_http.c:1006 builtin_shared_incr make_num PRODUCE c @@ -1785,15 +1784,11 @@ ext_http.c:1037 builtin_shared_delete make_num PRODUCE c ext_http.c:1053 builtin_shared_delete make_num PRODUCE c ext_http.c:1072 builtin_shared_size make_num PRODUCE c ext_http.c:1076 builtin_shared_size make_num PRODUCE c -ext_net.c:112 net_lookup VAL_NUM TEST a ext_net.c:113 net_lookup eigs_num_arg READ b ext_net.c:148 net_num_at eigs_slot_opt_num READ b -ext_net.c:158 builtin_net_listen VAL_NUM TEST a ext_net.c:163 builtin_net_listen eigs_num_arg READ b ext_net.c:181 builtin_net_listen make_num PRODUCE c -ext_net.c:188 builtin_net_port VAL_NUM TEST a ext_net.c:199 builtin_net_port make_num PRODUCE c -ext_net.c:215 builtin_net_accept VAL_NUM TEST a ext_net.c:229 builtin_net_accept make_num PRODUCE c ext_net.c:282 builtin_net_dial make_num PRODUCE c ext_net.c:327 net_send_bytes make_num PRODUCE c @@ -1802,7 +1797,6 @@ ext_net.c:335 net_send_bytes make_num PRODUCE c ext_net.c:361 builtin_net_send buffer_read_num READ b ext_net.c:362 builtin_net_send eigs_slot_elem_num READ b ext_net.c:364 builtin_net_send finite_num_to_byte READ b -ext_net.c:379 builtin_net_close VAL_NUM TEST a ext_net.c:385 builtin_net_close eigs_num_arg READ b ext_store.c:173 store_json_encode_slot slot_is_f64 TEST h ext_store.c:174 store_json_encode_slot eigs_slot_num READ h @@ -2014,7 +2008,8 @@ model_infer.c:611 builtin_eigen_generate eigs_slot_num READ b model_infer.c:621 builtin_eigen_generate make_num PRODUCE c model_infer.c:652 builtin_eigen_eval_loss make_num PRODUCE c model_infer.c:658 builtin_eigen_eval_loss make_num PRODUCE c -model_infer.c:660 builtin_eigen_eval_loss VAL_NUM TEST a +model_infer.c:660 builtin_eigen_eval_loss VAL_FLOAT TEST a +model_infer.c:660 builtin_eigen_eval_loss VAL_INT TEST a model_infer.c:662 builtin_eigen_eval_loss make_num PRODUCE c model_infer.c:664 builtin_eigen_eval_loss eigs_list_num READ b model_infer.c:669 builtin_eigen_eval_loss make_num PRODUCE c @@ -2026,7 +2021,8 @@ model_infer.c:719 builtin_eigen_eval_loss make_num PRODUCE c model_io.c:69 json_parse_number strtod PARSE h model_train.c:708 obs_drift_eps atof PARSE i model_train.c:1457 builtin_native_train_step eigs_slot_num READ b -model_train.c:1458 builtin_native_train_step VAL_NUM TEST a +model_train.c:1458 builtin_native_train_step VAL_FLOAT TEST a +model_train.c:1458 builtin_native_train_step VAL_INT TEST a model_train.c:1458 builtin_native_train_step eigs_list_num READ b model_train.c:1459 builtin_native_train_step strtod PARSE c model_train.c:1474 builtin_native_train_step eigs_slot_num READ b diff --git a/src/ext_db.c b/src/ext_db.c index 302df20e2..e361c9e3f 100644 --- a/src/ext_db.c +++ b/src/ext_db.c @@ -54,7 +54,10 @@ static int db_build_query(Value *arg, const char **sql, int *nparams, types[i] = DB_PARAM_OID_BOOL; } else if (v && v->type == VAL_STR) { params[i] = v->data.str; - } else if (v && v->type == VAL_NUM) { + } else if (v && v->type == VAL_INT) { + eigs_int_text(numbuf[i], 64, VAL_I64_RAW(v)); + params[i] = numbuf[i]; + } else if (v && v->type == VAL_FLOAT) { snprintf(numbuf[i], 64, "%g", eigs_num_arg(v, __func__)); params[i] = numbuf[i]; } else { diff --git a/src/ext_http.c b/src/ext_http.c index a3e6f834c..4dc254b5f 100644 --- a/src/ext_http.c +++ b/src/ext_http.c @@ -581,7 +581,7 @@ Value* builtin_http_early_bind(Value *arg) { } arg = list_get_view(arg, 0, &port_view); } - if (arg && arg->type != VAL_NULL && arg->type != VAL_NUM) { + if (arg && arg->type != VAL_NULL && !val_is_number(arg)) { rt_error(EK_TYPE, 0, "http_early_bind: port must be a number or null"); return make_null(); } @@ -945,7 +945,7 @@ Value* builtin_shared_incr(Value *arg) { if (!arg || arg->type != VAL_LIST || arg->data.list.count < 2) return make_null(); Value *key_v = list_get_view(arg, 0, &(EigsView){{0}}); Value *delta_v = list_get_view(arg, 1, &(EigsView){{0}}); - if (key_v->type != VAL_STR || delta_v->type != VAL_NUM) return make_null(); + if (key_v->type != VAL_STR || !val_is_number(delta_v)) return make_null(); Server *s = eigs_http_active; if (!s) return make_null(); @@ -961,7 +961,7 @@ Value* builtin_shared_incr(Value *arg) { /* Read the number out BEFORE dropping the ref — decref may free it — * and drop it on the mismatch path too, which is the one an early * return makes easy to miss. */ - int bad = (!parsed || parsed->type != VAL_NUM); + int bad = (!parsed || !val_is_number(parsed)); if (!bad) cur = eigs_num_arg(parsed, __func__); val_decref(parsed); if (bad) { diff --git a/src/ext_net.c b/src/ext_net.c index def69a3fb..0f2705966 100644 --- a/src/ext_net.c +++ b/src/ext_net.c @@ -109,7 +109,7 @@ static double net_register_sock(int fd, EigsNetSockKind kind) { } static EigsNetSock* net_lookup(Value *v, EigsNetSockKind kind) { - if (!v || v->type != VAL_NUM) return NULL; + if (!v || !val_is_number(v)) return NULL; EigsNetSock *s = net_unpack(eigs_num_arg(v, __func__), NULL, NULL); if (!s || s->kind != kind) return NULL; return s; @@ -155,7 +155,7 @@ static int net_num_at(Value *arg, int idx, int fallback) { * ephemeral port — read it back with net_port. Binds 0.0.0.0, matching * ext_http's server posture (SECURITY.md: the script is trusted). */ Value* builtin_net_listen(Value *arg) { - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "net_listen: expected a port number"); return make_null(); } @@ -185,7 +185,7 @@ Value* builtin_net_listen(Value *arg) { * for a port-0 listen), or null on a bad/closed handle. Kernel-chosen, * so it rides the tape like every other environment outcome. */ Value* builtin_net_port(Value *arg) { - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "net_port: expected a listener handle"); return make_null(); } @@ -212,7 +212,7 @@ Value* builtin_net_accept(Value *arg) { if (g_has_error) return make_null(); /* #1637: a bool timeout raised */ arg = list_get_view(arg, 0, &listener_view); } - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "net_accept: expected a listener handle"); return make_null(); } @@ -376,7 +376,7 @@ Value* builtin_net_send(Value *arg) { * idempotent bookkeeping, and under EIGS_REPLAY no handle exists so it * is a natural no-op (the audio_capture_close shape). */ Value* builtin_net_close(Value *arg) { - if (!arg || arg->type != VAL_NUM) { + if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "net_close: expected a socket handle"); return make_null(); } diff --git a/src/model_infer.c b/src/model_infer.c index 95cbafa9f..1cecbea5e 100644 --- a/src/model_infer.c +++ b/src/model_infer.c @@ -657,7 +657,7 @@ Value* builtin_eigen_eval_loss(Value *arg) { fprintf(stderr, "eigen_eval_loss: prompt_ids must be a list\n"); ARG_GUARD(1, "eigen_eval_loss", "a list of prompt ids", make_num(-1.0)); } - if (list_elem_type(arg, 1) != VAL_NUM) { + if ((list_elem_type(arg, 1) != VAL_FLOAT && list_elem_type(arg, 1) != VAL_INT)) { fprintf(stderr, "eigen_eval_loss: target_id must be a number\n"); ARG_GUARD(1, "eigen_eval_loss", "a numeric target_id", make_num(-1.0)); } diff --git a/src/model_train.c b/src/model_train.c index a4495aef8..02835cfcc 100644 --- a/src/model_train.c +++ b/src/model_train.c @@ -1455,7 +1455,7 @@ Value* builtin_native_train_step(Value *arg) { float lr = 0.001f; if (list_elem_type(arg, 2) == VAL_BOOL) { eigs_slot_num(list_slot(arg, 2), __func__); return make_null(); } /* #1637 */ - if (list_elem_type(arg, 2) == VAL_NUM) lr = eigs_list_num(arg, 2, __func__); + if ((list_elem_type(arg, 2) == VAL_FLOAT || list_elem_type(arg, 2) == VAL_INT)) lr = eigs_list_num(arg, 2, __func__); else if (list_elem_type(arg, 2) == VAL_STR) lr = strtod(list_get_ref(arg, 2)->data.str, NULL); if (lr <= 0 || lr > 1) lr = 0.001f; diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 4b7d97823..e62496b6a 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -86,3 +86,4 @@ builtins.c|builtin_sort_by|1|numeric key kind retained for exact mixed sorting ( builtins.c|sort_cmp_num|6|validated numeric slots viewed through slot_view; int comparisons are exact (#1758 N2) value_slot.h|slot_int_value|1|boxed VAL_INT payload after its type test (#1758 R1.2i) container.h|slot_view|3|typed float or int facade, preserving exact payload and kind (#1758 R1.2i) +ext_db.c|db_build_query|1|VAL_INT parameters encode as exact digits after the kind test (#1758 R1.2) From 1822df24f04f7fc92552dad481c2e083265c5569 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 06:50:40 -0500 Subject: [PATCH 037/188] phase2 R1.2p: migrate the C numeric fixtures before alias deletion (#1758) Migrate 28 deprecated code-token sites in 7 C test fixtures. The literals/constructors being asserted are floats; the host native-function number consumer accepts either numeric kind through the unchanged bridge. Validation: make all and all seven fixture binaries built. Full release and ASan execution follows after R1.2z. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/strict_shape_descriptor.c | 4 ++-- tests/test_container_slots.c | 8 ++++---- tests/test_loop_counter_sequential.c | 4 ++-- tests/test_native_fn.c | 2 +- tests/test_pool_poison.c | 8 ++++---- tests/test_sandbox_intern_lifetime.c | 4 ++-- tests/test_sandbox_work_budget.c | 10 +++++----- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/strict_shape_descriptor.c b/tests/strict_shape_descriptor.c index bd147f43f..653b7317d 100644 --- a/tests/strict_shape_descriptor.c +++ b/tests/strict_shape_descriptor.c @@ -24,8 +24,8 @@ int main(void) { if (chunk->code_len <= 0 || chunk->code_len > 64 || chunk->fn_count || chunk->local_count || chunk->param_count || chunk->const_count != 1 || !chunk->constants[0] || - chunk->constants[0]->type != VAL_NUM || - VAL_NUM_RAW(chunk->constants[0]) != 42) goto done; + chunk->constants[0]->type != VAL_FLOAT || + VAL_F64_RAW(chunk->constants[0]) != 42) goto done; descriptor = make_list(3); Value *code = make_list(chunk->code_len); diff --git a/tests/test_container_slots.c b/tests/test_container_slots.c index b52b2abbd..215941196 100644 --- a/tests/test_container_slots.c +++ b/tests/test_container_slots.c @@ -45,7 +45,7 @@ int main(int argc, char **argv) { CHECK(raw[3].u == SLOT_NULL_BITS && raw[4].u == SLOT_TRUE_BITS); CHECK(str->refcount == 1); /* one container ref; a list may also be GC-buffered */ - CHECK(slot_type(list_slot(list, 0)) == VAL_NUM); + CHECK(slot_type(list_slot(list, 0)) == VAL_FLOAT); CHECK(list_elem_type(list, 1) == VAL_STR); CHECK(list_get_ref(list, 0) == NULL && list_get_ref(list, 1) != NULL); CHECK(eigs_slot_num(list_slot(list, 0), "test") == 3.0); @@ -63,7 +63,7 @@ int main(int argc, char **argv) { } Value *owned = list_get_owned(list, 0); Value *returned = list_get_return(list, 0); - CHECK(owned != returned && owned->type == VAL_NUM && VAL_NUM_RAW(owned) == 3.0); + CHECK(owned != returned && owned->type == VAL_FLOAT && VAL_F64_RAW(owned) == 3.0); val_decref(owned); val_decref(returned); list_set_num(list, 0, 4.0); list_set_slot_owned(list, 1, slot_from_heap(make_str("owned"))); @@ -103,7 +103,7 @@ int main(int argc, char **argv) { dict_set_owned(dict, "b", make_bool(0)); int ni = env_hash_find_dict(dict, "n", env_hash_name("n")); int si = env_hash_find_dict(dict, "s", env_hash_name("s")); - CHECK(dict_value_type(dict, ni) == VAL_NUM && dict_value_get_ref(dict, ni) == NULL); + CHECK(dict_value_type(dict, ni) == VAL_FLOAT && dict_value_get_ref(dict, ni) == NULL); CHECK(slot_is_f64(dict_values_storage(dict)[ni])); CHECK(eigs_slot_num(dict_value_slot(dict, ni), "test") == 2.0); { EIGS_VIEW(v); CHECK(eigs_num_arg(dict_value_get_view(dict, ni, &v), "test") == 2.0); } @@ -113,7 +113,7 @@ int main(int argc, char **argv) { CHECK(found && slot_is_null(zs)); (void)dict_get_slot(dict, "missing", &found); CHECK(!found); } owned = dict_value_get_owned(dict, ni); returned = dict_value_get_return(dict, ni); - CHECK(owned != returned && VAL_NUM_RAW(owned) == 2.0); + CHECK(owned != returned && VAL_F64_RAW(owned) == 2.0); val_decref(owned); val_decref(returned); dict_value_set_num(dict, ni, 8.0); dict_value_set_slot_owned(dict, si, slot_from_heap(make_str("changed"))); diff --git a/tests/test_loop_counter_sequential.c b/tests/test_loop_counter_sequential.c index f2467801b..301b16177 100644 --- a/tests/test_loop_counter_sequential.c +++ b/tests/test_loop_counter_sequential.c @@ -41,9 +41,9 @@ static void step(Env *env, const char *label, int stall, * This getter returns a borrowed slot: do not decrement its ownership. */ EigsSlot value = env_get_hashed_slot(env, counter, 0, &found); int numeric = slot_is_f64(value) || - (slot_is_ptr(value) && slot_as_ptr(value)->type == VAL_NUM); + (slot_is_ptr(value) && slot_as_ptr(value)->type == VAL_FLOAT); double actual = slot_is_f64(value) ? SLOT_F64_RAW(value) : - (numeric ? VAL_NUM_RAW(slot_as_ptr(value)) : -1); + (numeric ? VAL_F64_RAW(slot_as_ptr(value)) : -1); int assignments = env_get_assign_count(env, counter, 0); int ok = rc == 0 && !g_has_error && found && numeric && actual == (double)expected_iterations && diff --git a/tests/test_native_fn.c b/tests/test_native_fn.c index fb81d8370..e83872f03 100644 --- a/tests/test_native_fn.c +++ b/tests/test_native_fn.c @@ -15,7 +15,7 @@ static void check(int ok, const char *what) { if (!ok) fail = 1; } static Value *probe_add1(Value *a) { - double d = (a && a->type == VAL_NUM) ? VAL_NUM_RAW(a) : 0.0; + double d = (a && val_is_number(a)) ? eigs_num_arg(a, __func__) : 0.0; return make_num(d + 1); } static Value *probe_plain(Value *a) { (void)a; return make_num(0); } diff --git a/tests/test_pool_poison.c b/tests/test_pool_poison.c index 21b834371..769e93a1b 100644 --- a/tests/test_pool_poison.c +++ b/tests/test_pool_poison.c @@ -54,9 +54,9 @@ static int plant_num(void) { val_decref(v); /* refcount 0 -> parked on the freelist */ if (g_num_freelist != v) { puts("NOT-ARMED num: value not parked"); return 3; } printf("ARMED num: parked NUM %p, reading %p\n", (void *)v, - (void *)&VAL_NUM_RAW(v)); + (void *)&VAL_F64_RAW(v)); fflush(stdout); - volatile double stale = VAL_NUM_RAW(v); /* the planted stale read */ + volatile double stale = VAL_F64_RAW(v); /* the planted stale read */ printf("UNDETECTED num: read %g from a parked NUM\n", stale); return 0; } @@ -112,7 +112,7 @@ static int control(void) { val_decref(v); Value *again = make_num(2.5); if (again != v) { puts("NOT-ARMED control: freelist did not reuse"); return 3; } - if (VAL_NUM_RAW(again) != 2.5 || again->refcount != 1) bad = 1; + if (VAL_F64_RAW(again) != 2.5 || again->refcount != 1) bad = 1; printf("control num reuse: %s\n", bad ? "WRONG" : "ok"); val_decref(again); @@ -143,7 +143,7 @@ static int control(void) { if (!r) { puts("control take: eval failed"); return 1; } eigs_value_release(r); Value *res = eigs_get_global("pool_poison_r"); - int ok = res && res->type == VAL_NUM && VAL_NUM_RAW(res) == 8.0; + int ok = res && res->type == VAL_FLOAT && VAL_F64_RAW(res) == 8.0; if (res) eigs_value_release(res); int same = c->env_cache == first; printf("control env take: %s (re-parked same env: %s)\n", diff --git a/tests/test_sandbox_intern_lifetime.c b/tests/test_sandbox_intern_lifetime.c index 015228bb4..283b1c987 100644 --- a/tests/test_sandbox_intern_lifetime.c +++ b/tests/test_sandbox_intern_lifetime.c @@ -135,8 +135,8 @@ int main(void) { fprintf(stderr, "escaped result=%s expected-key=%s\n", diagnostic, key); free(diagnostic); } - assert(escaped_value && escaped_value->type == VAL_NUM && - VAL_NUM_RAW(escaped_value) == 1.0); + assert(escaped_value && escaped_value->type == VAL_FLOAT && + VAL_F64_RAW(escaped_value) == 1.0); fprintf(stderr, "sandbox intern growth: baseline=%zu retained=%zu sandbox_only=%zu\n", baseline, sandbox_retained, sandbox_prefix_retained); diff --git a/tests/test_sandbox_work_budget.c b/tests/test_sandbox_work_budget.c index d3d7d83a8..6a5d8b8ab 100644 --- a/tests/test_sandbox_work_budget.c +++ b/tests/test_sandbox_work_budget.c @@ -21,7 +21,7 @@ static Value *ordinary_descriptor(void) { if (chunk && !g_has_error && !g_parse_errors && chunk->code_len > 0 && chunk->code_len <= 64 && !chunk->fn_count && !chunk->local_count && !chunk->param_count && chunk->const_count == 1 && - chunk->constants[0]->type == VAL_NUM && VAL_NUM_RAW(chunk->constants[0]) == 42) { + chunk->constants[0]->type == VAL_FLOAT && VAL_F64_RAW(chunk->constants[0]) == 42) { Value *code = make_list(chunk->code_len); Value *constants = make_list(1); for (int i = 0; i < chunk->code_len; i++) @@ -63,14 +63,14 @@ int main(void) { Value *ok = out ? dict_get_view(out, "ok", &ok_view) : NULL; Value *result = out ? dict_get_view(out, "result", &result_view) : NULL; REQUIRE(ok && ok->type == VAL_BOOL && ok->data.boolean == 1 && - result && result->type == VAL_NUM && VAL_NUM_RAW(result) == 42, + result && result->type == VAL_FLOAT && VAL_F64_RAW(result) == 42, "ordinary sandbox result"); REQUIRE(!g_sandbox_active && g_sandbox_work_used == 13 && g_sandbox_work_max == 77, "sandbox restores caller accounting"); val_decref(out); val_decref(args); Value *host = eigs_eval_string("return 7\n"); - REQUIRE(host && host->type == VAL_NUM && VAL_NUM_RAW(host) == 7, + REQUIRE(host && host->type == VAL_FLOAT && VAL_F64_RAW(host) == 7, "host work between sandbox calls"); val_decref(host); REQUIRE(g_sandbox_work_used == 13 && g_sandbox_work_max == 77, @@ -85,13 +85,13 @@ int main(void) { g_sandbox_work_max = 10000; g_sandbox_work_used = 0; Value *ordinary = eigs_eval_string("return 42\n"); - REQUIRE(ordinary && ordinary->type == VAL_NUM && VAL_NUM_RAW(ordinary) == 42, + REQUIRE(ordinary && ordinary->type == VAL_FLOAT && VAL_F64_RAW(ordinary) == 42, "ordinary arithmetic result"); val_decref(ordinary); REQUIRE(g_sandbox_work_used > 0, "ordinary dispatch charges shared account"); uint64_t previous_work = g_sandbox_work_used; ordinary = eigs_eval_string("define work_identity(x) as:\n return x\nreturn work_identity of 42\n"); - REQUIRE(ordinary && ordinary->type == VAL_NUM && VAL_NUM_RAW(ordinary) == 42, + REQUIRE(ordinary && ordinary->type == VAL_FLOAT && VAL_F64_RAW(ordinary) == 42, "ordinary function result"); val_decref(ordinary); REQUIRE(g_sandbox_work_used > previous_work, "re-entry preserves accounting"); From 14471e2fd2d1a3bdde6b0820000688cf099e7257 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 07:06:57 -0500 Subject: [PATCH 038/188] phase2 R1.2q: finish the VM Value consumers without a producer (#1758) Migrate 97 deprecated inventory code-token sites in vm.c (95 original matching lines). Generic indices, slice/dispatch bounds, interrogatives and temporal readers keep exact int values. Float leaf/JIT guards remain float only. Deferred arithmetic/comparison and iterator index/snapshot arms abort through eigs_int_unwired; a try cannot turn them into a wrong result. Share generic INDEX_GET with its existing JIT helper after restoring the untouched slots. Keep the boxed index conversion out of vm_run_ex, and use separate operand refusals so each diagnostic names the correct operand. No int Value producer, constructor or opcode is introduced. Validation: make built; inventory examined=1849 classified=1849 unclassified=0; num-read examined=199 functions=83 violations=0 stale=0. Temporary C-host controls: add/cmp float results 6/true, iterator helper and interpreter snapshots both 42. Each injected INT64_MAX counterpart aborts with SIGABRT and the R1.3 diagnostic (8/8 checks; no caught value). Callgrind vs 46617422, default release compiler and workload recipe: DMG500K: 1195422765 -> 1194707923 Ir (-0.059798%) float200K JIT: 172214775 -> 172216927 (+0.001250%) float200K off: 364233396 -> 364235286 (+0.000519%) All within +/-0.1%; outputs match (DMG timing lines omitted). All 18 candidates were measured; rejected variants are retained in the session logs, with no padding or compiler flag changes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2q.md | 1 + docs/design/phase2-inventory.txt | 525 +++++++++++++------------- src/vm.c | 300 ++++++++------- tools/num_read_allowlist.txt | 9 +- 4 files changed, 430 insertions(+), 405 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2q.md diff --git a/changes/internal/1758-phase2-r1-2q.md b/changes/internal/1758-phase2-r1-2q.md new file mode 100644 index 000000000..869f6fcee --- /dev/null +++ b/changes/internal/1758-phase2-r1-2q.md @@ -0,0 +1 @@ +Finish the VM Value number migration: exact int readers and explicit uncatchable refusals for arithmetic and iterator state whose semantics land in R1.3. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index a82fe4b61..c2a2f2c99 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,39 +1,37 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1854 classified=1854 unclassified=0 +examined=1847 classified=1847 unclassified=0 files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 374 CASE=60 DATA=5 TEST=306 YIELD=3 -(b) payload reads 556 RAW=139 READ=417 -(c) producers 474 GUARD=71 PARSE=3 PRODUCE=372 TAGSET=5 WRITE=23 +(a) type tests 376 CASE=60 DATA=5 TEST=308 YIELD=3 +(b) payload reads 547 RAW=122 READ=425 +(c) producers 473 GUARD=71 PARSE=3 PRODUCE=371 TAGSET=5 WRITE=23 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 17 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=4 -(f) equality, ordering and hashing 48 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=18 +(f) equality, ordering and hashing 47 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=17 (g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 (h) JSON, store and db encoders 67 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=6 READ=24 TEST=6 -(i) observer numeric paths 95 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=21 READ=7 TEST=23 +(i) observer numeric paths 97 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=7 TEST=23 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token -make_num 364 -eigs_num_arg 151 -VAL_FLOAT 139 -VAL_INT 135 +make_num 363 +VAL_FLOAT 161 +eigs_num_arg 160 +VAL_INT 159 eigs_list_num 130 SLOT_F64_RAW 83 -VAL_NUM_RAW 61 +VAL_F64_RAW 67 num_guard 60 AST_NUM 52 eigs_slot_num 50 slot_is_f64 50 eigs_value_as_num 48 +VAL_I64_RAW 43 slot_from_f64 41 -VAL_NUM 38 -buffer_read_num 38 -VAL_I64_RAW 37 -slot_is_smi 37 -VAL_F64_RAW 28 +buffer_read_num 37 +slot_is_smi 29 buffer_read_byte 22 list_set_num 22 slot_smi_val 18 @@ -60,7 +58,9 @@ f64_ 2 list_append_num 2 make_num_permanent 2 num_ 2 +VAL_NUM 1 VAL_NUM_OFFSET 1 +VAL_NUM_RAW 1 atof 1 d_ 1 dict_value_get_num 1 @@ -71,7 +71,7 @@ slot_int_value 1 data.num (AST) 7 ## Per file (category counts) -vm.c 299 a=78 b=97 c=68 e=2 f=9 i=45 +vm.c 292 a=80 b=88 c=67 e=2 f=8 i=47 ext_gfx.c 290 a=96 b=124 c=70 builtins.c 267 a=11 b=103 c=111 e=3 f=11 h=19 i=9 builtins_tensor.c 177 a=32 b=59 c=86 @@ -219,8 +219,8 @@ D1 value_slot.h:slot_is_smi smi-arm SLOT_TAG_MASK=1 T D1 value_slot.h:slot_smi_val smi-arm SLOT_PAYLOAD_MASK=1 SLOT_SMI_SIGN=2 slot_smi_val=1 D1 value_slot.h:slot_truthy_immediate smi-arm SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 slot_is_f64=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:#define ARITH_FAST guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 -D1 vm.c:#define INT_BINOP_R unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_is_smi=3 -D1 vm.c:#define NUM_CMP unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_is_smi=3 +D1 vm.c:#define INT_BINOP_R unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_type=2 +D1 vm.c:#define NUM_CMP unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_type=2 D1 vm.c:#define READ_SLICE_BOUND smi-arm slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:jit_helper_dot_set guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:jit_helper_index_get guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 @@ -236,16 +236,16 @@ D1 vm.c:slot_truthy smi-arm slot_as_ptr=1 slo D1 vm.c:slot_type_name smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL guarded slot_f64_value=2 D1 vm.c:vm_leaf_accessor_exec/OP_INDEX_GET guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(BNOT) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_is_smi=1 -D1 vm.c:vm_run_ex/CASE(DISPATCH) smi-arm slot_as_ptr=4 slot_is_f64=1 slot_is_ptr=2 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:vm_run_ex/CASE(BNOT) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_type=1 +D1 vm.c:vm_run_ex/CASE(DISPATCH) smi-arm slot_as_ptr=8 slot_is_f64=1 slot_is_ptr=3 slot_is_smi=1 slot_smi_val=1 D1 vm.c:vm_run_ex/CASE(DOT_SET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(EQ) guarded slot_f64_value=2 -D1 vm.c:vm_run_ex/CASE(INDEX_GET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(INDEX_GET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(INDEX_SET) guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(NE) guarded slot_f64_value=2 -D1 vm.c:vm_run_ex/CASE(NEG) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_is_smi=1 +D1 vm.c:vm_run_ex/CASE(NEG) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_type=1 D1 vm.c:vm_slot_lift smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_store_local_slot guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 D2 builtins.c:bool_gate_name guarded slot_as_ptr=1 slot_is_ptr=1 @@ -258,7 +258,7 @@ D2 eigenscript.c:env_get_local_hashed guarded slot_as_ptr=1 slo D2 eigenscript.c:gc_collect_at_exit guarded slot_as_ptr=1 slot_is_ptr=1 D2 value_slot.h:#define slot_as_heap refuse slot_as_heap=1 slot_as_ptr=1 D2 value_slot.h:slot_as_ptr refuse SLOT_PAYLOAD_MASK=1 slot_as_ptr=1 slot_is_heap=1 -D2 vm.c:jit_helper_iter_next guarded list_elem_type=1 slot_as_ptr=1 slot_is_ptr=1 +D2 vm.c:jit_helper_iter_next guarded list_elem_type=2 slot_as_ptr=1 slot_is_ptr=1 D2 vm.c:obs_slot_value guarded slot_as_ptr=1 slot_is_bool=1 D2 vm.c:vm_borrow_scan guarded slot_as_ptr=2 slot_is_heap=2 D2 vm.c:vm_builtin_name_for guarded slot_as_ptr=1 slot_is_heap=1 @@ -2091,8 +2091,8 @@ vm.c:118 obs_dump_value SLOT_F64_RAW RAW i vm.c:118 obs_dump_value slot_is_f64 TEST i vm.c:119 obs_dump_value slot_is_smi TEST i vm.c:119 obs_dump_value slot_smi_val RAW i -vm.c:125 obs_dump_value VAL_NUM CASE i -vm.c:125 obs_dump_value VAL_NUM_RAW RAW i +vm.c:125 obs_dump_value VAL_F64_RAW RAW i +vm.c:125 obs_dump_value VAL_FLOAT CASE i vm.c:126 obs_dump_value VAL_I64_RAW RAW i vm.c:126 obs_dump_value VAL_INT CASE i vm.c:215 obs_dump_scope slot_is_f64 TEST i @@ -2115,9 +2115,9 @@ vm.c:877 slot_truthy slot_smi_val RAW b vm.c:934 make_iter_state make_num PRODUCE c vm.c:947 make_iter_state make_num PRODUCE c vm.c:1166 vm_store_local_slot slot_is_f64 TEST a -vm.c:1170 vm_store_local_slot VAL_NUM TEST a +vm.c:1170 vm_store_local_slot VAL_FLOAT TEST a vm.c:1172 vm_store_local_slot SLOT_F64_RAW RAW b -vm.c:1172 vm_store_local_slot VAL_NUM_RAW WRITE c +vm.c:1172 vm_store_local_slot VAL_F64_RAW WRITE c vm.c:1363 jit_helper_local_idx_get buffer_read_num READ b vm.c:1363 jit_helper_local_idx_get slot_from_f64 PRODUCE c vm.c:1524 jit_helper_dot_set slot_is_f64 TEST a @@ -2129,215 +2129,202 @@ vm.c:1652 obs_slot_num SLOT_F64_RAW RAW i vm.c:1652 obs_slot_num slot_is_f64 TEST i vm.c:1653 obs_slot_num slot_is_smi TEST i vm.c:1653 obs_slot_num slot_smi_val RAW i -vm.c:1800 jit_helper_iter_next VAL_NUM TEST a -vm.c:1801 jit_helper_iter_next eigs_slot_num READ b -vm.c:1811 jit_helper_iter_next VAL_NUM TEST a -vm.c:1812 jit_helper_iter_next VAL_NUM_RAW RAW b -vm.c:1819 jit_helper_iter_next buffer_read_num READ b -vm.c:1819 jit_helper_iter_next num_guard GUARD c -vm.c:1819 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1825 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1895 vm_leaf_accessor_exec/OP_CONST VAL_NUM_RAW RAW b -vm.c:1895 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1899 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1902 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1941 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1955 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1955 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:1966 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1967 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1985 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:1985 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2068 loop_iter_store make_num PRODUCE c -vm.c:2075 loop_iter_store slot_is_f64 TEST a -vm.c:2076 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2081 loop_iter_store make_num PRODUCE c -vm.c:2203 jit_helper_index_set slot_is_f64 TEST a -vm.c:2208 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2209 jit_helper_index_set slot_is_f64 TEST a -vm.c:2211 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2213 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2223 jit_helper_index_set slot_is_f64 TEST a -vm.c:2225 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2226 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2228 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2240 jit_helper_index_set VAL_NUM TEST a -vm.c:2242 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2243 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2250 jit_helper_index_set VAL_NUM TEST a -vm.c:2252 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2253 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2256 jit_helper_index_set VAL_NUM TEST a -vm.c:2257 jit_helper_index_set VAL_NUM_RAW RAW b -vm.c:2276 jit_helper_index_get slot_is_f64 TEST a -vm.c:2278 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2285 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2296 jit_helper_index_get buffer_read_num READ b -vm.c:2298 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2300 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2316 jit_helper_index_get VAL_NUM TEST a -vm.c:2318 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2319 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2331 jit_helper_index_get VAL_NUM TEST a -vm.c:2333 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2334 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2343 jit_helper_index_get VAL_NUM TEST a -vm.c:2345 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2346 jit_helper_index_get VAL_NUM_RAW RAW b -vm.c:2348 jit_helper_index_get buffer_read_num READ b -vm.c:2348 jit_helper_index_get make_num PRODUCE c -vm.c:2934 vm_take_error_value make_num PRODUCE c -vm.c:3038 slot_type_name slot_is_f64 TEST e -vm.c:3039 slot_type_name slot_is_smi TEST e -vm.c:3279 vm_run_ex/CASE(CONST) VAL_NUM TEST a -vm.c:3280 vm_run_ex/CASE(CONST) VAL_NUM_RAW RAW b -vm.c:3280 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3294 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3299 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3319 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3319 #define NUM_REUSE VAL_NUM TEST a -vm.c:3330 #define ARITH_FAST slot_f64_value READ b -vm.c:3330 #define ARITH_FAST slot_f64_value READ b -vm.c:3331 #define ARITH_FAST num_guard GUARD c -vm.c:3336 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3337 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3345 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3346 #define ARITH_FAST VAL_NUM_RAW WRITE c -vm.c:3354 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3364 vm_run_ex/CASE(ADD) VAL_NUM TEST a -vm.c:3365 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3365 vm_run_ex/CASE(ADD) VAL_NUM_RAW RAW b -vm.c:3365 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3366 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3366 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3367 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3367 vm_run_ex/CASE(ADD) VAL_NUM_RAW WRITE c -vm.c:3368 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3417 #define NUM_BINOP VAL_NUM TEST a -vm.c:3417 #define NUM_BINOP VAL_NUM TEST a -vm.c:3418 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3418 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3418 #define NUM_BINOP num_guard GUARD c -vm.c:3419 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3419 #define NUM_BINOP VAL_NUM_RAW RAW b -vm.c:3421 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3421 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3422 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3422 #define NUM_BINOP VAL_NUM_RAW WRITE c -vm.c:3423 #define NUM_BINOP make_num PRODUCE c -vm.c:3427 #define NUM_BINOP make_num PRODUCE c -vm.c:3445 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3445 vm_run_ex/CASE(DIV) VAL_NUM TEST a -vm.c:3446 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3448 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3450 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3450 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3450 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3453 vm_run_ex/CASE(DIV) VAL_NUM_RAW RAW b -vm.c:3455 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3455 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3456 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3456 vm_run_ex/CASE(DIV) VAL_NUM_RAW WRITE c -vm.c:3457 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3462 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3470 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3471 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3471 vm_run_ex/CASE(MOD) VAL_NUM_RAW RAW b -vm.c:3471 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3472 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3472 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3473 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3473 vm_run_ex/CASE(MOD) VAL_NUM_RAW WRITE c -vm.c:3474 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3476 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3476 vm_run_ex/CASE(MOD) VAL_NUM TEST a -vm.c:3481 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3504 #define INT_BINOP_R slot_f64_value READ b -vm.c:3504 #define INT_BINOP_R slot_f64_value READ b -vm.c:3506 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3507 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3510 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3511 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3518 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3518 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3522 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3522 #define INT_BINOP_R VAL_NUM_RAW WRITE c -vm.c:3525 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3533 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3533 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3534 #define INT_BINOP_R slot_is_smi TEST a -vm.c:3544 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3571 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3574 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3574 vm_run_ex/CASE(NEG) VAL_NUM_RAW WRITE c -vm.c:3577 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3582 vm_run_ex/CASE(NEG) slot_is_smi TEST a -vm.c:3585 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3600 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3602 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b -vm.c:3605 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3611 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a -vm.c:3611 vm_run_ex/CASE(BNOT) VAL_NUM_RAW WRITE c -vm.c:3614 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3619 vm_run_ex/CASE(BNOT) slot_is_smi TEST a -vm.c:3625 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3635 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3635 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3656 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3656 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3678 #define NUM_CMP slot_f64_value READ f -vm.c:3678 #define NUM_CMP slot_f64_value READ f -vm.c:3701 #define NUM_CMP slot_is_smi TEST f -vm.c:3701 #define NUM_CMP slot_is_smi TEST f -vm.c:3702 #define NUM_CMP slot_is_smi TEST f -vm.c:4618 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4620 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4627 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4637 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4639 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4641 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4656 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4658 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4659 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4669 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4671 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4672 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4679 vm_run_ex/CASE(INDEX_GET) VAL_NUM TEST a -vm.c:4681 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4682 vm_run_ex/CASE(INDEX_GET) VAL_NUM_RAW RAW b -vm.c:4684 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4684 vm_run_ex/CASE(INDEX_GET) make_num PRODUCE c -vm.c:4701 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:1800 jit_helper_iter_next VAL_INT TEST a +vm.c:1802 jit_helper_iter_next VAL_FLOAT TEST a +vm.c:1803 jit_helper_iter_next eigs_slot_num READ b +vm.c:1813 jit_helper_iter_next VAL_INT TEST a +vm.c:1814 jit_helper_iter_next VAL_I64_RAW RAW b +vm.c:1815 jit_helper_iter_next VAL_FLOAT TEST a +vm.c:1816 jit_helper_iter_next VAL_F64_RAW RAW b +vm.c:1823 jit_helper_iter_next buffer_read_num READ b +vm.c:1823 jit_helper_iter_next num_guard GUARD c +vm.c:1823 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1829 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1899 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b +vm.c:1899 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1903 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1906 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1945 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:1959 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1959 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:1970 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1971 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1989 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:1989 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2072 loop_iter_store make_num PRODUCE c +vm.c:2079 loop_iter_store slot_is_f64 TEST a +vm.c:2080 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2085 loop_iter_store make_num PRODUCE c +vm.c:2203 vm_value_index_is_int VAL_INT TEST a +vm.c:2204 vm_value_index_is_int VAL_I64_RAW RAW b +vm.c:2209 vm_value_index_is_int VAL_F64_RAW RAW b +vm.c:2222 jit_helper_index_set slot_is_f64 TEST a +vm.c:2227 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2228 jit_helper_index_set slot_is_f64 TEST a +vm.c:2230 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2232 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2242 jit_helper_index_set slot_is_f64 TEST a +vm.c:2244 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2245 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2247 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2262 jit_helper_index_set eigs_num_arg READ b +vm.c:2272 jit_helper_index_set eigs_num_arg READ b +vm.c:2276 jit_helper_index_set eigs_num_arg READ b +vm.c:2295 jit_helper_index_get slot_is_f64 TEST a +vm.c:2297 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2304 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2315 jit_helper_index_get buffer_read_num READ b +vm.c:2317 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2319 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2338 jit_helper_index_get eigs_num_arg READ b +vm.c:2353 jit_helper_index_get eigs_num_arg READ b +vm.c:2365 jit_helper_index_get eigs_num_arg READ b +vm.c:2367 jit_helper_index_get buffer_read_num READ b +vm.c:2367 jit_helper_index_get make_num PRODUCE c +vm.c:2953 vm_take_error_value make_num PRODUCE c +vm.c:3057 slot_type_name slot_is_f64 TEST e +vm.c:3058 slot_type_name slot_is_smi TEST e +vm.c:3298 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3299 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3299 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3313 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3318 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3338 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3338 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3349 #define ARITH_FAST slot_f64_value READ b +vm.c:3349 #define ARITH_FAST slot_f64_value READ b +vm.c:3350 #define ARITH_FAST num_guard GUARD c +vm.c:3355 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3356 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3364 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3365 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3373 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3383 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3383 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3384 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3384 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3384 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3385 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3385 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3386 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3386 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3387 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3410 vm_run_ex/CASE(ADD) VAL_INT TEST a +vm.c:3410 vm_run_ex/CASE(ADD) VAL_INT TEST a +vm.c:3438 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3438 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3439 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3439 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3439 #define NUM_BINOP num_guard GUARD c +vm.c:3440 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3440 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3442 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3442 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3443 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3443 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3444 #define NUM_BINOP make_num PRODUCE c +vm.c:3446 #define NUM_BINOP VAL_INT TEST a +vm.c:3446 #define NUM_BINOP VAL_INT TEST a +vm.c:3450 #define NUM_BINOP make_num PRODUCE c +vm.c:3468 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a +vm.c:3468 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a +vm.c:3469 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b +vm.c:3471 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3473 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b +vm.c:3473 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b +vm.c:3473 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3476 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b +vm.c:3478 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3478 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3479 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3479 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3480 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3483 vm_run_ex/CASE(DIV) VAL_INT TEST a +vm.c:3483 vm_run_ex/CASE(DIV) VAL_INT TEST a +vm.c:3487 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3495 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b +vm.c:3495 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3495 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3496 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b +vm.c:3496 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b +vm.c:3496 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3497 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3497 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3498 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3498 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3499 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3501 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3501 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3503 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3503 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3508 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3531 #define INT_BINOP_R slot_f64_value READ b +vm.c:3531 #define INT_BINOP_R slot_f64_value READ b +vm.c:3533 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3534 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3537 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3538 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3545 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3545 #define INT_BINOP_R VAL_F64_RAW WRITE c +vm.c:3549 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3549 #define INT_BINOP_R VAL_F64_RAW WRITE c +vm.c:3552 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3560 #define INT_BINOP_R VAL_INT TEST a +vm.c:3562 #define INT_BINOP_R VAL_INT TEST a +vm.c:3573 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3600 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3603 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3603 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3606 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3611 vm_run_ex/CASE(NEG) VAL_INT TEST a +vm.c:3615 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3630 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3632 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b +vm.c:3635 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3641 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a +vm.c:3641 vm_run_ex/CASE(BNOT) VAL_F64_RAW WRITE c +vm.c:3644 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3649 vm_run_ex/CASE(BNOT) VAL_INT TEST a +vm.c:3656 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3666 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3666 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3687 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3687 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3709 #define NUM_CMP slot_f64_value READ f +vm.c:3709 #define NUM_CMP slot_f64_value READ f +vm.c:3732 #define NUM_CMP VAL_INT TEST f +vm.c:3734 #define NUM_CMP VAL_INT TEST f +vm.c:4651 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4653 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4660 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4670 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4672 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4674 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4696 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4698 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4699 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4701 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b vm.c:4703 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4704 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4706 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4708 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4718 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4720 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4720 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4722 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4734 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4736 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4737 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4744 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4746 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4747 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4750 vm_run_ex/CASE(INDEX_SET) VAL_NUM TEST a -vm.c:4751 vm_run_ex/CASE(INDEX_SET) VAL_NUM_RAW RAW b -vm.c:4807 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4810 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4871 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4872 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4898 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4898 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5004 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5005 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5050 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a -vm.c:5056 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5064 vm_run_ex/CASE(ITER_NEXT) VAL_NUM TEST a +vm.c:4713 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4715 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4715 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4717 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4732 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4742 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4746 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4802 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4805 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4866 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4867 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4893 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4893 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:4999 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5000 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5045 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a +vm.c:5048 vm_run_ex/CASE(ITER_NEXT) VAL_FLOAT TEST a +vm.c:5054 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b +vm.c:5061 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a +vm.c:5064 vm_run_ex/CASE(ITER_NEXT) VAL_FLOAT TEST a vm.c:5065 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b vm.c:5078 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c vm.c:5082 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b @@ -2348,40 +2335,46 @@ vm.c:5424 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i vm.c:5458 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i vm.c:5459 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i vm.c:5460 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5524 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5524 vm_run_ex/CASE(INTERROGATE) VAL_NUM_RAW RAW i -vm.c:5524 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5528 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5524 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5525 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5525 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5525 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5529 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5530 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5531 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5535 vm_run_ex/CASE(INTERROGATE) VAL_NUM TEST i -vm.c:5549 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5532 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5552 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5572 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5598 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5601 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5553 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5573 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5599 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5602 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5605 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5621 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM TEST i -vm.c:5628 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_NUM_RAW RAW i -vm.c:5648 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM TEST i -vm.c:5649 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_NUM_RAW RAW i -vm.c:5779 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5779 vm_run_ex/CASE(SLICE_GET) VAL_NUM CASE a -vm.c:5796 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5797 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5799 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5806 #define READ_SLICE_BOUND VAL_NUM TEST a -vm.c:5807 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5810 #define READ_SLICE_BOUND VAL_NUM_RAW RAW b -vm.c:5821 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5824 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6418 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6419 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6420 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6423 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6433 vm_run_ex/CASE(DISPATCH) VAL_NUM TEST a -vm.c:6434 vm_run_ex/CASE(DISPATCH) VAL_NUM_RAW RAW b +vm.c:5603 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5606 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5630 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5633 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5638 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5659 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5660 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5661 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5791 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5791 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5808 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5809 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5811 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5818 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5822 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5825 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5826 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5829 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5840 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5843 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6437 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6438 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6439 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6442 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6452 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6453 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6455 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6459 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/src/vm.c b/src/vm.c index ebf8584ea..cfd8cd8c9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -122,7 +122,7 @@ static void obs_dump_value(EigsSlot s, char *buf, size_t nbuf) { if (slot_is_ptr(s)) { Value *v = slot_as_ptr(s); switch (v->type) { - case VAL_NUM: obs_dump_num(VAL_NUM_RAW(v), buf, nbuf); break; + case VAL_FLOAT: obs_dump_num(VAL_F64_RAW(v), buf, nbuf); break; case VAL_INT: eigs_int_text(buf, nbuf, VAL_I64_RAW(v)); break; /* #1758 R1.2a */ case VAL_STR: { size_t o = 0, i; @@ -691,7 +691,7 @@ static inline void dict_set_cached(Value *dict, const char *key, uint32_t h, Val } /* Slot-aware dict set: for the DMG register-write hot path. If the dict - * cache hits and the existing slot is an exclusive untracked VAL_NUM, + * cache hits and the existing slot is an exclusive untracked VAL_FLOAT, * mutate data.num in place — no allocation, no refcount churn. Returns * 1 if the in-place fast path fired; 0 means the caller must materialize * and call dict_set_cached. */ @@ -1160,16 +1160,16 @@ static inline Env *env_resolve_store(Env *start, const char *name, uint32_t h, /* #1063: the ONE implementation of "store TOS into fn-local slot", shared by * CASE(SET_LOCAL) and the JIT's out-of-line path (jit_helper_set_local), so * the two can never disagree. The in-place branch is load-bearing beyond - * speed: g_last_observer may alias the exclusive VAL_NUM being overwritten, + * speed: g_last_observer may alias the exclusive VAL_FLOAT being overwritten, * and a swap+decref would free it under the observer. */ static inline void vm_store_local_slot(Env *e, int slot, EigsSlot tos) { if (slot_is_f64(tos)) { EigsSlot ex_s = e->values[slot]; if (slot_is_heap(ex_s)) { Value *existing = slot_as_ptr(ex_s); - if (existing && existing->type == VAL_NUM && + if (existing && existing->type == VAL_FLOAT && existing->refcount == 1) { - VAL_NUM_RAW(existing) = SLOT_F64_RAW(tos); + VAL_F64_RAW(existing) = SLOT_F64_RAW(tos); return; } } @@ -1797,7 +1797,9 @@ int jit_helper_iter_next(void) { EIGS_VIEW(iterable_view); Value *iterable = list_get_view(state, 0, &iterable_view); if (!iterable) return 1; - if (list_elem_type(state, 1) != VAL_NUM) return 1; + if (list_elem_type(state, 1) == VAL_INT) + eigs_int_unwired("jit_helper_iter_next index", 0); + if (list_elem_type(state, 1) != VAL_FLOAT) return 1; int idx = (int)eigs_slot_num(list_slot(state, 1), "for"); int len = 0; if (iterable->type == VAL_LIST) len = iterable->data.list.count; @@ -1808,8 +1810,10 @@ int jit_helper_iter_next(void) { if (state->data.list.count >= 3) { EIGS_VIEW(snap_v_view); Value *snap_v = list_get_view(state, 2, &snap_v_view); - if (snap_v && snap_v->type == VAL_NUM) { - int snap = (int)VAL_NUM_RAW(snap_v); + if (snap_v && snap_v->type == VAL_INT) + eigs_int_unwired("jit_helper_iter_next snapshot", (uint64_t)VAL_I64_RAW(snap_v)); + if (snap_v && snap_v->type == VAL_FLOAT) { + int snap = (int)VAL_F64_RAW(snap_v); if (snap < len) len = snap; } } @@ -1820,7 +1824,7 @@ int jit_helper_iter_next(void) { } else { elem = slot_read_owned(list_slot(iterable, idx)); } - /* In-place idx bump when the slot is an exclusive plain VAL_NUM + /* In-place idx bump when the slot is an exclusive plain VAL_FLOAT * (matches the interpreter's NUM_REUSE fast path). */ list_set_num(state, 1, (double)(idx + 1)); vm_push_slot(elem); @@ -1891,8 +1895,8 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { break; case OP_CONST: { uint16_t idx = read_u16(ip); ip += 2; - /* Scanner guarantees VAL_NUM. */ - mini[msp++] = slot_from_f64(VAL_NUM_RAW(c->constants[idx])); + /* Scanner guarantees VAL_FLOAT. */ + mini[msp++] = slot_from_f64(VAL_F64_RAW(c->constants[idx])); break; } case OP_NUM_ZERO: @@ -1934,7 +1938,7 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { EigsSlot idx_s = mini[--msp]; EigsSlot tgt_s = mini[--msp]; double idx_d; - /* slot_f64_value: immediate OR boxed VAL_NUM index — a for-in + /* slot_f64_value: immediate OR boxed VAL_FLOAT index — a for-in * loop variable arrives as a heap num, same as ARITH_FAST. * #1758: an int index is not a float: bail, and the generic call * indexes with it (design 4.5; round 5 adds the SMI index). */ @@ -2190,6 +2194,21 @@ int jit_helper_loop_cap_check(void) { return eigs_loop_cap_step(g_vm.frames[g_vm.frame_count - 1].env); } +/* #1758 R1.2: an int subscript is its exact value in the VM's C-index + * domain. Floats keep the existing integrality test. No int exists yet. */ +#if defined(__GNUC__) || defined(__clang__) +__attribute__((noinline)) +#endif +static int vm_value_index_is_int(const Value *v, int *out) { + if (v->type == VAL_INT) { + int64_t i = VAL_I64_RAW(v); + if (i < INT_MIN || i > INT_MAX) return 0; + *out = (int)i; + return 1; + } + return vm_index_is_int(VAL_F64_RAW(v), out); +} + /* Stage 4v: out-of-line helper for OP_INDEX_SET. Pops 3 (val, idx, * target), pushes val back (net sp -2). Full opcode semantics including * the slot fast paths, so the emitter never bails; errors go through @@ -2237,24 +2256,24 @@ void jit_helper_index_set(void) { } } Value *val = vm_pop(); Value *idx = vm_pop(); Value *target = vm_pop(); - if (target->type == VAL_LIST && idx->type == VAL_NUM) { + if (target->type == VAL_LIST && val_is_number(idx)) { int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); + if (!vm_value_index_is_int(idx, &i)) { + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); } else if (vm_index_resolve(&i, target->data.list.count)) { val_incref(val); list_set_slot_owned(target, i, slot_from_heap(val)); } else { rt_error(EK_INDEX, g_vm.current_line, "index %d out of range (list length %d)", i, target->data.list.count); } - } else if (target->type == VAL_BUFFER && idx->type == VAL_NUM) { + } else if (target->type == VAL_BUFFER && val_is_number(idx)) { int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); + if (!vm_value_index_is_int(idx, &i)) { + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); } else if (!vm_index_resolve(&i, target->data.buffer.count)) { rt_error(EK_INDEX, g_vm.current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); - } else if (val->type == VAL_NUM) { - target->data.buffer.data[i] = VAL_NUM_RAW(val); + } else if (val_is_number(val)) { + target->data.buffer.data[i] = eigs_num_arg(val, "buffer store"); } else { /* #1061 -- mirror of CASE(INDEX_SET)'s buffer arm. */ rt_error(EK_TYPE, g_vm.current_line, "cannot store %s in a buffer (buffers hold numbers)", @@ -2313,10 +2332,10 @@ int jit_helper_index_get(void) { Value *target = slot_to_value(tgt_s); slot_decref(tgt_s); Value *result = make_null(); - if (target->type == VAL_LIST && idx->type == VAL_NUM) { + if (target->type == VAL_LIST && val_is_number(idx)) { int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); + if (!vm_value_index_is_int(idx, &i)) { + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); } else if (vm_index_resolve(&i, target->data.list.count)) { result = list_get_owned(target, i); } else { @@ -2328,10 +2347,10 @@ int jit_helper_index_get(void) { EigsSlot v = vm_dict_slot_cached(target, idx->data.str, env_hash_name(idx->data.str)); if (!slot_is_null(v)) result = eigs_slot_box(v); - } else if (target->type == VAL_STR && idx->type == VAL_NUM) { + } else if (target->type == VAL_STR && val_is_number(idx)) { int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); + if (!vm_value_index_is_int(idx, &i)) { + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); } else if (vm_index_resolve(&i, (int)val_str_len(target))) { char buf[2] = { target->data.str[i], 0 }; result = make_str_len(buf, 1); @@ -2340,10 +2359,10 @@ int jit_helper_index_get(void) { "string index %d out of range (length %d)", i, (int)val_str_len(target)); } - } else if (target->type == VAL_BUFFER && idx->type == VAL_NUM) { + } else if (target->type == VAL_BUFFER && val_is_number(idx)) { int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); + if (!vm_value_index_is_int(idx, &i)) + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); else if (vm_index_resolve(&i, target->data.buffer.count)) result = make_num(buffer_read_num(target, i)); else @@ -2451,7 +2470,7 @@ static inline void vm_borrow_scan(Value *arg, Value *result, /* #720: the one place the builtin-result borrow protocol is written down. * * A builtin's raw return may BORROW from its argument vector with no - * compensating incref: `num` returns its argument unchanged for VAL_NUM, + * compensating incref: `num` returns its argument unchanged for VAL_FLOAT, * `sort` returns its arg, and `append` / `dict_set` / `set_at` / `coalesce` * return their target — a direct child of the arg vector. Whoever receives * that result must compensate, or it over-releases into a use-after-free. @@ -3276,8 +3295,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, Value *v = chunk->constants[idx]; /* Numeric constants without observer state ship as immediates — * skips an incref/decref pair on every push/pop. */ - if (v->type == VAL_NUM) { - vm_push_slot(slot_from_f64(VAL_NUM_RAW(v))); + if (v->type == VAL_FLOAT) { + vm_push_slot(slot_from_f64(VAL_F64_RAW(v))); } else { val_incref(v); vm_push(v); @@ -3316,10 +3335,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * make_num then realize they could have mutated in place. The hot * arith fast path no longer needs it: immediate doubles have no * refcount and heap-num results are emitted as immediates. */ -#define NUM_REUSE(v) ((v)->type == VAL_NUM && (v)->refcount == 1) +#define NUM_REUSE(v) ((v)->type == VAL_FLOAT && (v)->refcount == 1) /* Stack-top fast path: read two slots, extract doubles from either - * immediate or heap VAL_NUM form, compute. Result is wrapped as a + * immediate or heap VAL_FLOAT form, compute. Result is wrapped as a * heap Value (via make_num or in-place NUM_REUSE). Immediates aren't * emitted until B-3 audits every vm_peek caller for immediate-safe * refcount handling. */ @@ -3334,7 +3353,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (slot_is_ptr(_as)) { \ Value *_a = slot_as_ptr(_as); \ if (NUM_REUSE(_a)) { \ - VAL_NUM_RAW(_a) = _r; \ + VAL_F64_RAW(_a) = _r; \ slot_decref(_bs); \ g_vm.sp--; \ DISPATCH(); \ @@ -3343,7 +3362,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (slot_is_ptr(_bs)) { \ Value *_b = slot_as_ptr(_bs); \ if (NUM_REUSE(_b)) { \ - VAL_NUM_RAW(_b) = _r; \ + VAL_F64_RAW(_b) = _r; \ g_vm.stack[g_vm.sp - 2] = _bs; \ slot_decref(_as); \ g_vm.sp--; \ @@ -3361,10 +3380,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, ARITH_FAST(+, 0); /* Slow path: handles string concat etc */ Value *b = vm_pop(); Value *a = vm_pop(); - if (a->type == VAL_NUM && b->type == VAL_NUM) { - double r = num_guard(VAL_NUM_RAW(a) + VAL_NUM_RAW(b)); - if (NUM_REUSE(a)) { VAL_NUM_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } - if (NUM_REUSE(b)) { VAL_NUM_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } + if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) { + double r = num_guard(VAL_F64_RAW(a) + VAL_F64_RAW(b)); + if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } + if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } vm_push(make_num(r)); } else if (a->type == VAL_STR && b->type == VAL_STR) { int la = val_str_len(a), lb = val_str_len(b); @@ -3388,6 +3407,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, /* #1183: the length is already known — don't re-scan the result. */ vm_push(make_str_owned_len(s, (size_t)la + lb)); } else { + if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) + eigs_int_unwired("addition", 0); /* Strict: + adds two numbers or concatenates two strings; it does * not coerce across types ("3" + 4 was a footgun). For mixed * concatenation use an f-string — f"{a}{b}" — or str of. */ @@ -3414,14 +3435,16 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NAME): { \ ARITH_FAST(OP, UF); \ Value *b = vm_pop(); Value *a = vm_pop(); \ - if (a->type == VAL_NUM && b->type == VAL_NUM) { \ - double r = num_guard(VAL_NUM_RAW(a) OP VAL_NUM_RAW(b)); \ - if ((UF) && r == 0.0 && VAL_NUM_RAW(a) != 0.0 && VAL_NUM_RAW(b) != 0.0) \ + if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) { \ + double r = num_guard(VAL_F64_RAW(a) OP VAL_F64_RAW(b)); \ + if ((UF) && r == 0.0 && VAL_F64_RAW(a) != 0.0 && VAL_F64_RAW(b) != 0.0) \ g_math_flags |= EIGS_MATH_UNDERFLOW; \ - if (NUM_REUSE(a)) { VAL_NUM_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } \ - if (NUM_REUSE(b)) { VAL_NUM_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } \ + if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } \ + if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } \ vm_push(make_num(r)); \ } else { \ + if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) \ + eigs_int_unwired(OPNAME, 0); \ rt_error(EK_TYPE, current_line, "cannot apply '%s' to %s and %s", \ OPNAME, val_type_name(a->type), val_type_name(b->type)); \ vm_push(make_num(0)); \ @@ -3442,21 +3465,23 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(DIV): { Value *b = vm_pop(); Value *a = vm_pop(); - if (a->type == VAL_NUM && b->type == VAL_NUM) { - if (VAL_NUM_RAW(b) == 0.0) { + if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) { + if (VAL_F64_RAW(b) == 0.0) { rt_error(EK_VALUE, current_line, "division by zero"); vm_push(make_num(0)); } else { - double r = num_guard(VAL_NUM_RAW(a) / VAL_NUM_RAW(b)); + double r = num_guard(VAL_F64_RAW(a) / VAL_F64_RAW(b)); /* divisor already known nonzero (the raise above), so a zero * quotient from a nonzero dividend is underflow. */ - if (r == 0.0 && VAL_NUM_RAW(a) != 0.0) + if (r == 0.0 && VAL_F64_RAW(a) != 0.0) g_math_flags |= EIGS_MATH_UNDERFLOW; - if (NUM_REUSE(a)) { VAL_NUM_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } - if (NUM_REUSE(b)) { VAL_NUM_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } + if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } + if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } vm_push(make_num(r)); } } else { + if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) + eigs_int_unwired("division", 0); rt_error(EK_TYPE, current_line, "cannot apply '/' to %s and %s", val_type_name(a->type), val_type_name(b->type)); vm_push(make_num(0)); @@ -3467,13 +3492,15 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(MOD): { Value *b = vm_pop(); Value *a = vm_pop(); - if (a->type == VAL_NUM && b->type == VAL_NUM && VAL_NUM_RAW(b) != 0.0) { - double r = num_guard(fmod(VAL_NUM_RAW(a), VAL_NUM_RAW(b))); - if (NUM_REUSE(a)) { VAL_NUM_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } - if (NUM_REUSE(b)) { VAL_NUM_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } + if (a->type == VAL_FLOAT && b->type == VAL_FLOAT && VAL_F64_RAW(b) != 0.0) { + double r = num_guard(fmod(VAL_F64_RAW(a), VAL_F64_RAW(b))); + if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } + if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } vm_push(make_num(r)); } else { - if (!(a->type == VAL_NUM && b->type == VAL_NUM)) + if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) + eigs_int_unwired("modulo", 0); + if (!(a->type == VAL_FLOAT && b->type == VAL_FLOAT)) rt_error(EK_TYPE, current_line, "cannot apply '%%' to %s and %s", val_type_name(a->type), val_type_name(b->type)); else @@ -3515,11 +3542,11 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, double _r = (double)(INT_OP_##NAME(_ai, (RHS))); \ if (slot_is_ptr(_as)) { \ Value *_a = slot_as_ptr(_as); \ - if (NUM_REUSE(_a)) { VAL_NUM_RAW(_a) = _r; slot_decref(_bs); g_vm.sp--; DISPATCH(); } \ + if (NUM_REUSE(_a)) { VAL_F64_RAW(_a) = _r; slot_decref(_bs); g_vm.sp--; DISPATCH(); } \ } \ if (slot_is_ptr(_bs)) { \ Value *_b = slot_as_ptr(_bs); \ - if (NUM_REUSE(_b)) { VAL_NUM_RAW(_b) = _r; g_vm.stack[g_vm.sp - 2] = _bs; slot_decref(_as); g_vm.sp--; DISPATCH(); } \ + if (NUM_REUSE(_b)) { VAL_F64_RAW(_b) = _r; g_vm.stack[g_vm.sp - 2] = _bs; slot_decref(_as); g_vm.sp--; DISPATCH(); } \ } \ slot_decref(_as); slot_decref(_bs); \ g_vm.stack[g_vm.sp - 2] = slot_from_f64(_r); \ @@ -3530,8 +3557,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * it would become a wrong value). The arm refuses until R1.3 \ * gives it exact int64 operands, and deleting eigs_int_unwired \ * there forces that. */ \ - if (slot_is_smi(_as) || slot_is_smi(_bs)) \ - eigs_int_unwired("bitwise '" OPNAME "'", (slot_is_smi(_as) ? _as : _bs).u); \ + if (slot_type(_as) == VAL_INT) \ + eigs_int_unwired("bitwise '" OPNAME "'", _as.u); \ + if (slot_type(_bs) == VAL_INT) \ + eigs_int_unwired("bitwise '" OPNAME "'", _bs.u); \ /* Mixed/non-numeric: error rather than silently returning 0, \ * matching the arithmetic operators and the strict error model. \ * Capture type names before decref (cf. NUM_CMP above). */ \ @@ -3571,7 +3600,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (__builtin_expect(slot_f64_value(s, &d), 1)) { if (slot_is_ptr(s)) { Value *v = slot_as_ptr(s); - if (NUM_REUSE(v)) { VAL_NUM_RAW(v) = -d; DISPATCH(); } + if (NUM_REUSE(v)) { VAL_F64_RAW(v) = -d; DISPATCH(); } } slot_decref(s); g_vm.stack[g_vm.sp - 1] = slot_from_f64(-d); @@ -3579,7 +3608,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } /* #1758 R1.1: an int is refused, not a type error, until R1.3 * gives NEG its int arm (N4b) and deletes eigs_int_unwired. */ - if (slot_is_smi(s)) eigs_int_unwired("negation", s.u); + if (slot_type(s) == VAL_INT) + eigs_int_unwired("negation", s.u); rt_error(EK_TYPE, current_line, "cannot negate %s", slot_type_name(s)); /* #1637: names bool */ slot_decref(s); g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); @@ -3608,7 +3638,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, double r = (double)(~i); if (slot_is_ptr(s)) { Value *v = slot_as_ptr(s); - if (NUM_REUSE(v)) { VAL_NUM_RAW(v) = r; DISPATCH(); } + if (NUM_REUSE(v)) { VAL_F64_RAW(v) = r; DISPATCH(); } } slot_decref(s); g_vm.stack[g_vm.sp - 1] = slot_from_f64(r); @@ -3616,7 +3646,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } /* #1758 R1.1: an int is refused, not a type error, until R1.3 * gives the bitwise arms exact int64 operands. */ - if (slot_is_smi(s)) eigs_int_unwired("bitwise '~'", s.u); + if (slot_type(s) == VAL_INT) + eigs_int_unwired("bitwise '~'", s.u); { const char *_tn = slot_type_name(s); slot_decref(s); @@ -3698,8 +3729,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, /* #1758 R1.1: an int operand is refused, not a type error (which \ * a try would turn into a wrong `false`), until R1.3 gives this \ * arm N2's exact compare and deletes eigs_int_unwired. */ \ - if (slot_is_smi(_as) || slot_is_smi(_bs)) \ - eigs_int_unwired("compare '" OPNAME "'", (slot_is_smi(_as) ? _as : _bs).u); \ + if (slot_type(_as) == VAL_INT) \ + eigs_int_unwired("compare '" OPNAME "'", _as.u); \ + if (slot_type(_bs) == VAL_INT) \ + eigs_int_unwired("compare '" OPNAME "'", _bs.u); \ /* Mixed/uncomparable types: error rather than silently returning \ * false (e.g. "3" < 4 used to be 0). Capture type names before \ * decref. ==/!= keep cross-type "not equal"; only ordering errors. */ \ @@ -4647,48 +4680,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, DISPATCH(); } } - /* Slow path: materialize both via slot_to_value for unified handling. */ - Value *idx = slot_to_value(idx_s); - slot_decref(idx_s); - Value *target = slot_to_value(tgt_s); - slot_decref(tgt_s); - Value *result = make_null(); - if (target->type == VAL_LIST && idx->type == VAL_NUM) { - int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); - } else if (vm_index_resolve(&i, target->data.list.count)) { - result = list_get_owned(target, i); - } else { - rt_error(EK_INDEX, current_line, "index %d out of range (list length %d)", i, target->data.list.count); - } - } else if (target->type == VAL_DICT && idx->type == VAL_STR) { - EigsSlot v = vm_dict_slot_cached(target, idx->data.str, - env_hash_name(idx->data.str)); - if (!slot_is_null(v)) result = eigs_slot_box(v); - } else if (target->type == VAL_STR && idx->type == VAL_NUM) { - int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); - } else if (vm_index_resolve(&i, (int)val_str_len(target))) { - char buf[2] = { target->data.str[i], 0 }; - result = make_str_len(buf, 1); - } else { - rt_error(EK_INDEX, current_line, "string index %d out of range (length %d)", i, (int)val_str_len(target)); - } - } else if (target->type == VAL_BUFFER && idx->type == VAL_NUM) { - int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) - rt_error(EK_VALUE, current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); - else if (vm_index_resolve(&i, target->data.buffer.count)) - result = make_num(buffer_read_num(target, i)); - else - rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); - } else { - rt_error(EK_TYPE, current_line, "cannot index %s", val_type_name(target->type)); - } - val_decref(target); val_decref(idx); - vm_push(result); + /* The helper owns the same slow path and int decisions. Restore the + * two borrowed stack slots before handing their ownership to it. */ + g_vm.sp += 2; + (void)jit_helper_index_get(); DISPATCH(); } @@ -4731,24 +4726,24 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } } Value *val = vm_pop(); Value *idx = vm_pop(); Value *target = vm_pop(); - if (target->type == VAL_LIST && idx->type == VAL_NUM) { + if (target->type == VAL_LIST && val_is_number(idx)) { int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); + if (!vm_value_index_is_int(idx, &i)) { + rt_error(EK_VALUE, current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); } else if (vm_index_resolve(&i, target->data.list.count)) { val_incref(val); list_set_slot_owned(target, i, slot_from_heap(val)); } else { rt_error(EK_INDEX, current_line, "index %d out of range (list length %d)", i, target->data.list.count); } - } else if (target->type == VAL_BUFFER && idx->type == VAL_NUM) { + } else if (target->type == VAL_BUFFER && val_is_number(idx)) { int i; - if (!vm_index_is_int(VAL_NUM_RAW(idx), &i)) { - rt_error(EK_VALUE, current_line, "index must be an integer, got %g", VAL_NUM_RAW(idx)); + if (!vm_value_index_is_int(idx, &i)) { + rt_error(EK_VALUE, current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); } else if (!vm_index_resolve(&i, target->data.buffer.count)) { rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); - } else if (val->type == VAL_NUM) { - target->data.buffer.data[i] = VAL_NUM_RAW(val); + } else if (val_is_number(val)) { + target->data.buffer.data[i] = eigs_num_arg(val, "buffer store"); } else { /* #1061: the last fail-soft numeric context. A non-number * store was silently DROPPED (the old element stayed), so @@ -5044,10 +5039,13 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, Value *state = vm_peek(0); /* The index slot must be a number: make_iter_state always builds one, * but an untrusted chunk (vm_run_bytecode / sandbox_run) can reach a - * bare ITER_NEXT with any list on TOS, and reading VAL_NUM_RAW() off a + * bare ITER_NEXT with any list on TOS, and reading VAL_F64_RAW() off a * VAL_STR is a type confusion whose result then indexes items[] (#721). */ + if (__builtin_expect(state && state->type == VAL_LIST && state->data.list.count >= 2 && + list_elem_type(state, 1) == VAL_INT, 0)) + eigs_int_unwired("ITER_NEXT index", 0); if (!state || state->type != VAL_LIST || state->data.list.count < 2 || - list_elem_type(state, 1) != VAL_NUM) { + list_elem_type(state, 1) != VAL_FLOAT) { ip += exit_offset; DISPATCH(); } @@ -5060,8 +5058,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, /* #491: cap by the entry-time snapshot (items[2]) so a body that * appends can't extend the loop; min() with the live length keeps a * remove from reading past the end. See make_iter_state. */ + if (state->data.list.count >= 3 && list_elem_type(state, 2) == VAL_INT) + eigs_int_unwired("ITER_NEXT snapshot", 0); if (state->data.list.count >= 3 && - list_elem_type(state, 2) == VAL_NUM) { + list_elem_type(state, 2) == VAL_FLOAT) { int snap = (int)eigs_slot_num(list_slot(state, 2), "for"); if (snap < len) len = snap; } @@ -5074,7 +5074,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, ip += exit_offset; } else { /* Update index — mutate in place when the existing slot is - * an exclusive plain VAL_NUM (avoids per-iter make_num/free). */ + * an exclusive plain VAL_FLOAT (avoids per-iter make_num/free). */ list_set_num(state, 1, (double)(idx + 1)); if (iterable->type == VAL_BUFFER) { /* Push number immediate directly — skip make_num + immediate- @@ -5521,7 +5521,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, Value *result = make_null(); switch (kind) { case 0: /* what */ - if (v && v->type == VAL_NUM) { result = make_num(VAL_NUM_RAW(v)); } + if (v && v->type == VAL_INT) { val_incref(v); result = v; } + else if (v && v->type == VAL_FLOAT) { result = make_num(VAL_F64_RAW(v)); } /* #1637: a bool is its own value -- it fell to the else arm and * answered 0, so `what is (5 > 3)` read as false. */ else if (v && v->type == VAL_BOOL) { result = make_bool(v->data.boolean); } @@ -5532,7 +5533,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, break; case 1: /* who — returns descriptive type name */ if (v) result = make_str( - v->type == VAL_NUM ? "number" : + val_is_number(v) ? "number" : v->type == VAL_STR ? "string" : v->type == VAL_LIST ? "list" : v->type == VAL_DICT ? "dict" : @@ -5618,14 +5619,23 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, Value *line_v = vm_pop(); /* #1637: the line is a number, as `when`'s ordinal is. A bool (or any * other type) used to read as line 0 and answer null silently. */ - if (!line_v || line_v->type != VAL_NUM) { + if (!line_v || !val_is_number(line_v)) { rt_error(EK_TYPE, current_line, "'at' line must be a number, got %s", line_v ? val_type_name(line_v->type) : "none"); val_decref(line_v); vm_push(make_null()); DISPATCH(); } - int line = (int)VAL_NUM_RAW(line_v); + int line; + if (line_v->type == VAL_INT) { + if (!vm_value_index_is_int(line_v, &line)) { + rt_error(EK_VALUE, current_line, "'at' line %lld is out of range", + (long long)VAL_I64_RAW(line_v)); + val_decref(line_v); + vm_push(make_null()); + DISPATCH(); + } + } else line = (int)VAL_F64_RAW(line_v); val_decref(line_v); Value *result = make_null(); const char *name = chunk->const_interns[name_idx]; @@ -5645,8 +5655,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, uint16_t kind = read_u16(ip); ip += 2; uint16_t name_idx = read_u16(ip); ip += 2; Value *ord_v = vm_pop(); - int ord_is_num = (ord_v && ord_v->type == VAL_NUM); - double ord_d = ord_is_num ? VAL_NUM_RAW(ord_v) : 0.0; + int ord_is_num = (ord_v && val_is_number(ord_v)); + int ord_is_int = ord_v && ord_v->type == VAL_INT; + int64_t ord_i = ord_is_int ? VAL_I64_RAW(ord_v) : 0; + double ord_d = ord_is_num && !ord_is_int ? VAL_F64_RAW(ord_v) : 0.0; val_decref(ord_v); const char *name = chunk->const_interns[name_idx]; @@ -5665,7 +5677,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, DISPATCH(); } - long long ordinal = (long long)ord_d; + long long ordinal = ord_is_int ? (long long)ord_i : (long long)ord_d; EigsSlot w_slot; long long total = 0, oldest = 0; int r = trace_query_when(kind, name, ordinal, &w_slot, &total, &oldest); @@ -5776,7 +5788,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, case VAL_BUFFER: len = target->data.buffer.count; break; /* Not sliceable. Enumerated rather than covered by a `default:` * so -Werror=switch forces a new ValType to choose here. */ - case VAL_NUM: case VAL_INT: case VAL_FN: case VAL_BUILTIN: case VAL_NULL: + case VAL_FLOAT: case VAL_INT: case VAL_FN: case VAL_BUILTIN: case VAL_NULL: case VAL_JSON_RAW: case VAL_DICT: case VAL_TEXT_BUILDER: case VAL_BOOL: rt_error(EK_TYPE, g_vm.current_line, "cannot slice %s", val_type_name(target->type)); @@ -5786,7 +5798,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } /* Extract a slice bound from a slot: null → use default; immediate - * num or VAL_NUM → must be an exact integer. Returns 1 on success + * num or VAL_FLOAT → must be an exact integer. Returns 1 on success * (with *out set), 0 on type error (after raising). */ int start = 0, end = len; int bound_err = 0; @@ -5803,11 +5815,18 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, Value *bv = slot_as_ptr(slot); \ if (bv->type == VAL_NULL) { \ (outvar) = (defval); \ - } else if (bv->type == VAL_NUM) { \ - if (!vm_index_is_int(VAL_NUM_RAW(bv), &(outvar))) { \ + } else if (bv->type == VAL_INT) { \ + if (!vm_value_index_is_int(bv, &(outvar))) { \ + rt_error(EK_VALUE, g_vm.current_line, \ + "slice bound %lld is out of range", \ + (long long)VAL_I64_RAW(bv)); \ + bound_err = 1; \ + } \ + } else if (bv->type == VAL_FLOAT) { \ + if (!vm_index_is_int(VAL_F64_RAW(bv), &(outvar))) { \ rt_error(EK_VALUE, g_vm.current_line, \ "slice bound must be an integer, got %g", \ - VAL_NUM_RAW(bv)); \ + VAL_F64_RAW(bv)); \ bound_err = 1; \ } \ } else { \ @@ -6406,7 +6425,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(DISPATCH): { /* Native dispatch: stack [table, key, arg] -> table[key](arg). * Key may be an immediate-num slot (literal key) or a boxed - * VAL_NUM (key sourced from a fn return, arithmetic, variable + * VAL_FLOAT (key sourced from a fn return, arithmetic, variable * read — DMG's per-instruction `op` path). Table and arg are * heap pointers in practice (list + ctx). */ EigsSlot arg_s = g_vm.stack[g_vm.sp - 1]; @@ -6430,8 +6449,19 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } key_d = (double)kv; } else if (slot_is_ptr(key_s) && slot_as_ptr(key_s) - && slot_as_ptr(key_s)->type == VAL_NUM) { - key_d = VAL_NUM_RAW(slot_as_ptr(key_s)); + && slot_as_ptr(key_s)->type == VAL_FLOAT) { + key_d = VAL_F64_RAW(slot_as_ptr(key_s)); + } else if (slot_is_ptr(key_s) && slot_as_ptr(key_s) + && slot_as_ptr(key_s)->type == VAL_INT) { + int kv; + if (!vm_value_index_is_int(slot_as_ptr(key_s), &kv)) { + rt_error(EK_VALUE, current_line, "dispatch key %lld is out of range", + (long long)VAL_I64_RAW(slot_as_ptr(key_s))); + slot_decref(arg_s); slot_decref(key_s); slot_decref(table_s); + vm_push_slot(slot_null()); + DISPATCH(); + } + key_d = (double)kv; } else { slot_decref(arg_s); slot_decref(key_s); slot_decref(table_s); rt_error(EK_TYPE, current_line, "dispatch: key must be a number"); diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index e62496b6a..b75e1ddef 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -65,9 +65,9 @@ vm.c|#define ARITH_FAST|2|arithmetic fast path after both operands tested VAL_NU vm.c|#define INT_BINOP_R|2|integer op fast path after both slots slot_is_f64 vm.c|#define NUM_BINOP|6|arithmetic after a->type == VAL_NUM && b->type == VAL_NUM; NUM_REUSE writes vm.c|jit_helper_dot_set|1|JIT helper: number store after slot_is_f64 -vm.c|jit_helper_index_get|9|JIT helper: index read after slot_is_f64 / VAL_NUM tests on index and element -vm.c|jit_helper_index_set|10|JIT helper: index store after slot_is_f64 / VAL_NUM tests on index and value -vm.c|jit_helper_iter_next|1|JIT helper: loop state list [iterable, idx, snap] built by the VM, each read behind a VAL_NUM test +vm.c|jit_helper_index_get|3|JIT helper: index read after slot_is_f64 / VAL_NUM tests on index and element +vm.c|jit_helper_index_set|5|JIT helper: index store after slot_is_f64 / VAL_NUM tests on index and value +vm.c|jit_helper_iter_next|2|JIT helper: loop state list [iterable, idx, snap] built by the VM, each read behind a VAL_NUM test vm.c|jit_helper_local_dot_set|1|JIT helper: number store after slot_is_f64 vm.c|loop_iter_store|1|writes the loop counter slot after slot_is_f64 vm.c|obs_dump_scope|1|SIGUSR1 observer dump after slot_is_f64 @@ -76,7 +76,7 @@ vm.c|obs_slot_num|1|observer numeric channel (#1758): reads an immediate after s vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 vm.c|slot_truthy|1|truthiness after slot_is_f64 vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_NUM (chunk_scan_leaf_accessor) and values behind VAL_NUM tests -vm.c|vm_run_ex|49|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_NUM dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built +vm.c|vm_run_ex|42|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_NUM dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 builtins.c|builtin_json_build|1|VAL_INT text is exact digits; float text retains the bridge (#1758 R1.2d) @@ -87,3 +87,4 @@ builtins.c|sort_cmp_num|6|validated numeric slots viewed through slot_view; int value_slot.h|slot_int_value|1|boxed VAL_INT payload after its type test (#1758 R1.2i) container.h|slot_view|3|typed float or int facade, preserving exact payload and kind (#1758 R1.2i) ext_db.c|db_build_query|1|VAL_INT parameters encode as exact digits after the kind test (#1758 R1.2) +vm.c|vm_value_index_is_int|2|Guarded exact VAL_INT-to-C-index conversion; the other numeric kind keeps the float integrality test (#1758 R1.2) From ce66ede5a8312cb9453c459f040fc2489f4152ee Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 07:16:36 -0500 Subject: [PATCH 039/188] phase2 R1.2z: delete the deprecated Value number aliases (#1758) Delete the five remaining deprecated inventory sites: VAL_NUM, VAL_NUM_RAW, VAL_NUM_OFFSET and the old Value payload member. The old names no longer compile. Retire their inventory vocabulary and add the shared number predicate; the token gate carries the four deleted names. The cleanup leaves the real inventory identical before/after removing its legacy-only matcher arms. Numeric builtin coverage stays 230/230. Keep sort_by's two alternative numeric key payloads in a union, preserving its previous 16-byte pair footprint on this 64-bit target. No int producer is introduced; the R1.6 bridge names stay. One-time plants against the actual source/build, then restored: - VAL_NUM in builtin_usleep: token gate hits=1; make build/release/builtins.o exits 2, undeclared VAL_NUM. - Delete eigs_json_encode_value's VAL_INT arm: the same make target exits 2, VAL_INT not handled in switch [-Werror=switch]. Source audit: all 17 switches with ValType cases enumerate all 12 types and have no default. - Delete slot_int_value's boxed reader: slot_layer.sh exits 1 with five assertion failures (not a warning/build-failure witness). Restore: 33 readers, 165 calls, 396 matrix cells, 32 arm rows, failures=0. Validation: make built with gcc -O2 warnings=0. Tokens=9 files=90 hits=0. Inventory examined=2014 classified=2014 unclassified=0, freshness PASS; num-read examined=197 functions=81 violations=0 stale=0. Static int-source: make_int_defs=0 outside_writers=0 tag_homes=4/4 tag_spellings_outside=0. Final callgrind vs 46617422 after alias deletion: DMG500K 1195422765 -> 1194717491 Ir (-0.058998%) float200K JIT 172214775 -> 172216927 (+0.001250%) float200K off 364233396 -> 364235286 (+0.000519%) All within +/-0.1%; outputs match (DMG timing lines omitted). Full suite/corpus/ASan validation follows in the round report. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2z.md | 1 + docs/design/phase2-inventory.txt | 546 +++++++++++++++++--------- src/builtins.c | 2 +- src/container.h | 2 +- src/eigenscript.c | 4 +- src/eigenscript.h | 26 +- src/value_slot.h | 2 +- tools/num_read_allowlist.txt | 58 ++- tools/num_read_check.sh | 6 +- tools/phase2_check.py | 1 + tools/phase2_inventory.py | 43 +- 11 files changed, 418 insertions(+), 273 deletions(-) create mode 100644 changes/internal/1758-phase2-r1-2z.md diff --git a/changes/internal/1758-phase2-r1-2z.md b/changes/internal/1758-phase2-r1-2z.md new file mode 100644 index 000000000..83f4e11ce --- /dev/null +++ b/changes/internal/1758-phase2-r1-2z.md @@ -0,0 +1 @@ +Remove the transitional Value numeric aliases after migrating all consumers; retain the number bridge until R1.6. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index c2a2f2c99..370a2e266 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,23 +1,24 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=1847 classified=1847 unclassified=0 -files=64 tokens=48 role_rules=8 derived_accessors=18 wrappers=7 +examined=2014 classified=2014 unclassified=0 +files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 376 CASE=60 DATA=5 TEST=308 YIELD=3 -(b) payload reads 547 RAW=122 READ=425 -(c) producers 473 GUARD=71 PARSE=3 PRODUCE=371 TAGSET=5 WRITE=23 +(a) type tests 516 CASE=60 DATA=4 TEST=449 YIELD=3 +(b) payload reads 543 RAW=118 READ=425 +(c) producers 472 GUARD=71 PARSE=3 PRODUCE=371 TAGSET=4 WRITE=23 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 -(e) number formatting 17 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=4 -(f) equality, ordering and hashing 47 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=17 +(e) number formatting 20 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=7 +(f) equality, ordering and hashing 51 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=21 (g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 -(h) JSON, store and db encoders 67 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=6 READ=24 TEST=6 -(i) observer numeric paths 97 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=7 TEST=23 +(h) JSON, store and db encoders 82 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=6 READ=24 TEST=21 +(i) observer numeric paths 107 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=7 TEST=33 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token make_num 363 -VAL_FLOAT 161 +val_is_number 173 +VAL_FLOAT 160 eigs_num_arg 160 VAL_INT 159 eigs_list_num 130 @@ -57,10 +58,6 @@ eigs_elem_num 2 f64_ 2 list_append_num 2 make_num_permanent 2 -num_ 2 -VAL_NUM 1 -VAL_NUM_OFFSET 1 -VAL_NUM_RAW 1 atof 1 d_ 1 dict_value_get_num 1 @@ -71,28 +68,28 @@ slot_int_value 1 data.num (AST) 7 ## Per file (category counts) -vm.c 292 a=80 b=88 c=67 e=2 f=8 i=47 -ext_gfx.c 290 a=96 b=124 c=70 -builtins.c 267 a=11 b=103 c=111 e=3 f=11 h=19 i=9 -builtins_tensor.c 177 a=32 b=59 c=86 -eigenscript.c 113 a=22 b=17 c=13 e=7 f=16 i=38 -builtins_buf.c 102 a=26 b=37 c=39 +builtins.c 346 a=81 b=103 c=111 e=6 f=13 h=21 i=11 +vm.c 304 a=89 b=88 c=67 e=2 f=8 i=50 +ext_gfx.c 298 a=104 b=124 c=70 +builtins_tensor.c 200 a=55 b=59 c=86 +eigenscript.c 120 a=22 b=17 c=13 e=7 f=18 i=43 +builtins_buf.c 110 a=34 b=37 c=39 +container.h 98 a=39 b=31 c=28 jit.c 96 d=96 -container.h 95 a=36 b=31 c=28 +ext_store.c 54 h=54 embed_smoke.c 50 j=50 -eigenscript.h 44 a=7 b=24 c=12 e=1 -ext_store.c 41 h=41 -builtins_host.c 40 a=4 b=24 c=12 +builtins_host.c 49 a=13 b=24 c=12 +eigenscript.h 39 a=7 b=20 c=11 e=1 jit_smoke.c 31 d=31 lint.c 29 a=29 trace.c 23 g=23 value_slot.h 22 a=8 b=11 c=3 compiler.c 21 a=13 b=5 c=1 i=2 -chunk.c 17 a=1 e=4 f=12 +chunk.c 19 a=3 e=4 f=12 +ext_net.c 19 a=5 b=7 c=7 model_infer.c 17 a=2 b=6 c=9 -ext_net.c 14 b=7 c=7 +ext_http.c 14 a=3 b=4 c=7 eigs_embed.c 11 j=11 -ext_http.c 11 b=4 c=7 model_train.c 8 a=2 b=4 c=1 i=1 embed_concurrent.c 6 j=6 ext_db.c 6 h=6 @@ -299,43 +296,43 @@ registered=311 numeric=230 classified=230 unclassified=0 stale=0 classes: float-producing=57 int-preserving=37 int-requiring=85 other=51 LOSS (42): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_execute db_query_json db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed Q7: geometry=9 bounded=13 magnitude=13 -abs builtin_abs int-preserving LOSS - eigs_num_arg,make_num -acos builtin_acos float-producing - - eigs_num_arg,make_num -add builtin_tensor_add int-preserving LOSS - eigs_num_arg,make_num,num_guard +abs builtin_abs int-preserving LOSS - eigs_num_arg,make_num,val_is_number +acos builtin_acos float-producing - - eigs_num_arg,make_num,val_is_number +add builtin_tensor_add int-preserving LOSS - eigs_num_arg,make_num,num_guard,val_is_number append builtin_append other - - VAL_FLOAT -asin builtin_asin float-producing - - eigs_num_arg,make_num +asin builtin_asin float-producing - - eigs_num_arg,make_num,val_is_number assert builtin_assert other - - eigs_num_text -atan builtin_atan float-producing - - eigs_num_arg,make_num -atan2 builtin_atan2 float-producing - - eigs_num_arg,make_num +atan builtin_atan float-producing - - eigs_num_arg,make_num,val_is_number +atan2 builtin_atan2 float-producing - - eigs_num_arg,make_num,val_is_number audio_capture_open builtin_audio_capture_open int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num audio_envelope builtin_audio_envelope float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,eigs_slot_num,make_num audio_gain builtin_audio_gain float-producing - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_slot_num,make_num audio_mix builtin_audio_mix float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num audio_music_play builtin_audio_music_play int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num -audio_music_volume builtin_audio_music_volume other - bounded VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg +audio_music_volume builtin_audio_music_volume other - bounded VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,val_is_number audio_noise builtin_audio_noise float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num audio_open builtin_audio_open int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num -audio_pause builtin_audio_pause int-requiring - - eigs_num_arg +audio_pause builtin_audio_pause int-requiring - - eigs_num_arg,val_is_number audio_play builtin_audio_play other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,make_num audio_play_loop builtin_audio_play_loop int-requiring - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_list_num,eigs_slot_num,make_num audio_queue_size builtin_audio_queue_size int-preserving - - make_num audio_saw builtin_audio_saw float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num audio_sine builtin_audio_sine float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num audio_square builtin_audio_square float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num -audio_stop builtin_audio_stop int-requiring - - eigs_num_arg,make_num +audio_stop builtin_audio_stop int-requiring - - eigs_num_arg,make_num,val_is_number audio_stream_open builtin_audio_stream_open int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num audio_stream_push builtin_audio_stream_push other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num audio_stream_queued builtin_audio_stream_queued int-preserving - - make_num audio_sweep builtin_audio_sweep float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num audio_volume builtin_audio_volume int-requiring - bounded VAL_FLOAT,VAL_INT,eigs_slot_num,make_num -bit_and builtin_bit_and int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact -bit_not builtin_bit_not int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact -bit_or builtin_bit_or int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact -bit_shl builtin_bit_shift_left int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact -bit_shr builtin_bit_shift_right int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact -bit_xor builtin_bit_xor int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact +bit_and builtin_bit_and int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number +bit_not builtin_bit_not int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number +bit_or builtin_bit_or int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number +bit_shl builtin_bit_shift_left int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number +bit_shr builtin_bit_shift_right int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number +bit_xor builtin_bit_xor int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number buf_copy builtin_buf_copy int-requiring - - VAL_FLOAT,VAL_INT,eigs_slot_num -buf_deinterleave builtin_buf_deinterleave int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num +buf_deinterleave builtin_buf_deinterleave int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,val_is_number buf_dot builtin_buf_dot float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,make_num,num_guard buf_fill builtin_buf_fill float-producing - - VAL_FLOAT,VAL_INT,buf_num_arg,eigs_slot_num buf_from_list builtin_buf_from_list float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num @@ -348,40 +345,40 @@ buf_resample_linear builtin_buf_resample_linear float-producing buf_scale_range builtin_buf_scale_range float-producing - - VAL_FLOAT,VAL_INT,buf_num_arg,eigs_slot_num,num_guard buf_set builtin_buf_set int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num buf_to_pcm16le builtin_buf_to_pcm16le other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,num_guard -buffer builtin_buffer int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg -build_corpus builtin_build_corpus int-requiring - - eigs_num_arg,eigs_opt_num,make_num,num_val -ceil builtin_ceil int-preserving LOSS - eigs_num_arg,make_num +buffer builtin_buffer int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,val_is_number +build_corpus builtin_build_corpus int-requiring - - eigs_num_arg,eigs_opt_num,make_num,num_val,val_is_number +ceil builtin_ceil int-preserving LOSS - eigs_num_arg,make_num,val_is_number channel builtin_channel int-preserving - - make_num -channel_closed builtin_channel_closed int-requiring - - eigs_num_arg -char_at builtin_char_at int-requiring - - eigs_num_arg -chr builtin_chr int-requiring - - eigs_num_arg +channel_closed builtin_channel_closed int-requiring - - eigs_num_arg,val_is_number +char_at builtin_char_at int-requiring - - eigs_num_arg,val_is_number +chr builtin_chr int-requiring - - eigs_num_arg,val_is_number clock_unix builtin_clock_unix float-producing - - make_num -close_channel builtin_close_channel int-requiring - - eigs_num_arg -copy_into builtin_copy_into int-requiring - - eigs_num_arg -cos builtin_cos float-producing - - eigs_num_arg,make_num +close_channel builtin_close_channel int-requiring - - eigs_num_arg,val_is_number +copy_into builtin_copy_into int-requiring - - eigs_num_arg,val_is_number +cos builtin_cos float-producing - - eigs_num_arg,make_num,val_is_number db_execute builtin_db_execute other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg db_query_json builtin_db_query_json other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg db_query_value builtin_db_query_value other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,strtod -dispatch builtin_dispatch int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num -divide builtin_tensor_divide float-producing - - eigs_num_arg,make_num,num_guard +dispatch builtin_dispatch int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,val_is_number +divide builtin_tensor_divide float-producing - - eigs_num_arg,make_num,num_guard,val_is_number dot builtin_dot float-producing - - buffer_read_num,make_num,num_guard eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_slot_num,make_num eigen_generate builtin_eigen_generate int-requiring - - eigs_slot_num,eigs_slot_opt_num,make_num eigen_model_load builtin_eigen_model_load other - - strtod exec_capture builtin_exec_capture other - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,list_append_num -exit builtin_exit int-requiring - - eigs_list_num,eigs_num_arg -exp builtin_tensor_exp float-producing - - eigs_num_arg,make_num,num_guard +exit builtin_exit int-requiring - - eigs_list_num,eigs_num_arg,val_is_number +exp builtin_tensor_exp float-producing - - eigs_num_arg,make_num,num_guard,val_is_number f64_from_bytes builtin_f64_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,finite_num_to_byte,make_num,num_guard_named -f64_to_bytes builtin_f64_to_bytes other - - eigs_num_arg,make_num +f64_to_bytes builtin_f64_to_bytes other - - eigs_num_arg,make_num,val_is_number fill builtin_fill int-requiring - - eigs_list_num -floor builtin_floor int-preserving LOSS - eigs_num_arg,make_num -gather builtin_tensor_gather int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num -get_at builtin_get_at int-requiring - - buffer_read_num,eigs_num_arg,make_num +floor builtin_floor int-preserving LOSS - eigs_num_arg,make_num,val_is_number +gather builtin_tensor_gather int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_num_arg_slow,eigs_slot_elem_num,eigs_slot_num,make_num,val_is_number +get_at builtin_get_at int-requiring - - buffer_read_num,eigs_num_arg,make_num,val_is_number get_observer_thresholds builtin_get_observer_thresholds float-producing - - make_num gfx_circle builtin_gfx_circle other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num gfx_clear builtin_gfx_clear other - bounded VAL_FLOAT,VAL_INT,eigs_list_num gfx_clip builtin_gfx_clip other - geometry VAL_FLOAT,VAL_INT,eigs_list_num -gfx_delay builtin_gfx_delay other - magnitude eigs_num_arg +gfx_delay builtin_gfx_delay other - magnitude eigs_num_arg,val_is_number gfx_fb builtin_gfx_fb int-requiring - geometry VAL_FLOAT,VAL_INT,buffer_read_byte,eigs_list_num gfx_line builtin_gfx_line other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num gfx_open builtin_gfx_open other - magnitude VAL_FLOAT,VAL_INT,eigs_list_num @@ -391,153 +388,157 @@ gfx_read builtin_gfx_read other gfx_rect builtin_gfx_rect other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num gfx_rrect builtin_gfx_rrect other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num gfx_text builtin_gfx_text other - geometry,bounded VAL_FLOAT,VAL_INT,eigs_list_num -gfx_text_height builtin_gfx_text_height int-preserving - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num +gfx_text_height builtin_gfx_text_height int-preserving - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num,val_is_number gfx_text_width builtin_gfx_text_width int-preserving - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num gfx_ticks builtin_gfx_ticks int-preserving - - make_num -hex builtin_hex int-requiring LOSS - eigs_list_num,eigs_num_arg -http_early_bind builtin_http_early_bind int-requiring - - eigs_opt_num +hex builtin_hex int-requiring LOSS - eigs_list_num,eigs_num_arg,val_is_number +http_early_bind builtin_http_early_bind int-requiring - - eigs_opt_num,val_is_number http_post builtin_http_post other - - eigs_num_text http_route builtin_http_route other - - eigs_num_text http_route_authed builtin_http_route_authed other - - eigs_num_text http_serve builtin_http_serve int-requiring - - eigs_num_text,eigs_opt_num http_static builtin_http_static other - - eigs_num_text index_of builtin_index_of int-preserving - - make_num -inflate builtin_inflate int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num +inflate builtin_inflate int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,make_num,val_is_number join builtin_join other - - eigs_num_text -json_build builtin_json_build other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text +json_build builtin_json_build other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text,val_is_number json_decode builtin_json_decode other LOSS - make_num,strtod json_encode builtin_json_encode other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text -json_path builtin_json_path other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text,make_num,strtod -leaky_relu builtin_tensor_leaky_relu float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,make_num +json_path builtin_json_path other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_num_text,make_num,strtod,val_is_number +leaky_relu builtin_tensor_leaky_relu float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,val_is_number len builtin_len int-preserving - - make_num list_contains builtin_list_contains other - - values_equal list_index_of builtin_list_index_of int-preserving - - make_num,values_equal -list_insert_at builtin_list_insert_at int-requiring - - eigs_num_arg -list_remove_at builtin_list_remove_at int-requiring - - eigs_num_arg -list_slice builtin_list_slice int-requiring - - eigs_num_arg -list_truncate builtin_list_truncate int-requiring - - eigs_num_arg -log builtin_tensor_log float-producing - - eigs_num_arg,make_num,num_guard -log_softmax builtin_tensor_log_softmax float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num +list_insert_at builtin_list_insert_at int-requiring - - eigs_num_arg,val_is_number +list_remove_at builtin_list_remove_at int-requiring - - eigs_num_arg,val_is_number +list_slice builtin_list_slice int-requiring - - eigs_num_arg,val_is_number +list_truncate builtin_list_truncate int-requiring - - eigs_num_arg,val_is_number +log builtin_tensor_log float-producing - - eigs_num_arg,make_num,num_guard,val_is_number +log_softmax builtin_tensor_log_softmax float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num,val_is_number matmul builtin_tensor_matmul float-producing - - SLOT_F64_RAW,VAL_FLOAT,VAL_INT,eigs_slot_num,make_num,num_guard_named matmul_at builtin_tensor_matmul_at float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num matmul_bt builtin_tensor_matmul_bt float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num -max builtin_max int-preserving LOSS - eigs_num_arg,make_num -mean builtin_tensor_mean float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard -min builtin_min int-preserving LOSS - eigs_num_arg,make_num +max builtin_max int-preserving LOSS - eigs_num_arg,make_num,val_is_number +mean builtin_tensor_mean float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard,val_is_number +min builtin_min int-preserving LOSS - eigs_num_arg,make_num,val_is_number model_load_weights builtin_eigen_model_load other - - strtod monotonic_ms builtin_monotonic_ms float-producing - - make_num monotonic_ns builtin_monotonic_ns int-preserving LOSS - make_num -multiply builtin_tensor_multiply int-preserving LOSS - eigs_num_arg,make_num,num_guard +multiply builtin_tensor_multiply int-preserving LOSS - eigs_num_arg,make_num,num_guard,val_is_number native_train_step_builtin builtin_native_train_step int-requiring - - VAL_FLOAT,VAL_INT,atof,eigs_list_num,eigs_slot_num,strtod -nearest_in_range builtin_nearest_in_range float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num -nearest_in_range_all builtin_nearest_in_range_all float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num -negative builtin_tensor_negative int-preserving LOSS - eigs_num_arg,make_num -net_accept builtin_net_accept int-requiring - - eigs_num_arg,eigs_slot_opt_num,make_num -net_close builtin_net_close int-requiring - - eigs_num_arg +nearest_in_range builtin_nearest_in_range float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num,val_is_number +nearest_in_range_all builtin_nearest_in_range_all float-producing - - eigs_list_num,eigs_num_arg,eigs_num_arg_slow,make_num,val_is_number +negative builtin_tensor_negative int-preserving LOSS - eigs_num_arg,make_num,val_is_number +net_accept builtin_net_accept int-requiring - - eigs_num_arg,eigs_slot_opt_num,make_num,val_is_number +net_close builtin_net_close int-requiring - - eigs_num_arg,val_is_number net_dial builtin_net_dial int-requiring - - eigs_slot_opt_num,make_num -net_listen builtin_net_listen int-requiring - - eigs_num_arg,make_num -net_port builtin_net_port int-requiring - - eigs_num_arg,make_num -net_recv builtin_net_recv int-requiring - - eigs_num_arg,eigs_slot_opt_num -net_send builtin_net_send int-requiring - - buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num -norm builtin_tensor_norm float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard -num builtin_num other LOSS - make_num,num_guard_named,strtod -num_copy builtin_num_copy int-preserving LOSS - eigs_num_arg,make_num -numerical_grad builtin_numerical_grad float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num -numerical_grad_cols builtin_numerical_grad_cols float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num -numerical_grad_rows builtin_numerical_grad_rows float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num +net_listen builtin_net_listen int-requiring - - eigs_num_arg,make_num,val_is_number +net_port builtin_net_port int-requiring - - eigs_num_arg,make_num,val_is_number +net_recv builtin_net_recv int-requiring - - eigs_num_arg,eigs_slot_opt_num,val_is_number +net_send builtin_net_send int-requiring - - buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num,val_is_number +norm builtin_tensor_norm float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard,val_is_number +num builtin_num other LOSS - make_num,num_guard_named,strtod,val_is_number +num_copy builtin_num_copy int-preserving LOSS - eigs_num_arg,make_num,val_is_number +numerical_grad builtin_numerical_grad float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num,val_is_number +numerical_grad_cols builtin_numerical_grad_cols float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num,val_is_number +numerical_grad_rows builtin_numerical_grad_rows float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num,val_is_number observe builtin_observe other - - make_num ord builtin_ord int-preserving - - make_num pi builtin_pi float-producing - - make_num -pow builtin_tensor_pow float-producing - - eigs_num_arg,make_num,num_guard_named +pow builtin_tensor_pow float-producing - - eigs_num_arg,make_num,num_guard_named,val_is_number ppu_render_frame builtin_ppu_render_frame int-requiring - - buffer_read_byte print builtin_print other - - eigs_num_text -proc_read_buf builtin_proc_read_buf int-requiring - - eigs_num_arg +proc_read_buf builtin_proc_read_buf int-requiring - - eigs_num_arg,val_is_number random builtin_random float-producing - - make_num -random_hex builtin_random_hex int-requiring - - eigs_num_arg -random_int builtin_random_int int-requiring LOSS - eigs_num_arg,make_num +random_hex builtin_random_hex int-requiring - - eigs_num_arg,val_is_number +random_int builtin_random_int int-requiring LOSS - eigs_num_arg,make_num,val_is_number random_normal builtin_random_normal float-producing - - eigs_list_num,make_num -range builtin_range int-preserving - - eigs_list_num,eigs_num_arg,make_num +range builtin_range int-preserving - - eigs_list_num,eigs_num_arg,make_num,val_is_number read_bytes builtin_read_bytes int-preserving - - make_num -read_bytes_buf builtin_read_bytes_buf int-requiring - - eigs_num_arg,make_num -record_history builtin_record_history other - - eigs_num_arg,make_num -recv builtin_recv int-requiring - - eigs_num_arg -recv_timeout builtin_recv_timeout int-requiring - magnitude eigs_num_arg -relu builtin_tensor_relu float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,make_num +read_bytes_buf builtin_read_bytes_buf int-requiring - - eigs_num_arg,make_num,val_is_number +record_history builtin_record_history other - - eigs_num_arg,make_num,val_is_number +recv builtin_recv int-requiring - - eigs_num_arg,val_is_number +recv_timeout builtin_recv_timeout int-requiring - magnitude eigs_num_arg,val_is_number +relu builtin_tensor_relu float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,val_is_number reshape builtin_reshape int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num -round builtin_round int-preserving LOSS - eigs_num_arg,make_num -sandbox_run builtin_sandbox_run int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num +round builtin_round int-preserving LOSS - eigs_num_arg,make_num,val_is_number +sandbox_run builtin_sandbox_run int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num,val_is_number scan_int_tokens builtin_scan_int_tokens int-preserving LOSS - make_num scan_ints builtin_scan_ints int-preserving LOSS - make_num -scatter_add builtin_tensor_scatter_add float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard -seed_random builtin_seed_random int-requiring LOSS - eigs_num_arg -send builtin_send int-requiring - - eigs_num_arg -set_at builtin_set_at int-requiring - - eigs_num_arg +scatter_add builtin_tensor_scatter_add float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,num_guard,val_is_number +seed_random builtin_seed_random int-requiring LOSS - eigs_num_arg,val_is_number +send builtin_send int-requiring - - eigs_num_arg,val_is_number +set_at builtin_set_at int-requiring - - eigs_num_arg,val_is_number sgd_update builtin_sgd_update float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,eigs_slot_opt_num,list_set_num sgd_update_cols builtin_sgd_update_cols float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num sgd_update_rows builtin_sgd_update_rows float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,eigs_slot_opt_num,list_set_num -shape builtin_tensor_shape int-preserving - - make_num +shape builtin_tensor_shape int-preserving - - make_num,val_is_number shared_delete builtin_shared_delete int-preserving - - make_num -shared_incr builtin_shared_incr int-preserving LOSS - eigs_num_arg,make_num +shared_incr builtin_shared_incr int-preserving LOSS - eigs_num_arg,make_num,val_is_number shared_size builtin_shared_size int-preserving - - make_num -sign_extend builtin_sign_extend int-requiring LOSS - eigs_num_arg,make_num -sin builtin_sin float-producing - - eigs_num_arg,make_num -softmax builtin_tensor_softmax float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num -sort builtin_sort other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg -sort_by builtin_sort_by other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg +sign_extend builtin_sign_extend int-requiring LOSS - eigs_num_arg,make_num,val_is_number +sin builtin_sin float-producing - - eigs_num_arg,make_num,val_is_number +softmax builtin_tensor_softmax float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num,make_num,val_is_number +sort builtin_sort other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,val_is_number +sort_by builtin_sort_by other LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg,val_is_number spawn builtin_spawn int-preserving - - make_num -sqrt builtin_tensor_sqrt float-producing - - eigs_num_arg,make_num -state_at builtin_state_at int-requiring - - eigs_num_arg -store_close builtin_store_close int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val -store_collections builtin_store_collections int-requiring - - eigs_num_arg -store_count builtin_store_count int-requiring - - eigs_num_arg,make_num -store_delete builtin_store_delete int-requiring LOSS - eigs_num_arg -store_drop builtin_store_drop int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val -store_get builtin_store_get int-requiring LOSS - eigs_num_arg,make_num,strtod -store_open builtin_store_open int-preserving - - eigs_num_arg,make_num,strtod -store_put builtin_store_put other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val -store_query builtin_store_query other LOSS - eigs_num_arg,make_num,strtod -store_update builtin_store_update other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val +sqrt builtin_tensor_sqrt float-producing - - eigs_num_arg,make_num,val_is_number +state_at builtin_state_at int-requiring - - eigs_num_arg,val_is_number +store_close builtin_store_close int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number +store_collections builtin_store_collections int-requiring - - eigs_num_arg,val_is_number +store_count builtin_store_count int-requiring - - eigs_num_arg,make_num,val_is_number +store_delete builtin_store_delete int-requiring LOSS - eigs_num_arg,val_is_number +store_drop builtin_store_drop int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number +store_get builtin_store_get int-requiring LOSS - eigs_num_arg,make_num,strtod,val_is_number +store_open builtin_store_open int-preserving - - eigs_num_arg,make_num,strtod,val_is_number +store_put builtin_store_put other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number +store_query builtin_store_query other LOSS - eigs_num_arg,make_num,strtod,val_is_number +store_update builtin_store_update other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,eigs_slot_num,make_num,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number str builtin_str other - - eigs_num_text -str_from_bytes builtin_str_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte -stream_open builtin_stream_open int-requiring - - eigs_num_arg -stream_write builtin_stream_write float-producing - - eigs_num_arg -substr builtin_substr int-requiring - - eigs_num_arg -subtract builtin_tensor_subtract int-preserving LOSS - eigs_num_arg,make_num,num_guard -sum builtin_tensor_sum int-preserving LOSS - buffer_read_num,eigs_num_arg,make_num,num_guard -tan builtin_tan float-producing - - eigs_num_arg,make_num -task_alive builtin_task_alive int-requiring - - eigs_num_arg -task_detach builtin_task_detach int-requiring - - eigs_num_arg,make_num -task_join builtin_task_join int-requiring - - eigs_num_arg -task_kill builtin_task_kill int-requiring - - eigs_num_arg -task_sched_seed builtin_task_sched_seed int-requiring LOSS - eigs_num_arg +str_from_bytes builtin_str_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,finite_num_to_byte,val_is_number +stream_open builtin_stream_open int-requiring - - eigs_num_arg,val_is_number +stream_write builtin_stream_write float-producing - - eigs_num_arg,val_is_number +substr builtin_substr int-requiring - - eigs_num_arg,val_is_number +subtract builtin_tensor_subtract int-preserving LOSS - eigs_num_arg,make_num,num_guard,val_is_number +sum builtin_tensor_sum int-preserving LOSS - buffer_read_num,eigs_num_arg,make_num,num_guard,val_is_number +tan builtin_tan float-producing - - eigs_num_arg,make_num,val_is_number +task_alive builtin_task_alive int-requiring - - eigs_num_arg,val_is_number +task_detach builtin_task_detach int-requiring - - eigs_num_arg,make_num,val_is_number +task_join builtin_task_join int-requiring - - eigs_num_arg,val_is_number +task_kill builtin_task_kill int-requiring - - eigs_num_arg,val_is_number +task_sched_seed builtin_task_sched_seed int-requiring LOSS - eigs_num_arg,val_is_number task_self builtin_task_self int-preserving - - make_num -task_send builtin_task_send int-requiring - - eigs_num_arg -task_sleep builtin_task_sleep other - - eigs_num_arg +task_send builtin_task_send int-requiring - - eigs_num_arg,val_is_number +task_sleep builtin_task_sleep other - - eigs_num_arg,val_is_number task_spawn builtin_task_spawn int-preserving - - make_num tensor_load builtin_tensor_load float-producing - - VAL_FLOAT,VAL_INT,eigs_list_num,make_num,num_guard_named tensor_save builtin_tensor_save float-producing - - VAL_FLOAT,VAL_INT,eigs_slot_num text_builder_append builtin_text_builder_append other - - eigs_num_text text_builder_append_line builtin_text_builder_append_line other - - eigs_num_text -thread_join builtin_thread_join int-requiring - - eigs_num_arg +thread_join builtin_thread_join int-requiring - - eigs_num_arg,val_is_number throw builtin_throw other - - eigs_num_text -token_name builtin_token_name int-requiring - - eigs_num_arg -try_recv builtin_try_recv int-requiring - - eigs_num_arg +token_name builtin_token_name int-requiring - - eigs_num_arg,val_is_number +try_recv builtin_try_recv int-requiring - - eigs_num_arg,val_is_number type builtin_type other - - VAL_FLOAT,VAL_INT -usleep builtin_usleep other - magnitude eigs_num_arg -vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg +usleep builtin_usleep other - magnitude eigs_num_arg,val_is_number +vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg,val_is_number write builtin_write other - - eigs_num_text write_bytes builtin_write_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_elem_num,finite_num_to_byte,make_num -zeros builtin_tensor_zeros int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num -zeros_like builtin_tensor_zeros_like float-producing - - make_num +zeros builtin_tensor_zeros int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,make_num,val_is_number +zeros_like builtin_tensor_zeros_like float-producing - - make_num,val_is_number ## Sites (file:line scope token kind category) +builtins.c:164 builtin_usleep val_is_number TEST a builtins.c:165 builtin_usleep eigs_num_arg READ b builtins.c:350 bit_int num_to_i64_exact READ b +builtins.c:361 bit_pair val_is_number TEST a +builtins.c:361 bit_pair val_is_number TEST a builtins.c:362 bit_pair eigs_num_arg READ b builtins.c:363 bit_pair eigs_num_arg READ b builtins.c:372 builtin_bit_and make_num PRODUCE c builtins.c:380 builtin_bit_or make_num PRODUCE c builtins.c:388 builtin_bit_xor make_num PRODUCE c +builtins.c:392 builtin_bit_not val_is_number TEST a builtins.c:394 builtin_bit_not eigs_num_arg READ b builtins.c:395 builtin_bit_not make_num PRODUCE c builtins.c:403 builtin_bit_shift_left make_num PRODUCE c @@ -552,6 +553,7 @@ builtins.c:454 builtin_len make_num PRODUCE c builtins.c:456 builtin_len make_num PRODUCE c builtins.c:466 builtin_len make_num PRODUCE c builtins.c:495 builtin_num make_num PRODUCE c +builtins.c:496 builtin_num val_is_number TEST a builtins.c:503 builtin_num make_num PRODUCE c builtins.c:522 builtin_num make_num PRODUCE c builtins.c:530 builtin_num make_num PRODUCE c @@ -564,7 +566,9 @@ builtins.c:557 builtin_append VAL_FLOAT YIELD a builtins.c:591 builtin_get_observer_thresholds make_num PRODUCE i builtins.c:592 builtin_get_observer_thresholds make_num PRODUCE i builtins.c:593 builtin_get_observer_thresholds make_num PRODUCE i +builtins.c:643 builtin_exit val_is_number TEST a builtins.c:644 builtin_exit eigs_num_arg READ b +builtins.c:647 builtin_exit val_is_number TEST a builtins.c:648 builtin_exit eigs_list_num READ b builtins.c:783 builtin_observe make_num PRODUCE i builtins.c:784 builtin_observe make_num PRODUCE i @@ -582,6 +586,7 @@ builtins.c:1309 eigs_json_parse_number make_num PRODUCE h builtins.c:1314 eigs_json_parse_number strtod PARSE h builtins.c:1324 eigs_json_parse_number strtod PARSE h builtins.c:1328 eigs_json_parse_number make_num PRODUCE h +builtins.c:1499 builtin_json_build val_is_number TEST h builtins.c:1501 builtin_json_build VAL_I64_RAW RAW h builtins.c:1501 builtin_json_build VAL_INT TEST h builtins.c:1502 builtin_json_build eigs_num_arg READ h @@ -593,7 +598,10 @@ builtins.c:1804 builtin_scan_int_tokens make_num PRODUCE c builtins.c:1805 builtin_scan_int_tokens make_num PRODUCE c builtins.c:1806 builtin_scan_int_tokens make_num PRODUCE c builtins.c:1807 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1910 builtin_char_at val_is_number TEST a builtins.c:1912 builtin_char_at eigs_num_arg READ b +builtins.c:1946 builtin_substr val_is_number TEST a +builtins.c:1947 builtin_substr val_is_number TEST a builtins.c:1949 builtin_substr eigs_num_arg READ b builtins.c:1950 builtin_substr eigs_num_arg READ b builtins.c:1980 builtin_index_of make_num PRODUCE c @@ -601,47 +609,61 @@ builtins.c:1987 builtin_index_of make_num PRODUCE c builtins.c:1992 builtin_index_of make_num PRODUCE c builtins.c:1993 builtin_index_of make_num PRODUCE c builtins.c:2001 builtin_sin make_num PRODUCE c +builtins.c:2001 builtin_sin val_is_number TEST a builtins.c:2002 builtin_sin eigs_num_arg READ b builtins.c:2002 builtin_sin make_num PRODUCE c builtins.c:2006 builtin_cos make_num PRODUCE c +builtins.c:2006 builtin_cos val_is_number TEST a builtins.c:2007 builtin_cos eigs_num_arg READ b builtins.c:2007 builtin_cos make_num PRODUCE c builtins.c:2011 builtin_tan make_num PRODUCE c +builtins.c:2011 builtin_tan val_is_number TEST a builtins.c:2012 builtin_tan eigs_num_arg READ b builtins.c:2012 builtin_tan make_num PRODUCE c builtins.c:2016 builtin_asin make_num PRODUCE c +builtins.c:2016 builtin_asin val_is_number TEST a builtins.c:2017 builtin_asin eigs_num_arg READ b builtins.c:2022 builtin_asin make_num PRODUCE c builtins.c:2026 builtin_asin make_num PRODUCE c builtins.c:2030 builtin_acos make_num PRODUCE c +builtins.c:2030 builtin_acos val_is_number TEST a builtins.c:2031 builtin_acos eigs_num_arg READ b builtins.c:2036 builtin_acos make_num PRODUCE c builtins.c:2040 builtin_acos make_num PRODUCE c builtins.c:2044 builtin_atan make_num PRODUCE c +builtins.c:2044 builtin_atan val_is_number TEST a builtins.c:2045 builtin_atan eigs_num_arg READ b builtins.c:2045 builtin_atan make_num PRODUCE c builtins.c:2050 builtin_atan2 make_num PRODUCE c builtins.c:2053 builtin_atan2 make_num PRODUCE c +builtins.c:2053 builtin_atan2 val_is_number TEST a +builtins.c:2053 builtin_atan2 val_is_number TEST a builtins.c:2054 builtin_atan2 eigs_num_arg READ b builtins.c:2054 builtin_atan2 eigs_num_arg READ b builtins.c:2054 builtin_atan2 make_num PRODUCE c builtins.c:2058 builtin_floor make_num PRODUCE c +builtins.c:2058 builtin_floor val_is_number TEST a builtins.c:2059 builtin_floor eigs_num_arg READ b builtins.c:2059 builtin_floor make_num PRODUCE c builtins.c:2063 builtin_ceil make_num PRODUCE c +builtins.c:2063 builtin_ceil val_is_number TEST a builtins.c:2064 builtin_ceil eigs_num_arg READ b builtins.c:2064 builtin_ceil make_num PRODUCE c builtins.c:2068 builtin_round make_num PRODUCE c +builtins.c:2068 builtin_round val_is_number TEST a builtins.c:2069 builtin_round eigs_num_arg READ b builtins.c:2069 builtin_round make_num PRODUCE c builtins.c:2073 builtin_abs make_num PRODUCE c +builtins.c:2073 builtin_abs val_is_number TEST a builtins.c:2074 builtin_abs eigs_num_arg READ b builtins.c:2074 builtin_abs make_num PRODUCE c builtins.c:2083 minmax_reduce eigs_num_arg READ b builtins.c:2083 minmax_reduce make_num PRODUCE c +builtins.c:2083 minmax_reduce val_is_number TEST a builtins.c:2088 minmax_reduce make_num PRODUCE c builtins.c:2091 minmax_reduce make_num PRODUCE c builtins.c:2095 minmax_reduce make_num PRODUCE c +builtins.c:2095 minmax_reduce val_is_number TEST a builtins.c:2096 minmax_reduce eigs_num_arg READ b builtins.c:2096 minmax_reduce eigs_num_arg READ b builtins.c:2097 minmax_reduce eigs_num_arg READ b @@ -649,58 +671,85 @@ builtins.c:2099 minmax_reduce make_num PRODUCE c builtins.c:2108 builtin_pi make_num PRODUCE c builtins.c:2164 builtin_random make_num PRODUCE c builtins.c:2173 builtin_random_int make_num PRODUCE c +builtins.c:2176 builtin_random_int val_is_number TEST a +builtins.c:2176 builtin_random_int val_is_number TEST a builtins.c:2177 builtin_random_int make_num PRODUCE c builtins.c:2181 builtin_random_int eigs_num_arg READ b builtins.c:2182 builtin_random_int eigs_num_arg READ b builtins.c:2192 builtin_random_int make_num PRODUCE c builtins.c:2204 builtin_random_int make_num PRODUCE c +builtins.c:2209 builtin_seed_random val_is_number TEST a builtins.c:2211 builtin_seed_random eigs_num_arg READ b +builtins.c:2439 builtin_json_path val_is_number TEST h builtins.c:2441 builtin_json_path VAL_I64_RAW RAW h builtins.c:2441 builtin_json_path VAL_INT TEST h builtins.c:2442 builtin_json_path eigs_num_arg READ h builtins.c:2442 builtin_json_path eigs_num_text FORMAT h +builtins.c:2546 builtin_token_name val_is_number TEST a builtins.c:2547 builtin_token_name eigs_num_arg READ b +builtins.c:2583 builtin_state_at val_is_number TEST i builtins.c:2584 builtin_state_at eigs_num_arg READ i +builtins.c:2630 builtin_chr val_is_number TEST a builtins.c:2634 builtin_chr eigs_num_arg READ b +builtins.c:2658 builtin_hex val_is_number TEST e builtins.c:2659 builtin_hex eigs_num_arg READ e +builtins.c:2661 builtin_hex val_is_number TEST e +builtins.c:2662 builtin_hex val_is_number TEST e builtins.c:2663 builtin_hex eigs_list_num READ e builtins.c:2664 builtin_hex eigs_list_num READ e builtins.c:2691 builtin_ord make_num PRODUCE c builtins.c:2694 builtin_ord make_num PRODUCE c builtins.c:2695 builtin_ord make_num PRODUCE c +builtins.c:2812 vm_desc_abi_error val_is_number TEST a builtins.c:2820 vm_desc_abi_error eigs_num_arg READ b builtins.c:2825 vm_desc_abi_error eigs_num_arg READ b builtins.c:2921 desc_isolate_const VAL_FLOAT CASE a builtins.c:2922 desc_isolate_const VAL_INT CASE a +builtins.c:3040 vm_build_chunk_desc_body val_is_number TEST a builtins.c:3045 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3101 vm_build_chunk_desc_body val_is_number TEST a builtins.c:3102 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3419 builtin_sandbox_run val_is_number TEST a builtins.c:3420 builtin_sandbox_run eigs_list_num READ b +builtins.c:3426 builtin_sandbox_run val_is_number TEST a builtins.c:3427 builtin_sandbox_run eigs_list_num READ b builtins.c:3428 builtin_sandbox_run eigs_list_num READ b +builtins.c:3435 builtin_sandbox_run val_is_number TEST a builtins.c:3436 builtin_sandbox_run eigs_list_num READ b builtins.c:3478 builtin_sandbox_run make_num PRODUCE c builtins.c:3659 builtin_sandbox_run make_num PRODUCE c builtins.c:3671 builtin_sandbox_run make_num PRODUCE c builtins.c:3685 builtin_sandbox_run make_num PRODUCE c builtins.c:3719 builtin_sandbox_run make_num PRODUCE c +builtins.c:3745 builtin_record_history val_is_number TEST i builtins.c:3751 builtin_record_history eigs_num_arg READ i builtins.c:3756 builtin_record_history make_num PRODUCE i +builtins.c:3784 builtin_copy_into val_is_number TEST a builtins.c:3789 builtin_copy_into eigs_num_arg READ b +builtins.c:3801 builtin_copy_into val_is_number TEST a builtins.c:3806 builtin_copy_into eigs_num_arg READ b +builtins.c:3839 builtin_list_slice val_is_number TEST a +builtins.c:3839 builtin_list_slice val_is_number TEST a builtins.c:3842 builtin_list_slice eigs_num_arg READ b builtins.c:3843 builtin_list_slice eigs_num_arg READ b +builtins.c:3865 builtin_num_copy val_is_number TEST a builtins.c:3866 builtin_num_copy eigs_num_arg READ b builtins.c:3866 builtin_num_copy make_num PRODUCE c +builtins.c:3910 builtin_range val_is_number TEST a builtins.c:3912 builtin_range eigs_num_arg READ b +builtins.c:3919 builtin_range val_is_number TEST a builtins.c:3927 builtin_range eigs_list_num READ b builtins.c:3930 builtin_range eigs_list_num READ b builtins.c:3934 builtin_range eigs_list_num READ b builtins.c:3978 builtin_range make_num PRODUCE c builtins.c:3994 builtin_fill eigs_list_num READ b +builtins.c:4016 at_index val_is_number TEST a builtins.c:4020 at_index eigs_num_arg READ b builtins.c:4024 at_index eigs_num_arg READ b +builtins.c:4035 buf_at_index val_is_number TEST a builtins.c:4040 buf_at_index eigs_num_arg READ b builtins.c:4044 buf_at_index eigs_num_arg READ b +builtins.c:4085 builtin_set_at val_is_number TEST a builtins.c:4090 builtin_set_at eigs_num_arg READ b builtins.c:4151 builtin_get_at buffer_read_num READ b builtins.c:4151 builtin_get_at make_num PRODUCE c @@ -709,20 +758,33 @@ builtins.c:4159 builtin_get_at make_num PRODUCE c builtins.c:4521 builtin_spawn make_num PRODUCE c builtins.c:4527 builtin_spawn make_num PRODUCE c builtins.c:4528 builtin_spawn make_num PRODUCE c +builtins.c:4553 builtin_thread_join val_is_number TEST a builtins.c:4557 builtin_thread_join eigs_num_arg READ b builtins.c:4558 builtin_thread_join eigs_num_arg READ b +builtins.c:4558 builtin_thread_join val_is_number TEST a +builtins.c:4638 get_channel_why val_is_number TEST a builtins.c:4639 get_channel_why eigs_num_arg READ b builtins.c:4641 get_channel_why eigs_num_arg READ b +builtins.c:4641 get_channel_why val_is_number TEST a builtins.c:4706 builtin_channel make_num PRODUCE c builtins.c:4707 builtin_channel make_num PRODUCE c +builtins.c:4809 builtin_recv_timeout val_is_number TEST a builtins.c:4813 builtin_recv_timeout eigs_num_arg READ b builtins.c:4995 builtin_task_spawn make_num PRODUCE c +builtins.c:5005 task_handle_resolve val_is_number TEST a builtins.c:5006 task_handle_resolve eigs_num_arg READ b +builtins.c:5057 builtin_task_join val_is_number TEST a +builtins.c:5099 builtin_task_send val_is_number TEST a builtins.c:5107 builtin_task_send eigs_num_arg READ b +builtins.c:5130 builtin_task_kill val_is_number TEST a +builtins.c:5142 builtin_task_alive val_is_number TEST a +builtins.c:5164 builtin_task_sleep val_is_number TEST a builtins.c:5170 builtin_task_sleep eigs_num_arg READ b builtins.c:5202 builtin_task_self make_num PRODUCE c +builtins.c:5214 builtin_task_detach val_is_number TEST a builtins.c:5219 builtin_task_detach make_num PRODUCE c builtins.c:5220 builtin_task_detach make_num PRODUCE c +builtins.c:5231 builtin_task_sched_seed val_is_number TEST a builtins.c:5235 builtin_task_sched_seed eigs_num_arg READ b builtins.c:5384 builtin_nearest_in_range eigs_list_num READ b builtins.c:5385 builtin_nearest_in_range eigs_list_num READ b @@ -730,7 +792,10 @@ builtins.c:5386 builtin_nearest_in_range eigs_list_num READ b builtins.c:5387 builtin_nearest_in_range eigs_list_num READ b builtins.c:5388 builtin_nearest_in_range eigs_list_num READ b builtins.c:5444 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5444 builtin_nearest_in_range val_is_number TEST a builtins.c:5468 builtin_nearest_in_range eigs_num_arg_slow READ b +builtins.c:5471 builtin_nearest_in_range val_is_number TEST a +builtins.c:5471 builtin_nearest_in_range val_is_number TEST a builtins.c:5473 builtin_nearest_in_range eigs_num_arg READ b builtins.c:5474 builtin_nearest_in_range eigs_num_arg READ b builtins.c:5488 builtin_nearest_in_range make_num PRODUCE c @@ -741,7 +806,10 @@ builtins.c:5516 builtin_nearest_in_range_all eigs_list_num READ b builtins.c:5517 builtin_nearest_in_range_all eigs_list_num READ b builtins.c:5518 builtin_nearest_in_range_all eigs_list_num READ b builtins.c:5573 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5573 builtin_nearest_in_range_all val_is_number TEST a builtins.c:5593 builtin_nearest_in_range_all eigs_num_arg_slow READ b +builtins.c:5596 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5596 builtin_nearest_in_range_all val_is_number TEST a builtins.c:5600 builtin_nearest_in_range_all eigs_num_arg READ b builtins.c:5601 builtin_nearest_in_range_all eigs_num_arg READ b builtins.c:5642 builtin_nearest_in_range_all make_num PRODUCE c @@ -750,18 +818,24 @@ builtins.c:5644 builtin_nearest_in_range_all make_num PRODUCE c builtins.c:5645 builtin_nearest_in_range_all make_num PRODUCE c builtins.c:5668 builtin_sign_extend make_num PRODUCE c builtins.c:5678 builtin_sign_extend make_num PRODUCE c +builtins.c:5678 builtin_sign_extend val_is_number TEST a +builtins.c:5678 builtin_sign_extend val_is_number TEST a builtins.c:5679 builtin_sign_extend eigs_num_arg READ b builtins.c:5680 builtin_sign_extend eigs_num_arg READ b builtins.c:5681 builtin_sign_extend make_num PRODUCE c builtins.c:5684 builtin_sign_extend make_num PRODUCE c builtins.c:5685 builtin_sign_extend make_num PRODUCE c +builtins.c:5702 builtin_list_truncate val_is_number TEST a builtins.c:5706 builtin_list_truncate eigs_num_arg READ b +builtins.c:5732 builtin_list_remove_at val_is_number TEST a builtins.c:5733 builtin_list_remove_at eigs_num_arg READ b +builtins.c:5754 builtin_list_insert_at val_is_number TEST a builtins.c:5755 builtin_list_insert_at eigs_num_arg READ b builtins.c:5782 builtin_list_index_of make_num PRODUCE f builtins.c:5786 builtin_list_index_of make_num PRODUCE f builtins.c:5792 builtin_list_index_of make_num PRODUCE f builtins.c:5796 builtin_list_index_of make_num PRODUCE f +builtins.c:5867 builtin_sort_by val_is_number TEST f builtins.c:5876 builtin_sort_by VAL_INT TEST f builtins.c:5877 builtin_sort_by VAL_I64_RAW RAW f builtins.c:5878 builtin_sort_by eigs_num_arg READ f @@ -781,8 +855,10 @@ builtins.c:5910 sort_cmp_num eigs_num_arg READ b builtins.c:5910 sort_cmp_num eigs_num_arg READ b builtins.c:5928 builtin_sort VAL_FLOAT TEST f builtins.c:5928 builtin_sort VAL_INT TEST f +builtins.c:5929 builtin_sort val_is_number TEST f builtins.c:5936 builtin_sort VAL_FLOAT TEST f builtins.c:5936 builtin_sort VAL_INT TEST f +builtins.c:5957 builtin_dispatch val_is_number TEST a builtins.c:5961 builtin_dispatch eigs_num_arg READ b builtins.c:5962 builtin_dispatch eigs_num_arg READ b builtins.c:5964 builtin_dispatch eigs_num_arg READ b @@ -804,7 +880,9 @@ builtins_buf.c:36 builtin_buffer VAL_FLOAT TEST a builtins_buf.c:36 builtin_buffer VAL_INT TEST a builtins_buf.c:37 builtin_buffer eigs_list_num READ b builtins_buf.c:38 builtin_buffer eigs_list_num READ b +builtins_buf.c:56 builtin_buffer val_is_number TEST a builtins_buf.c:57 builtin_buffer eigs_num_arg READ b +builtins_buf.c:57 builtin_buffer val_is_number TEST a builtins_buf.c:78 builtin_reshape VAL_FLOAT TEST a builtins_buf.c:78 builtin_reshape VAL_INT TEST a builtins_buf.c:79 builtin_reshape VAL_FLOAT TEST a @@ -829,6 +907,8 @@ builtins_buf.c:164 builtin_buf_len make_num PRODUCE c builtins_buf.c:184 builtin_buf_from_list VAL_FLOAT TEST a builtins_buf.c:184 builtin_buf_from_list VAL_INT TEST a builtins_buf.c:185 builtin_buf_from_list eigs_slot_num READ b +builtins_buf.c:206 strict_numeric_byte_list val_is_number TEST a +builtins_buf.c:213 strict_numeric_byte_list val_is_number TEST a builtins_buf.c:214 strict_numeric_byte_list eigs_num_arg READ b builtins_buf.c:214 strict_numeric_byte_list finite_num_to_byte READ b builtins_buf.c:239 builtin_str_from_bytes VAL_FLOAT TEST a @@ -836,7 +916,9 @@ builtins_buf.c:239 builtin_str_from_bytes VAL_INT TEST a builtins_buf.c:239 builtin_str_from_bytes eigs_slot_num READ b builtins_buf.c:240 builtin_str_from_bytes buffer_read_num READ b builtins_buf.c:242 builtin_str_from_bytes finite_num_to_byte READ b +builtins_buf.c:260 builtin_f64_to_bytes val_is_number TEST a builtins_buf.c:261 builtin_f64_to_bytes eigs_num_arg READ b +builtins_buf.c:261 builtin_f64_to_bytes val_is_number TEST a builtins_buf.c:267 builtin_f64_to_bytes make_num PRODUCE c builtins_buf.c:279 builtin_f64_from_bytes VAL_FLOAT TEST a builtins_buf.c:279 builtin_f64_from_bytes VAL_INT TEST a @@ -891,6 +973,8 @@ builtins_buf.c:799 builtin_buf_to_pcm16le num_guard GUARD c builtins_buf.c:800 builtin_buf_to_pcm16le num_guard GUARD c builtins_buf.c:801 builtin_buf_to_pcm16le num_guard GUARD c builtins_buf.c:801 builtin_buf_to_pcm16le num_guard GUARD c +builtins_buf.c:827 builtin_buf_deinterleave val_is_number TEST a +builtins_buf.c:827 builtin_buf_deinterleave val_is_number TEST a builtins_buf.c:831 builtin_buf_deinterleave eigs_num_arg READ b builtins_buf.c:832 builtin_buf_deinterleave eigs_num_arg READ b builtins_buf.c:909 builtin_buf_resample_linear num_guard GUARD c @@ -900,13 +984,16 @@ builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c builtins_buf.c:924 builtin_buf_resample_linear num_guard GUARD c builtins_buf.c:925 builtin_buf_resample_linear num_guard GUARD c +builtins_host.c:218 builtin_stream_open val_is_number TEST a builtins_host.c:220 builtin_stream_open eigs_num_arg READ b builtins_host.c:221 builtin_stream_open eigs_num_arg READ b builtins_host.c:222 builtin_stream_open eigs_num_arg READ b builtins_host.c:222 builtin_stream_open eigs_num_arg READ b builtins_host.c:225 builtin_stream_open eigs_num_arg READ b builtins_host.c:236 builtin_stream_open eigs_num_arg READ b +builtins_host.c:255 builtin_stream_write val_is_number TEST a builtins_host.c:260 builtin_stream_write eigs_num_arg READ b +builtins_host.c:413 builtin_build_corpus val_is_number TEST a builtins_host.c:417 builtin_build_corpus eigs_num_arg READ b builtins_host.c:449 builtin_build_corpus eigs_opt_num READ b builtins_host.c:478 builtin_build_corpus eigs_opt_num READ b @@ -915,19 +1002,25 @@ builtins_host.c:808 builtin_build_corpus make_num PRODUCE c builtins_host.c:809 builtin_build_corpus make_num PRODUCE c builtins_host.c:810 builtin_build_corpus make_num PRODUCE c builtins_host.c:1055 builtin_read_bytes make_num PRODUCE c +builtins_host.c:1106 builtin_read_bytes_buf val_is_number TEST a builtins_host.c:1110 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1111 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1114 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1117 builtin_read_bytes_buf eigs_num_arg READ b +builtins_host.c:1131 builtin_read_bytes_buf val_is_number TEST a builtins_host.c:1132 builtin_read_bytes_buf eigs_num_arg READ b builtins_host.c:1152 builtin_read_bytes_buf make_num PRODUCE c builtins_host.c:1263 exec_capture_result list_append_num PRODUCE c builtins_host.c:1290 builtin_exec_capture VAL_FLOAT TEST a builtins_host.c:1290 builtin_exec_capture VAL_INT TEST a builtins_host.c:1292 builtin_exec_capture eigs_list_num READ b +builtins_host.c:1441 builtin_proc_read_buf val_is_number TEST a +builtins_host.c:1441 builtin_proc_read_buf val_is_number TEST a builtins_host.c:1443 builtin_proc_read_buf eigs_num_arg READ b builtins_host.c:1444 builtin_proc_read_buf eigs_num_arg READ b +builtins_host.c:1475 builtin_random_hex val_is_number TEST a builtins_host.c:1476 builtin_random_hex eigs_num_arg READ b +builtins_host.c:1476 builtin_random_hex val_is_number TEST a builtins_host.c:1502 builtin_write_bytes make_num PRODUCE c builtins_host.c:1508 builtin_write_bytes make_num PRODUCE c builtins_host.c:1516 builtin_write_bytes eigs_num_arg READ b @@ -952,7 +1045,9 @@ builtins_tensor.c:299 tensor_to_flat VAL_INT TEST a builtins_tensor.c:299 tensor_to_flat eigs_slot_num READ b builtins_tensor.c:311 flat_to_tensor_2d make_num PRODUCE c builtins_tensor.c:327 flat_to_tensor_1d make_num PRODUCE c +builtins_tensor.c:359 tensor_total val_is_number TEST a builtins_tensor.c:380 tensor_flatten_recursive eigs_num_arg READ b +builtins_tensor.c:380 tensor_flatten_recursive val_is_number TEST a builtins_tensor.c:383 tensor_flatten_recursive buffer_read_num READ b builtins_tensor.c:399 op_add num_guard GUARD c builtins_tensor.c:400 op_sub num_guard GUARD c @@ -960,20 +1055,28 @@ builtins_tensor.c:401 op_mul num_guard GUARD c builtins_tensor.c:408 op_div num_guard GUARD c builtins_tensor.c:412 op_pow num_guard_named GUARD c builtins_tensor.c:488 tensor_elementwise make_num PRODUCE c +builtins_tensor.c:491 tensor_elementwise val_is_number TEST a +builtins_tensor.c:491 tensor_elementwise val_is_number TEST a builtins_tensor.c:492 tensor_elementwise eigs_num_arg READ b builtins_tensor.c:492 tensor_elementwise eigs_num_arg READ b builtins_tensor.c:492 tensor_elementwise make_num PRODUCE c +builtins_tensor.c:500 tensor_elementwise val_is_number TEST a builtins_tensor.c:501 tensor_elementwise eigs_num_arg READ b +builtins_tensor.c:502 tensor_elementwise val_is_number TEST a builtins_tensor.c:503 tensor_elementwise eigs_num_arg READ b +builtins_tensor.c:520 tensor_elementwise val_is_number TEST a +builtins_tensor.c:531 tensor_elementwise val_is_number TEST a builtins_tensor.c:629 tensor_elementwise make_num PRODUCE c builtins_tensor.c:683 tensor_unary eigs_num_arg READ b builtins_tensor.c:683 tensor_unary make_num PRODUCE c +builtins_tensor.c:683 tensor_unary val_is_number TEST a builtins_tensor.c:705 tensor_unary make_num PRODUCE c builtins_tensor.c:718 op_exp num_guard GUARD c builtins_tensor.c:732 op_log_safe num_guard GUARD c builtins_tensor.c:734 op_log_safe num_guard GUARD c builtins_tensor.c:797 builtin_tensor_matmul SLOT_F64_RAW RAW b builtins_tensor.c:828 builtin_tensor_matmul num_guard_named GUARD c +builtins_tensor.c:995 builtin_tensor_scatter_add val_is_number TEST a builtins_tensor.c:1026 builtin_tensor_scatter_add VAL_FLOAT TEST a builtins_tensor.c:1026 builtin_tensor_scatter_add VAL_INT TEST a builtins_tensor.c:1030 builtin_tensor_scatter_add eigs_slot_num READ b @@ -985,23 +1088,29 @@ builtins_tensor.c:1049 builtin_tensor_scatter_add eigs_num_arg READ b builtins_tensor.c:1077 builtin_tensor_scatter_add num_guard GUARD c builtins_tensor.c:1080 builtin_tensor_scatter_add num_guard GUARD c builtins_tensor.c:1091 builtin_tensor_softmax make_num PRODUCE c +builtins_tensor.c:1091 builtin_tensor_softmax val_is_number TEST a builtins_tensor.c:1125 builtin_tensor_log_softmax VAL_FLOAT TEST a builtins_tensor.c:1125 builtin_tensor_log_softmax VAL_INT TEST a builtins_tensor.c:1131 builtin_tensor_log_softmax make_num PRODUCE c +builtins_tensor.c:1131 builtin_tensor_log_softmax val_is_number TEST a +builtins_tensor.c:1165 builtin_tensor_relu val_is_number TEST a builtins_tensor.c:1166 builtin_tensor_relu eigs_num_arg READ b builtins_tensor.c:1167 builtin_tensor_relu make_num PRODUCE c +builtins_tensor.c:1186 builtin_tensor_leaky_relu val_is_number TEST a builtins_tensor.c:1187 builtin_tensor_leaky_relu eigs_num_arg READ b builtins_tensor.c:1188 builtin_tensor_leaky_relu make_num PRODUCE c builtins_tensor.c:1219 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1222 builtin_tensor_mean buffer_read_num READ b builtins_tensor.c:1224 builtin_tensor_mean num_guard GUARD c builtins_tensor.c:1226 builtin_tensor_mean make_num PRODUCE c +builtins_tensor.c:1236 builtin_tensor_mean val_is_number TEST a builtins_tensor.c:1238 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1243 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1253 builtin_tensor_mean make_num PRODUCE c builtins_tensor.c:1265 builtin_tensor_sum buffer_read_num READ b builtins_tensor.c:1267 builtin_tensor_sum num_guard GUARD c builtins_tensor.c:1269 builtin_tensor_sum make_num PRODUCE c +builtins_tensor.c:1279 builtin_tensor_sum val_is_number TEST a builtins_tensor.c:1281 builtin_tensor_sum make_num PRODUCE c builtins_tensor.c:1286 builtin_tensor_sum make_num PRODUCE c builtins_tensor.c:1294 builtin_tensor_sum num_guard GUARD c @@ -1011,12 +1120,14 @@ builtins_tensor.c:1307 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1307 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1309 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1309 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1319 builtin_tensor_norm val_is_number TEST a builtins_tensor.c:1321 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1325 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1333 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1333 builtin_tensor_norm num_guard GUARD c builtins_tensor.c:1335 builtin_tensor_norm make_num PRODUCE c builtins_tensor.c:1335 builtin_tensor_norm num_guard GUARD c +builtins_tensor.c:1356 builtin_tensor_zeros val_is_number TEST a builtins_tensor.c:1357 builtin_tensor_zeros eigs_num_arg READ b builtins_tensor.c:1365 builtin_tensor_zeros VAL_FLOAT TEST a builtins_tensor.c:1365 builtin_tensor_zeros VAL_INT TEST a @@ -1026,6 +1137,7 @@ builtins_tensor.c:1367 builtin_tensor_zeros eigs_list_num READ b builtins_tensor.c:1368 builtin_tensor_zeros eigs_list_num READ b builtins_tensor.c:1381 builtin_tensor_zeros make_num PRODUCE c builtins_tensor.c:1396 builtin_tensor_zeros_like make_num PRODUCE c +builtins_tensor.c:1396 builtin_tensor_zeros_like val_is_number TEST a builtins_tensor.c:1413 builtin_tensor_zeros_like make_num PRODUCE c builtins_tensor.c:1430 flat_index_at VAL_FLOAT TEST a builtins_tensor.c:1430 flat_index_at VAL_INT TEST a @@ -1033,6 +1145,7 @@ builtins_tensor.c:1431 flat_index_at eigs_slot_num READ b builtins_tensor.c:1436 flat_index_at buffer_read_num READ b builtins_tensor.c:1445 flat_index_is_num VAL_FLOAT TEST a builtins_tensor.c:1445 flat_index_is_num VAL_INT TEST a +builtins_tensor.c:1488 builtin_tensor_gather val_is_number TEST a builtins_tensor.c:1489 builtin_tensor_gather eigs_num_arg READ b builtins_tensor.c:1495 builtin_tensor_gather buffer_read_num READ b builtins_tensor.c:1495 builtin_tensor_gather make_num PRODUCE c @@ -1043,6 +1156,7 @@ builtins_tensor.c:1545 builtin_tensor_gather VAL_INT TEST a builtins_tensor.c:1551 builtin_tensor_gather eigs_slot_num READ b builtins_tensor.c:1561 builtin_tensor_gather eigs_slot_elem_num READ b builtins_tensor.c:1563 builtin_tensor_gather make_num PRODUCE c +builtins_tensor.c:1568 builtin_tensor_gather val_is_number TEST a builtins_tensor.c:1569 builtin_tensor_gather eigs_num_arg READ b builtins_tensor.c:1575 builtin_tensor_gather eigs_slot_elem_num READ b builtins_tensor.c:1577 builtin_tensor_gather make_num PRODUCE c @@ -1054,6 +1168,7 @@ builtins_tensor.c:1700 builtin_random_normal make_num PRODUCE c builtins_tensor.c:1708 builtin_random_normal eigs_list_num READ b builtins_tensor.c:1709 builtin_random_normal eigs_list_num READ b builtins_tensor.c:1715 builtin_random_normal make_num PRODUCE c +builtins_tensor.c:1726 builtin_tensor_shape val_is_number TEST a builtins_tensor.c:1734 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1735 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1739 builtin_tensor_shape make_num PRODUCE c @@ -1061,6 +1176,7 @@ builtins_tensor.c:1745 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1753 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1754 builtin_tensor_shape make_num PRODUCE c builtins_tensor.c:1759 builtin_tensor_shape make_num PRODUCE c +builtins_tensor.c:1768 numerical_loss val_is_number TEST a builtins_tensor.c:1769 numerical_loss eigs_num_arg READ b builtins_tensor.c:1804 tensor_cells_numeric VAL_FLOAT TEST a builtins_tensor.c:1804 tensor_cells_numeric VAL_INT TEST a @@ -1129,6 +1245,8 @@ chunk.c:222 const_equal VAL_INT TEST f chunk.c:222 const_equal VAL_INT TEST f chunk.c:223 const_equal VAL_I64_RAW RAW f chunk.c:223 const_equal VAL_I64_RAW RAW f +chunk.c:243 const_dedup_grow val_is_number TEST a +chunk.c:252 chunk_add_constant_ex val_is_number TEST a chunk.c:430 chunk_disassemble VAL_FLOAT TEST e chunk.c:431 chunk_disassemble VAL_F64_RAW RAW e chunk.c:432 chunk_disassemble VAL_INT TEST e @@ -1189,6 +1307,7 @@ container.h:145 eigs_slot_num SLOT_F64_RAW RAW b container.h:145 eigs_slot_num slot_is_f64 TEST a container.h:146 eigs_slot_num slot_is_smi TEST a container.h:146 eigs_slot_num slot_smi_val RAW b +container.h:147 eigs_slot_num val_is_number TEST a container.h:148 eigs_slot_num eigs_num_arg READ b container.h:149 eigs_slot_num eigs_num_arg_slow READ b container.h:151 eigs_slot_elem_num eigs_slot_elem_num READ b @@ -1197,12 +1316,14 @@ container.h:152 eigs_slot_elem_num slot_is_f64 TEST a container.h:153 eigs_slot_elem_num slot_is_smi TEST a container.h:153 eigs_slot_elem_num slot_smi_val RAW b container.h:155 eigs_slot_elem_num eigs_num_arg READ b +container.h:155 eigs_slot_elem_num val_is_number TEST a container.h:156 eigs_slot_elem_num eigs_num_arg_slow READ b container.h:159 eigs_slot_opt_num eigs_slot_opt_num READ b container.h:161 eigs_slot_opt_num SLOT_F64_RAW RAW b container.h:161 eigs_slot_opt_num slot_is_f64 TEST a container.h:162 eigs_slot_opt_num slot_is_smi TEST a container.h:162 eigs_slot_opt_num slot_smi_val RAW b +container.h:163 eigs_slot_opt_num val_is_number TEST a container.h:164 eigs_slot_opt_num eigs_num_arg READ b container.h:166 eigs_slot_opt_num eigs_num_arg_slow READ b container.h:175 slot_view slot_is_smi TEST a @@ -1262,9 +1383,11 @@ eigenscript.c:442 compute_entropy_impl VAL_F64_RAW RAW i eigenscript.c:442 compute_entropy_impl VAL_FLOAT CASE i eigenscript.c:445 compute_entropy_impl VAL_I64_RAW RAW i eigenscript.c:445 compute_entropy_impl VAL_INT CASE i +eigenscript.c:796 observer_slot_update val_is_number TEST i eigenscript.c:798 observer_slot_update VAL_I64_RAW RAW i eigenscript.c:798 observer_slot_update VAL_INT TEST i eigenscript.c:799 observer_slot_update VAL_F64_RAW RAW i +eigenscript.c:861 observer_slot_sample_gated val_is_number TEST i eigenscript.c:862 observer_slot_sample_gated VAL_I64_RAW RAW i eigenscript.c:862 observer_slot_sample_gated VAL_INT TEST i eigenscript.c:863 observer_slot_sample_gated VAL_F64_RAW RAW i @@ -1282,6 +1405,8 @@ eigenscript.c:1454 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1455 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1461 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1494 observer_slot_from_trajectory eigs_num_arg READ i +eigenscript.c:1494 observer_slot_from_trajectory val_is_number TEST i +eigenscript.c:1495 observer_slot_from_trajectory val_is_number TEST i eigenscript.c:1513 observer_slot_from_trajectory VAL_FLOAT TEST i eigenscript.c:1513 observer_slot_from_trajectory VAL_FLOAT TEST i eigenscript.c:1513 observer_slot_from_trajectory VAL_INT TEST i @@ -1291,6 +1416,7 @@ eigenscript.c:1519 observer_slot_from_trajectory eigs_slot_num READ i eigenscript.c:1529 observer_slot_from_trajectory VAL_FLOAT TEST i eigenscript.c:1529 observer_slot_from_trajectory VAL_INT TEST i eigenscript.c:1534 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1547 observer_slot_from_trajectory val_is_number TEST i eigenscript.c:1552 observer_slot_from_trajectory eigs_num_arg READ i eigenscript.c:1655 free_value VAL_FLOAT TEST a eigenscript.c:1737 free_value VAL_FLOAT CASE a @@ -1348,6 +1474,8 @@ eigenscript.c:2918 values_equal_impl VAL_FLOAT TEST f eigenscript.c:2918 values_equal_impl VAL_INT TEST f eigenscript.c:2919 values_equal_impl VAL_F64_RAW RAW f eigenscript.c:2919 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2920 values_equal_impl val_is_number TEST f +eigenscript.c:2921 values_equal_impl val_is_number TEST f eigenscript.c:2935 values_equal_impl VAL_F64_RAW RAW f eigenscript.c:2935 values_equal_impl VAL_F64_RAW RAW f eigenscript.c:2935 values_equal_impl VAL_FLOAT CASE f @@ -1367,48 +1495,43 @@ eigenscript.c:4261 gc_value_is_node VAL_FLOAT CASE a eigenscript.c:4262 gc_value_is_node VAL_INT CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a -eigenscript.h:281 VAL_FLOAT DATA a -eigenscript.h:289 VAL_INT DATA a -eigenscript.h:290 VAL_FLOAT TAGSET c -eigenscript.h:290 VAL_NUM DATA a -eigenscript.h:298 #define val_is_number VAL_FLOAT TEST a -eigenscript.h:298 #define val_is_number VAL_INT TEST a -eigenscript.h:319 #define VAL_F64_RAW VAL_F64_RAW RAW b -eigenscript.h:319 #define VAL_F64_RAW f64_ RAW b -eigenscript.h:320 #define VAL_I64_RAW VAL_I64_RAW RAW b -eigenscript.h:320 #define VAL_I64_RAW i64_ RAW b -eigenscript.h:321 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b -eigenscript.h:321 #define VAL_F64_OFFSET f64_ RAW b -eigenscript.h:323 #define VAL_NUM_RAW VAL_NUM_RAW RAW b -eigenscript.h:323 #define VAL_NUM_RAW num_ RAW b -eigenscript.h:324 #define VAL_NUM_OFFSET VAL_NUM_OFFSET RAW b -eigenscript.h:324 #define VAL_NUM_OFFSET num_ RAW b -eigenscript.h:1430 eigs_num_arg_slow READ b -eigenscript.h:1431 eigs_num_arg eigs_num_arg READ b -eigenscript.h:1432 eigs_num_arg VAL_F64_RAW RAW b -eigenscript.h:1432 eigs_num_arg VAL_FLOAT TEST a -eigenscript.h:1433 eigs_num_arg eigs_num_arg_slow READ b -eigenscript.h:1435 eigs_list_num READ b -eigenscript.h:1440 eigs_elem_num READ b -eigenscript.h:1441 eigs_opt_num READ b -eigenscript.h:1812 make_num PRODUCE c -eigenscript.h:1822 make_num_permanent PRODUCE c -eigenscript.h:1874 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1916 num_guard num_guard GUARD c -eigenscript.h:1924 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1924 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1925 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1925 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1934 buffer_read_num buffer_read_num READ b -eigenscript.h:1935 buffer_read_num num_guard GUARD c -eigenscript.h:1941 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1950 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1959 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1960 buffer_read_byte buffer_read_num READ b -eigenscript.h:1962 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1973 num_guard_named num_guard_named GUARD c -eigenscript.h:1979 num_guard_named num_guard GUARD c -eigenscript.h:2291 eigs_num_text FORMAT e +eigenscript.h:272 VAL_FLOAT DATA a +eigenscript.h:280 VAL_INT DATA a +eigenscript.h:288 #define val_is_number VAL_FLOAT TEST a +eigenscript.h:288 #define val_is_number VAL_INT TEST a +eigenscript.h:288 #define val_is_number val_is_number TEST a +eigenscript.h:309 #define VAL_F64_RAW VAL_F64_RAW RAW b +eigenscript.h:309 #define VAL_F64_RAW f64_ RAW b +eigenscript.h:310 #define VAL_I64_RAW VAL_I64_RAW RAW b +eigenscript.h:310 #define VAL_I64_RAW i64_ RAW b +eigenscript.h:311 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b +eigenscript.h:311 #define VAL_F64_OFFSET f64_ RAW b +eigenscript.h:1416 eigs_num_arg_slow READ b +eigenscript.h:1417 eigs_num_arg eigs_num_arg READ b +eigenscript.h:1418 eigs_num_arg VAL_F64_RAW RAW b +eigenscript.h:1418 eigs_num_arg VAL_FLOAT TEST a +eigenscript.h:1419 eigs_num_arg eigs_num_arg_slow READ b +eigenscript.h:1421 eigs_list_num READ b +eigenscript.h:1426 eigs_elem_num READ b +eigenscript.h:1427 eigs_opt_num READ b +eigenscript.h:1798 make_num PRODUCE c +eigenscript.h:1808 make_num_permanent PRODUCE c +eigenscript.h:1860 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1902 num_guard num_guard GUARD c +eigenscript.h:1910 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1910 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1911 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1911 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1920 buffer_read_num buffer_read_num READ b +eigenscript.h:1921 buffer_read_num num_guard GUARD c +eigenscript.h:1927 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1936 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1945 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1946 buffer_read_byte buffer_read_num READ b +eigenscript.h:1948 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1959 num_guard_named num_guard_named GUARD c +eigenscript.h:1965 num_guard_named num_guard GUARD c +eigenscript.h:2277 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j @@ -1558,6 +1681,7 @@ ext_gfx.c:819 builtin_gfx_poll make_num PRODUCE c ext_gfx.c:827 builtin_gfx_poll make_num PRODUCE c ext_gfx.c:828 builtin_gfx_poll make_num PRODUCE c ext_gfx.c:848 builtin_gfx_ticks make_num PRODUCE c +ext_gfx.c:853 builtin_gfx_delay val_is_number TEST a ext_gfx.c:855 builtin_gfx_delay eigs_num_arg READ b ext_gfx.c:1003 builtin_gfx_text eigs_list_num READ b ext_gfx.c:1004 builtin_gfx_text eigs_list_num READ b @@ -1571,8 +1695,10 @@ ext_gfx.c:1076 builtin_gfx_text_width eigs_list_num READ b ext_gfx.c:1084 builtin_gfx_text_width make_num PRODUCE c ext_gfx.c:1094 builtin_gfx_text_width make_num PRODUCE c ext_gfx.c:1096 builtin_gfx_text_width make_num PRODUCE c +ext_gfx.c:1109 builtin_gfx_text_height val_is_number TEST a ext_gfx.c:1111 builtin_gfx_text_height VAL_FLOAT TEST a ext_gfx.c:1111 builtin_gfx_text_height VAL_INT TEST a +ext_gfx.c:1113 builtin_gfx_text_height val_is_number TEST a ext_gfx.c:1114 builtin_gfx_text_height eigs_num_arg READ b ext_gfx.c:1116 builtin_gfx_text_height VAL_FLOAT TEST a ext_gfx.c:1116 builtin_gfx_text_height VAL_INT TEST a @@ -1594,7 +1720,9 @@ ext_gfx.c:1334 builtin_audio_open eigs_list_num READ b ext_gfx.c:1335 builtin_audio_open eigs_list_num READ b ext_gfx.c:1339 builtin_audio_open make_num PRODUCE c ext_gfx.c:1343 builtin_audio_open make_num PRODUCE c +ext_gfx.c:1362 builtin_audio_pause val_is_number TEST a ext_gfx.c:1365 builtin_audio_pause eigs_num_arg READ b +ext_gfx.c:1365 builtin_audio_pause val_is_number TEST a ext_gfx.c:1457 builtin_audio_capture_open VAL_FLOAT TEST a ext_gfx.c:1457 builtin_audio_capture_open VAL_INT TEST a ext_gfx.c:1458 builtin_audio_capture_open VAL_FLOAT TEST a @@ -1628,9 +1756,11 @@ ext_gfx.c:1703 builtin_audio_music_play VAL_INT TEST a ext_gfx.c:1706 builtin_audio_music_play VAL_FLOAT TEST a ext_gfx.c:1706 builtin_audio_music_play VAL_INT TEST a ext_gfx.c:1707 builtin_audio_music_play eigs_list_num READ b +ext_gfx.c:1742 builtin_audio_music_volume val_is_number TEST a ext_gfx.c:1744 builtin_audio_music_volume VAL_FLOAT TEST a ext_gfx.c:1744 builtin_audio_music_volume VAL_INT TEST a ext_gfx.c:1748 builtin_audio_music_volume eigs_num_arg READ b +ext_gfx.c:1748 builtin_audio_music_volume val_is_number TEST a ext_gfx.c:1750 builtin_audio_music_volume VAL_FLOAT TEST a ext_gfx.c:1750 builtin_audio_music_volume VAL_INT TEST a ext_gfx.c:1751 builtin_audio_music_volume eigs_list_num READ b @@ -1657,6 +1787,7 @@ ext_gfx.c:1842 builtin_audio_volume eigs_slot_num READ b ext_gfx.c:1843 builtin_audio_volume make_num PRODUCE c ext_gfx.c:1844 builtin_audio_volume eigs_slot_num READ b ext_gfx.c:1851 builtin_audio_volume make_num PRODUCE c +ext_gfx.c:1858 builtin_audio_stop val_is_number TEST a ext_gfx.c:1859 builtin_audio_stop make_num PRODUCE c ext_gfx.c:1860 builtin_audio_stop make_num PRODUCE c ext_gfx.c:1861 builtin_audio_stop eigs_num_arg READ b @@ -1773,9 +1904,12 @@ ext_gfx.c:2467 builtin_ppu_render_frame buffer_read_byte READ b ext_gfx.c:2469 builtin_ppu_render_frame buffer_read_byte READ b ext_gfx.c:2506 builtin_ppu_render_frame buffer_read_byte READ b ext_gfx.c:2508 builtin_ppu_render_frame buffer_read_byte READ b +ext_http.c:584 builtin_http_early_bind val_is_number TEST a ext_http.c:594 builtin_http_early_bind eigs_opt_num READ b ext_http.c:662 builtin_http_serve eigs_opt_num READ b +ext_http.c:948 builtin_shared_incr val_is_number TEST a ext_http.c:952 builtin_shared_incr eigs_num_arg READ b +ext_http.c:964 builtin_shared_incr val_is_number TEST a ext_http.c:965 builtin_shared_incr eigs_num_arg READ b ext_http.c:975 builtin_shared_incr make_num PRODUCE c ext_http.c:1006 builtin_shared_incr make_num PRODUCE c @@ -1784,11 +1918,15 @@ ext_http.c:1037 builtin_shared_delete make_num PRODUCE c ext_http.c:1053 builtin_shared_delete make_num PRODUCE c ext_http.c:1072 builtin_shared_size make_num PRODUCE c ext_http.c:1076 builtin_shared_size make_num PRODUCE c +ext_net.c:112 net_lookup val_is_number TEST a ext_net.c:113 net_lookup eigs_num_arg READ b ext_net.c:148 net_num_at eigs_slot_opt_num READ b +ext_net.c:158 builtin_net_listen val_is_number TEST a ext_net.c:163 builtin_net_listen eigs_num_arg READ b ext_net.c:181 builtin_net_listen make_num PRODUCE c +ext_net.c:188 builtin_net_port val_is_number TEST a ext_net.c:199 builtin_net_port make_num PRODUCE c +ext_net.c:215 builtin_net_accept val_is_number TEST a ext_net.c:229 builtin_net_accept make_num PRODUCE c ext_net.c:282 builtin_net_dial make_num PRODUCE c ext_net.c:327 net_send_bytes make_num PRODUCE c @@ -1797,6 +1935,7 @@ ext_net.c:335 net_send_bytes make_num PRODUCE c ext_net.c:361 builtin_net_send buffer_read_num READ b ext_net.c:362 builtin_net_send eigs_slot_elem_num READ b ext_net.c:364 builtin_net_send finite_num_to_byte READ b +ext_net.c:379 builtin_net_close val_is_number TEST a ext_net.c:385 builtin_net_close eigs_num_arg READ b ext_store.c:173 store_json_encode_slot slot_is_f64 TEST h ext_store.c:174 store_json_encode_slot eigs_slot_num READ h @@ -1808,24 +1947,36 @@ ext_store.c:209 store_json_encode VAL_INT CASE h ext_store.c:211 store_json_encode VAL_I64_RAW RAW h ext_store.c:334 store_json_parse_number strtod PARSE h ext_store.c:337 store_json_parse_number make_num PRODUCE h +ext_store.c:373 store_buffer_from_tag val_is_number TEST h +ext_store.c:373 store_buffer_from_tag val_is_number TEST h ext_store.c:383 store_buffer_from_tag eigs_num_arg READ h ext_store.c:383 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:403 store_buffer_from_tag val_is_number TEST h ext_store.c:418 store_buffer_from_tag eigs_num_arg READ h +ext_store.c:418 store_buffer_from_tag val_is_number TEST h +ext_store.c:756 store_load_catalog val_is_number TEST h +ext_store.c:756 store_load_catalog val_is_number TEST h ext_store.c:761 store_load_catalog eigs_num_arg READ h +ext_store.c:828 get_store_why val_is_number TEST h ext_store.c:829 get_store_why eigs_num_arg READ h ext_store.c:831 get_store_why eigs_num_arg READ h +ext_store.c:831 get_store_why val_is_number TEST h ext_store.c:979 builtin_store_open make_num PRODUCE h ext_store.c:980 builtin_store_open make_num PRODUCE h ext_store.c:993 builtin_store_close eigs_num_arg READ h +ext_store.c:993 builtin_store_close val_is_number TEST h ext_store.c:995 builtin_store_close eigs_num_arg READ h +ext_store.c:995 builtin_store_close val_is_number TEST h ext_store.c:1041 builtin_store_put make_num PRODUCE h ext_store.c:1042 builtin_store_put make_num PRODUCE h ext_store.c:1056 builtin_store_put eigs_num_arg READ h ext_store.c:1057 builtin_store_put eigs_num_arg READ h ext_store.c:1069 builtin_store_put make_num PRODUCE h +ext_store.c:1193 builtin_store_get val_is_number TEST h ext_store.c:1194 builtin_store_get eigs_num_arg READ h ext_store.c:1203 builtin_store_get eigs_num_arg READ h ext_store.c:1261 store_locate eigs_num_arg READ h +ext_store.c:1357 builtin_store_delete val_is_number TEST h ext_store.c:1358 builtin_store_delete eigs_num_arg READ h ext_store.c:1404 builtin_store_query eigs_num_arg READ h ext_store.c:1439 builtin_store_count make_num PRODUCE h @@ -1837,6 +1988,7 @@ ext_store.c:1461 builtin_store_count make_num PRODUCE h ext_store.c:1462 builtin_store_count eigs_num_arg READ h ext_store.c:1473 builtin_store_count make_num PRODUCE h ext_store.c:1479 builtin_store_count make_num PRODUCE h +ext_store.c:1513 builtin_store_update val_is_number TEST h ext_store.c:1514 builtin_store_update eigs_num_arg READ h ext_store.c:1655 builtin_store_drop eigs_num_arg READ h jit.c:1282 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d @@ -2167,8 +2319,11 @@ vm.c:2242 jit_helper_index_set slot_is_f64 TEST a vm.c:2244 jit_helper_index_set SLOT_F64_RAW RAW b vm.c:2245 jit_helper_index_set list_rewrite_num PRODUCE c vm.c:2247 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2259 jit_helper_index_set val_is_number TEST a vm.c:2262 jit_helper_index_set eigs_num_arg READ b +vm.c:2269 jit_helper_index_set val_is_number TEST a vm.c:2272 jit_helper_index_set eigs_num_arg READ b +vm.c:2275 jit_helper_index_set val_is_number TEST a vm.c:2276 jit_helper_index_set eigs_num_arg READ b vm.c:2295 jit_helper_index_get slot_is_f64 TEST a vm.c:2297 jit_helper_index_get SLOT_F64_RAW RAW b @@ -2176,8 +2331,11 @@ vm.c:2304 jit_helper_index_get SLOT_F64_RAW RAW b vm.c:2315 jit_helper_index_get buffer_read_num READ b vm.c:2317 jit_helper_index_get slot_from_f64 PRODUCE c vm.c:2319 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2335 jit_helper_index_get val_is_number TEST a vm.c:2338 jit_helper_index_get eigs_num_arg READ b +vm.c:2350 jit_helper_index_get val_is_number TEST a vm.c:2353 jit_helper_index_get eigs_num_arg READ b +vm.c:2362 jit_helper_index_get val_is_number TEST a vm.c:2365 jit_helper_index_get eigs_num_arg READ b vm.c:2367 jit_helper_index_get buffer_read_num READ b vm.c:2367 jit_helper_index_get make_num PRODUCE c @@ -2309,8 +2467,11 @@ vm.c:4713 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a vm.c:4715 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b vm.c:4715 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c vm.c:4717 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4729 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a vm.c:4732 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4739 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a vm.c:4742 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4745 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a vm.c:4746 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b vm.c:4802 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a vm.c:4805 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b @@ -2343,6 +2504,7 @@ vm.c:5529 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5530 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5531 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5532 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5536 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5552 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i @@ -2352,9 +2514,11 @@ vm.c:5599 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5602 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5603 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5606 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5622 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i vm.c:5630 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i vm.c:5633 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i vm.c:5638 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5658 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i vm.c:5659 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i vm.c:5660 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i vm.c:5661 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i diff --git a/src/builtins.c b/src/builtins.c index d79136b2b..5383b05b0 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -5820,7 +5820,7 @@ Value* builtin_list_contains(Value *arg) { /* sort_by of [list, key_fn] — sort list by numeric keys from key_fn. * Evaluates key_fn once per element, then qsorts by key (ascending). * Stable tiebreak by original index. Returns a NEW sorted list. */ -typedef struct { double key; int64_t int_key; int is_int; int index; } SortByPair; +typedef struct { union { double key; int64_t int_key; }; int is_int; int index; } SortByPair; static int sort_by_pair_cmp(const void *a, const void *b) { const SortByPair *pa = a, *pb = b; diff --git a/src/container.h b/src/container.h index 32eb00143..0609b3b74 100644 --- a/src/container.h +++ b/src/container.h @@ -136,7 +136,7 @@ static inline Value *dict_value_get_ref(const Value *dict, int i) { /* Numeric readers have the same strict/bool behavior as the Value readers: * required raises for every non-number, element raises for bool or in strict - * mode, and optional treats null as absent. The heap-VAL_NUM arms serve a + * mode, and optional treats null as absent. The heap-VAL_FLOAT arms serve a * slot that did not come from container storage (a VM-internal box). * #1758: these are the bridge (design 2.7) -- until R1.6 deletes them a * number read is a double, so an int (an SMI) converts, exactly: |SMI| < diff --git a/src/eigenscript.c b/src/eigenscript.c index eebfc545a..37d8ea704 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -353,7 +353,7 @@ static void env_intern_scope_remove(char *name); /* #262 Phase-3 D: scalar entropy of a number, factored out so the slot * observer can update from a raw immediate double without materializing a * Value (the default path no longer promotes observed nums to tracked - * pointers). Single source of truth for the VAL_NUM entropy formula. */ + * pointers). Single source of truth for the VAL_FLOAT entropy formula. */ static double entropy_of_num(double num) { /* #412: unity is the HORIZON, not a home point. The binary-entropy * formula is smooth and maximal at |x| = 1 (p = 0.5, H = 1.0); the old @@ -1876,7 +1876,7 @@ int eigs_arg_has_bool(const Value *arg) { * * slot_from_value: takes ownership of the input ref. * - NULL or VAL_NULL singleton -> immediate null (input is borrowed) - * - VAL_NUM -> immediate double; input released (#262 Step E: nums never + * - VAL_FLOAT -> immediate double; input released (#262 Step E: nums never * carry observer state, so there is no tracked-pointer case) * - any other type -> TAG_HEAP; ref transferred * diff --git a/src/eigenscript.h b/src/eigenscript.h index 8666a608b..f604fc261 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -266,17 +266,8 @@ struct ASTNode { /* ---- Value types ---- */ -/* #1758 R1.2: deprecated spellings, kept only while R1.2b-n migrate their - * sites (the compiler's warnings are the progress meter); R1.2z deletes them, - * so a straggler stops compiling. */ -#if defined(__GNUC__) || defined(__clang__) -#define EIGS_R12_DEPRECATED(msg) __attribute__((deprecated(msg))) -#else -#define EIGS_R12_DEPRECATED(msg) -#endif - typedef enum { - /* #1758 R1.2a: a double (was VAL_NUM). A number Value is a VAL_FLOAT or a + /* #1758 R1.2a: a double. A number Value is a VAL_FLOAT or a * VAL_INT; `type of` says "num" for both (decision (B)). */ VAL_FLOAT, VAL_STR, VAL_LIST, VAL_FN, VAL_BUILTIN, VAL_NULL, VAL_JSON_RAW, VAL_DICT, VAL_BUFFER, VAL_TEXT_BUILDER, /* #1637: a distinct boolean. Two immortal singletons (make_bool); the @@ -287,7 +278,6 @@ typedef enum { * 2.1). Nothing produces one before R1.3 (make_int does not exist yet): * every arm that handles it is dead code until then. */ VAL_INT, - VAL_NUM EIGS_R12_DEPRECATED("#1758 R1.2: VAL_FLOAT, with an explicit VAL_INT arm") = VAL_FLOAT } ValType; typedef struct Value Value; @@ -315,13 +305,10 @@ static inline int eigs_cmp_int_float(int64_t i, double f) { * VAL_INT for the int64), in a function listed in tools/num_read_allowlist.txt * with its use count. Everything else uses eigs_num_arg / eigs_list_num / * eigs_opt_num. VAL_F64_OFFSET is the double member for JIT-emitted loads and - * stores (#1758 R1.2a: were VAL_NUM_RAW, VAL_NUM_OFFSET and the member num_). */ + * stores (#1758 R1.2). */ #define VAL_F64_RAW(v) ((v)->data.f64_) #define VAL_I64_RAW(v) ((v)->data.i64_) #define VAL_F64_OFFSET ((int32_t)offsetof(Value, data.f64_)) -/* Deprecated until R1.2z: both spell the deprecated member, so every use warns. */ -#define VAL_NUM_RAW(v) ((v)->data.num_) -#define VAL_NUM_OFFSET ((int32_t)offsetof(Value, data.num_)) /* EigsSlot union — full inline helpers in value_slot.h, which is * included below after the Value struct is fully declared. We need the @@ -456,12 +443,11 @@ struct Value { /* #1637 round 4: renamed so no unchecked read compiles. A Value's * number is read through the checking accessors (eigs_num_arg, * eigs_list_num, eigs_opt_num), which raise on a bool or any other - * non-number, or through VAL_NUM_RAW where the type is already - * proven -- and every VAL_NUM_RAW use sits in a function on the + * non-number, or through VAL_F64_RAW where the type is already + * proven -- and every VAL_F64_RAW use sits in a function on the * reviewed list tools/num_read_allowlist.txt, pinned by count * (tools/num_read_check.sh). */ - double f64_; /* VAL_FLOAT (#1758 R1.2a: was num_) */ - double num_ EIGS_R12_DEPRECATED("#1758 R1.2: f64_ through VAL_F64_RAW"); + double f64_; /* VAL_FLOAT (#1758 R1.2a) */ int64_t i64_; /* VAL_INT (#1758 R1.2a; no producer before R1.3) */ int boolean; /* VAL_BOOL: 0 or 1 (only the two singletons exist) */ /* VAL_STR / VAL_JSON_RAW payload: NUL-terminated bytes. @@ -1417,7 +1403,7 @@ extern __thread EigsThread *eigs_current; int eigs_arg_has_bool(const Value *arg); /* #1637: THE checked number reads. C code turning a Value into a double goes * through one of these (tools/num_read_check.sh enforces it: a raw - * `->data.num` read needs a VAL_NUM test in the same function, or a reviewed + * `->data.f64_` read needs a VAL_FLOAT test in the same function, or a reviewed * allowlist entry). A bool -- or any other non-number -- raises a type error * naming `who` (a `builtin_` prefix is dropped) and reads as 0.0; the caller * checks g_has_error before acting on the value. diff --git a/src/value_slot.h b/src/value_slot.h index 6c81b7ea1..a20b7cbb4 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -263,7 +263,7 @@ static inline int slot_int_value(EigsSlot s, int64_t *out) { /* Boundary shims declared here, defined in eigenscript.c. * * slot_from_value (takes ownership of the input ref): - * - VAL_NUM -> immediate double, input decref'd (#262 Step E: numbers never + * - VAL_FLOAT -> immediate double, input decref'd (#262 Step E: numbers never * carry observer state, so there is no tracked-pointer case). * - VAL_NULL -> SLOT_NULL (incref skipped; null is borrowed). * - any heap type -> TAG_HEAP pointer (incref). diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index b75e1ddef..f8d525c35 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -1,6 +1,6 @@ # tools/num_read_allowlist.txt -- every raw number token, reviewed (#1637 round 4). -# file|function|count|reason. tools/num_read_check.sh counts VAL_NUM_RAW / -# SLOT_F64_RAW / VAL_NUM_OFFSET tokens per function and fails when a count +# file|function|count|reason. tools/num_read_check.sh counts VAL_F64_RAW / +# SLOT_F64_RAW / VAL_F64_OFFSET tokens per function and fails when a count # differs (a new raw read, however it is spelled across lines, changes the # count), when a function with raw tokens is missing here, or a row is stale. # Builtins never belong here: they read through eigs_num_arg / eigs_list_num / @@ -18,16 +18,16 @@ container.h|eigs_slot_num|1|required numeric accessor reads only after slot_is_f container.h|eigs_slot_opt_num|1|optional numeric accessor reads only after slot_is_f64 container.h|list_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) container.h|list_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 -chunk.c|chunk_disassemble|2|debug disassembly prints a constant behind its own type == VAL_NUM test -chunk.c|const_equal|4|constant-pool dedup compares two constants after testing both are VAL_NUM -chunk.c|const_hash_value|2|constant-pool hash of a constant inside its type == VAL_NUM branch -eigenscript.c|chan_clone_rec|2|channel deep-copy, switch case VAL_NUM; case VAL_INT names the int it refuses (unwired, R1.3) -eigenscript.c|compute_entropy_impl|2|observer entropy, switch case VAL_NUM, and case VAL_INT (an int's entropy is its double's, design 7) +chunk.c|chunk_disassemble|2|debug disassembly prints a constant behind its own type == VAL_FLOAT test +chunk.c|const_equal|4|constant-pool dedup compares two constants after testing both are VAL_FLOAT +chunk.c|const_hash_value|2|constant-pool hash of a constant inside its type == VAL_FLOAT branch +eigenscript.c|chan_clone_rec|2|channel deep-copy, switch case VAL_FLOAT; case VAL_INT names the int it refuses (unwired, R1.3) +eigenscript.c|compute_entropy_impl|2|observer entropy, switch case VAL_FLOAT, and case VAL_INT (an int's entropy is its double's, design 7) eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_f64 eigenscript.c|eigs_num_arg_slow|2|checked reader slow path: reads only after type == VAL_FLOAT, or VAL_INT (the bridge converts an int, design 2.7) -eigenscript.c|is_truthy|2|truthiness, switch case VAL_NUM and case VAL_INT (a bool has its own case) -eigenscript.c|make_num|1|constructor: writes the number of a Value it just typed VAL_NUM -eigenscript.c|make_num_permanent|1|constructor: writes the number of a Value it just typed VAL_NUM +eigenscript.c|is_truthy|2|truthiness, switch case VAL_FLOAT and case VAL_INT (a bool has its own case) +eigenscript.c|make_num|1|constructor: writes the number of a Value it just typed VAL_FLOAT +eigenscript.c|make_num_permanent|1|constructor: writes the number of a Value it just typed VAL_FLOAT eigenscript.c|module_ns_project|1|mirror refresh: reads the binding slot after slot_is_f64 and stores it over a numeric mirror slot eigenscript.c|observer_entropy_now|1|observer entropy of a slot after slot_is_f64 eigenscript.c|observer_slot_sample_gated|2|observer sample inside val_is_number: the VAL_INT box as its double, else the VAL_FLOAT (design 7) @@ -35,18 +35,16 @@ eigenscript.c|observer_slot_update|2|observer update inside val_is_number: the V eigenscript.c|slot_from_value|2|NaN-boxing boundary, inside its VAL_FLOAT branch and its VAL_INT branch (an SMI in range, design 2.1) eigenscript.c|slot_to_value|1|NaN-boxing boundary after slot_is_f64 eigenscript.c|values_equal_impl|8|equality: the int/float pair by eigs_cmp_int_float (N2), each read inside its own type test; switch case VAL_FLOAT and case VAL_INT (both ints) -eigenscript.c|value_to_string|2|printing, switch case VAL_NUM and case VAL_INT (exact digits) -eigenscript.h|#define VAL_NUM_OFFSET|1|the raw member offset definition (JIT) -eigenscript.h|#define VAL_F64_OFFSET|1|the raw double member offset definition (JIT; #1758 R1.2a: was VAL_NUM_OFFSET) -eigenscript.h|#define VAL_NUM_RAW|1|the raw read definition -eigenscript.h|#define VAL_F64_RAW|1|the raw double read definition (#1758 R1.2a: was VAL_NUM_RAW) +eigenscript.c|value_to_string|2|printing, switch case VAL_FLOAT and case VAL_INT (exact digits) +eigenscript.h|#define VAL_F64_OFFSET|1|the raw double member offset definition (JIT; #1758 R1.2a: was VAL_F64_OFFSET) +eigenscript.h|#define VAL_F64_RAW|1|the raw double read definition (#1758 R1.2a: was VAL_F64_RAW) eigenscript.h|#define VAL_I64_RAW|1|the raw int64 read definition (#1758 R1.2a) -eigenscript.h|eigs_num_arg|1|inline fast path of the checking accessor: reads only after type == VAL_NUM -eigs_embed.c|eigs_value_as_num|2|embedding API: reads only after type == VAL_NUM; a bool answers NaN and other non-numbers 0.0 (docs/EMBEDDING.md) +eigenscript.h|eigs_num_arg|1|inline fast path of the checking accessor: reads only after type == VAL_FLOAT +eigs_embed.c|eigs_value_as_num|2|embedding API: reads only after type == VAL_FLOAT; a bool answers NaN and other non-numbers 0.0 (docs/EMBEDDING.md) embed_smoke.c|main|7|C test program: builds and inspects slots it constructed as numbers ext_store.c|store_json_encode|1|store record encoder: case VAL_INT writes the int's exact digits (#1758 R1.2a) -jit.c|emit_load_numeric_operand|2|emits the load of data.num_ after the emitted type == VAL_NUM / refcount guard -jit.c|jit_compile_to_thunk|2|emits loads/stores of data.num_ behind emitted immediate-number checks; reads a VAL_NUM constant +jit.c|emit_load_numeric_operand|2|emits the load of data.f64_ after the emitted type == VAL_FLOAT / refcount guard +jit.c|jit_compile_to_thunk|2|emits loads/stores of data.f64_ behind emitted immediate-number checks; reads a VAL_FLOAT constant jit_smoke.c|jit_helper_index_get|2|JIT smoke test program (stubbed helpers over slots it built as numbers) jit_smoke.c|jit_helper_iter_next|1|JIT smoke test program (stubbed helpers over slots it built as numbers) jit_smoke.c|jit_helper_set_name|4|JIT smoke test program (stubbed helpers over slots it built as numbers) @@ -55,28 +53,28 @@ jit_smoke.c|run_index_bail_cases|2|JIT smoke test program (stubbed helpers over jit_smoke.c|run_reader_bail_cases|8|JIT smoke test program (stubbed helpers over slots it built as numbers) jit_smoke.c|run_store_cases|4|JIT smoke test program (stubbed helpers over slots it built as numbers) trace.c|write_slot|1|tape writer after slot_is_f64 -trace.c|write_value_ptr|2|tape writer, switch case VAL_NUM; case VAL_INT names the int it refuses (tape v7, R1.3) -trace.c|write_value_ptr_full|2|tape writer, switch case VAL_NUM; case VAL_INT names the int it refuses (tape v7, R1.3) +trace.c|write_value_ptr|2|tape writer, switch case VAL_FLOAT; case VAL_INT names the int it refuses (tape v7, R1.3) +trace.c|write_value_ptr_full|2|tape writer, switch case VAL_FLOAT; case VAL_INT names the int it refuses (tape v7, R1.3) value_slot.h|#define SLOT_F64_RAW|1|the raw slot read definition (#1758: was SLOT_NUM_RAW) -value_slot.h|slot_f64_value|2|float reader (#1758: was vm.c slot_as_double): an immediate after slot_is_f64, a box after type == VAL_NUM; 0 for an int +value_slot.h|slot_f64_value|2|float reader (#1758: was vm.c slot_as_double): an immediate after slot_is_f64, a box after type == VAL_FLOAT; 0 for an int value_slot.h|slot_from_f64|1|constructor: writes a double into a fresh slot (#1758: was slot_from_num) value_slot.h|slot_truthy_immediate|1|truthiness after slot_is_f64 -vm.c|#define ARITH_FAST|2|arithmetic fast path after both operands tested VAL_NUM; NUM_REUSE writes +vm.c|#define ARITH_FAST|2|arithmetic fast path after both operands tested VAL_FLOAT; NUM_REUSE writes vm.c|#define INT_BINOP_R|2|integer op fast path after both slots slot_is_f64 -vm.c|#define NUM_BINOP|6|arithmetic after a->type == VAL_NUM && b->type == VAL_NUM; NUM_REUSE writes +vm.c|#define NUM_BINOP|6|arithmetic after a->type == VAL_FLOAT && b->type == VAL_FLOAT; NUM_REUSE writes vm.c|jit_helper_dot_set|1|JIT helper: number store after slot_is_f64 -vm.c|jit_helper_index_get|3|JIT helper: index read after slot_is_f64 / VAL_NUM tests on index and element -vm.c|jit_helper_index_set|5|JIT helper: index store after slot_is_f64 / VAL_NUM tests on index and value -vm.c|jit_helper_iter_next|2|JIT helper: loop state list [iterable, idx, snap] built by the VM, each read behind a VAL_NUM test +vm.c|jit_helper_index_get|3|JIT helper: index read after slot_is_f64 / VAL_FLOAT tests on index and element +vm.c|jit_helper_index_set|5|JIT helper: index store after slot_is_f64 / VAL_FLOAT tests on index and value +vm.c|jit_helper_iter_next|2|JIT helper: loop state list [iterable, idx, snap] built by the VM, each read behind a VAL_FLOAT test vm.c|jit_helper_local_dot_set|1|JIT helper: number store after slot_is_f64 vm.c|loop_iter_store|1|writes the loop counter slot after slot_is_f64 vm.c|obs_dump_scope|1|SIGUSR1 observer dump after slot_is_f64 -vm.c|obs_dump_value|3|SIGUSR1 observer dump after slot_is_f64 / case VAL_NUM / case VAL_INT (exact digits) +vm.c|obs_dump_value|3|SIGUSR1 observer dump after slot_is_f64 / case VAL_FLOAT / case VAL_INT (exact digits) vm.c|obs_slot_num|1|observer numeric channel (#1758): reads an immediate after slot_is_f64; an int converts exactly vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 vm.c|slot_truthy|1|truthiness after slot_is_f64 -vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_NUM (chunk_scan_leaf_accessor) and values behind VAL_NUM tests -vm.c|vm_run_ex|42|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_NUM dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built +vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_FLOAT (chunk_scan_leaf_accessor) and values behind VAL_FLOAT tests +vm.c|vm_run_ex|42|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_FLOAT dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 builtins.c|builtin_json_build|1|VAL_INT text is exact digits; float text retains the bridge (#1758 R1.2d) diff --git a/tools/num_read_check.sh b/tools/num_read_check.sh index 67e98d85c..61ccc4546 100644 --- a/tools/num_read_check.sh +++ b/tools/num_read_check.sh @@ -4,8 +4,8 @@ # # The Value union's number members are `f64_` (a VAL_FLOAT) and `i64_` (a # VAL_INT), and the EigsSlot union's double is `d_`, so no unreviewed spelling -# compiles. (#1758 R1.2 renamed `num_`/VAL_NUM_RAW/VAL_NUM_OFFSET; until R1.2z -# deletes them, the old spellings are counted too.) Code reaches a number in +# compiles. #1758 R1.2z removed the deprecated numeric aliases; the scanner +# also catches their reintroduction before compilation. Code reaches a number in # exactly two ways: # - the checking accessors eigs_num_arg / eigs_list_num / eigs_opt_num, # which raise a type error on a bool or any other non-number; @@ -20,7 +20,7 @@ # a count and goes red until someone reviews it. # # It also fails on: -# - `data.num_` / `.d_` spelled out anywhere except the macro definitions +# - raw Value payload members / `.d_` outside the macro definitions # (a bypass of the macros); # - a bare `->data.builtin(` call: every builtin call must pass the bool # gate, eigs_call_builtin; diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 68d0c1d27..686157318 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -87,6 +87,7 @@ # in the commit that deletes them (R1.6's bridge, 21 tokens, with R1.6). DELETED_TOKENS = { 'R1.1': ['slot_is_num', 'slot_is_numeric', 'SLOT_NUM_RAW', 'slot_from_num', 'slot_as_double'], + 'R1.2': ['VAL_NUM', 'VAL_NUM_RAW', 'VAL_NUM_OFFSET', 'num_'], 'R1.3': ['eigs_int_unwired'], 'R2.2': ['num_guard', 'num_guard_named', 'EIGS_NUM_MAX'], } diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index a353d8512..f51746fdb 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -12,7 +12,7 @@ payload (a raw or checked read appears in its body) is a numeric accessor; it must be in VOCAB (its call sites are then sites) or in WRAPPERS with a reason. A new accessor nobody reviewed is UNCLASSIFIED. - - every VAL_NUM must sit in a syntactic position the classifier recognizes + - every VAL_FLOAT must sit in a syntactic position the classifier recognizes (test, case, tag store, type yield, emitter immediate); any other position is UNCLASSIFIED. Not in the population: src/freestanding/ (outside the src/*.c glob), and code @@ -57,22 +57,19 @@ # Kinds decide the default category (a/b/c/e) when no role rule matches. VOCAB = { # (a) type tests and type derivations - 'VAL_NUM': 'TAG', # position decides: TEST/CASE/TAGSET/YIELD/EMIT - # (#1758 R1.2a: deprecated; R1.2z deletes it) - 'VAL_FLOAT': 'TAG', # R1.2a: was VAL_NUM + 'VAL_FLOAT': 'TAG', # R1.2a: the float ValType 'VAL_INT': 'TAG', # R1.2a: the int ValType (no producer before R1.3) 'slot_is_f64': 'TEST', # R1.1: was slot_is_num (slot_is_numeric deleted) 'slot_is_smi': 'TEST', # R1.1: the SMI tag test 'NUM_REUSE': 'TEST', + 'val_is_number': 'TEST', # the Value test admits both numeric kinds 'AST_NUM': 'TAG', # (b) payload reads - 'VAL_NUM_RAW': 'RAW', # an lvalue: `VAL_NUM_RAW(v) = x` is a WRITE (deprecated, R1.2z) - 'VAL_F64_RAW': 'RAW', # R1.2a: was VAL_NUM_RAW + 'VAL_F64_RAW': 'RAW', # the float payload 'VAL_I64_RAW': 'RAW', # R1.2a: a VAL_INT's int64 'SLOT_F64_RAW': 'RAW', # R1.1: was SLOT_NUM_RAW 'slot_smi_val': 'RAW', # R1.1: an SMI's int (no int Value exists before R1.3) - 'VAL_NUM_OFFSET': 'RAW', # deprecated, R1.2z - 'VAL_F64_OFFSET': 'RAW', # R1.2a: was VAL_NUM_OFFSET + 'VAL_F64_OFFSET': 'RAW', # the JIT float payload offset 'slot_f64_value': 'READ', # R1.1: replaces vm.c's slot_as_double (floats only) 'slot_int_value': 'READ', # R1.1: an int's value (SMI; R1.2a adds the VAL_INT box) 'eigs_num_arg': 'READ', @@ -121,8 +118,8 @@ r'emit_(?:add|sub|mul|div)sd_xmm0_xmm1|emit_ucomisd_\w+|emit_cvttsd2si_\w+|' r'emit_cvtsi2sd_\w+|emit_btr_63_\w+|fmod)\b') -# `data.num` is the AST literal's double (`data.num_` is the Value member, -# reached only through VAL_NUM_RAW); matched as a member access, below. +# `data.num` is the AST literal's double (`data.f64_` is the Value member, +# reached only through VAL_F64_RAW); matched as a member access, below. AST_NUM_FIELD = re.compile(r'(?:->|\.)data\.num\b(?!_)') KIND_CATEGORY = { @@ -191,11 +188,11 @@ } TOKEN_RE = re.compile(r'\b(' + '|'.join(sorted(VOCAB, key=len, reverse=True)) + r')\b') -# Raw union members: the Value's double (`num_`) and the slot's (`d_`). Only +# Raw union members: the Value's numeric payloads (`f64_`/`i64_`) and the slot's (`d_`). Only # the accessor macros may name them; anywhere else is a bypass. -RAW_MEMBER = re.compile(r'(?:\.|->)(d_|num_|f64_|i64_)\b') -RAW_MEMBER_HOMES = {'#define VAL_NUM_RAW', '#define SLOT_F64_RAW', '#define VAL_NUM_OFFSET', - '#define VAL_F64_RAW', '#define VAL_I64_RAW', '#define VAL_F64_OFFSET'} +RAW_MEMBER = re.compile(r'(?:\.|->)(d_|f64_|i64_)\b') +RAW_MEMBER_HOMES = {'#define SLOT_F64_RAW', '#define VAL_F64_RAW', + '#define VAL_I64_RAW', '#define VAL_F64_OFFSET'} C_KEYWORDS = {'if', 'while', 'for', 'switch', 'return', 'sizeof', 'do', 'else', 'case', 'defined', '__attribute__', '__typeof__', '_Generic'} @@ -370,7 +367,7 @@ def function_name(sig): def val_num_kind(line, start, end, token): - """Syntactic role of a VAL_NUM / AST_NUM occurrence.""" + """Syntactic role of a VAL_FLOAT / AST_NUM occurrence.""" before = line[:start].rstrip() after = line[end:].lstrip() if re.search(r'(==|!=)\s*$', before) or re.match(r'(==|!=)', after): @@ -385,13 +382,11 @@ def val_num_kind(line, start, end, token): return 'EMIT' # JIT immediate operand of a type compare if (re.search(r'[({,]\s*$', before) or not before) and re.match(r'[)},]', after): return 'DATA' # the tag as data: enumerator, kind table, argument - if not before and re.match(r'EIGS_R12_DEPRECATED\(', after): - return 'DATA' # #1758 R1.2a-z: the deprecated alias enumerator itself return 'UNKNOWN' def raw_kind(line, end): - """VAL_NUM_RAW(...)/SLOT_F64_RAW(...) followed by a plain `=` is a write.""" + """VAL_F64_RAW(...)/SLOT_F64_RAW(...) followed by a plain `=` is a write.""" depth, i = 0, end while i < len(line): ch = line[i] @@ -423,7 +418,7 @@ def scan_file(path, rel): kind = VOCAB[tok] if kind == 'TAG': kind = val_num_kind(line, m.start(), m.end(), tok) - elif tok in ('VAL_NUM_RAW', 'VAL_F64_RAW', 'VAL_I64_RAW', 'SLOT_F64_RAW'): + elif tok in ('VAL_F64_RAW', 'VAL_I64_RAW', 'SLOT_F64_RAW'): kind = raw_kind(line, m.end()) sites.append((rel, ln, scope[ln], tok, kind)) if JIT_FILES.match(rel): @@ -453,9 +448,9 @@ def classify(site): # ---- derived accessor check ---------------------------------------------- -READ_IN_BODY = re.compile(r'\b(VAL_NUM_RAW|VAL_F64_RAW|VAL_I64_RAW|SLOT_F64_RAW|eigs_num_arg|eigs_list_num|' +READ_IN_BODY = re.compile(r'\b(VAL_F64_RAW|VAL_I64_RAW|SLOT_F64_RAW|eigs_num_arg|eigs_list_num|' r'eigs_slot_num|list_get_num|dict_value_get_num|slot_f64_value)\b|' - r'(?:\.|->)(?:d_|num_|f64_|i64_)\b') + r'(?:\.|->)(?:d_|f64_|i64_)\b') def derived_accessors(stripped_by_file, scope_by_file, sigs_by_file): @@ -726,7 +721,7 @@ def read_marked_table(doc, tag, row_re): # A LOSS row claims the body computes through a double; it must have one. DOUBLE_PATH = {'eigs_num_arg', 'eigs_list_num', 'eigs_slot_num', 'eigs_opt_num', 'eigs_slot_opt_num', 'eigs_slot_elem_num', 'eigs_elem_num', 'buffer_read_num', 'make_num', 'slot_f64_value', - 'VAL_NUM_RAW', 'VAL_F64_RAW', 'SLOT_F64_RAW', 'strtod', 'atof', 'num_guard', 'list_set_num'} + 'VAL_F64_RAW', 'SLOT_F64_RAW', 'strtod', 'atof', 'num_guard', 'list_set_num'} def read_table(doc): @@ -795,14 +790,14 @@ def main(): classified, unclassified = [], [] rule_hits = [0] * len(ROLE_RULES) token_hits = {t: 0 for t in VOCAB} - token_hits.update({'d_': 0, 'num_': 0, 'f64_': 0, 'i64_': 0}) + token_hits.update({'d_': 0, 'f64_': 0, 'i64_': 0}) for site in sites: cat, rule = classify(site) if site[3] in token_hits: token_hits[site[3]] += 1 if cat is None: why = ('raw union member outside its accessor macro' if site[4] == 'BYPASS' - else 'VAL_NUM/AST_NUM in an unrecognized position') + else 'VAL_FLOAT/VAL_INT/AST_NUM in an unrecognized position') unclassified.append((site, why)) continue if rule is not None: From 664c28d5724b299dff07af4fbb52bcfde0905c9c Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 08:15:55 -0500 Subject: [PATCH 040/188] phase2 R1.2r: migrate the P4 int-source plant templates (#1758) Update four template spellings from VAL_NUM_RAW to VAL_F64_RAW. Both the runtime and static P4 anchors were stale (zero source matches); all thirteen build/static anchors now match their real source exactly once. Keep deleted token denylists unchanged. One-time calibration using the official planted builder and restricted corpus differential: the unplanted smi-trap control has 2/2 same, diff=0; the P4 mutant has 2/2 DIFF with the slot_from_int under EIGS_SMI_TRAP fatal diagnostic. The mutant built and executed, rather than failing to compile. No new permanent self-check is added. Runtime sites=0; template spellings=4. Validation: make built; P4 calibration PASS (13/13 anchors, 2/2 controls, 2/2 plant failures through the runtime trap). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tools/phase2_check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 686157318..3b1786348 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -989,8 +989,8 @@ def stray(rd): 'b2-trap': ('src/vm.c', ' if (target->type == VAL_BUFFER) {\n if (_ok && vm_index_resolve(&i, target->data.buffer.count)) {\n double v = buffer_read_num(target, i);\n slot_decref(tgt_s);\n vm_push_slot(slot_from_f64(v));\n } else {\n if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s));\n else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)",\n', ' if (target->type == VAL_BUFFER) {\n if (_ok && vm_index_resolve(&i, target->data.buffer.count)) {\n double v = buffer_read_num(target, i);\n slot_decref(tgt_s);\n if (isnan(target->data.buffer.data[i])) { /* CRITIC PLANT B2: an int producer, bits spelled */\n EigsSlot p; p.u = (SLOT_QNAN_MASK | (UINT64_C(2) << 48)) | 7u;\n vm_push_slot(p);\n } else {\n vm_push_slot(slot_from_f64(v));\n }\n } else {\n if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s));\n else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)",\n', 'smi-trap'), # the critic's P4 (an int produced inside an allowed writer) on the smi-trap build - 'p4-trap': ('src/eigenscript.c', ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', - ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n' + 'p4-trap': ('src/eigenscript.c', ' double n = VAL_F64_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', + ' double n = VAL_F64_RAW(v);\n val_decref(v);\n' ' if (n == 1.0) return slot_from_int(1); /* PLANT P4 */\n return slot_from_f64(n);', 'smi-trap'), } @@ -1028,8 +1028,8 @@ def build_plant(name, out): ('P3 raw TAG_SMI bits in vm.c', [ ('vm.c', _NUM_ONE, ' CASE(NUM_ONE): {\n { EigsSlot one; one.u = TAG_SMI | 1u; vm_push_slot(one); }')]), ('P4 a producer inside an allowed writer', [ - ('eigenscript.c', ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', - ' double n = VAL_NUM_RAW(v);\n val_decref(v);\n if (n == 1.0) return slot_from_int(1);\n' + ('eigenscript.c', ' double n = VAL_F64_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', + ' double n = VAL_F64_RAW(v);\n val_decref(v);\n if (n == 1.0) return slot_from_int(1);\n' ' return slot_from_f64(n);')]), ('P5 a raw-bits header macro', [ ('value_slot.h', '/* Constructors */', '/* Constructors */\n' From 7e5662d0fba914115e838e17f860700c90112996 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 08:18:19 -0500 Subject: [PATCH 041/188] phase2 R1.2s: renew strict shape fingerprints after the Value migration (#1758) The first full suite caught 39 stale exempt body/helper fingerprints: SHAPE_CONTRACT candidates=190 guarded=139 exempt=51 errors=39, producing 4266/4268 passed, 2 failed. Review all affected roots and helper closures; their existing data, variadic, overload, descriptor and output exemptions still apply. Independent review found no incorrect exemption. Update only body_sha256/source_sha256 in those 39 rows; no disposition, reason or population changes. Runtime alias sites=0; metadata rows=39. Validation: make built; SHAPE_CONTRACT candidates=190 guarded=139 exempt=51 errors=0. Full strict differential against 0740af03: identical-when-off=156 differing=0; unset-equals-strict=156/156; raises=156 silent=0 misattributed=0; valid-input unchanged=252/252; fixed-shape declared=139 examined=139 passed=130 failed=0 unavailable=9 pending=0 unrun=0; final OK. Pixel identity was explicitly skipped by the dummy video backend; strict raise/coverage ran. Full release/ASan reruns follow in the round report. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tools/strict_shape_contracts.json | 144 +++++++++++++++--------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/tools/strict_shape_contracts.json b/tools/strict_shape_contracts.json index 47ef1dc71..7fb87da4e 100644 --- a/tools/strict_shape_contracts.json +++ b/tools/strict_shape_contracts.json @@ -147,7 +147,7 @@ ], "source_sha256": { "audio_convert_samples": [ - "e04ac47c64a12a0ff9ffc8ae3acd398ce813a028a55880060c74cb282ef3ff9c" + "7461217b99129cc5df928ab02218d62c5cd7730fd88d3582f614396b0f935981" ], "builtin_audio_play": [ "093742db555c0b87c29dea9095751714c0320123fb999941490bd1357b72640a" @@ -233,7 +233,7 @@ ], "source_sha256": { "audio_convert_samples": [ - "e04ac47c64a12a0ff9ffc8ae3acd398ce813a028a55880060c74cb282ef3ff9c" + "7461217b99129cc5df928ab02218d62c5cd7730fd88d3582f614396b0f935981" ], "builtin_audio_stream_push": [ "b838449be37f5d9d6d58b12d588dbb5deb389a90343061ea18e2bd579a68f057" @@ -387,11 +387,11 @@ ], "disposition": "exempt", "body_sha256": [ - "9800ff3dcb6c1929c5b9326884f3d1a9cf99668756e25da259ba7dc962e198ee" + "c736aa2de0261df888fd40d93a44985273b784bf0951cdc97b2f6ef73e6d818d" ], "source_sha256": { "builtin_buf_from_list": [ - "9800ff3dcb6c1929c5b9326884f3d1a9cf99668756e25da259ba7dc962e198ee" + "c736aa2de0261df888fd40d93a44985273b784bf0951cdc97b2f6ef73e6d818d" ] } }, @@ -503,11 +503,11 @@ ], "disposition": "exempt", "body_sha256": [ - "2fd695baaa8e9743399e40a9483778ca9c3bda2b1d297f012b6b844fc5806103" + "5705f10a1e3e60d47d4e385849c863a6775ed004ceafb65dee990e348bd8b022" ], "source_sha256": { "builtin_buffer": [ - "2fd695baaa8e9743399e40a9483778ca9c3bda2b1d297f012b6b844fc5806103" + "5705f10a1e3e60d47d4e385849c863a6775ed004ceafb65dee990e348bd8b022" ], "eigs_list_num": [ "25755c9b1f519fb0447e2d648dc0272419914db805f9249954cd2e146b48a3bc" @@ -617,7 +617,7 @@ "669dc58628bb911edaa53afcc37a9c2ca7dfd0faee8bef0613e72cfba6904c73" ], "db_build_query": [ - "43adc9e73c43cc8806b029b7b9abb68141f106ac27ef0627d768c65e5d407c21" + "843c8010ee5d8c26152ce16fdbf0918d7cafe5b9c88d2b91a47f1ef9ba7e28e0" ], "db_exec_from_arg": [ "cbcf24fbb55c5a6f9bfdbb6535dc22a89086dab2ed311d0fc0892eb6eb287145" @@ -643,7 +643,7 @@ "083b679b60be2d040b1671ef418a0473fc9031f2456fe2f2f37869ec85330085" ], "db_build_query": [ - "43adc9e73c43cc8806b029b7b9abb68141f106ac27ef0627d768c65e5d407c21" + "843c8010ee5d8c26152ce16fdbf0918d7cafe5b9c88d2b91a47f1ef9ba7e28e0" ], "db_exec_from_arg": [ "cbcf24fbb55c5a6f9bfdbb6535dc22a89086dab2ed311d0fc0892eb6eb287145" @@ -669,7 +669,7 @@ "ac1ace66298435daa38e6f6ac83a6c8fcd5677c87261adac82489493ca967f26" ], "db_build_query": [ - "43adc9e73c43cc8806b029b7b9abb68141f106ac27ef0627d768c65e5d407c21" + "843c8010ee5d8c26152ce16fdbf0918d7cafe5b9c88d2b91a47f1ef9ba7e28e0" ], "db_exec_from_arg": [ "cbcf24fbb55c5a6f9bfdbb6535dc22a89086dab2ed311d0fc0892eb6eb287145" @@ -772,11 +772,11 @@ ], "disposition": "exempt", "body_sha256": [ - "167f0efe94c146d6daa77ed91fd3ef73368fcfacfd373a2ee91ba6f5bccc9e0d" + "4070717c832c2e4150564bdd324ccc1fb81f427c5cd2b7ab1c3b6397b3b0ba98" ], "source_sha256": { "builtin_exec_capture": [ - "167f0efe94c146d6daa77ed91fd3ef73368fcfacfd373a2ee91ba6f5bccc9e0d" + "4070717c832c2e4150564bdd324ccc1fb81f427c5cd2b7ab1c3b6397b3b0ba98" ], "eigs_list_num": [ "25755c9b1f519fb0447e2d648dc0272419914db805f9249954cd2e146b48a3bc" @@ -807,11 +807,11 @@ ], "disposition": "exempt", "body_sha256": [ - "37cace163aae93897420ade0a6cb5ad56c3c7a3dfa43d351c93e299a1f4e3d57" + "8af177621b6aae6d233a44c4a5add234ed6bae4d72b9f91eee6c67fd4d76a9e2" ], "source_sha256": { "builtin_f64_from_bytes": [ - "37cace163aae93897420ade0a6cb5ad56c3c7a3dfa43d351c93e299a1f4e3d57" + "8af177621b6aae6d233a44c4a5add234ed6bae4d72b9f91eee6c67fd4d76a9e2" ] } }, @@ -1039,11 +1039,11 @@ ], "disposition": "exempt", "body_sha256": [ - "99f90345e3f1cc841980a9f6c866e486358a6180c2e68f983412efcee1cfa3c1" + "668fd2cd0502cf0c57c636522504b553a15eac1a83b79a16d583bf729bf68c55" ], "source_sha256": { "builtin_http_early_bind": [ - "99f90345e3f1cc841980a9f6c866e486358a6180c2e68f983412efcee1cfa3c1" + "668fd2cd0502cf0c57c636522504b553a15eac1a83b79a16d583bf729bf68c55" ], "eigs_opt_num": [ "a59259f1f1c8f200ce3f1c7e6f668b797fbfa1219686fb8f9078719cdc9d129e" @@ -1151,10 +1151,10 @@ "d89562220316e85c2ed110b250eee934769205aab21a2f3bc76a9804aa171060" ], "strict_numeric_byte_list": [ - "c44801e4253c003e32d5daa43ec63454efc8faa0b13403ccd8f6e7b7bbe92b7e" + "049e896f6231c29f666669a17d40a2a233305146baf380e237505b2a20de0aeb" ], "zlib_bytes_arg": [ - "482e756d657040d3c334c618e569d1824ed17c26f49a826b564aec1b0e86e5d3" + "6dd4334ac90d54b268baf36c04075a5cae70794196eb346f68d4408ad6f32fc4" ], "zlib_inflate_impl": [ "a54f1d8a2b596ca7c363f20303516358bf5992479e5aadc7ea6f2536e2089914" @@ -1185,11 +1185,11 @@ ], "disposition": "exempt", "body_sha256": [ - "6be773a899e620154d0984cb8adc99adb8767128437828d17b0db11a5375a590" + "3680cc2fb864eb40e7fc914d05a12564df2b34d3f2edcd8406e50e33c415b71d" ], "source_sha256": { "builtin_json_build": [ - "6be773a899e620154d0984cb8adc99adb8767128437828d17b0db11a5375a590" + "3680cc2fb864eb40e7fc914d05a12564df2b34d3f2edcd8406e50e33c415b71d" ] } }, @@ -1212,7 +1212,7 @@ "5815ee115524cd711b01ba1bca89f1e152cd2303c2214447e1482ffde5df1189" ], "eigs_json_encode_value": [ - "3624642731f3daaa091b7fdbe2f5fd8a12649ab1d9012b536e86f91f48a8bc7b" + "ca2b8670510e547e67ea9232a95363e70fa35928f50cb0c0aafcc0ab41a9023d" ] } }, @@ -1409,7 +1409,7 @@ "957d6367080150932b0eb91b77222af62118688b594ef3e894134f13c7ea1765" ], "minmax_reduce": [ - "595d20f4e17f76ec9e5f7b1f2ad47dd9a1703501bbb4fb975f889ed464f57066" + "0083469877182bd056d6b1ce157644d68171704eb677eb9f9c7a56dafe004d58" ] } }, @@ -1432,7 +1432,7 @@ "895d02903f98e67d498faf4410e6d7d4cedc13d14f2d5699c86a24deccbea53c" ], "minmax_reduce": [ - "595d20f4e17f76ec9e5f7b1f2ad47dd9a1703501bbb4fb975f889ed464f57066" + "0083469877182bd056d6b1ce157644d68171704eb677eb9f9c7a56dafe004d58" ] } }, @@ -1516,14 +1516,14 @@ ], "disposition": "exempt", "body_sha256": [ - "41cb5563ee3dfe084c915b7f37e997ff311b5a87ddcef1e1b21edafc8e9f012d" + "efb036db9f06e2cdc00ead9b2345d1c956fa94b59d779ec752637c981cf44d9f" ], "source_sha256": { "builtin_net_accept": [ - "41cb5563ee3dfe084c915b7f37e997ff311b5a87ddcef1e1b21edafc8e9f012d" + "efb036db9f06e2cdc00ead9b2345d1c956fa94b59d779ec752637c981cf44d9f" ], "net_lookup": [ - "80716b1becf33449a83c7700e1aac433cdcf96492fa0c7d5bbe29d1a4f3b58ea" + "eeb07c145ad60f6a504c6679e0b67b07ec6c4e604f4ef6b150635a279e9daebd" ], "net_num_at": [ "7310ee4a771073b341da2ed594f8263422358a2cb7178a1a6c7d38ad906bafb5" @@ -1687,7 +1687,7 @@ "bcb3999873c5e085e20e6370e6ae81ddaf01a610069729a2a12dd5d402df301c" ], "value_to_string": [ - "c5f081c068f1ae84bec75b29c9954f194376fbaa26f557bd596eb2bf889db46f" + "feb6315af098c35864b9b54030e8e84ca9321c2871685b530fccbdba4ec2d8ba" ] } }, @@ -1871,11 +1871,11 @@ ], "disposition": "exempt", "body_sha256": [ - "5506544aa198f8dd9521f0ed4605b857f75d426806797afd20265a6990548b5f" + "d6eda264cb5efcf396bf823275e60d2b08f3f4d8b339fba1c0f76b6c92ad26cf" ], "source_sha256": { "builtin_set_at": [ - "5506544aa198f8dd9521f0ed4605b857f75d426806797afd20265a6990548b5f" + "d6eda264cb5efcf396bf823275e60d2b08f3f4d8b339fba1c0f76b6c92ad26cf" ] } }, @@ -1963,11 +1963,11 @@ ], "disposition": "exempt", "body_sha256": [ - "8a22c6ab7d441da0f47dc11ca19e0286132298db87e1402725a2ded6c80a826e" + "87b51d351caee962903636165f8d80c680774990ff9cc308731208464136ea62" ], "source_sha256": { "builtin_sort": [ - "8a22c6ab7d441da0f47dc11ca19e0286132298db87e1402725a2ded6c80a826e" + "87b51d351caee962903636165f8d80c680774990ff9cc308731208464136ea62" ] } }, @@ -2130,7 +2130,7 @@ "54d7497ad4bc951a7f8b8e0e690f901fcab06ed74c92050e4e68be8c36921372" ], "value_to_string": [ - "c5f081c068f1ae84bec75b29c9954f194376fbaa26f557bd596eb2bf889db46f" + "feb6315af098c35864b9b54030e8e84ca9321c2871685b530fccbdba4ec2d8ba" ] } }, @@ -2146,14 +2146,14 @@ ], "disposition": "exempt", "body_sha256": [ - "aff6b5f42bc298bbd9e89a1b3b4e6869e6675974152841f17a47bee7a7cde312" + "266fe6f318707383a46998a2ba6d2b04c2e1c720fd0d8ec5f481680e80a39e32" ], "source_sha256": { "builtin_str_from_bytes": [ - "aff6b5f42bc298bbd9e89a1b3b4e6869e6675974152841f17a47bee7a7cde312" + "266fe6f318707383a46998a2ba6d2b04c2e1c720fd0d8ec5f481680e80a39e32" ], "strict_numeric_byte_list": [ - "c44801e4253c003e32d5daa43ec63454efc8faa0b13403ccd8f6e7b7bbe92b7e" + "049e896f6231c29f666669a17d40a2a233305146baf380e237505b2a20de0aeb" ] } }, @@ -2268,7 +2268,7 @@ "f6bb04ca6134dd41d1a67ee91ea2b9587e13477f13ed51afaa3834de1d4f2b78" ], "tensor_unary": [ - "6cd5986e901ac953b121ba49c8b8d0eac1c53a1cf27cb8889b7f8f9a7e1b9a11" + "1af75bad7d2bf52e684f7b38fc0bd07ad4dde6d2477d678084124c48416571c5" ] } }, @@ -2296,11 +2296,11 @@ ], "disposition": "exempt", "body_sha256": [ - "1a99f96780f83e71ed85eaa5c61c0d01ba9c14a0fd844f6bd1cfd26ffa0f5202" + "5e2ddb201b45a65ebb07466ff09a20b1e2457f5b402bec0f524efd2dbd3b28b6" ], "source_sha256": { "builtin_tensor_leaky_relu": [ - "1a99f96780f83e71ed85eaa5c61c0d01ba9c14a0fd844f6bd1cfd26ffa0f5202" + "5e2ddb201b45a65ebb07466ff09a20b1e2457f5b402bec0f524efd2dbd3b28b6" ], "flat_to_like": [ "9829b048a1af1233bfeae6329573e79d83cd7acb01e548d3737011a625fbdc02" @@ -2309,7 +2309,7 @@ "40100cc6cf4d92300cf1d3fbae23cb21adf4241bd01edecc9a683a07fb30bc01" ], "tensor_to_flat": [ - "d6c74fa5dc6c5d4d702b6f2eb1746dbe61271fd05f9bae972bdefa05d607cedc" + "19f5a199223011e28a91da3f7310457051e9757cd0d082c69ba850279f964e1e" ] } }, @@ -2325,11 +2325,11 @@ ], "disposition": "exempt", "body_sha256": [ - "a247feeafdfc05d844eb1bdd0f3eed2be3cf37a4801ca34add1628d8f141b8a5" + "c3710ef41cb4dfa0502da1377a8d20f45a5e133b14e2a54a5eaeee8b5093a84c" ], "source_sha256": { "builtin_tensor_load": [ - "a247feeafdfc05d844eb1bdd0f3eed2be3cf37a4801ca34add1628d8f141b8a5" + "c3710ef41cb4dfa0502da1377a8d20f45a5e133b14e2a54a5eaeee8b5093a84c" ] } }, @@ -2352,7 +2352,7 @@ "ff086ad360320823ab29cb9cfbeed6ec340ae78f959cb18c187c227db55f947f" ], "tensor_unary": [ - "6cd5986e901ac953b121ba49c8b8d0eac1c53a1cf27cb8889b7f8f9a7e1b9a11" + "1af75bad7d2bf52e684f7b38fc0bd07ad4dde6d2477d678084124c48416571c5" ] } }, @@ -2368,11 +2368,11 @@ ], "disposition": "exempt", "body_sha256": [ - "868db4f26fa6b315a63c25e1474c2ba2bbea74c1ff294876bfef6c715906a0e3" + "489ba8b13afde99102707f530aff5a17892ab9d91e5a4f04fd66e2cf814d0de4" ], "source_sha256": { "builtin_tensor_log_softmax": [ - "868db4f26fa6b315a63c25e1474c2ba2bbea74c1ff294876bfef6c715906a0e3" + "489ba8b13afde99102707f530aff5a17892ab9d91e5a4f04fd66e2cf814d0de4" ] } }, @@ -2424,17 +2424,17 @@ ], "disposition": "exempt", "body_sha256": [ - "f6eec99bd0153900403028372a294cf84be9485ce98b7ad8843ce4e2a5d390ee" + "1fcfe61f468a053dfe68fdb710c24b2ebbf4b2162365375741ba70ef576871aa" ], "source_sha256": { "builtin_tensor_mean": [ - "f6eec99bd0153900403028372a294cf84be9485ce98b7ad8843ce4e2a5d390ee" + "1fcfe61f468a053dfe68fdb710c24b2ebbf4b2162365375741ba70ef576871aa" ], "tensor_flatten_recursive": [ - "be389e2e858e13f1dc09f309722e7e6ccebf4bb2bb829b2b1ad176401d2e86ae" + "83ae12ef8455961c802dd4b2ad0510a0c8909ced5ce8f0764ffbbd07122f5572" ], "tensor_total": [ - "e08db1676199c3179be8948bba78f43af63fecc404ef75b8d0b55ac59be72484" + "3d8462c70952661bb8d5eb44673f96c5108b2198142434d145c6c0443d3b43f6" ] } }, @@ -2469,7 +2469,7 @@ "a345f0c30c4b1b80943b9c718c0002fc19981d0336a9a1ea0aca3b5966bf8462" ], "tensor_unary": [ - "6cd5986e901ac953b121ba49c8b8d0eac1c53a1cf27cb8889b7f8f9a7e1b9a11" + "1af75bad7d2bf52e684f7b38fc0bd07ad4dde6d2477d678084124c48416571c5" ] } }, @@ -2485,17 +2485,17 @@ ], "disposition": "exempt", "body_sha256": [ - "817e544211920e1216ff102393d66f3cb7a8def4a9ea05611872433b5ad8f87c" + "a61b299c03728007c16c2ec85c94459cec1659b6463372404565ca542f70aa68" ], "source_sha256": { "builtin_tensor_norm": [ - "817e544211920e1216ff102393d66f3cb7a8def4a9ea05611872433b5ad8f87c" + "a61b299c03728007c16c2ec85c94459cec1659b6463372404565ca542f70aa68" ], "tensor_flatten_recursive": [ - "be389e2e858e13f1dc09f309722e7e6ccebf4bb2bb829b2b1ad176401d2e86ae" + "83ae12ef8455961c802dd4b2ad0510a0c8909ced5ce8f0764ffbbd07122f5572" ], "tensor_total": [ - "e08db1676199c3179be8948bba78f43af63fecc404ef75b8d0b55ac59be72484" + "3d8462c70952661bb8d5eb44673f96c5108b2198142434d145c6c0443d3b43f6" ] } }, @@ -2523,17 +2523,17 @@ ], "disposition": "exempt", "body_sha256": [ - "e69663c14d78c3bda0a319969a0159a98b282bd90263ede6d152f060df8b96c8" + "d951d17e028b0cb3c75269936e4cb8cfa71bc52ea129e1b29fc60c0ac5f749ec" ], "source_sha256": { "builtin_tensor_relu": [ - "e69663c14d78c3bda0a319969a0159a98b282bd90263ede6d152f060df8b96c8" + "d951d17e028b0cb3c75269936e4cb8cfa71bc52ea129e1b29fc60c0ac5f749ec" ], "flat_to_like": [ "9829b048a1af1233bfeae6329573e79d83cd7acb01e548d3737011a625fbdc02" ], "tensor_to_flat": [ - "d6c74fa5dc6c5d4d702b6f2eb1746dbe61271fd05f9bae972bdefa05d607cedc" + "19f5a199223011e28a91da3f7310457051e9757cd0d082c69ba850279f964e1e" ] } }, @@ -2573,11 +2573,11 @@ ], "disposition": "exempt", "body_sha256": [ - "f78ba93eb0b22a35b1c8a328a1f557b7096bf05bdbf38fe3259876cc7d1b8bb9" + "d2f043c8013c90056a07eda303181476e750937882546e3f20f561a558dfa3ef" ], "source_sha256": { "builtin_tensor_shape": [ - "f78ba93eb0b22a35b1c8a328a1f557b7096bf05bdbf38fe3259876cc7d1b8bb9" + "d2f043c8013c90056a07eda303181476e750937882546e3f20f561a558dfa3ef" ] } }, @@ -2593,14 +2593,14 @@ ], "disposition": "exempt", "body_sha256": [ - "8f880cc73ad6e7e48aa891ef2acb00a653c9b110ccea7c386c3189224fb2cd7a" + "36bd1d3ef2012f91d80a19f503693e38bba0bbe143569400c7f0088ed7d69de7" ], "source_sha256": { "buf_dims": [ "edfe0613daa3910ade3374de6fb9fe4486e51f0fea899fc3ec891441e259010e" ], "builtin_tensor_softmax": [ - "8f880cc73ad6e7e48aa891ef2acb00a653c9b110ccea7c386c3189224fb2cd7a" + "36bd1d3ef2012f91d80a19f503693e38bba0bbe143569400c7f0088ed7d69de7" ], "flat_to_like": [ "9829b048a1af1233bfeae6329573e79d83cd7acb01e548d3737011a625fbdc02" @@ -2609,7 +2609,7 @@ "40100cc6cf4d92300cf1d3fbae23cb21adf4241bd01edecc9a683a07fb30bc01" ], "tensor_to_flat": [ - "d6c74fa5dc6c5d4d702b6f2eb1746dbe61271fd05f9bae972bdefa05d607cedc" + "19f5a199223011e28a91da3f7310457051e9757cd0d082c69ba850279f964e1e" ] } }, @@ -2632,7 +2632,7 @@ "f38d9057e3c1e2a049e7cd4d4f38df6aace72af77d1a718b357b4f2a5bf4f54d" ], "tensor_unary": [ - "6cd5986e901ac953b121ba49c8b8d0eac1c53a1cf27cb8889b7f8f9a7e1b9a11" + "1af75bad7d2bf52e684f7b38fc0bd07ad4dde6d2477d678084124c48416571c5" ] } }, @@ -2660,17 +2660,17 @@ ], "disposition": "exempt", "body_sha256": [ - "196480c8b98743ea57d8bf3bc4bdf0b0fdc3ca70c56ef6cd1289342e15fcd544" + "3547e36409bdec126b353da212d4bd6b2a080d5dda849c2936dbaeee5da5ceeb" ], "source_sha256": { "builtin_tensor_sum": [ - "196480c8b98743ea57d8bf3bc4bdf0b0fdc3ca70c56ef6cd1289342e15fcd544" + "3547e36409bdec126b353da212d4bd6b2a080d5dda849c2936dbaeee5da5ceeb" ], "tensor_flatten_recursive": [ - "be389e2e858e13f1dc09f309722e7e6ccebf4bb2bb829b2b1ad176401d2e86ae" + "83ae12ef8455961c802dd4b2ad0510a0c8909ced5ce8f0764ffbbd07122f5572" ], "tensor_total": [ - "e08db1676199c3179be8948bba78f43af63fecc404ef75b8d0b55ac59be72484" + "3d8462c70952661bb8d5eb44673f96c5108b2198142434d145c6c0443d3b43f6" ] } }, @@ -2698,11 +2698,11 @@ ], "disposition": "exempt", "body_sha256": [ - "0de72aaa352907156e4244579f587cadc755557642f4e297485a5c4a019233eb" + "de7cfc7d58f684b0387b034f30dce9ba17f1034de4dab955242bc5996ee244dd" ], "source_sha256": { "builtin_tensor_zeros_like": [ - "0de72aaa352907156e4244579f587cadc755557642f4e297485a5c4a019233eb" + "de7cfc7d58f684b0387b034f30dce9ba17f1034de4dab955242bc5996ee244dd" ], "make_buffer_like": [ "40100cc6cf4d92300cf1d3fbae23cb21adf4241bd01edecc9a683a07fb30bc01" @@ -2752,7 +2752,7 @@ "dce6eda1020469efb73a67c34f60fa7cc66c03c617d1fb4bc96aaea536346ae3" ], "value_to_string": [ - "c5f081c068f1ae84bec75b29c9954f194376fbaa26f557bd596eb2bf889db46f" + "feb6315af098c35864b9b54030e8e84ca9321c2871685b530fccbdba4ec2d8ba" ] } }, @@ -2768,11 +2768,11 @@ ], "disposition": "exempt", "body_sha256": [ - "3b2456c11794f2c97b3fdff67d7dec23ca93b74804b0c09172bbab4a3e628144" + "8a0d46b25329fdb51f6cadad9cc60afd36630ca07f8cb2a601d0d1e9dc262941" ], "source_sha256": { "builtin_type": [ - "3b2456c11794f2c97b3fdff67d7dec23ca93b74804b0c09172bbab4a3e628144" + "8a0d46b25329fdb51f6cadad9cc60afd36630ca07f8cb2a601d0d1e9dc262941" ] } }, @@ -2821,7 +2821,7 @@ "fce8334d124e479de21cd22dfed262a8edcc656341a1f7c272507762481c57fc" ], "vm_desc_abi_error": [ - "d04f5e7fb2d2e37822a432fe90a03208d9de9cfcb1cbcb44774186f730fd1333" + "d68adff43db3fe20e9f49ef018917f6d7e926f5093b9af3c7467fe78050df28d" ] } }, @@ -2844,7 +2844,7 @@ "5556903dd96019edcff890e180e1e8f04ffc7101fe80b5fcf93520968ea3c180" ], "value_to_string": [ - "c5f081c068f1ae84bec75b29c9954f194376fbaa26f557bd596eb2bf889db46f" + "feb6315af098c35864b9b54030e8e84ca9321c2871685b530fccbdba4ec2d8ba" ] } }, From 95ce2fed148143835279cee9b8f3d799eaff3940 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 08:36:22 -0500 Subject: [PATCH 042/188] phase2 R1.2t: recognize the bool renderer result in the strict differential (#1758) The renderer probe compared gfx_open's printed bool to the obsolete number 1. Direct capped X11 probe returns true, so the old checker incorrectly skipped pixel identity even with an available renderer. Compare to true. Runtime alias sites=0; probe expectation sites=1. No runtime change. One-time calibration against the real gate: temporarily flip a red bit in gfx_read at (31,31). The old checker exits 0 and skips pixel identity. The fixed checker exits 1 with 37/37 pixel rows differing. Restore the exact C source and rebuild: 37/37 pixel rows identical, differing=0; strict pixel raises=23 silent=0 misattributed=0, final OK against main 0740af03. No permanent check of the check is added. Validation: make built; complete strict differential with X11 passes; SHAPE_CAPTURE_SELFTEST: 88 passed, 0 failed, 88 declared. The previous strict results' no-renderer notes were this stale expectation, not unavailable SDL. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tools/strict_differential.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/strict_differential.sh b/tools/strict_differential.sh index 93f011006..796648759 100755 --- a/tools/strict_differential.sh +++ b/tools/strict_differential.sh @@ -1590,7 +1590,7 @@ fi # ------------------------------------------------ pixel differential printf 'print of (gfx_open of [8, 8, "pixdiff-probe"])\n' > "$TMP/open.eigs" NO_RENDERER=0 -if [ "$("$NEW" "$TMP/open.eigs" 2>&1 | tail -1)" != "1" ]; then +if [ "$("$NEW" "$TMP/open.eigs" 2>&1 | tail -1)" != "true" ]; then NO_RENDERER=1 echo " NOTE: no renderer — pixel identity is OFF; strict-raise and coverage still run." fi From 0b6d9673e153b0fc95d50e6e0c38900a005ea4da Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 09:23:21 -0500 Subject: [PATCH 043/188] phase2 R1.2u: report the graphics sanitizer renderer state as a bool (#1758) The sanitizer helper used the same stale sdl-present: 1 expectation as the strict renderer probe. The corpus still executed, but the note incorrectly claimed SDL was absent after gfx_open printed true. Match the exact true line and report only renderer unavailability, without inferring audio availability. Align the inert timeout control with the actual false print. Runtime alias sites=0; bool spellings=3 (including the explanatory comment). Validation: make asan built, with unlimited RLIMIT_AS. Focused real helper: renderer available (dummy video/software renderer), 15 passed, 0 failed, no false absence note; unavailable video driver, 15 passed, 0 failed, accurate renderer-unavailable note. Existing timeout controls ran in each. An invalid renderer hint initially fell back to a working renderer; that attempt was not counted as the negative control. Default make restored and built before commit. No runtime C source or permanent self-check changes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/test_asan_gfx.sh | 8 ++++---- tests/test_gfx_timeout.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_asan_gfx.sh b/tests/test_asan_gfx.sh index 15bea25bf..211b8fb69 100755 --- a/tests/test_asan_gfx.sh +++ b/tests/test_asan_gfx.sh @@ -33,7 +33,7 @@ WERROR_FLAGS_FILE="$(dirname "$0")/../tools/werror_flags.txt" # has no gfx builtins. Explicit compiler selection and build failures are # errors. libSDL2 # is NOT required: it is dlopen'd, so the corpus runs either way -- gfx_open -# answers 0 and the drawing calls no-op, which still walks every allocation +# answers false and the drawing calls no-op, which still walks every allocation # path on the argument side. Whether SDL was present is reported, so a green # line is not read as more coverage than the environment gave. # @@ -343,9 +343,9 @@ if [ "$SDL_RC" -ne 0 ] || [ "$SDL_CLASS" -ne 2 ]; then echo "ASan gfx: $PASS passed, $FAIL failed" exit 1 fi -printf '%s' "$SDL_OUT" | grep -q "sdl-present: 1" \ - || echo " NOTE: libSDL2 absent — the corpus exercised the argument and"\ - "allocation paths but no real renderer or audio device." +printf '%s' "$SDL_OUT" | grep -q '^sdl-present: true$' \ + || echo " NOTE: SDL renderer unavailable — the corpus exercised the argument and"\ + "allocation paths without real rendering." echo "ASan gfx: $PASS passed, $FAIL failed" [ "$FAIL" = 0 ] || exit 1 diff --git a/tests/test_gfx_timeout.py b/tests/test_gfx_timeout.py index ed93102ef..cb6705a10 100644 --- a/tests/test_gfx_timeout.py +++ b/tests/test_gfx_timeout.py @@ -47,7 +47,7 @@ def main(): "mode=os.environ['EIGS_TIMEOUT_CONTROL_MODE']\n" "if mode in ('ignore','leak-ignore'): signal.signal(signal.SIGTERM,signal.SIG_IGN)\n" "open(" + repr(str(pidfile)) + ", 'w').write(str(os.getpid()))\n" - "if mode=='clean': print('sdl-present: 0'); raise SystemExit(0)\n" + "if mode=='clean': print('sdl-present: false'); raise SystemExit(0)\n" "if mode=='error': raise SystemExit(7)\n" "if mode.startswith('leak-'): print('==123==ERROR: LeakSanitizer: detected memory leaks',flush=True)\n" "if mode=='leak-clean': raise SystemExit(1)\n" From 7ade7cc7ffe6ebf7428c766ad844b01d743803a4 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 10:42:11 -0500 Subject: [PATCH 044/188] phase2 R1.2v: retire the non-reproducing audio replay fixture row (#1758) The shared audio policy now uses SDL_AUDIODRIVER=dummy. The full replay corpus previously failed with only test_audio.eigs missing from the ledger; no new divergence appeared. Removing that row makes a recurring failure red. The fixture also matches across clock seconds on both this candidate and 0740af03 (53/53 assertions plus mixer checks). Its noise assertions inspect length/range, never the samples. Remove the unsupported noise attribution. This does not fix the branch's untaped audio_noise: a separate sample-printing probe still diverges across seconds on BOTH binaries, with no audio_noise tape entry. The old CI log supplies no underlying record/replay transcripts; its cause is unknown. An independent reviewer agreed with the narrower fixture-ledger retirement under the dummy policy. Sites: 0 runtime alias sites; 1 stale replay ledger row removed. Build: make exits 0 (EigenScript 0.46.0 built. Binary: 1.3M). Gate: replay_diff: OK (258 programs record+replay; 21 at the documented boundary; 0 nondeterministic; 1 ledgered). Full ASan: RESULTS: 4259/4259 passed, 0 failed, 8 skipped; child exits 0; LeakSanitizer nonzero-exit tally 0; RLIMIT_AS unlimited. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/replay_diff_expected.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/replay_diff_expected.txt b/tests/replay_diff_expected.txt index 851fff17e..73bf91dc4 100644 --- a/tests/replay_diff_expected.txt +++ b/tests/replay_diff_expected.txt @@ -1,9 +1,4 @@ # tests/replay_diff_expected.txt -- the programs whose record-vs-replay output # diverges reproducibly (tools/replay_diff.sh). A ledger to work down: a row # is a fidelity hole, with its issue on the line above it. -# -# test_audio.eigs -- #1803: audio_noise is not taped. Reached since the run -# conditions (EIGS_STRICT=0) carried test_audio past its first strict raise; -# it diverges on CI (job 116494830590) and not on the 4 GB dev box. -test_audio.eigs test_store_corruption.eigs From a49ebe5850e860ce4cfebb0380eab31d624b4ea8 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 11:16:19 -0500 Subject: [PATCH 045/188] phase2 R1.2w: record the Value layer's full verification and handoff (#1758) Record all file groups and their deprecated-token site counts, the measured VM candidates, the one-time real-source red/green plants, all final gate commands/results, and the constraints on the sandbox Git-metadata handoff. Runtime C source is unchanged after ce66ede5; no int producer was added. Sites: 0 (report only). The migrated runtime inventory totals 370 sites; seven C fixture files add 28 sites outside that source inventory. Build: make exits 0. Independent committed-tree builds: 20/20 succeeded serially with the server-db target; final gcc -O0/-O1/-O2 each compiled 35/35 translation units with zero warnings. Final gate witnesses: RESULTS: 4268/4268 passed, 0 failed, 9 skipped (release). RESULTS: 4259/4259 passed, 0 failed, 8 skipped (full ASan; leak exits 0; RLIMIT_AS unlimited). Both child-script ledgers have 0 nonzero exits. jit_diff: OK (258 programs x {jit, osr} vs the interpreter; suite-env completed=15; OBS examined=630 denied=12; 30 arms adjudicated; 2 ledgered). replay_diff: OK (258 programs record+replay; 21 at the documented boundary; 0 nondeterministic; 1 ledgered). phase2-check: PASS through R1.2. Both corpus halves examined=441 diff=0 undeclared=0 incomplete=0. Tokens hits=0; inventory unclassified=0; make_int_defs=0 outside_writers=0; slot matrix 396 cells, failures=0. JIT smoke: all cases passed. embed_smoke: OK. Strict differential: OK, including 37/37 pixel rows identical and the real pixel-fault red. Final callgrind vs 46617422: DMG500K -0.058998%, float JIT +0.001250%, float interpreter +0.000519%; all within +/-0.1%. No push or main merge. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- reports/phase2-r12.md | 299 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 reports/phase2-r12.md diff --git a/reports/phase2-r12.md b/reports/phase2-r12.md new file mode 100644 index 000000000..2cb5b6620 --- /dev/null +++ b/reports/phase2-r12.md @@ -0,0 +1,299 @@ +# Phase 2 R1.2 Value layer report + +Implementation is committed in the isolated Git metadata used by this sandbox. +The full release, sanitizer, differential, and Phase 2 gates are green. + +## Summary + +All runtime and C-fixture aliases are migrated. Int consumers either have +their final reader arm or abort through the R1.3 unwired token. The number +bridge names remain. No `make_int` or int-producing opcode exists. + +The sandbox makes the worktree common Git metadata read-only. +`/tmp/phase2-r12/git.sh` commits this worktree through isolated metadata; +`/tmp/phase2-r12/commits.bundle` contains the series from `46617422`. +The orchestrator can import with `git fetch /tmp/phase2-r12/commits.bundle +phase2-numbers` then `git reset --mixed FETCH_HEAD` (updates branch/index; +keeps working files). No push or main merge was performed. + +## Commits + +Counts are deprecated code-token inventory sites; the C fixtures are outside +that source inventory. The runtime total is 370; fixtures add 28. + +| Round | Commit | File group | Sites | +|---|---|---|---:| +| R1.2d | `40ef2d84` | builtins.c | 85 | +| R1.2e | `10849e60` | builtins_tensor.c | 39 | +| R1.2f | `f28b94b0` | builtins_buf.c | 21 | +| R1.2g | `f9e711df` | builtins_host.c | 11 | +| R1.2h | `2fb9b5e2` | ext_gfx.c; audio policy | 56 | +| R1.2i | `7038423c` | container/value-slot reader arms | 0 | +| R1.2j | `3f1ff968` | jit.c, jit_smoke.c | 10 | +| R1.2k | `a0f66387` | chunk.c | 11 | +| R1.2l | `6640b3d5` | trace.c | 6 | +| R1.2m | `d5ff982c` | ext_store.c | 14 | +| R1.2n | `23262614` | eigs_embed.c | 4 | +| R1.2o | `1a2c4e44` | network/HTTP/database/model | 11 | +| R1.2p | `1822df24` | seven C test fixtures | 28 | +| R1.2q | `14471e2f` | vm.c | 97 | +| R1.2z | `ce66ede5` | alias definitions and final cleanup | 5 | +| R1.2r | `664c28d5` | P4 calibration templates (4 spellings) | 0 | +| R1.2s | `7e5662d0` | strict shape fingerprints (39 rows) | 0 | +| R1.2t | `95ce2fed` | bool renderer probe (1 expectation) | 0 | +| R1.2u | `0b6d9673` | sanitizer renderer note and inert timeout control | 0 | +| R1.2v | `7ade7cc7` | retire stale audio replay fixture ledger row | 0 | +| R1.2w | this report | verification report and handoff | 0 | + +The reader follow-up additionally completes three int arms. Each group was +built while landing it, and all twenty implementation/tooling commits were +then independently rebuilt from their committed trees, serially. The report +commit also gets a default build. Logs are in `/tmp/phase2-r12/logs`. +Every commit carries the requested Claude trailers. + +## Cost + +Default release gcc -O2: GCC 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1), +Valgrind 3.26.0.codspeed7. Same DMG source/ROM and float program for every arm. +DMG export: `afd9bd52778cb0a8d1ab0473ec726aaae556fb90`, all 19 runtime +EigenScript/ROM files checked against its Git blobs, zero mismatches. +ROM SHA256: `8c5e12f41e0ba5bbca796944f92ffe6de28809198682c4332e38d1b3cf56fcf2`. +Float program SHA256: `67a1dc2f7db8ae581c58f0c781c21de3037e8f6b3d8a14f63ee5ee4e12e88fe6`. + +Commands (all serial; `BINARY` is the independently built baseline or candidate): + +Baseline binary: `/tmp/phase2-r12/baseline/src/eigenscript`; final candidate: +`/home/jon/src/wt/es-phase2/src/eigenscript`. + +```sh +cd /tmp/phase2-r11-critic2/DMG +valgrind --tool=callgrind BINARY dmg.eigs roms/cpu_instrs.gb --cycles 500000 +cd /tmp/phase2-r12 +valgrind --tool=callgrind BINARY float_loop.eigs +EIGS_JIT_OFF=1 valgrind --tool=callgrind BINARY float_loop.eigs +``` + +The float loop runs 200,000 iterations. Source/build inputs for baseline +`46617422`, corpus oracle `0740af03`, and tag `v0.46.0` were checked against +150 Git blobs each, all with zero mismatches. No binary copies were used. + +| Candidate | DMG 500K Ir | Float JIT Ir | Float interpreter Ir | Verdict | +|---|---:|---:|---:|---| +| baseline | 1,195,422,765 (+0.000000%) | 172,214,775 (+0.000000%) | 364,233,396 (+0.000000%) | baseline | +| vmrename | 1,195,320,483 (-0.008556%) | 172,216,054 (+0.000743%) | 364,235,224 (+0.000502%) | rename control | +| vm1 | 1,193,790,787 (-0.136519%) | 172,190,897 (-0.013865%) | 363,235,041 (-0.274098%) | rejected | +| vm2 | 1,193,798,401 (-0.135882%) | 172,191,010 (-0.013800%) | 363,235,208 (-0.274052%) | rejected | +| vm3 | 1,198,112,295 (+0.224986%) | 172,276,017 (+0.035561%) | 366,635,271 (+0.659433%) | rejected | +| vm4 | 1,199,112,814 (+0.308682%) | 172,276,017 (+0.035561%) | 366,635,271 (+0.659433%) | rejected | +| vm5 | 1,193,848,621 (-0.131681%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | +| vm6 | 1,200,113,794 (+0.392416%) | 172,306,061 (+0.053007%) | 367,835,319 (+0.988905%) | rejected | +| vm7 | 1,192,778,866 (-0.221169%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | +| vm8 | 1,194,010,544 (-0.118136%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | +| vm9 | 1,197,353,964 (+0.161549%) | 172,246,061 (+0.018167%) | 365,435,313 (+0.329985%) | rejected | +| vm10 | 1,193,839,891 (-0.132411%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | +| vm11 | 1,195,567,598 (+0.012116%) | 172,251,028 (+0.021051%) | 365,635,216 (+0.384869%) | rejected | +| vm12 | 1,193,533,071 (-0.158077%) | 172,190,961 (-0.013828%) | 363,235,170 (-0.274062%) | rejected | +| vm13 | 1,200,115,350 (+0.392546%) | 172,271,887 (+0.033163%) | 366,435,423 (+0.604565%) | rejected | +| vm14 | 1,197,839,406 (+0.202158%) | 172,276,879 (+0.036062%) | 366,635,321 (+0.659447%) | rejected | +| vm15 | 1,196,101,881 (+0.056810%) | 172,226,927 (+0.007056%) | 364,635,287 (+0.110339%) | rejected | +| vm16 | 1,197,057,949 (+0.136787%) | 172,226,919 (+0.007052%) | 364,635,279 (+0.110337%) | rejected | +| vm17 | 1,200,722,940 (+0.443372%) | 172,281,935 (+0.038998%) | 366,835,395 (+0.714377%) | rejected | +| vm18 | 1,194,707,923 (-0.059798%) | 172,216,927 (+0.001250%) | 364,235,286 (+0.000519%) | PASS | +| final | 1,194,717,491 (-0.058998%) | 172,216,927 (+0.001250%) | 364,235,286 (+0.000519%) | PASS | + +Candidate 18 is the committed VM. Final reruns it after alias deletion and +restoring the old sort-key pair footprint. All three final deltas fit +±0.1%; stdout matches the baseline (DMG Time/Speed lines omitted). +The same callgrind brk-segment note appears on baseline and candidates; +each completed normally and reported its instruction count. + +## Plants + +- A `VAL_NUM` straggler in actual `builtin_usleep`: token gate `hits=1`; + `make build/release/builtins.o` exits 2, undeclared identifier. Restored: + `tokens: rounds<=R1.2 tokens=9 files=90 hits=0`. +- Remove the JSON encoder's `VAL_INT` arm: actual make exits 2 with + `VAL_INT not handled in switch [-Werror=switch]`. All 17 Value-type + switches enumerate all 12 types, with no default. +- Remove the boxed `slot_int_value` reader: actual slot gate exits 1 with + five assertion failures and no build-warning witness. Restored: + `examined=33 calls=165 matrix_cells=396 arm_rows=32 failures=0`. + +- P4 calibration templates: both stale anchors had zero matches. After the + four token spellings were migrated, all 13 build/static anchors match once. + Official planted builder plus restricted corpus: control 2/2 same; mutant + 2/2 DIFF with `slot_from_int under EIGS_SMI_TRAP` observed. +- The strict renderer probe expected `1`, while a real capped X11 call to + `gfx_open` prints `true`. Temporary `gfx_read` fault flips a red bit at + (31,31): old checker exits 0 and skips pixels; fixed checker exits 1 with + 37/37 pixel rows differing. Restore exact C source and rebuild: 37/37 + identical, differing=0, final `OK`. Existing capture self-test: 88/88. + +These mutations were temporary. No permanent check of these checks was added. +The inventory's legacy-matcher retirement was also compared before/after +on the real source: identical output. Its numeric builtin population stays +230/230. + +A temporary C host injected `INT64_MAX` into try-wrapped addition/comparison +and both iterator snapshot implementations. All four aborted via the +R1.3 diagnostic/SIGABRT; paired floats returned 6, true, 42, 42 (8/8). + +## Gates run + +- Default `make`: gcc -O2 warnings=0. +- `make build/server-db/eigenscript CFLAGS='-Wall -Wextra -Werror=implicit-function-declaration -Werror=switch -Werror=comment -Werror=misleading-indentation -O0 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE'`: + 35/35 translation units, warnings=0. +- `make -B build/server-db/eigenscript CFLAGS='-Wall -Wextra -Werror=implicit-function-declaration -Werror=switch -Werror=comment -Werror=misleading-indentation -O1 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE'`: + 35/35 translation units, warnings=0. +- `make -B build/server-db/eigenscript` (default -O2): + 35/35 translation units, warnings=0. +- `make jit-smoke`: `JIT smoke: all cases passed.` +- `make embed-smoke`: `embed_smoke: OK`. +- `make smi-trap` in the `ce66ede5` archive (runtime C identical to final HEAD): built. +- `python3 tools/phase2_inventory.py --check`: + `builtins: registered=311 numeric=230 classified=230 unclassified=0 stale=0`; + `examined=2014 classified=2014 unclassified=0`; `phase2-inventory: PASS`. +- `bash tools/num_read_check.sh`: + `num-read: examined=197 functions=81 allowlisted=81 violations=0 stale=0`; + `num-read: PASS`. +- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy bash tools/phase2_check.sh /tmp/eigs-oracle-anchor/v0.46.0/src/eigenscript /home/jon/src/wt/es-phase2/src/eigenscript --through R1.2 --baseline /tmp/phase2-r12/main/src/eigenscript --smi-trap /tmp/phase2-r12/trap/src/eigenscript`: + `phase2-check: PASS` (final checker artifact; 1351.09 seconds). Both corpus halves: + `examined=441 same=435 same_nonzero=31 same_under_replay=4 nondet=1 diff=0 new=14 deleted=0 crash_both=0 timeout_both=1 conditioned=15 incomplete=0 undeclared=0 stale=0 ledger_refused=0 unpinned=1 capped=13`. + Static int-source: `files=64 slot_from_int_defs=1 make_int_defs=0 calls=2 outside_writers=0 tag_homes=4/4 tag_spellings_outside=0`. + Inventory: `examined=2014 classified=2014 unclassified=0`; freshness PASS; + numeric builtins 230/230, dispositions 101 missing=0 stale=0, leaf 11/11. + Slot gate: `examined=33 calls=165 matrix_cells=396 arm_rows=32 failures=0`. +- `make test`: `RESULTS: 4268/4268 passed, 0 failed, 9 skipped`; child-script ledger: `0 nonzero exits`. +- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy + bash tools/jit_diff.sh`: + `jit_diff: OK (258 programs x {jit, osr} vs the interpreter; suite-env completed=15; OBS examined=630 denied=12; 30 arms adjudicated; 2 ledgered)`. +- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy bash tools/replay_diff.sh`: + `replay_diff: OK (258 programs record+replay; 21 at the documented boundary; 0 nondeterministic; 1 ledgered)`. +- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=x11 SDL_AUDIODRIVER=dummy + bash tools/strict_differential.sh /tmp/phase2-r12/main/src/eigenscript`: `OK`. + `identical-when-off: 156 differing: 0`; `unset-equals-strict: 156 / 156`; + `raises-under-strict: 156 silent: 0 misattributed: 0`; + `valid-input rows unchanged in all three modes: 252 / 252`. + Typed controls: `declared=139 examined=139 passed=130 failed=0 unavailable=9 backend_absent=0 pending=0 unrun=0`. + Pixels: `rows=37 (valid=14 wrong=23)`, `identical-when-off: 37 differing: 0`. + `bash tools/strict_differential.sh --selftest`: + `SHAPE_CAPTURE_SELFTEST: 88 passed, 0 failed, 88 declared`. +- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy make asan`: + build exits 0. Then `(cd tests && env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy ASAN_OPTIONS=detect_leaks=1 bash run_all_tests.sh)`: + `RESULTS: 4259/4259 passed, 0 failed, 8 skipped`; + `PASS: every child .sh test ran to completion (0 nonzero exits)`. + LeakSanitizer nonzero-exit tally: 0. `RLIMIT_AS` was unlimited throughout. + The full suite took 2401.51 seconds; default `make` restored the release alias. +- `bash tools/suite_label_check.sh`: + `PASS: 294 labelled echo lines; labels and tallies carry no hand-typed counts; no two sections share a label`. +- `python3 /tmp/phase2-r12/build_committed_trees.py`: + `committed-tree-builds: examined=20 failures=0 target=build/server-db/eigenscript`. + This covers every implementation/tooling commit; the report-only commit + also receives its own default build. + +The first full release suite caught stale strict shape fingerprints: +`RESULTS: 4266/4268 passed, 2 failed, 9 skipped` and +`SHAPE_CONTRACT: candidates=190 guarded=139 exempt=51 errors=39`. +All 39 exemption roots and helper closures were reviewed, including an +independent pass; only fingerprint fields changed. The checker now reports +`SHAPE_CONTRACT: candidates=190 guarded=139 exempt=51 errors=0`. +The final suite rerun uses those reviewed fingerprints and the repaired bool +renderer probe. Earlier runs' no-renderer notes came from that stale probe; +they were not evidence of an unavailable renderer. + +The first `jit_diff` run inherited native X11 video and reported two extra +OBS rows (`ui_canvas_events.eigs`, `ui_dock.eigs`): JIT programs=258, +OBS examined=630 denied=12. The subsequent bounded X11 controls ran both +examples on candidate and `0740af03`, each in REF and OBS mode: all eight +were silent and timed out at 25 seconds (rc=124). The remaining gate train +uses explicit `SDL_VIDEODRIVER=dummy`; its full JIT verdict is green with +only the existing two ledger rows. The ledger is unchanged; the +initial failed run is retained as `logs/jit-diff-native-x11.log`. + +The first unforced -O1/-O2 requests reused objects; those logs are retained +as `warnings-*-unforced.log` and are not evidence. The forced builds above +count actual compiler invocations. + +An independent serial replay of all twenty committed trees builds the +server-db target from archived Git sources and exact successive Git blobs. +Intermediate trees retain the intentional deprecated-alias warnings; the +zero-warning requirement is measured on the final tree at all three levels. +The initial replay driver mistakenly required zero warnings on the first +intermediate tree: its actual make exited 0 with 340 warnings, all tagged +`-Wdeprecated-declarations`. That log is retained; the driver was narrowed +to successful builds and resumed from that successful first build. + +The sanitizer renderer note shared the obsolete `sdl-present: 1` spelling. +Its corrected helper was run with an available software renderer and an +unavailable video driver: `15 passed, 0 failed` in each profile, respectively +no false note and an accurate renderer-unavailable note. `RLIMIT_AS` was +unlimited. The initial invalid renderer hint fell back to a working renderer; +that attempt was not counted as a negative control. + +## Audio artifact + +`strace` identified `test_audio.eigs` using SDL's disk backend: it opened +`sdlaudio.raw` four times from src/. The shared per-program policy now sets +`SDL_AUDIODRIVER=dummy`; the same test completed 53/53 plus mixer checks and +left no raw artifact even with an inherited disk-driver setting. The stray +file was removed. + +The first full replay gate examined 258 programs and failed because +`test_audio.eigs` no longer diverged under the dummy-driver policy; no new +divergence was reported. The candidate and `0740af03` also matched on that +whole fixture when record and replay were separated by more than a second +(53/53 assertions plus mixer checks). Its noise assertions check length +and range, never sample values. The old CI log records a divergent row +without the underlying transcripts, so its cause remains unknown. + +A separate minimal program that prints the noise samples still diverges +across seconds on both binaries, with no `audio_noise` entry in either tape: +`NOISE_FIDELITY_PREEXISTING: candidate=divergent main0740=divergent`. +Retiring the whole-fixture row tightens the current gate's expectation; +it does not claim the sample-level issue is fixed on this branch. The +remaining untaped mixer-queue timing is another reason any future CI failure +needs actual record/replay transcripts before a cause is assigned. + +## Design deviations and caveats + +The header-reader follow-up completes arms missed by the earlier R1.2a +commit. Seven C fixtures needed an extra group. R1.2z also changes the two +mutually exclusive sort-key fields to a union to retain the old 16-byte +allocation footprint. These implement the behaviour-preserving scope. +After alias deletion, two stale P4 injection templates, 39 reviewed source +fingerprints and the renderer probe needed follow-up groups. The latter +restores pixel coverage that had silently disappeared with bool printing. +The sanitizer helper’s matching diagnostic and inert false control were +corrected in a separate group; its pass/fail predicate is unchanged. +The no-longer-reproducing audio-fixture replay row was retired after the +full gate failed on its absence and a fresh review checked the scope; +the replacement full run passes with one remaining fidelity row. +Runtime C source after `ce66ede5` is byte-identical; these follow-ups change +checker fixtures and machinery only. After the temporary pixel fault was +restored, the release binary SHA256 is +`9fa86d63826b385a2e21133ee78b7a292ba6665c45e379e6106532874be509c2`, +whose prefix matches the pre-plant SHA256 recorded by the completed R1.2 gate. + +The Git metadata import remains an orchestrator action because of sandbox +permissions. Raw logs and profiles are under /tmp/phase2-r12. +The global instructions mention failsoft_classify_check, which is absent +from this checkout; no result is claimed for that nonexistent command. + +## Distillation + +The cost table records why the VM's cold int refusals need measurement: +17 rejected source candidates changed the interpreter instruction count +beyond the round's tolerance despite leaving today's numeric semantics +unchanged. The existing performance skill already requires measuring this +effect; no new performance rule is needed. + +The real pixel fault exposed an untested capability assumption: the renderer +was available while a bool-printing change made the checker skip its rows. +The repaired probes use the actual `true`/`false` output. The one-time red +and restored green above document that repair without a permanent check of +the check, following PRINCIPLES §5. + +## Out of scope + +R1.3 int producers, arithmetic and tape v7; R1.6 bridge deletion and builtin +semantic changes; main integration, CI upload, and pushing. From 655546a7851e1e90ba0eabc3fa10dcd52e13c5dc Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 18:28:27 -0500 Subject: [PATCH 046/188] phase2: format all fourteen R1.2 changelog fragments (#1758) Reproduced fourteen malformed-fragment failures before the edit. Each now begins with the required list marker. tools/changelog_fragments.sh check: rc=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-r1-2e.md | 2 +- changes/internal/1758-phase2-r1-2f.md | 2 +- changes/internal/1758-phase2-r1-2g.md | 2 +- changes/internal/1758-phase2-r1-2j.md | 2 +- changes/internal/1758-phase2-r1-2k.md | 2 +- changes/internal/1758-phase2-r1-2l.md | 2 +- changes/internal/1758-phase2-r1-2m.md | 2 +- changes/internal/1758-phase2-r1-2n.md | 2 +- changes/internal/1758-phase2-r1-2o.md | 2 +- changes/internal/1758-phase2-r1-2q.md | 2 +- changes/internal/1758-phase2-r1-2z.md | 2 +- changes/internal/1758-phase2-value-builtins.md | 2 +- changes/internal/1758-phase2-value-gfx.md | 2 +- changes/internal/1758-phase2-value-readers.md | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/changes/internal/1758-phase2-r1-2e.md b/changes/internal/1758-phase2-r1-2e.md index d221ced8e..5d2e17e29 100644 --- a/changes/internal/1758-phase2-r1-2e.md +++ b/changes/internal/1758-phase2-r1-2e.md @@ -1 +1 @@ -Admit int Values in the tensor bridge. +- Admit int Values in the tensor bridge. diff --git a/changes/internal/1758-phase2-r1-2f.md b/changes/internal/1758-phase2-r1-2f.md index dcb1efa6e..86ee604b2 100644 --- a/changes/internal/1758-phase2-r1-2f.md +++ b/changes/internal/1758-phase2-r1-2f.md @@ -1 +1 @@ -Admit int Values in the buffer bridge. +- Admit int Values in the buffer bridge. diff --git a/changes/internal/1758-phase2-r1-2g.md b/changes/internal/1758-phase2-r1-2g.md index 794a33863..6b3fa6ff2 100644 --- a/changes/internal/1758-phase2-r1-2g.md +++ b/changes/internal/1758-phase2-r1-2g.md @@ -1 +1 @@ -Admit int Values in the host bridge. +- Admit int Values in the host bridge. diff --git a/changes/internal/1758-phase2-r1-2j.md b/changes/internal/1758-phase2-r1-2j.md index acff4f0be..e8b1ff545 100644 --- a/changes/internal/1758-phase2-r1-2j.md +++ b/changes/internal/1758-phase2-r1-2j.md @@ -1 +1 @@ -Migrate the JIT float guards and standalone emitter stub. +- Migrate the JIT float guards and standalone emitter stub. diff --git a/changes/internal/1758-phase2-r1-2k.md b/changes/internal/1758-phase2-r1-2k.md index 3a5e9c6f0..7347aed5b 100644 --- a/changes/internal/1758-phase2-r1-2k.md +++ b/changes/internal/1758-phase2-r1-2k.md @@ -1 +1 @@ -Give constant deduplication and disassembly exact int arms. +- Give constant deduplication and disassembly exact int arms. diff --git a/changes/internal/1758-phase2-r1-2l.md b/changes/internal/1758-phase2-r1-2l.md index 6db0d0627..2df619c1d 100644 --- a/changes/internal/1758-phase2-r1-2l.md +++ b/changes/internal/1758-phase2-r1-2l.md @@ -1 +1 @@ -Migrate float tape tokens and retain the v7 int refusal. +- Migrate float tape tokens and retain the v7 int refusal. diff --git a/changes/internal/1758-phase2-r1-2m.md b/changes/internal/1758-phase2-r1-2m.md index 236ba0e89..4f95853f5 100644 --- a/changes/internal/1758-phase2-r1-2m.md +++ b/changes/internal/1758-phase2-r1-2m.md @@ -1 +1 @@ -Migrate the store encoder and numeric bridge. +- Migrate the store encoder and numeric bridge. diff --git a/changes/internal/1758-phase2-r1-2n.md b/changes/internal/1758-phase2-r1-2n.md index e62a5f6a9..efe359c6f 100644 --- a/changes/internal/1758-phase2-r1-2n.md +++ b/changes/internal/1758-phase2-r1-2n.md @@ -1 +1 @@ -Admit int Values in the embedding number bridge. +- Admit int Values in the embedding number bridge. diff --git a/changes/internal/1758-phase2-r1-2o.md b/changes/internal/1758-phase2-r1-2o.md index 9d6044561..03a4e6dfd 100644 --- a/changes/internal/1758-phase2-r1-2o.md +++ b/changes/internal/1758-phase2-r1-2o.md @@ -1 +1 @@ -Migrate extension numeric guards and exact database int encoding. +- Migrate extension numeric guards and exact database int encoding. diff --git a/changes/internal/1758-phase2-r1-2q.md b/changes/internal/1758-phase2-r1-2q.md index 869f6fcee..fc7b0b0d0 100644 --- a/changes/internal/1758-phase2-r1-2q.md +++ b/changes/internal/1758-phase2-r1-2q.md @@ -1 +1 @@ -Finish the VM Value number migration: exact int readers and explicit uncatchable refusals for arithmetic and iterator state whose semantics land in R1.3. +- Finish the VM Value number migration: exact int readers and explicit uncatchable refusals for arithmetic and iterator state whose semantics land in R1.3. diff --git a/changes/internal/1758-phase2-r1-2z.md b/changes/internal/1758-phase2-r1-2z.md index 83f4e11ce..f1245c940 100644 --- a/changes/internal/1758-phase2-r1-2z.md +++ b/changes/internal/1758-phase2-r1-2z.md @@ -1 +1 @@ -Remove the transitional Value numeric aliases after migrating all consumers; retain the number bridge until R1.6. +- Remove the transitional Value numeric aliases after migrating all consumers; retain the number bridge until R1.6. diff --git a/changes/internal/1758-phase2-value-builtins.md b/changes/internal/1758-phase2-value-builtins.md index 02c899951..238d39493 100644 --- a/changes/internal/1758-phase2-value-builtins.md +++ b/changes/internal/1758-phase2-value-builtins.md @@ -1 +1 @@ -Prepare builtin number guards for both Value kinds while retaining the double bridge; preserve exact integer text and numeric sort keys for the future int producer. +- Prepare builtin number guards for both Value kinds while retaining the double bridge; preserve exact integer text and numeric sort keys for the future int producer. diff --git a/changes/internal/1758-phase2-value-gfx.md b/changes/internal/1758-phase2-value-gfx.md index 9f8cbb7b1..ec1618500 100644 --- a/changes/internal/1758-phase2-value-gfx.md +++ b/changes/internal/1758-phase2-value-gfx.md @@ -1 +1 @@ -Prepare graphics and audio numeric guards to admit ints through the unchanged bridge. Pin the audio corpus program to SDL's dummy driver so inherited disk audio settings cannot create sdlaudio.raw in the source tree. +- Prepare graphics and audio numeric guards to admit ints through the unchanged bridge. Pin the audio corpus program to SDL's dummy driver so inherited disk audio settings cannot create sdlaudio.raw in the source tree. diff --git a/changes/internal/1758-phase2-value-readers.md b/changes/internal/1758-phase2-value-readers.md index 5a3a9274d..7e88004bc 100644 --- a/changes/internal/1758-phase2-value-readers.md +++ b/changes/internal/1758-phase2-value-readers.md @@ -1 +1 @@ -Complete the allocation-free int readers: SMI type and Value views preserve VAL_INT and exact digits, and slot_int_value extracts boxed int64 values without converting through double. +- Complete the allocation-free int readers: SMI type and Value views preserve VAL_INT and exact digits, and slot_int_value extracts boxed int64 values without converting through double. From 84ec0f28ca61406812f93b5e73976660177c3fd8 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 18:28:27 -0500 Subject: [PATCH 047/188] phase2: schedule the completed exact readers at their first reachable round (#1758) Retain exact int comparisons and JSON text reads. Move N2.sort-exact to R1.3, when int literals first reach its comparator. Document json_path reader readiness separately from its R1.6 decoder. Float text still waits for R1.7. Principle: No silent wrong answers. Validation: MAP plan items=22 rows=116 shaped=35 arms=20 covered=20; R1.2=0 R1.3=44 R1.6=17; no plan errors. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 43 ++++++++++++++++++++++++----------- tests/phase2/MAP.md | 3 ++- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 179b56f70..a2d504322 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -882,8 +882,9 @@ its family, `buf_num_arg`, `make_num`/`make_num_permanent`, the container `buffer_read_num`. Through R1.5 they keep exactly today's meaning: a number read is a double (an int converts, as every number already is on the tag), a number produced is a float. R1.6 deletes the bridge, so every builtin site -stops compiling in the commit that gives it its §6 semantics. R1.2 touches -no builtin's behaviour. +stops compiling in the commit that gives it its §6 semantics. R1.2 changes no reachable builtin behaviour: no int exists yet. Its exact +sort and JSON text reader arms are the explicit exceptions to the bridge +policy below; they retain final int semantics instead of converting to double. | commit | meaning change | token change in that commit | a missed site | |---|---|---|---| @@ -901,7 +902,7 @@ no builtin's behaviour. catches a miss: - **R1.3, the int arms written in R1.1 and R1.2 go live.** They were forced then and written with their final semantics while no int could reach them. - Gate: R1.3's 42 MAP rows and the C slot test; and the int-source check + Gate: R1.3's 44 MAP rows and the C slot test; and the int-source check (§8) proves nothing before R1.3 could produce an int, so nothing earlier could have exercised an unfinished arm. The R1.1 arms that could not be final (`unwired`, 2.5) are token-forced instead: R1.3 deletes @@ -1255,7 +1256,19 @@ exactly as an int. That is the path the bar critic found missing: payload (§2.6). (Byte consumers, which truncated and wrapped modulo 256 here in round 0, are int-requiring under Q1.) -**The `loss` column.** `LOSS` marks a builtin whose *current* body reads its +**Exact readers completed in R1.2.** `sort` and `sort_by` compare int +values and numeric keys exactly, and `json_build` and `json_path` format an +int as exact digits. These final semantics are retained: rounding through +the double bridge would lose information above 2^53 (principle 2, No silent +wrong answers). The sort comparators and `json_build` become reachable with +R1.3's first int literals, so MAP `N2.sort-exact` is R1.3. `json_path`'s +reader is ready too; its parser still starts producing integer values in +R1.6. Float formatting stays on its existing path until R1.7, and the +remaining builtin readers keep the bridge until R1.6. + +**The `loss` column.** This records the original inventory tree's risk, +rather than remaining work in R1.2; the completed readers above retain their +historical marks. `LOSS` marks a builtin whose inventoried body reads its argument through a double accessor, or builds its result from a computed double, on a path where its class needs an exact int. An int beyond 2^53 would then come out silently wrong if the body were kept and its accessor @@ -1441,10 +1454,10 @@ current state behind several rows: | `index_of` | int-preserving | - | - | byte index or -1 | | `inflate` | int-requiring | - | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone) | | `join` | other | - | - | elements via value_to_string (N6) | -| `json_build` | other | LOSS | - | N14 encoder; reads values through eigs_num_arg (a double) | +| `json_build` | other | LOSS | - | N14 encoder; exact int text arm written in R1.2, live from R1.3; float text stays on the bridge until R1.7 | | `json_decode` | other | LOSS | - | N14 decoder; integer text decodes through strtod (a double) | | `json_encode` | other | LOSS | - | N13/N14 encoder; reads values through eigs_num_arg; its `default:` writes null (builtins.c:998) | -| `json_path` | other | LOSS | - | decodes with strtod, then formats (N14, N6) | +| `json_path` | other | LOSS | - | exact int text reader written in R1.2; decoder int production remains R1.6, float text R1.7 (N14, N6) | | `leaky_relu` | float-producing | - | - | ML activation (float tensors; no Lua counterpart) | | `len` | int-preserving | - | - | count (Lua `#` is an integer) | | `list_contains` | other | - | - | equality via values_equal (N2) | @@ -1519,8 +1532,8 @@ current state behind several rows: | `sign_extend` | int-requiring | LOSS | - | `(int64_t)` of a double | | `sin` | float-producing | - | - | Lua math.sin | | `softmax` | float-producing | - | - | ML (float) | -| `sort` | other | LOSS | - | sort_cmp_num compares doubles: ints beyond 2^53 tie (N2 needs exact); from R2.2 floats sort by IEEE totalOrder, NaN after +inf (Q8) | -| `sort_by` | other | LOSS | - | key results compared as doubles; from R2.2 by IEEE totalOrder, NaN after +inf (Q8) | +| `sort` | other | LOSS | - | exact int comparator written in R1.2, live from R1.3 (N2.sort-exact); from R2.2 floats sort by IEEE totalOrder, NaN after +inf (Q8) | +| `sort_by` | other | LOSS | - | numeric key kind retained for exact comparison in R1.2, live from R1.3; from R2.2 by IEEE totalOrder, NaN after +inf (Q8) | | `spawn` | int-preserving | - | - | handle dict with int id/gen fields | | `sqrt` | float-producing | - | - | Lua math.sqrt; sqrt of -1 is NaN (N11) | | `state_at` | int-requiring | - | - | step index | @@ -1867,7 +1880,7 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: | the tape | R1.3: v7 writer and parser | ints as digits, floats marked as floats; a v6 tape is refused | | the JIT | nothing to convert: its guards bail on an SMI or a `VAL_INT` box (§4.1), and its scanner refuses `OP_INT_*` | interpreted | | the leaf evaluator | R1.1 (its arithmetic and index arms bail) | the generic path computes it | -| builtins | the bridge (R1.2's number tests admit ints) | a double, exactly as the tag sees every number, until R1.6 | +| builtins | R1.2's number tests admit ints; most readers retain the bridge | a double until R1.6, except the exact `sort`/`sort_by` comparators and `json_build` text reader (§6); `json_path`'s exact text reader is also complete, awaiting decoder int production in R1.6 | | JSON, store and db encoders | R1.2a (their `VAL_INT` arms) | exact digits | | the embed API (`eigs_value_as_num`) | R1.2 (its forced `VAL_NUM` test) | converts to a double (Q3) | | lint and the LSP | R1.3 (the AST payload rename) | the literal's kind | @@ -1901,8 +1914,10 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: silently. - R1.2b-n: one commit per file group. Each forced site gets its final int arm (dead until R1.3), and a builtin's number test admits an int - and reads it through the bridge (§2.7). The bridge's names are NOT - touched: no builtin's behaviour changes. 464 sites first forced. + and normally reads it through the bridge (§2.7). The exact sorting and + JSON text readers are completed here (§6), to avoid a later lossy + conversion. The bridge's names are NOT touched; no behaviour changes + before ints exist. 464 sites first forced. - R1.2z: delete the deprecated aliases. A straggler fails to compile. - Gates (a mechanical round, zero MAP rows): the compile errors; the differential over the suite's `.eigs` corpus (identical to the @@ -1915,6 +1930,8 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: CASEs; the JIT and leaf scanners refuse them by their `default:`); `make_int` is introduced. `OP_NUM_ZERO`/`OP_NUM_ONE`/`OP_CONST` keep their float meaning in all three executors. + - The exact `sort`/`sort_by` comparators and `json_build` reader written + in R1.2 go live; `N2.sort-exact` is checked here, not R1.6 (§6). - N3 with (A), N2's exact cross-kind comparison, N4b `-x`, N7 `num_type`; EQ/NE's only bit fast path is "both SMI" (§2.1). - The JIT scanner refuses `BAND`/`BOR`/`BXOR`/`SHL`/`SHR`/`BNOT`/`MOD`. @@ -2154,10 +2171,10 @@ failing on zero rows: |---|---:|---| | R1.1 | 0 | mechanical: the compile errors (223 sites), the C slot test (§2.5; `examined` equals the derived classifier count), plant 1, the int-source check, and the differential over the suite's `.eigs` corpus | | R1.2 | 0 | mechanical: the compile errors (464 sites), the int-source check, and the differential over the suite's `.eigs` corpus (behaviour-preserving) | -| R1.3 | 43 | | +| R1.3 | 44 | | | R1.4 | 6 | | | R1.5 | 7 | | -| R1.6 | 18 | `gate.N5.q7-readers`, and the per-builtin behaviour table (§9.4) | +| R1.6 | 17 | `gate.N5.q7-readers`, and the per-builtin behaviour table (§9.4) | | R1.7 | 12 | `gate.N14.db-param-exact` | | R1.8 | 0 | `gate.N7.embed-int` (the embed smoke test), the executed doc fences (suite [89]/[90]), the LSP and lint suite sections | | R2.1 | 0 | mechanical: the C slot test's NaN-payload rows and plant 2 (no program can make a NaN before R2.2) | diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 33b51130d..6693c107d 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -168,9 +168,10 @@ gates (design §9.2). - `N2.membership-exact` [R1.3] `print of [list_contains of [[9007199254740993], 9007199254740992.0], list_index_of of [[1, 9007199254740993], 9007199254740992.0]]` -> `[false, -1]` tag: `[true, 1]` (read: everything is a double) -- `N2.sort-exact` [R1.6] `print of (sort of [9007199254740993, 9007199254740992, -1])` +- `N2.sort-exact` [R1.3] `print of (sort of [9007199254740993, 9007199254740992, -1])` -> `[-1, 9007199254740992, 9007199254740993]` tag: the literal rounds, so `[-1, 9007199254740992, 9007199254740992]` (probed main, same shape) + round: R1.2 wrote the exact int comparator; the first int literals make it live in R1.3. - `N2.fn-exact-compare` [R1.3] `define lt(a, b) as: t is a < b / return t`, called 60 times with `[9007199254740992, 9007199254740993]`; print the last result -> `true` tag: `false` (probed main) From baaa40f5a208b0bbcfc85e4d35d6a26e22c6faae Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 18:28:27 -0500 Subject: [PATCH 048/188] phase2: record the three reader arms completed in R1.2i (#1758) Align sections 2.5 and 8: slot_type, slot_view and the boxed slot_int_value arm are done. Only allocation and tape placeholders remain for R1.3. Verified against commit 7038423c and current definitions; no runtime change. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index a2d504322..7ff04e3a0 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -592,11 +592,12 @@ result).** - **A fifth disposition, `unwired`.** Some D1 arms need what R1.1 does not have: an int Value (`make_int`, R1.3), the int ValType (R1.2a), or tape v7 (R1.3). Each calls `eigs_int_unwired(who, bits)`, which aborts naming the - reader. R1.3 deletes `eigs_int_unwired`, so each one stops compiling in the - commit that makes ints reachable (2.7). They are `slot_to_value` (the one + reader. R1.2 completed `slot_type` and `slot_view` when `VAL_INT` + became available; it also completed `slot_int_value`'s boxed reader. + R1.3 deletes `eigs_int_unwired`, so the remaining arms in this group stop + compiling in the commit that makes ints reachable (2.7): `slot_to_value` (the one place that boxes an SMI: the lifts, `slot_bridge_unwrap`, `eigs_slot_box` - and the `*_get_return` readers route there), `slot_type`, `slot_view`, - `write_slot`, and `slot_from_int`'s out-of-range arm (the `VAL_INT` box). + and the `*_get_return` readers route there), `write_slot`, and `slot_from_int`'s out-of-range arm (the `VAL_INT` box). - **The permanent refusals** (`refuse`) go through `eigs_slot_refuse(who, slot)`, which prints the bits and aborts; `slot_as_ptr` refuses a non-heap slot under ASan and `-DEIGS_SLOT_CHECKED`. Readers that used to turn an @@ -661,8 +662,11 @@ result).** scan's stderr was read as two classifiers). The Python runs with `-W error`. - **"The int's Value"** cannot be checked in R1.1: no int Value kind exists, - so `slot_to_value` and the readers that route to it are ABORT rows until - R1.3 turns them into RETURN rows. + so allocating readers were ABORT rows. R1.2 turned `slot_type` and `slot_view` into RETURN rows as scheduled + with the Value type (the R1.2i follow-up completed them). Their boxed + companion `slot_int_value` was completed in the same follow-up. + `slot_to_value` and the readers that allocate an int Value remain ABORT + rows until R1.3 introduces `make_int`. | name | disposition | what an int (an SMI) does there, as of R1.1 | @@ -1918,6 +1922,10 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: JSON text readers are completed here (§6), to avoid a later lossy conversion. The bridge's names are NOT touched; no behaviour changes before ints exist. 464 sites first forced. + - The three reader arms scheduled with the Value kind are complete in + R1.2i: `slot_type` types an SMI, `slot_view` exposes an exact int + facade, and `slot_int_value` extracts a boxed int. None produces an + int; R1.3 does not implement these arms a second time. - R1.2z: delete the deprecated aliases. A straggler fails to compile. - Gates (a mechanical round, zero MAP rows): the compile errors; the differential over the suite's `.eigs` corpus (identical to the @@ -1938,7 +1946,8 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: - **Tape v7 in this commit**: a v6 writer would print `3` for both kinds and replay would turn ints into floats. The float token marks its kind now (`3.0`); N6's repr replaces it in R1.7, still inside v7. - - `eigs_int_unwired` is deleted: `slot_to_value` boxes an SMI with + - The remaining `eigs_int_unwired` placeholders are deleted, including: + `slot_to_value` boxes an SMI with `make_int`, `write_slot` writes v7 digits, and `slot_from_int` boxes an int outside the SMI range (each R1.1 placeholder, 2.5). - The observer routes an SMI and a boxed int into the numeric channel From 56eaaaf876f658e0e6b7e92ba712cbcc39da55f6 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 18:28:27 -0500 Subject: [PATCH 049/188] phase2: state the reviewed builtin raw-read exceptions (#1758) Replace the contradicted blanket ban with the narrow reasons already enforced by the allowlist: exact kind/text readers, an int refusal and a sentinel write. Argument coercion still uses checked readers; exact token counts remain mandatory. Validation: num-read: examined=197 functions=81 allowlisted=81 violations=0 stale=0; PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tools/num_read_allowlist.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index f8d525c35..c944bbda1 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -1,10 +1,15 @@ # tools/num_read_allowlist.txt -- every raw number token, reviewed (#1637 round 4). -# file|function|count|reason. tools/num_read_check.sh counts VAL_F64_RAW / +# file|function|count|reason. tools/num_read_check.sh counts VAL_F64_RAW / VAL_I64_RAW / # SLOT_F64_RAW / VAL_F64_OFFSET tokens per function and fails when a count # differs (a new raw read, however it is spelled across lines, changes the # count), when a function with raw tokens is missing here, or a row is stale. -# Builtins never belong here: they read through eigs_num_arg / eigs_list_num / -# eigs_opt_num / eigs_elem_num, which raise on a bool. +# Ordinary builtin argument reads use eigs_num_arg / eigs_list_num / +# eigs_opt_num / eigs_elem_num, which raise on a bool. The explicitly reviewed +# exceptions below preserve a numeric kind or exact int text (JSON and sorting), +# name an unwired int refusal (dispatch), or write a typed sentinel (matmul). +# A double bridge would lose int digits in the exact readers; each raw payload +# read is behind its own kind test. Exceptions still need exact per-function +# token counts and reasons; they do not exempt ordinary argument coercion. builtins_tensor.c|builtin_tensor_matmul|1|writes the NaN-boxed null sentinel into a result buffer cell (EIGS_STRICT=0 path); a write, no Value is read builtins.c|eigs_json_encode_value|1|JSON encoder: case VAL_INT writes the int's exact digits (#1758 R1.2a) container.h|dict_value_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) @@ -36,8 +41,8 @@ eigenscript.c|slot_from_value|2|NaN-boxing boundary, inside its VAL_FLOAT branch eigenscript.c|slot_to_value|1|NaN-boxing boundary after slot_is_f64 eigenscript.c|values_equal_impl|8|equality: the int/float pair by eigs_cmp_int_float (N2), each read inside its own type test; switch case VAL_FLOAT and case VAL_INT (both ints) eigenscript.c|value_to_string|2|printing, switch case VAL_FLOAT and case VAL_INT (exact digits) -eigenscript.h|#define VAL_F64_OFFSET|1|the raw double member offset definition (JIT; #1758 R1.2a: was VAL_F64_OFFSET) -eigenscript.h|#define VAL_F64_RAW|1|the raw double read definition (#1758 R1.2a: was VAL_F64_RAW) +eigenscript.h|#define VAL_F64_OFFSET|1|the raw double member offset definition (JIT; #1758 R1.2a: was VAL_NUM_OFFSET) +eigenscript.h|#define VAL_F64_RAW|1|the raw double read definition (#1758 R1.2a: was VAL_NUM_RAW) eigenscript.h|#define VAL_I64_RAW|1|the raw int64 read definition (#1758 R1.2a) eigenscript.h|eigs_num_arg|1|inline fast path of the checking accessor: reads only after type == VAL_FLOAT eigs_embed.c|eigs_value_as_num|2|embedding API: reads only after type == VAL_FLOAT; a bool answers NaN and other non-numbers 0.0 (docs/EMBEDDING.md) From c045259a26e40ab25c86a54fc5f901327ed664ea Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 18:28:27 -0500 Subject: [PATCH 050/188] docs: name float and int Values in architecture, concurrency and trace (#1758) Replace retired VAL_NUM vocabulary. Record the float-only freelist and the explicit channel int-copy placeholder, rather than promising an int producer before R1.3. Checked against free_value, chan_clone_rec and the read_bytes_buf tape path; no VAL_NUM remains in these three docs. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/ARCHITECTURE.md | 5 +++-- docs/CONCURRENCY.md | 9 +++++---- docs/TRACE.md | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 1ed1c2d6f..e3f3ae785 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -202,9 +202,10 @@ EigenScript uses reference counting plus numeric and environment freelists. (`__ATOMIC_RELAXED` increment, `__ATOMIC_ACQ_REL` decrement). When the refcount reaches zero, `free_value` tears down the value and its children. -**Numeric freelist.** Freed `VAL_NUM` values are placed in a per-thread +**Numeric freelist.** Freed `VAL_FLOAT` values are placed in a per-thread freelist (up to 4096 entries) and reused by `make_num`, avoiding -malloc/free churn in arithmetic-heavy loops. +malloc/free churn in arithmetic-heavy loops. `VAL_INT` boxes are freed +directly; immediate floats and SMIs need no heap reference count. **Environment freelist.** Freed `Env` structs are cached per-thread (up to 1024 entries) and reused by `env_new`, avoiding allocation in tight diff --git a/docs/CONCURRENCY.md b/docs/CONCURRENCY.md index 5e0133c58..47f24d559 100644 --- a/docs/CONCURRENCY.md +++ b/docs/CONCURRENCY.md @@ -164,10 +164,11 @@ depth-64 tail SHARES **The rows the table cannot construct in three lines, and why they behave the way they do.** `chan_clone_rec` (src/eigenscript.c) switches on `ValType` with no `default:`, so `-Werror=switch` forces every new type to choose a side; the -switch handles each type explicitly: `VAL_NUM`, `VAL_NULL`, `VAL_STR`, -`VAL_LIST`, `VAL_DICT`, `VAL_BUFFER`, and `VAL_TEXT_BUILDER` are rebuilt +switch handles each type explicitly: `VAL_FLOAT`, `VAL_NULL`, `VAL_STR`, +`VAL_LIST`, `VAL_DICT`, `VAL_BUFFER`, `VAL_BOOL`, and `VAL_TEXT_BUILDER` are rebuilt (copy), while `VAL_FN` and `VAL_BUILTIN` take a refcount -(share). +(share). `VAL_INT` has an explicit refusal until R1.3 supplies `make_int` +for a fresh exact copy; R1.2 has no program-visible int producer. A new `ValType` must choose a side in the switch for the compiler to accept it. The copy is recursive but not an identity-preserving graph copy: two references to one list or dict become two independent copies. At recursion depth 65 @@ -175,7 +176,7 @@ to one list or dict become two independent copies. At recursion depth 65 bound C-stack use. The final two executable rows pin both limits explicitly. Two kinds are not in the table: `null` and a builtin have no mutable state, so there is nothing to observe. And a **store handle** and a **thread handle** behave exactly like the channel row: they are -`VAL_NUM` ids into the process handle table (CLAUDE.md, leak tally), so the +`VAL_FLOAT` ids into the process handle table (CLAUDE.md, leak tally), so the NUMBER copies while the resource it names is shared — which is why the channel row says SHARES even though a number copies. diff --git a/docs/TRACE.md b/docs/TRACE.md index 390f31184..876e548ef 100644 --- a/docs/TRACE.md +++ b/docs/TRACE.md @@ -221,7 +221,7 @@ perspective lands on the tape as an `N` record: served and the directory is **not** created a second time — replay does not re-run the side effect, the same rule as the subprocess/audio boundary. `read_bytes_buf`'s over-cap **raise** (#601) also rides the tape: the - observed file size is recorded as a `VAL_NUM` `N` record (unambiguous — + observed file size is recorded as a `VAL_FLOAT` `N` record (unambiguous — success records a `VAL_BUFFER`, open-failure records null) and the identical `io` error is re-derived from it under `EIGS_REPLAY`, so an over-cap failure replays byte-identically with no live fs access From e8b78e9e9f34feac7d9441c618c197cf855d873d Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 18:28:27 -0500 Subject: [PATCH 051/188] phase2: restore float hot-path cost and gate the complete CodSpeed set (#1758) Read iterator metadata once through the checked float reader; take each existing int refusal only after that read fails. Borrow the reference-valued iterable without an unused numeric facade, restore inline index validation and reference acquisition, and let valid float views exit before int checks. Keep the exact int readers, refusal identities, ownership and sort-key layout. Derive the cost workloads from codspeed.yml, align that list with every tracked bench/*.eigs and tests/bench_*.eigs file, and reject missing/stale or unsupported commands. Run both VM tiers with a declared +0.3% Ir ceiling. Use the machine's graphics-only corpus ceiling without limiting thread stacks. Principles: Checks are anchored outside the system, narrow, and few; It runs on a small machine. Validation: full cost before a49ebe58: 15 workloads, 30 rows, 17 OVER, rc=1; after: 15 workloads, 30 rows, 0 OVER, rc=0. Every corrected delta is negative. Config plants: 3/3 red; CodSpeed self-test 7/7 and live targets 19/19. Graphics-ceiling probe: old setting assertion failed, new setting passed; nongraphics thread control: REF/OBS spawned=255 raises=45 joined=255. -O0/-O1/-O2: make rc=0, warnings=0 each. Full release 4289/4289; full ASan with detect_leaks=1: 4281/4281, leak tally=0. JIT: 258 programs, OBS 647, 32 adjudicated, 2 ledgered. Replay: 258, boundary 21, nondeterministic 0, ledgered 1. Strict: 156 off-identical, 252/252 valid rows unchanged; typed controls 139 examined, 130 passed, 9 unavailable, 0 failed; pixels 37 identical, 23 strict raises. Phase 2 through R1.2: PASS; both baseline corpora examined=458 diff=0 undeclared=0 incomplete=0. Slot matrix 33 sites, 165 calls, 396 cells, failures=0. Inventory 2012/2012; raw tokens 195, functions 80, violations 0. Intflow: 341 scenarios x 3 tiers x 3 modes, no result/exit changes or new crashes; separate C checks 409/409. Changelog check rc=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/internal/1758-phase2-cost.md | 2 + codspeed.yml | 30 +- docs/design/phase2-inventory.txt | 623 +++++++++++++-------------- docs/design/phase2-numbers.md | 3 +- src/container.h | 24 +- src/eigenscript.h | 3 +- src/vm.c | 74 ++-- tools/codspeed_targets_check.sh | 2 +- tools/num_read_allowlist.txt | 1 - tools/phase2_corpus_diff.sh | 6 +- tools/phase2_cost.sh | 91 ++++ 11 files changed, 491 insertions(+), 368 deletions(-) create mode 100644 changes/internal/1758-phase2-cost.md create mode 100755 tools/phase2_cost.sh diff --git a/changes/internal/1758-phase2-cost.md b/changes/internal/1758-phase2-cost.md new file mode 100644 index 000000000..7afaeaff2 --- /dev/null +++ b/changes/internal/1758-phase2-cost.md @@ -0,0 +1,2 @@ +- Keep float iterator exits ahead of int refusals and retain inlined index validation and reference acquisition; measure the CodSpeed workload list in both execution tiers (#1758). +- Apply the machine's graphics-only memory ceiling in the Phase 2 corpus comparison without limiting thread-stack reservations (#1758). diff --git a/codspeed.yml b/codspeed.yml index de283159a..55ac58585 100644 --- a/codspeed.yml +++ b/codspeed.yml @@ -24,13 +24,13 @@ # make && codspeed run -m simulation --cycle-estimation=false # every target # (CLI 5.3.1 has no per-target selector; the ids exist for the report only) # -# Workloads: bench/*.eigs are the five Ir-gate workloads; the three tests/ -# benches are the JIT's own shapes (CLAUDE.md "Benchmarks"), dmg_shape being -# the consumer stand-in for the DMG emulator's hot loop. +# In-repo workloads: every bench/*.eigs and tests/bench_*.eigs file. +# tools/phase2_cost.sh reads this same set and measures each in both tiers. +# dmg_shape is the consumer stand-in for the DMG emulator's hot loop. $schema: https://raw.githubusercontent.com/CodSpeedHQ/codspeed/refs/heads/main/schemas/codspeed.schema.json benchmarks: - # --- the five Ir-gate workloads (bench/) --- + # --- the Ir-gate workloads (bench/) --- - name: "scalar_loop" id: scalar-loop exec: ./src/eigenscript bench/scalar_loop.eigs @@ -50,7 +50,17 @@ benchmarks: id: unobserved-armed-loop exec: ./src/eigenscript bench/unobserved_armed_loop.eigs - # --- the JIT's own shapes (tests/) --- + - name: "alloc_heavy" + id: alloc-heavy + exec: ./src/eigenscript bench/alloc_heavy.eigs + - name: "conservative_observed_loop" + id: conservative-observed-loop + exec: ./src/eigenscript bench/conservative_observed_loop.eigs + - name: "conservative_unobserved_loop" + id: conservative-unobserved-loop + exec: ./src/eigenscript bench/conservative_unobserved_loop.eigs + + # --- runtime and JIT workloads (tests/) --- - name: "bench_perf" id: bench-perf exec: ./src/eigenscript tests/bench_perf.eigs @@ -61,6 +71,16 @@ benchmarks: id: idxset exec: ./src/eigenscript tests/bench_idxset.eigs + - name: "bench_buf_mix" + id: buf-mix + exec: ./src/eigenscript tests/bench_buf_mix.eigs + - name: "bench_buf_resample" + id: buf-resample + exec: ./src/eigenscript tests/bench_buf_resample.eigs + - name: "bench_pcm_codec" + id: pcm-codec + exec: ./src/eigenscript tests/bench_pcm_codec.eigs + # --- a REAL consumer: the DMG Game Boy emulator running Blargg's cpu_instrs --- # The in-repo dmg_shape bench flatters the JIT ~10x against the emulator it # names (measured 2026-09-21 under cachegrind: JIT removes 48% of the diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 7c4736e63..4e24a2f3d 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,11 +1,11 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2016 classified=2016 unclassified=0 +examined=2012 classified=2012 unclassified=0 files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 517 CASE=60 DATA=4 TEST=450 YIELD=3 -(b) payload reads 544 RAW=118 READ=426 +(a) type tests 513 CASE=60 DATA=4 TEST=446 YIELD=3 +(b) payload reads 544 RAW=116 READ=428 (c) producers 472 GUARD=71 PARSE=3 PRODUCE=371 TAGSET=4 WRITE=23 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 20 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=7 @@ -19,24 +19,24 @@ files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 make_num 363 val_is_number 174 eigs_num_arg 161 -VAL_FLOAT 160 VAL_INT 159 +VAL_FLOAT 156 eigs_list_num 130 SLOT_F64_RAW 83 -VAL_F64_RAW 67 +VAL_F64_RAW 66 num_guard 60 AST_NUM 52 -eigs_slot_num 50 slot_is_f64 50 eigs_value_as_num 48 -VAL_I64_RAW 43 +eigs_slot_num 47 +VAL_I64_RAW 42 slot_from_f64 41 buffer_read_num 37 slot_is_smi 29 buffer_read_byte 22 list_set_num 22 +slot_f64_value 20 slot_smi_val 18 -slot_f64_value 16 strtod 16 NUM_REUSE 15 eigs_slot_opt_num 12 @@ -58,18 +58,18 @@ eigs_elem_num 2 f64_ 2 list_append_num 2 make_num_permanent 2 +slot_int_value 2 atof 1 d_ 1 dict_value_get_num 1 dict_value_set_num 1 i64_ 1 list_get_num 1 -slot_int_value 1 data.num (AST) 7 ## Per file (category counts) builtins.c 346 a=81 b=103 c=111 e=6 f=13 h=21 i=11 -vm.c 304 a=89 b=88 c=67 e=2 f=8 i=50 +vm.c 300 a=85 b=88 c=67 e=2 f=8 i=50 ext_gfx.c 298 a=104 b=124 c=70 builtins_tensor.c 200 a=55 b=59 c=86 eigenscript.c 120 a=22 b=17 c=13 e=7 f=18 i=43 @@ -188,7 +188,7 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=56 D2=19 D3=26 T=67 dispositions=101 missing=0 stale=0 +D1=58 D2=18 D3=26 T=66 dispositions=102 missing=0 stale=0 D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 @@ -222,6 +222,7 @@ D1 vm.c:#define READ_SLICE_BOUND smi-arm slot_as_ptr=1 slo D1 vm.c:jit_helper_dot_set guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:jit_helper_index_get guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 D1 vm.c:jit_helper_index_set guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 +D1 vm.c:jit_helper_iter_next unwired slot_as_ptr=1 slot_f64_value=2 slot_int_value=1 slot_is_ptr=1 slot_type=2 D1 vm.c:jit_helper_local_dot_set guarded slot_is_f64=1 D1 vm.c:loop_iter_store guarded slot_is_f64=1 D1 vm.c:obs_dump_scope smi-arm slot_as_ptr=3 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=3 slot_is_smi=1 slot_smi_val=1 @@ -239,6 +240,7 @@ D1 vm.c:vm_run_ex/CASE(DOT_SET) guarded slot_as_ptr=1 slo D1 vm.c:vm_run_ex/CASE(EQ) guarded slot_f64_value=2 D1 vm.c:vm_run_ex/CASE(INDEX_GET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(INDEX_SET) guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 +D1 vm.c:vm_run_ex/CASE(ITER_NEXT) unwired slot_f64_value=2 slot_type=2 D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(NE) guarded slot_f64_value=2 @@ -255,7 +257,6 @@ D2 eigenscript.c:env_get_local_hashed guarded slot_as_ptr=1 slo D2 eigenscript.c:gc_collect_at_exit guarded slot_as_ptr=1 slot_is_ptr=1 D2 value_slot.h:#define slot_as_heap refuse slot_as_heap=1 slot_as_ptr=1 D2 value_slot.h:slot_as_ptr refuse SLOT_PAYLOAD_MASK=1 slot_as_ptr=1 slot_is_heap=1 -D2 vm.c:jit_helper_iter_next guarded list_elem_type=2 slot_as_ptr=1 slot_is_ptr=1 D2 vm.c:obs_slot_value guarded slot_as_ptr=1 slot_is_bool=1 D2 vm.c:vm_borrow_scan guarded slot_as_ptr=2 slot_is_heap=2 D2 vm.c:vm_builtin_name_for guarded slot_as_ptr=1 slot_is_heap=1 @@ -1326,51 +1327,51 @@ container.h:162 eigs_slot_opt_num slot_smi_val RAW b container.h:163 eigs_slot_opt_num val_is_number TEST a container.h:164 eigs_slot_opt_num eigs_num_arg READ b container.h:166 eigs_slot_opt_num eigs_num_arg_slow READ b -container.h:175 slot_view slot_is_smi TEST a -container.h:176 slot_view VAL_INT TAGSET c -container.h:177 slot_view VAL_I64_RAW WRITE c -container.h:177 slot_view slot_smi_val RAW b -container.h:182 slot_view VAL_FLOAT TEST a -container.h:182 slot_view slot_is_f64 TEST a -container.h:183 slot_view VAL_FLOAT TAGSET c -container.h:184 slot_view SLOT_F64_RAW RAW b -container.h:184 slot_view VAL_F64_RAW WRITE c -container.h:184 slot_view slot_is_f64 TEST a -container.h:185 slot_view eigs_num_arg READ b -container.h:196 eigs_view_check VAL_FLOAT TEST a -container.h:196 eigs_view_check VAL_INT TEST a -container.h:223 list_get_return slot_is_smi TEST a -container.h:224 list_get_return SLOT_F64_RAW RAW b -container.h:224 list_get_return make_num PRODUCE c -container.h:224 list_get_return slot_is_f64 TEST a -container.h:231 dict_value_get_return slot_is_smi TEST a -container.h:232 dict_value_get_return SLOT_F64_RAW RAW b -container.h:232 dict_value_get_return make_num PRODUCE c -container.h:232 dict_value_get_return slot_is_f64 TEST a -container.h:262 eigs_slot_box SLOT_F64_RAW RAW b -container.h:262 eigs_slot_box make_num PRODUCE c -container.h:262 eigs_slot_box num_guard GUARD c -container.h:262 eigs_slot_box slot_is_f64 TEST a -container.h:263 eigs_slot_box slot_is_smi TEST a -container.h:285 list_set_num list_set_num PRODUCE c -container.h:286 list_set_num list_rewrite_num PRODUCE c -container.h:286 list_set_num num_guard GUARD c -container.h:288 list_append_num list_append_num PRODUCE c -container.h:289 list_append_num num_guard GUARD c -container.h:291 list_append_num slot_from_f64 PRODUCE c -container.h:293 dict_value_set_num dict_value_set_num PRODUCE c -container.h:294 dict_value_set_num dict_value_rewrite_num PRODUCE c -container.h:294 dict_value_set_num num_guard GUARD c -container.h:323 list_get_num list_get_num READ b -container.h:325 list_get_num slot_is_smi TEST a -container.h:325 list_get_num slot_smi_val RAW b -container.h:326 list_get_num slot_is_f64 TEST a -container.h:327 list_get_num SLOT_F64_RAW RAW b -container.h:330 dict_value_get_num dict_value_get_num READ b -container.h:332 dict_value_get_num slot_is_smi TEST a -container.h:332 dict_value_get_num slot_smi_val RAW b -container.h:333 dict_value_get_num slot_is_f64 TEST a -container.h:334 dict_value_get_num SLOT_F64_RAW RAW b +container.h:176 slot_view slot_is_f64 TEST a +container.h:177 slot_view slot_is_smi TEST a +container.h:178 slot_view VAL_INT TAGSET c +container.h:179 slot_view VAL_I64_RAW WRITE c +container.h:179 slot_view slot_smi_val RAW b +container.h:184 slot_view VAL_FLOAT TEST a +container.h:186 slot_view VAL_FLOAT TAGSET c +container.h:187 slot_view SLOT_F64_RAW RAW b +container.h:187 slot_view VAL_F64_RAW WRITE c +container.h:187 slot_view slot_is_f64 TEST a +container.h:188 slot_view eigs_num_arg READ b +container.h:201 eigs_view_check VAL_FLOAT TEST a +container.h:201 eigs_view_check VAL_INT TEST a +container.h:227 list_get_return slot_is_smi TEST a +container.h:228 list_get_return SLOT_F64_RAW RAW b +container.h:228 list_get_return make_num PRODUCE c +container.h:228 list_get_return slot_is_f64 TEST a +container.h:235 dict_value_get_return slot_is_smi TEST a +container.h:236 dict_value_get_return SLOT_F64_RAW RAW b +container.h:236 dict_value_get_return make_num PRODUCE c +container.h:236 dict_value_get_return slot_is_f64 TEST a +container.h:266 eigs_slot_box SLOT_F64_RAW RAW b +container.h:266 eigs_slot_box make_num PRODUCE c +container.h:266 eigs_slot_box num_guard GUARD c +container.h:266 eigs_slot_box slot_is_f64 TEST a +container.h:267 eigs_slot_box slot_is_smi TEST a +container.h:289 list_set_num list_set_num PRODUCE c +container.h:290 list_set_num list_rewrite_num PRODUCE c +container.h:290 list_set_num num_guard GUARD c +container.h:292 list_append_num list_append_num PRODUCE c +container.h:293 list_append_num num_guard GUARD c +container.h:295 list_append_num slot_from_f64 PRODUCE c +container.h:297 dict_value_set_num dict_value_set_num PRODUCE c +container.h:298 dict_value_set_num dict_value_rewrite_num PRODUCE c +container.h:298 dict_value_set_num num_guard GUARD c +container.h:327 list_get_num list_get_num READ b +container.h:329 list_get_num slot_is_smi TEST a +container.h:329 list_get_num slot_smi_val RAW b +container.h:330 list_get_num slot_is_f64 TEST a +container.h:331 list_get_num SLOT_F64_RAW RAW b +container.h:334 dict_value_get_num dict_value_get_num READ b +container.h:336 dict_value_get_num slot_is_smi TEST a +container.h:336 dict_value_get_num slot_smi_val RAW b +container.h:337 dict_value_get_num slot_is_f64 TEST a +container.h:338 dict_value_get_num SLOT_F64_RAW RAW b eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a eigenscript.c:309 val_type_name VAL_FLOAT CASE a @@ -1531,7 +1532,7 @@ eigenscript.h:1917 buffer_read_byte buffer_read_num READ b eigenscript.h:1919 buffer_read_byte finite_num_to_byte READ b eigenscript.h:1930 num_guard_named num_guard_named GUARD c eigenscript.h:1936 num_guard_named num_guard GUARD c -eigenscript.h:2248 eigs_num_text FORMAT e +eigenscript.h:2249 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j @@ -2283,264 +2284,260 @@ vm.c:1649 obs_slot_num SLOT_F64_RAW RAW i vm.c:1649 obs_slot_num slot_is_f64 TEST i vm.c:1650 obs_slot_num slot_is_smi TEST i vm.c:1650 obs_slot_num slot_smi_val RAW i -vm.c:1797 jit_helper_iter_next VAL_INT TEST a -vm.c:1799 jit_helper_iter_next VAL_FLOAT TEST a -vm.c:1800 jit_helper_iter_next eigs_slot_num READ b -vm.c:1810 jit_helper_iter_next VAL_INT TEST a -vm.c:1811 jit_helper_iter_next VAL_I64_RAW RAW b -vm.c:1812 jit_helper_iter_next VAL_FLOAT TEST a -vm.c:1813 jit_helper_iter_next VAL_F64_RAW RAW b -vm.c:1820 jit_helper_iter_next buffer_read_num READ b -vm.c:1820 jit_helper_iter_next num_guard GUARD c -vm.c:1820 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1826 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1896 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b -vm.c:1896 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1900 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1903 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1942 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1956 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1956 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:1967 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1968 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1986 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:1986 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2069 loop_iter_store make_num PRODUCE c -vm.c:2076 loop_iter_store slot_is_f64 TEST a -vm.c:2077 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2082 loop_iter_store make_num PRODUCE c -vm.c:2200 vm_value_index_is_int VAL_INT TEST a -vm.c:2201 vm_value_index_is_int VAL_I64_RAW RAW b -vm.c:2206 vm_value_index_is_int VAL_F64_RAW RAW b -vm.c:2219 jit_helper_index_set slot_is_f64 TEST a -vm.c:2224 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2225 jit_helper_index_set slot_is_f64 TEST a +vm.c:1798 jit_helper_iter_next slot_f64_value READ b +vm.c:1799 jit_helper_iter_next VAL_INT TEST a +vm.c:1814 jit_helper_iter_next slot_f64_value READ b +vm.c:1817 jit_helper_iter_next VAL_INT TEST a +vm.c:1819 jit_helper_iter_next slot_int_value READ b +vm.c:1826 jit_helper_iter_next buffer_read_num READ b +vm.c:1826 jit_helper_iter_next num_guard GUARD c +vm.c:1826 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1832 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1902 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b +vm.c:1902 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1906 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1909 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1948 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:1962 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1962 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:1973 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1974 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:1992 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:1992 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2075 loop_iter_store make_num PRODUCE c +vm.c:2082 loop_iter_store slot_is_f64 TEST a +vm.c:2083 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2088 loop_iter_store make_num PRODUCE c +vm.c:2203 vm_value_index_is_int VAL_INT TEST a +vm.c:2204 vm_value_index_is_int VAL_I64_RAW RAW b +vm.c:2209 vm_value_index_is_int VAL_F64_RAW RAW b +vm.c:2222 jit_helper_index_set slot_is_f64 TEST a vm.c:2227 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2229 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2239 jit_helper_index_set slot_is_f64 TEST a -vm.c:2241 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2242 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2228 jit_helper_index_set slot_is_f64 TEST a +vm.c:2230 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2232 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2242 jit_helper_index_set slot_is_f64 TEST a vm.c:2244 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2256 jit_helper_index_set val_is_number TEST a -vm.c:2259 jit_helper_index_set eigs_num_arg READ b -vm.c:2266 jit_helper_index_set val_is_number TEST a -vm.c:2269 jit_helper_index_set eigs_num_arg READ b -vm.c:2272 jit_helper_index_set val_is_number TEST a -vm.c:2273 jit_helper_index_set eigs_num_arg READ b -vm.c:2292 jit_helper_index_get slot_is_f64 TEST a -vm.c:2294 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2301 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2312 jit_helper_index_get buffer_read_num READ b -vm.c:2314 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2316 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2332 jit_helper_index_get val_is_number TEST a -vm.c:2335 jit_helper_index_get eigs_num_arg READ b -vm.c:2347 jit_helper_index_get val_is_number TEST a -vm.c:2350 jit_helper_index_get eigs_num_arg READ b -vm.c:2359 jit_helper_index_get val_is_number TEST a -vm.c:2362 jit_helper_index_get eigs_num_arg READ b -vm.c:2364 jit_helper_index_get buffer_read_num READ b -vm.c:2364 jit_helper_index_get make_num PRODUCE c -vm.c:2950 vm_take_error_value make_num PRODUCE c -vm.c:3054 slot_type_name slot_is_f64 TEST e -vm.c:3055 slot_type_name slot_is_smi TEST e -vm.c:3295 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a -vm.c:3296 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b -vm.c:3296 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3310 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3315 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3335 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3335 #define NUM_REUSE VAL_FLOAT TEST a -vm.c:3346 #define ARITH_FAST slot_f64_value READ b -vm.c:3346 #define ARITH_FAST slot_f64_value READ b -vm.c:3347 #define ARITH_FAST num_guard GUARD c -vm.c:3352 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3353 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3361 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3362 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3370 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3380 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3380 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3381 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3381 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3381 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3382 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3382 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3383 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3383 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3384 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3407 vm_run_ex/CASE(ADD) VAL_INT TEST a -vm.c:3407 vm_run_ex/CASE(ADD) VAL_INT TEST a -vm.c:3435 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3435 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3436 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3436 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3436 #define NUM_BINOP num_guard GUARD c -vm.c:3437 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3437 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3439 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3439 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3440 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3440 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3441 #define NUM_BINOP make_num PRODUCE c -vm.c:3443 #define NUM_BINOP VAL_INT TEST a -vm.c:3443 #define NUM_BINOP VAL_INT TEST a -vm.c:3447 #define NUM_BINOP make_num PRODUCE c -vm.c:3465 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a -vm.c:3465 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a -vm.c:3466 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3468 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3470 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3470 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3470 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:2245 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2247 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2259 jit_helper_index_set val_is_number TEST a +vm.c:2262 jit_helper_index_set eigs_num_arg READ b +vm.c:2269 jit_helper_index_set val_is_number TEST a +vm.c:2272 jit_helper_index_set eigs_num_arg READ b +vm.c:2275 jit_helper_index_set val_is_number TEST a +vm.c:2276 jit_helper_index_set eigs_num_arg READ b +vm.c:2295 jit_helper_index_get slot_is_f64 TEST a +vm.c:2297 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2304 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2315 jit_helper_index_get buffer_read_num READ b +vm.c:2317 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2319 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2335 jit_helper_index_get val_is_number TEST a +vm.c:2338 jit_helper_index_get eigs_num_arg READ b +vm.c:2350 jit_helper_index_get val_is_number TEST a +vm.c:2353 jit_helper_index_get eigs_num_arg READ b +vm.c:2362 jit_helper_index_get val_is_number TEST a +vm.c:2365 jit_helper_index_get eigs_num_arg READ b +vm.c:2367 jit_helper_index_get buffer_read_num READ b +vm.c:2367 jit_helper_index_get make_num PRODUCE c +vm.c:2953 vm_take_error_value make_num PRODUCE c +vm.c:3057 slot_type_name slot_is_f64 TEST e +vm.c:3058 slot_type_name slot_is_smi TEST e +vm.c:3298 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3299 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3299 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3313 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3318 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3338 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3338 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3349 #define ARITH_FAST slot_f64_value READ b +vm.c:3349 #define ARITH_FAST slot_f64_value READ b +vm.c:3350 #define ARITH_FAST num_guard GUARD c +vm.c:3355 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3356 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3364 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3365 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3373 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3383 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3383 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3384 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3384 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3384 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3385 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3385 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3386 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3386 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3387 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3410 vm_run_ex/CASE(ADD) VAL_INT TEST a +vm.c:3410 vm_run_ex/CASE(ADD) VAL_INT TEST a +vm.c:3438 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3438 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3439 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3439 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3439 #define NUM_BINOP num_guard GUARD c +vm.c:3440 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3440 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3442 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3442 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3443 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3443 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3444 #define NUM_BINOP make_num PRODUCE c +vm.c:3446 #define NUM_BINOP VAL_INT TEST a +vm.c:3446 #define NUM_BINOP VAL_INT TEST a +vm.c:3450 #define NUM_BINOP make_num PRODUCE c +vm.c:3468 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a +vm.c:3468 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a +vm.c:3469 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b +vm.c:3471 vm_run_ex/CASE(DIV) make_num PRODUCE c vm.c:3473 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3475 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3475 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3476 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3476 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3477 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3480 vm_run_ex/CASE(DIV) VAL_INT TEST a -vm.c:3480 vm_run_ex/CASE(DIV) VAL_INT TEST a -vm.c:3484 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3492 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b -vm.c:3492 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3492 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3493 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b -vm.c:3493 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b -vm.c:3493 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3494 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3494 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3495 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3495 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3496 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3498 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3498 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3500 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3500 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3505 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3528 #define INT_BINOP_R slot_f64_value READ b -vm.c:3528 #define INT_BINOP_R slot_f64_value READ b -vm.c:3530 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3531 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3473 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b +vm.c:3473 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3476 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b +vm.c:3478 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3478 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3479 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3479 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3480 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3483 vm_run_ex/CASE(DIV) VAL_INT TEST a +vm.c:3483 vm_run_ex/CASE(DIV) VAL_INT TEST a +vm.c:3487 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3495 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b +vm.c:3495 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3495 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3496 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b +vm.c:3496 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b +vm.c:3496 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3497 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3497 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3498 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3498 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3499 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3501 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3501 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3503 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3503 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a +vm.c:3508 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3531 #define INT_BINOP_R slot_f64_value READ b +vm.c:3531 #define INT_BINOP_R slot_f64_value READ b +vm.c:3533 #define INT_BINOP_R num_to_i64_exact READ b vm.c:3534 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3535 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3542 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3542 #define INT_BINOP_R VAL_F64_RAW WRITE c -vm.c:3546 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3546 #define INT_BINOP_R VAL_F64_RAW WRITE c -vm.c:3549 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3557 #define INT_BINOP_R VAL_INT TEST a -vm.c:3559 #define INT_BINOP_R VAL_INT TEST a -vm.c:3570 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3597 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3600 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3600 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3603 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3608 vm_run_ex/CASE(NEG) VAL_INT TEST a -vm.c:3612 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3627 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3629 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b -vm.c:3632 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3638 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a -vm.c:3638 vm_run_ex/CASE(BNOT) VAL_F64_RAW WRITE c -vm.c:3641 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3646 vm_run_ex/CASE(BNOT) VAL_INT TEST a -vm.c:3653 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3663 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3663 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3684 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3684 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3706 #define NUM_CMP slot_f64_value READ f -vm.c:3706 #define NUM_CMP slot_f64_value READ f -vm.c:3729 #define NUM_CMP VAL_INT TEST f -vm.c:3731 #define NUM_CMP VAL_INT TEST f -vm.c:4648 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4650 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4657 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4667 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4669 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4671 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4693 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4695 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:3537 #define INT_BINOP_R num_to_i64_exact READ b +vm.c:3538 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3545 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3545 #define INT_BINOP_R VAL_F64_RAW WRITE c +vm.c:3549 #define INT_BINOP_R NUM_REUSE TEST a +vm.c:3549 #define INT_BINOP_R VAL_F64_RAW WRITE c +vm.c:3552 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3560 #define INT_BINOP_R VAL_INT TEST a +vm.c:3562 #define INT_BINOP_R VAL_INT TEST a +vm.c:3573 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3600 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3603 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3603 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3606 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3611 vm_run_ex/CASE(NEG) VAL_INT TEST a +vm.c:3615 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3630 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3632 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b +vm.c:3635 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3641 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a +vm.c:3641 vm_run_ex/CASE(BNOT) VAL_F64_RAW WRITE c +vm.c:3644 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3649 vm_run_ex/CASE(BNOT) VAL_INT TEST a +vm.c:3656 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3666 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3666 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3687 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3687 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3709 #define NUM_CMP slot_f64_value READ f +vm.c:3709 #define NUM_CMP slot_f64_value READ f +vm.c:3732 #define NUM_CMP VAL_INT TEST f +vm.c:3734 #define NUM_CMP VAL_INT TEST f +vm.c:4651 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4653 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4660 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4670 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4672 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4674 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b vm.c:4696 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a vm.c:4698 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4700 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4710 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4712 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4712 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4714 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4726 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4729 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4736 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4739 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4742 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4743 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4799 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4802 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4863 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4864 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4890 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4890 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:4996 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:4997 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5042 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a -vm.c:5045 vm_run_ex/CASE(ITER_NEXT) VAL_FLOAT TEST a -vm.c:5051 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5058 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a -vm.c:5061 vm_run_ex/CASE(ITER_NEXT) VAL_FLOAT TEST a -vm.c:5062 vm_run_ex/CASE(ITER_NEXT) eigs_slot_num READ b -vm.c:5075 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5079 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5079 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5419 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5420 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5421 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5455 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5456 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5457 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5521 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5522 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5522 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5522 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5526 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5527 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5528 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5529 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5533 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5547 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5548 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5549 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5570 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5596 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5599 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5600 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5603 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5619 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5630 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5635 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5655 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5656 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5657 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5658 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5788 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5788 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5805 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5806 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5808 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5815 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5819 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5822 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5823 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5826 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5837 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5840 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6434 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6435 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6436 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6439 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6449 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6450 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6452 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6456 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:4699 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4701 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4703 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4713 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4715 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4715 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4717 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4729 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4732 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4739 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4742 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4745 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4746 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4802 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4805 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4866 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4867 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4893 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4893 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:4999 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5000 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5050 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b +vm.c:5051 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a +vm.c:5067 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b +vm.c:5070 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a +vm.c:5084 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5088 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5088 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5427 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5428 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5429 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5463 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5464 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5465 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5529 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5530 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5530 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5530 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5534 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5535 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5536 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5537 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5541 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5555 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5556 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5557 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5558 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5578 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5604 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5607 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5608 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5611 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5635 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5638 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5663 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5664 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5665 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5666 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5796 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5796 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5813 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5814 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5816 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5823 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5827 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5830 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5831 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5834 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5845 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5848 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6442 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6443 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6444 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6447 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6457 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6458 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6460 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6464 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 7ff04e3a0..8ebd403fd 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -736,7 +736,7 @@ result).** | `vm.c:jit_helper_dot_set` | guarded | an int value skips the immediate store: the slow path pops it through `slot_bridge_unwrap` (D1) | | `vm.c:jit_helper_index_get` | guarded | an int index skips the fast path: the slow path lifts it through `slot_to_value` (D1) | | `vm.c:jit_helper_index_set` | guarded | an int index or value skips the fast path: the slow path pops it through `slot_bridge_unwrap` (D1) | -| `vm.c:jit_helper_iter_next` | guarded | a non-pointer state slot returns 1 (bail); its index-kind test `!= VAL_NUM` is compile-forced (D2) | +| `vm.c:jit_helper_iter_next` | unwired | float-first index and snapshot readers; an int takes the existing R1.3 refusal only after the float reader fails; a non-pointer state returns 1 (D1) | | `vm.c:jit_helper_local_dot_set` | guarded | an int value skips the immediate store: `vm_slot_lift` boxes it (D1) | | `vm.c:jit_helper_local_idx_dot_get` | guarded | as `jit_helper_dot_get` (D3) | | `vm.c:loop_iter_store` | guarded | the loop counter is a float the VM makes; a non-float slot takes the `make_num` path (D1) | @@ -772,6 +772,7 @@ result).** | `vm.c:vm_slot_lift` | smi-arm | an int is boxed on purpose through `slot_to_value` (2.1; unwired until R1.3); a reserved tag refuses, where it became null (D1) | | `vm.c:vm_slot_value_opaque` | guarded | only a pointer can be a fn or builtin; an SMI answers "not opaque", which is right (D2) | | `vm.c:vm_store_local_slot` | guarded | an int skips the in-place float store; the generic swap stores the SMI (D1) | +| `vm.c:vm_run_ex/CASE(ITER_NEXT)` | unwired | float-first index and snapshot readers; an int takes the existing R1.3 refusal only after the float reader fails (D1) | ### 2.6 The accessor API after round 1 (Alt 1R) diff --git a/src/container.h b/src/container.h index 0609b3b74..9880553a6 100644 --- a/src/container.h +++ b/src/container.h @@ -26,7 +26,7 @@ static inline EigsSlot eigs_container_slot(Value *v) { if (v->type == VAL_FLOAT) return slot_from_f64(num_guard(VAL_F64_RAW(v))); /* #1758 (design 2.1): container storage is canonical -- a small int is * an SMI, and only an int outside [-2^47, 2^47) stays its box. */ - if (v->type == VAL_INT) { + if (__builtin_expect(v->type == VAL_INT, 0)) { int64_t i = VAL_I64_RAW(v); return (i >= SLOT_SMI_MIN && i <= SLOT_SMI_MAX) ? slot_from_int(i) : slot_from_heap(v); } @@ -172,14 +172,17 @@ static inline int eigs_slot_opt_num(EigsSlot s, double *out, const char *who) { * decrefing a numeric facade: its sentinel refcount must be unchanged. * #1758: an SMI's facade preserves its exact int Value kind. */ static inline Value *slot_view(EigsSlot s, EigsView *view) { - if (slot_is_smi(s)) { - view->v.type = VAL_INT; - VAL_I64_RAW(&view->v) = slot_smi_val(s); - view->v.refcount = EIGS_VIEW_RC; - return &view->v; + /* Float storage exits before any int classification (#1758 cost gate). */ + if (!slot_is_f64(s)) { + if (slot_is_smi(s)) { + view->v.type = VAL_INT; + VAL_I64_RAW(&view->v) = slot_smi_val(s); + view->v.refcount = EIGS_VIEW_RC; + return &view->v; + } + /* A heap VAL_INT is a real Value, returned as itself. */ + if (slot_type(s) != VAL_FLOAT) return eigs_slot_ref(s); } - /* a heap VAL_INT box is a real Value: it is returned as itself */ - if (!slot_is_f64(s) && slot_type(s) != VAL_FLOAT) return eigs_slot_ref(s); view->v.type = VAL_FLOAT; VAL_F64_RAW(&view->v) = slot_is_f64(s) ? SLOT_F64_RAW(s) : eigs_num_arg(slot_as_ptr(s), "slot_view"); @@ -193,8 +196,9 @@ static inline Value *dict_value_get_view(const Value *dict, int i, EigsView *vie return slot_view(dict_value_slot(dict, i), view); } static inline void eigs_view_check(EigsView *view) { - if ((view->v.type == VAL_FLOAT || view->v.type == VAL_INT) && view->v.refcount != 0 && - view->v.refcount != EIGS_VIEW_RC) { + /* A valid facade (or an unused zero view) exits before kind checks. */ + if (view->v.refcount != 0 && view->v.refcount != EIGS_VIEW_RC && + (view->v.type == VAL_FLOAT || view->v.type == VAL_INT)) { fprintf(stderr, "%s:%d: EigenScript FATAL: numeric view refcount moved (%d)\n", __FILE__, __LINE__, view->v.refcount); abort(); diff --git a/src/eigenscript.h b/src/eigenscript.h index fb7d7a891..fc9386211 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -1962,7 +1962,8 @@ static inline double num_guard_named(double x, const char *who) { * inside on GC-enabled / not-collecting / single-threaded. */ void gc_note_possible_root(Value *v); -static inline void val_incref(Value *v) { +/* Keep reference acquisition inline as the numeric slow paths grow (#1758). */ +static inline __attribute__((always_inline)) void val_incref(Value *v) { if (v && v->type != VAL_NULL && v->type != VAL_BOOL) { if (__builtin_expect(g_vm_multithreaded, 0)) __atomic_add_fetch(&v->refcount, 1, __ATOMIC_RELAXED); diff --git a/src/vm.c b/src/vm.c index c0b3519ff..25dd64a58 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1791,13 +1791,17 @@ int jit_helper_iter_next(void) { Value *state = slot_as_ptr(state_slot); if (!state || state->type != VAL_LIST || state->data.list.count < 2) return 1; - EIGS_VIEW(iterable_view); - Value *iterable = list_get_view(state, 0, &iterable_view); + /* Iterables are reference values; a numeric facade cannot be iterable. */ + Value *iterable = list_get_ref(state, 0); + double idx_num; + EigsSlot idx_slot = list_slot(state, 1); + if (!slot_f64_value(idx_slot, &idx_num)) { + if (slot_type(idx_slot) == VAL_INT) + eigs_int_unwired("jit_helper_iter_next index", 0); + return 1; + } + int idx = (int)idx_num; if (!iterable) return 1; - if (list_elem_type(state, 1) == VAL_INT) - eigs_int_unwired("jit_helper_iter_next index", 0); - if (list_elem_type(state, 1) != VAL_FLOAT) return 1; - int idx = (int)eigs_slot_num(list_slot(state, 1), "for"); int len = 0; if (iterable->type == VAL_LIST) len = iterable->data.list.count; else if (iterable->type == VAL_BUFFER) len = iterable->data.buffer.count; @@ -1805,13 +1809,15 @@ int jit_helper_iter_next(void) { /* #491: cap by the entry-time snapshot (items[2]) — see make_iter_state. * Mirrors CASE(ITER_NEXT). */ if (state->data.list.count >= 3) { - EIGS_VIEW(snap_v_view); - Value *snap_v = list_get_view(state, 2, &snap_v_view); - if (snap_v && snap_v->type == VAL_INT) - eigs_int_unwired("jit_helper_iter_next snapshot", (uint64_t)VAL_I64_RAW(snap_v)); - if (snap_v && snap_v->type == VAL_FLOAT) { - int snap = (int)VAL_F64_RAW(snap_v); + EigsSlot snap_slot = list_slot(state, 2); + double snap_num; + if (slot_f64_value(snap_slot, &snap_num)) { + int snap = (int)snap_num; if (snap < len) len = snap; + } else if (slot_type(snap_slot) == VAL_INT) { + int64_t i = 0; + slot_int_value(snap_slot, &i); + eigs_int_unwired("jit_helper_iter_next snapshot", (uint64_t)i); } } if (idx >= len) return 1; @@ -2193,10 +2199,7 @@ int jit_helper_loop_cap_check(void) { /* #1758 R1.2: an int subscript is its exact value in the VM's C-index * domain. Floats keep the existing integrality test. No int exists yet. */ -#if defined(__GNUC__) || defined(__clang__) -__attribute__((noinline)) -#endif -static int vm_value_index_is_int(const Value *v, int *out) { +static inline int vm_value_index_is_int(const Value *v, int *out) { if (v->type == VAL_INT) { int64_t i = VAL_I64_RAW(v); if (i < INT_MIN || i > INT_MAX) return 0; @@ -5038,29 +5041,35 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * but an untrusted chunk (vm_run_bytecode / sandbox_run) can reach a * bare ITER_NEXT with any list on TOS, and reading VAL_F64_RAW() off a * VAL_STR is a type confusion whose result then indexes items[] (#721). */ - if (__builtin_expect(state && state->type == VAL_LIST && state->data.list.count >= 2 && - list_elem_type(state, 1) == VAL_INT, 0)) - eigs_int_unwired("ITER_NEXT index", 0); - if (!state || state->type != VAL_LIST || state->data.list.count < 2 || - list_elem_type(state, 1) != VAL_FLOAT) { + if (!state || state->type != VAL_LIST || state->data.list.count < 2) { + ip += exit_offset; + DISPATCH(); + } + double idx_num; + EigsSlot idx_slot = list_slot(state, 1); + if (!slot_f64_value(idx_slot, &idx_num)) { + if (slot_type(idx_slot) == VAL_INT) + eigs_int_unwired("ITER_NEXT index", 0); ip += exit_offset; DISPATCH(); } - EIGS_VIEW_NOCHECK(iterable_view); - Value *iterable = list_get_view(state, 0, &iterable_view); - int idx = (int)eigs_slot_num(list_slot(state, 1), "for"); + Value *iterable = list_get_ref(state, 0); + int idx = (int)idx_num; int len = 0; - if (iterable->type == VAL_LIST) len = iterable->data.list.count; - else if (iterable->type == VAL_BUFFER) len = iterable->data.buffer.count; + if (iterable && iterable->type == VAL_LIST) len = iterable->data.list.count; + else if (iterable && iterable->type == VAL_BUFFER) len = iterable->data.buffer.count; /* #491: cap by the entry-time snapshot (items[2]) so a body that * appends can't extend the loop; min() with the live length keeps a * remove from reading past the end. See make_iter_state. */ - if (state->data.list.count >= 3 && list_elem_type(state, 2) == VAL_INT) - eigs_int_unwired("ITER_NEXT snapshot", 0); - if (state->data.list.count >= 3 && - list_elem_type(state, 2) == VAL_FLOAT) { - int snap = (int)eigs_slot_num(list_slot(state, 2), "for"); - if (snap < len) len = snap; + if (state->data.list.count >= 3) { + EigsSlot snap_slot = list_slot(state, 2); + double snap_num; + if (slot_f64_value(snap_slot, &snap_num)) { + int snap = (int)snap_num; + if (snap < len) len = snap; + } else if (slot_type(snap_slot) == VAL_INT) { + eigs_int_unwired("ITER_NEXT snapshot", 0); + } } /* Unsigned compare bounds BOTH ends in one branch: a negative index @@ -5082,7 +5091,6 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, vm_push_slot(elem); } } - eigs_view_check(&iterable_view); DISPATCH(); } diff --git a/tools/codspeed_targets_check.sh b/tools/codspeed_targets_check.sh index 438639432..060e7679d 100755 --- a/tools/codspeed_targets_check.sh +++ b/tools/codspeed_targets_check.sh @@ -18,7 +18,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)" CFG="${CODSPEED_CFG:-$ROOT/codspeed.yml}" WF="${CODSPEED_WF:-$ROOT/.github/workflows/codspeed.yml}" -TARGET_COUNT=13 # the set is the claim +TARGET_COUNT=19 # the set is the claim CONSUMER_IDS="dmg-cpu-instrs dmg-cpu-instrs-vm" # the rows a proxy cannot replace CONSUMER_DIR=".codspeed-consumers/DMG" # what the fetch step populates diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index c944bbda1..9526fc263 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -70,7 +70,6 @@ vm.c|#define NUM_BINOP|6|arithmetic after a->type == VAL_FLOAT && b->type == VAL vm.c|jit_helper_dot_set|1|JIT helper: number store after slot_is_f64 vm.c|jit_helper_index_get|3|JIT helper: index read after slot_is_f64 / VAL_FLOAT tests on index and element vm.c|jit_helper_index_set|5|JIT helper: index store after slot_is_f64 / VAL_FLOAT tests on index and value -vm.c|jit_helper_iter_next|2|JIT helper: loop state list [iterable, idx, snap] built by the VM, each read behind a VAL_FLOAT test vm.c|jit_helper_local_dot_set|1|JIT helper: number store after slot_is_f64 vm.c|loop_iter_store|1|writes the loop counter slot after slot_is_f64 vm.c|obs_dump_scope|1|SIGUSR1 observer dump after slot_is_f64 diff --git a/tools/phase2_corpus_diff.sh b/tools/phase2_corpus_diff.sh index ba322a009..1750a2085 100755 --- a/tools/phase2_corpus_diff.sh +++ b/tools/phase2_corpus_diff.sh @@ -67,7 +67,7 @@ # MEMORY. No blanket cap (a 2 GiB `ulimit -v` made handles_full.eigs's 300 # spawns fail at 134-214, which read as nondeterminism -- the R1.1 critic). # Only a file that drives the gfx/ui/audio surface runs under -# `ulimit -v 2097152` (an unbounded GUI run can freeze the 4 GB box); the +# `ulimit -v 1500000` (an unbounded GUI run can freeze the 4 GB box); the # capped files are listed. # # A file only the branch tree has (a new fixture) is counted as `new`; a file @@ -217,7 +217,7 @@ run() { { ( cd "$BR_ROOT/src" || exit 99 - [ "$cap" = 1 ] && ulimit -v 2097152 + [ "$cap" = 1 ] && ulimit -v 1500000 suite_program_run "$rel" env -u XAUTHORITY DISPLAY=:99 SDL_AUDIODRIVER=dummy LD_PRELOAD="$SHIM" \ PHASE2_URANDOM_MARK="$out.urandom" "$extra" timeout 60 "$bin" "../$rel" ) < /dev/null > "$out.rawout" 2> "$out.rawerr" @@ -352,7 +352,7 @@ sed 's/^/NONDET (the baseline disagrees with itself, and its tape replays too) / sed 's/^/BOTH-CRASH-OR-TIMEOUT /' "$TMP/crash" sed 's/^/SAME-NONZERO (declared: both binaries exit so; compared up to the exit) /' "$TMP/samenz" sed 's/^/UNPINNED (opened \/dev\/urandom: random_hex values are live, by design) /' "$TMP/urandom" -sed 's/^/CAPPED (gfx\/ui\/audio: ulimit -v 2097152) /' "$TMP/capped" +sed 's/^/CAPPED (gfx\/ui\/audio: ulimit -v 1500000) /' "$TMP/capped" summary="examined=$examined same=$nsame same_nonzero=$same_nonzero same_under_replay=$nreplay nondet=$nondet diff=$ndiff new=$new deleted=$deleted crash_both=$crash_both timeout_both=$timeout_both conditioned=$conditioned incomplete=$incomplete undeclared=$undeclared stale=$stale ledger_refused=$ledger_bad unpinned=$unpinned capped=$capped" DONE=1 if [ -n "${PHASE2_DIFF_FILES:-}" ]; then diff --git a/tools/phase2_cost.sh b/tools/phase2_cost.sh new file mode 100755 index 000000000..e2cf50a48 --- /dev/null +++ b/tools/phase2_cost.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# Compare release Ir on the in-repo CodSpeed workload set, in BOTH VM tiers. +# The target list has one home: codspeed.yml. Consumer targets live elsewhere. +# Positive deltas above +0.3% fail; above +0.1% need attribution in the review. +set -eu +cd "$(dirname "$0")/.." +exec python3 - "$@" <<'PY' +import os +from pathlib import Path +import re +import shlex +import shutil +import subprocess +import sys +import tempfile + +THRESHOLD_PCT = 0.3 +root = Path.cwd() +if len(sys.argv) != 3: + sys.exit('usage: tools/phase2_cost.sh (from repo root)') +if not shutil.which('valgrind'): + sys.exit('phase2-cost: FAIL: valgrind is required') +bins = [str(Path(p).resolve(strict=True)) for p in sys.argv[1:]] +for binary in bins: + if not os.access(binary, os.X_OK): + sys.exit('phase2-cost: FAIL: not executable: ' + binary) + symbols = subprocess.run(['nm', '-D', binary], capture_output=True, text=True, check=True).stdout + if re.search(r'__(?:asan|ubsan)', symbols): + sys.exit('phase2-cost: FAIL: sanitizer binary: ' + binary) +local_workload = re.compile(r'(?:bench/[^/]+|tests/bench_[^/]+)\.eigs') +workloads = set() +for line in (root / 'codspeed.yml').read_text().splitlines(): + m = re.match(r'\s*exec:\s*(.*)', line) + if not m: + continue + argv = shlex.split(m[1]) + local = [p for p in argv if local_workload.fullmatch(p)] + if local: + if len(local) != 1 or argv[-2:] != ['./src/eigenscript', local[0]]: + sys.exit('phase2-cost: FAIL: unsupported local CodSpeed command: ' + m[1]) + workloads.add(local[0]) +if not workloads: + sys.exit('phase2-cost: FAIL: no in-repo CodSpeed workloads') +# The execution list has one home; tracked sources anchor its coverage. +tracked = subprocess.check_output(['git', 'ls-files', '-z'], cwd=root).decode().split('\0') +expected = {p for p in tracked if local_workload.fullmatch(p)} +if workloads != expected: + sys.exit('phase2-cost: FAIL: CodSpeed workload coverage missing=%s stale=%s' % + (sorted(expected - workloads), sorted(workloads - expected))) +logdir = Path(tempfile.mkdtemp(prefix='phase2-cost-')) +print('phase2-cost: source=codspeed.yml workloads=%d tiers=2 threshold=+%.1f%% logs=%s' % + (len(workloads), THRESHOLD_PCT, logdir), flush=True) +over = 0 +for workload in sorted(workloads): + for tier in ('jit', 'off'): + results = [] + for arm, binary in zip(('base', 'cand'), bins): + prefix = logdir / (workload.replace('/', '_') + '.' + tier + '.' + arm) + env = {k: v for k, v in os.environ.items() if not k.startswith('EIGS_')} + if tier == 'off': + env['EIGS_JIT_OFF'] = '1' + with prefix.with_suffix(prefix.suffix + '.stdout').open('wb') as stdout, \ + prefix.with_suffix(prefix.suffix + '.stderr').open('wb') as stderr: + run = subprocess.run(['valgrind', '--tool=cachegrind', '--cache-sim=no', + '--branch-sim=no', '--cachegrind-out-file=' + str(prefix) + '.cg', + binary, workload], cwd=root, env=env, stdin=subprocess.DEVNULL, + stdout=stdout, stderr=stderr, timeout=900) + if run.returncode: + sys.exit('phase2-cost: FAIL: %s %s %s rc=%d (see %s)' % + (workload, tier, arm, run.returncode, prefix)) + summary = re.findall(r'^summary:\s*(\d+)\s*$', Path(str(prefix) + '.cg').read_text(), re.M) + if len(summary) != 1 or int(summary[0]) <= 0: + sys.exit('phase2-cost: FAIL: missing/ambiguous Ir: ' + str(prefix)) + out = Path(str(prefix) + '.stdout').read_bytes() + # The bench prints elapsed milliseconds; compare every result field. + out = re.sub(rb'\b[0-9]+(?:\.[0-9]+)?ms\b', b'ms', out) + err = Path(str(prefix) + '.stderr').read_text() + err = re.sub(r'^==\d+==.*\n?', '', err, flags=re.M) + results.append((int(summary[0]), out, err)) + (base, out_a, err_a), (cand, out_b, err_b) = results + if (out_a, err_a) != (out_b, err_b): + sys.exit('phase2-cost: FAIL: output differs: %s %s (see %s)' % (workload, tier, logdir)) + delta = 100 * (cand - base) / base + fail = (cand - base) * 100 > THRESHOLD_PCT * base + over += fail + print('%-34s %-3s base=%12d cand=%12d delta=%+.4f%% %s' % + (workload, tier, base, cand, delta, 'OVER' if fail else 'ok'), flush=True) +print('phase2-cost: workloads=%d rows=%d over_0.3pct=%d %s' % + (len(workloads), len(workloads) * 2, over, 'FAIL' if over else 'PASS')) +sys.exit(bool(over)) +PY From 90d20c50a5c9c192f541903d666401c81dcfda99 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 18:28:27 -0500 Subject: [PATCH 052/188] phase2: keep durable verification notes in the number design (#1758) Remove the sandbox handoff report. Record the baseline, complete 15-workload cost table, real gate counts and calibration evidence in design section 12 without private temporary paths. Distinguish historical R1.2 fault checks from this fix round and state the known interactive timeout limitation (#1823). Validation: release 4289/4289, ASan 4281/4281 with leak tally 0; JIT, replay, strict and Phase 2 through R1.2 all green. Both corpus halves: examined=458, diff=0, undeclared=0, incomplete=0. Full cost: 30/30 under the +0.3% ceiling; unfixed control 17/30 over it. All fourteen fragment repairs pass the check. The design retains the actual 341 supplied scenario count and its precise address-only diagnostic normalization, rather than claiming the brief's 389. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 156 +++++++++++++++++- reports/phase2-r12.md | 299 ---------------------------------- 2 files changed, 154 insertions(+), 301 deletions(-) delete mode 100644 reports/phase2-r12.md diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 8ebd403fd..4a9d9aebf 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1,7 +1,9 @@ # Phase 2 numbers (#1758): design (round 0, revised in design rounds 2 and 3) -Status: the last design round before round 1 builds. Nothing here changes -`src/`. Spec: issue #1758 (Revision 1), its owner decisions (A), (B), (C), the +Status: design round 3, with R1.1/R1.2 implementation notes and R1.2 +fix-round verification in §12. The first program-visible int producer +remains R1.3. Inventory and prototype measurements below describe the +original design tree. Spec: issue #1758 (Revision 1), its owner decisions (A), (B), (C), the Q1-Q6 decisions ([comment](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6171744498)) and the Q7-Q8 decisions @@ -71,6 +73,7 @@ Contents: 9. Test plan 10. Lua differential tool 11. Decided questions (Q1-Q8) +12. R1.2 verification notes --- @@ -2623,3 +2626,152 @@ The owner may overrule any of them; until then this design follows them. order here (probed for #1758: Lua's `table.sort` left a list holding NaNs unsorted without an error). Applied: R2.2, when NaN first becomes reachable; rows `N11.sort-total-order` and `N11.min-max-nan`. + + +## 12. R1.2 verification notes + +The fix round merged `origin/main` at `540f0bcf` before measuring. It keeps +`VAL_DICT = 7` after main's removal of `VAL_JSON_RAW`, with `VAL_INT` still +appended. Main's taped `audio_noise` is included: the merged replay gate +reported `258 programs record+replay; 21 at the documented boundary; +0 nondeterministic; 1 ledgered`, confirming the retired `test_audio` row. + +**Float cost.** The former three-probe report missed for-in and boxed-index +costs. `tools/phase2_cost.sh BASE CAND` now derives its in-repo workloads +from `codspeed.yml`, deduplicates tier aliases and measures every workload +with the JIT on and off. The CodSpeed list now includes all tracked +`bench/*.eigs` and `tests/bench_*.eigs` files. A Git-derived coverage check +rejects missing or stale entries; unsupported commands also fail before +measurement. The three planted config faults were rejected (3/3), and the +CodSpeed target check reported 19 declared targets with its 7/7 self-test. The declared regression threshold is +0.3% Ir; +any result above +0.1% needs attribution. A failed program, sanitizer binary, +missing instruction count or different result fails the tool; only printed +elapsed milliseconds are normalized. Logs retain each run's stdout, stderr +and cachegrind data. This is the narrow, externally anchored check required +by principle 5, Checks are anchored outside the system, narrow, and few. + +Same-environment release builds (gcc 13.3.0, default Makefile -O2 flags), +Valgrind 3.26.0.codspeed7, cache simulation disabled. Both columns compare +against the fresh `540f0bcf` build. The unfixed `a49ebe58` binary failed +with `workloads=15 rows=30 over_0.3pct=17 FAIL`; the corrected binary passed +with `workloads=15 rows=30 over_0.3pct=0 PASS`. Every corrected delta is +negative, so no positive delta above +0.1% needs attribution. + +| workload | unfixed JIT | corrected JIT | unfixed interpreter | corrected interpreter | +|---|---:|---:|---:|---:| +| `bench/alloc_heavy.eigs` | -0.7750% | -0.8015% | -1.3411% | -1.3247% | +| `bench/conservative_observed_loop.eigs` | +2.4924% | -1.9758% | +1.2051% | -1.7020% | +| `bench/conservative_unobserved_loop.eigs` | +3.1284% | -2.4944% | +1.3736% | -2.1230% | +| `bench/dict_ops.eigs` | +0.7736% | -0.5208% | +0.7736% | -0.2752% | +| `bench/observed_loop.eigs` | +4.6862% | -3.5071% | +1.7607% | -2.7203% | +| `bench/scalar_loop.eigs` | +4.1131% | -3.1679% | +1.5824% | -2.5250% | +| `bench/string_build.eigs` | +1.0707% | -0.0827% | +0.8484% | -0.0920% | +| `bench/unobserved_armed_loop.eigs` | -0.5739% | -0.5734% | -2.6672% | -2.5973% | +| `bench/unobserved_loop.eigs` | +4.6856% | -3.5065% | +1.7599% | -2.7201% | +| `tests/bench_buf_mix.eigs` | -0.4679% | -0.4750% | -1.3133% | -1.6209% | +| `tests/bench_buf_resample.eigs` | +0.3307% | -0.1916% | -0.6375% | -1.0595% | +| `tests/bench_dmg_shape.eigs` | -0.1762% | -0.1807% | -1.5526% | -1.9744% | +| `tests/bench_idxset.eigs` | +0.2827% | -0.4619% | +0.6823% | -0.5958% | +| `tests/bench_pcm_codec.eigs` | -0.4691% | -0.4698% | -0.8728% | -1.3577% | +| `tests/bench_perf.eigs` | +0.8874% | -0.9616% | -0.1238% | -1.4599% | + +Function counts and disassembly localized the remaining cost after merely +moving the four refusals: numeric views and their cleanup checks still +classified ints on float paths, and iterator metadata was read through +unnecessary facades. The corrected iterator uses the checked float reader +once per metadata slot and borrows its reference-valued iterable directly; +int metadata still reaches the named R1.3 refusal after a failed float read. +`slot_view` and valid-view cleanup now exit before int checks. Index +validation and reference acquisition remain inline. No int producer was +introduced, and the sort-key pair layout was retained. + +**Integer readers and refusals.** The supplied critic harness was rerun over +all 341 supplied scenario blocks, in the interpreter, default JIT and forced +OSR tiers, with float, SMI and boxed-int inputs. Across 6,138 transcript and +exit-status files, results and statuses were unchanged from the critic's +R1.2 binary. The only 198 byte differences were heap addresses in the named +boxed-slot refusal diagnostic; comparisons retained the diagnostic, slot +tag, SIGABRT status and every other output byte. There were no unexpected +crashes. The separate C checks reported `checks=409 fails=0`, including +`sizeof(SortByPair)=16`, union payload offset 0, kind offset 8 and index +offset 12. + +A focused iterator probe used the state `[[42], 0.0, 1.0]`: the two float +controls yielded 42; replacing either metadata slot with an SMI or boxed +int reached its named R1.3 refusal in both executors. Result: +`cases=10 float_controls=2 int_refusals=8 failures=0`. +A separate malformed-iterable differential agreed with the original R1.2 +binary in four JIT-helper cases: two int-index refusals and two snapshot +bails, with no failures. This preserves the helper's early-return order. + +**Earlier gate calibration.** The original R1.2 calibration inserted a +`VAL_NUM` token in `builtin_usleep` (token hits=1 and compile exit 2), +removed the JSON encoder's `VAL_INT` arm (compile exit 2 under +`-Werror=switch`), and removed the boxed `slot_int_value` reader (five +assertion failures). These are historical one-time fault checks, not +additional reruns in this fix round. Restored slot coverage remains +33 sites, 165 calls and 396 matrix cells with no failures. + +**Builds.** Default release builds at -O0, -O1 and -O2 each exited 0 with +zero warnings. The final -O2 rebuild was byte-identical to the measured +candidate (`04c10293ab1b94b92ac5ae56063655038c3b47b8a245ab3d763ca0978682614b`). + +**Completed suites.** Full release: `4289/4289 passed, 0 failed, 9 skipped`. +Full ASan with `detect_leaks=1` and no virtual-memory limit: +`4281/4281 passed, 0 failed, 8 skipped`; LeakSanitizer nonzero-exit +tally 0 and sanitizer error reports 0. Both child-script ledgers reported +0 nonzero exits. `make jit-smoke`: `JIT smoke: all cases passed.` + +**GUI conditions.** An initial native-X11 JIT differential run omitted the +graphics memory cap and reported two extra OBS rows, `ui_canvas_events` +and `ui_dock`. Both examples are among the nine nonterminating GUI +comparisons already tracked by [#1823](https://github.com/InauguralSystems/EigenScript/issues/1823). +A focused check on fresh main and the candidate used X11 and dummy SDL, +REF and OBS, and a 1,500,000 KiB virtual-memory cap: all 16 runs agreed +with empty output and exit 124. These are timeout agreements, not completed +GUI comparisons. The existing ledger was retained. + +A process-wide 1,500,000 KiB JIT cap changed `handles_full` on both main +and the candidate: uncapped REF/OBS each reported `spawned=255 raises=45`, +while the blanket cap caused variable earlier spawn failures. The final +JIT/replay invocations therefore apply the existing corpus graphics-source +selector to each program, exec the same release binary, and leave nongraphics +thread fixtures uncapped. Strict graphics checks use their existing child +limit. The corpus graphics ceiling is now 1,500,000 KiB too; a restricted +real-VM probe failed its ceiling assertion at the previous 2 GiB setting +and passed at the machine setting (1/1 capped program), with the expected +restricted exit 3 in both calibration runs. The temporary probes were removed. + +**JIT differential.** With graphics-only caps and dummy SDL, the unchanged +ledger passed: `258 programs x {jit, osr} vs the interpreter; suite-env +completed=15; OBS examined=647 denied=12; 32 arms adjudicated; 2 ledgered`. +The nine interactive timeout agreements in #1823 remain a coverage limitation. + +**Replay differential.** The unchanged fidelity ledger passed under the same +graphics-only resource policy: `258 programs record+replay; 21 at the +documented boundary; 0 nondeterministic; 1 ledgered`. + +**Strict differential.** The real-X11 gate passed. Typed fixed-shape +controls: `declared=139 examined=139 passed=130 failed=0 unavailable=9 +backend_absent=0 pending=0 unrun=0`. All 37 pixel rows were identical with +strict mode off; the 23 wrong-input pixel rows all raised under strict +mode, with silent=0 and misattributed=0. + +**Candidate corpus.** Against fresh main, the full corpus comparison reported +`examined=458 same=452 same_nonzero=42 same_under_replay=4 nondet=1 diff=0 +new=14 deleted=0 crash_both=0 timeout_both=1 conditioned=15 incomplete=0 +undeclared=0 stale=0 ledger_refused=0 unpinned=1 capped=13` and PASS. +The 11 newly merged deliberate-error fixtures account for the increase +from the earlier 31 declared nonzero results to 42. + +**Final Phase 2 gate.** `phase2_check.sh --through R1.2` used the fresh +main baseline and a separately built SMI-trap binary. The trap corpus +reported the same full 458-file summary as the candidate corpus, including +`diff=0 incomplete=0 undeclared=0 stale=0` and 13 graphics-only caps. +Both corpus halves passed; `mechanical smi-trap: PASS` and +`phase2-check: PASS`. The retired-token scan reported `tokens=9 files=90 +hits=0`; inventory `examined=2012 classified=2012 unclassified=0`; int +source `make_int_defs=0 outside_writers=0`; slot matrix +`examined=33 calls=165 matrix_cells=396 arm_rows=32 failures=0`. +The changelog fragment check exited 0 after all fourteen malformed fragment +bullets were repaired. No push or CI run is claimed by these local results. diff --git a/reports/phase2-r12.md b/reports/phase2-r12.md deleted file mode 100644 index 2cb5b6620..000000000 --- a/reports/phase2-r12.md +++ /dev/null @@ -1,299 +0,0 @@ -# Phase 2 R1.2 Value layer report - -Implementation is committed in the isolated Git metadata used by this sandbox. -The full release, sanitizer, differential, and Phase 2 gates are green. - -## Summary - -All runtime and C-fixture aliases are migrated. Int consumers either have -their final reader arm or abort through the R1.3 unwired token. The number -bridge names remain. No `make_int` or int-producing opcode exists. - -The sandbox makes the worktree common Git metadata read-only. -`/tmp/phase2-r12/git.sh` commits this worktree through isolated metadata; -`/tmp/phase2-r12/commits.bundle` contains the series from `46617422`. -The orchestrator can import with `git fetch /tmp/phase2-r12/commits.bundle -phase2-numbers` then `git reset --mixed FETCH_HEAD` (updates branch/index; -keeps working files). No push or main merge was performed. - -## Commits - -Counts are deprecated code-token inventory sites; the C fixtures are outside -that source inventory. The runtime total is 370; fixtures add 28. - -| Round | Commit | File group | Sites | -|---|---|---|---:| -| R1.2d | `40ef2d84` | builtins.c | 85 | -| R1.2e | `10849e60` | builtins_tensor.c | 39 | -| R1.2f | `f28b94b0` | builtins_buf.c | 21 | -| R1.2g | `f9e711df` | builtins_host.c | 11 | -| R1.2h | `2fb9b5e2` | ext_gfx.c; audio policy | 56 | -| R1.2i | `7038423c` | container/value-slot reader arms | 0 | -| R1.2j | `3f1ff968` | jit.c, jit_smoke.c | 10 | -| R1.2k | `a0f66387` | chunk.c | 11 | -| R1.2l | `6640b3d5` | trace.c | 6 | -| R1.2m | `d5ff982c` | ext_store.c | 14 | -| R1.2n | `23262614` | eigs_embed.c | 4 | -| R1.2o | `1a2c4e44` | network/HTTP/database/model | 11 | -| R1.2p | `1822df24` | seven C test fixtures | 28 | -| R1.2q | `14471e2f` | vm.c | 97 | -| R1.2z | `ce66ede5` | alias definitions and final cleanup | 5 | -| R1.2r | `664c28d5` | P4 calibration templates (4 spellings) | 0 | -| R1.2s | `7e5662d0` | strict shape fingerprints (39 rows) | 0 | -| R1.2t | `95ce2fed` | bool renderer probe (1 expectation) | 0 | -| R1.2u | `0b6d9673` | sanitizer renderer note and inert timeout control | 0 | -| R1.2v | `7ade7cc7` | retire stale audio replay fixture ledger row | 0 | -| R1.2w | this report | verification report and handoff | 0 | - -The reader follow-up additionally completes three int arms. Each group was -built while landing it, and all twenty implementation/tooling commits were -then independently rebuilt from their committed trees, serially. The report -commit also gets a default build. Logs are in `/tmp/phase2-r12/logs`. -Every commit carries the requested Claude trailers. - -## Cost - -Default release gcc -O2: GCC 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1), -Valgrind 3.26.0.codspeed7. Same DMG source/ROM and float program for every arm. -DMG export: `afd9bd52778cb0a8d1ab0473ec726aaae556fb90`, all 19 runtime -EigenScript/ROM files checked against its Git blobs, zero mismatches. -ROM SHA256: `8c5e12f41e0ba5bbca796944f92ffe6de28809198682c4332e38d1b3cf56fcf2`. -Float program SHA256: `67a1dc2f7db8ae581c58f0c781c21de3037e8f6b3d8a14f63ee5ee4e12e88fe6`. - -Commands (all serial; `BINARY` is the independently built baseline or candidate): - -Baseline binary: `/tmp/phase2-r12/baseline/src/eigenscript`; final candidate: -`/home/jon/src/wt/es-phase2/src/eigenscript`. - -```sh -cd /tmp/phase2-r11-critic2/DMG -valgrind --tool=callgrind BINARY dmg.eigs roms/cpu_instrs.gb --cycles 500000 -cd /tmp/phase2-r12 -valgrind --tool=callgrind BINARY float_loop.eigs -EIGS_JIT_OFF=1 valgrind --tool=callgrind BINARY float_loop.eigs -``` - -The float loop runs 200,000 iterations. Source/build inputs for baseline -`46617422`, corpus oracle `0740af03`, and tag `v0.46.0` were checked against -150 Git blobs each, all with zero mismatches. No binary copies were used. - -| Candidate | DMG 500K Ir | Float JIT Ir | Float interpreter Ir | Verdict | -|---|---:|---:|---:|---| -| baseline | 1,195,422,765 (+0.000000%) | 172,214,775 (+0.000000%) | 364,233,396 (+0.000000%) | baseline | -| vmrename | 1,195,320,483 (-0.008556%) | 172,216,054 (+0.000743%) | 364,235,224 (+0.000502%) | rename control | -| vm1 | 1,193,790,787 (-0.136519%) | 172,190,897 (-0.013865%) | 363,235,041 (-0.274098%) | rejected | -| vm2 | 1,193,798,401 (-0.135882%) | 172,191,010 (-0.013800%) | 363,235,208 (-0.274052%) | rejected | -| vm3 | 1,198,112,295 (+0.224986%) | 172,276,017 (+0.035561%) | 366,635,271 (+0.659433%) | rejected | -| vm4 | 1,199,112,814 (+0.308682%) | 172,276,017 (+0.035561%) | 366,635,271 (+0.659433%) | rejected | -| vm5 | 1,193,848,621 (-0.131681%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | -| vm6 | 1,200,113,794 (+0.392416%) | 172,306,061 (+0.053007%) | 367,835,319 (+0.988905%) | rejected | -| vm7 | 1,192,778,866 (-0.221169%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | -| vm8 | 1,194,010,544 (-0.118136%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | -| vm9 | 1,197,353,964 (+0.161549%) | 172,246,061 (+0.018167%) | 365,435,313 (+0.329985%) | rejected | -| vm10 | 1,193,839,891 (-0.132411%) | 172,191,053 (-0.013775%) | 363,235,205 (-0.274053%) | rejected | -| vm11 | 1,195,567,598 (+0.012116%) | 172,251,028 (+0.021051%) | 365,635,216 (+0.384869%) | rejected | -| vm12 | 1,193,533,071 (-0.158077%) | 172,190,961 (-0.013828%) | 363,235,170 (-0.274062%) | rejected | -| vm13 | 1,200,115,350 (+0.392546%) | 172,271,887 (+0.033163%) | 366,435,423 (+0.604565%) | rejected | -| vm14 | 1,197,839,406 (+0.202158%) | 172,276,879 (+0.036062%) | 366,635,321 (+0.659447%) | rejected | -| vm15 | 1,196,101,881 (+0.056810%) | 172,226,927 (+0.007056%) | 364,635,287 (+0.110339%) | rejected | -| vm16 | 1,197,057,949 (+0.136787%) | 172,226,919 (+0.007052%) | 364,635,279 (+0.110337%) | rejected | -| vm17 | 1,200,722,940 (+0.443372%) | 172,281,935 (+0.038998%) | 366,835,395 (+0.714377%) | rejected | -| vm18 | 1,194,707,923 (-0.059798%) | 172,216,927 (+0.001250%) | 364,235,286 (+0.000519%) | PASS | -| final | 1,194,717,491 (-0.058998%) | 172,216,927 (+0.001250%) | 364,235,286 (+0.000519%) | PASS | - -Candidate 18 is the committed VM. Final reruns it after alias deletion and -restoring the old sort-key pair footprint. All three final deltas fit -±0.1%; stdout matches the baseline (DMG Time/Speed lines omitted). -The same callgrind brk-segment note appears on baseline and candidates; -each completed normally and reported its instruction count. - -## Plants - -- A `VAL_NUM` straggler in actual `builtin_usleep`: token gate `hits=1`; - `make build/release/builtins.o` exits 2, undeclared identifier. Restored: - `tokens: rounds<=R1.2 tokens=9 files=90 hits=0`. -- Remove the JSON encoder's `VAL_INT` arm: actual make exits 2 with - `VAL_INT not handled in switch [-Werror=switch]`. All 17 Value-type - switches enumerate all 12 types, with no default. -- Remove the boxed `slot_int_value` reader: actual slot gate exits 1 with - five assertion failures and no build-warning witness. Restored: - `examined=33 calls=165 matrix_cells=396 arm_rows=32 failures=0`. - -- P4 calibration templates: both stale anchors had zero matches. After the - four token spellings were migrated, all 13 build/static anchors match once. - Official planted builder plus restricted corpus: control 2/2 same; mutant - 2/2 DIFF with `slot_from_int under EIGS_SMI_TRAP` observed. -- The strict renderer probe expected `1`, while a real capped X11 call to - `gfx_open` prints `true`. Temporary `gfx_read` fault flips a red bit at - (31,31): old checker exits 0 and skips pixels; fixed checker exits 1 with - 37/37 pixel rows differing. Restore exact C source and rebuild: 37/37 - identical, differing=0, final `OK`. Existing capture self-test: 88/88. - -These mutations were temporary. No permanent check of these checks was added. -The inventory's legacy-matcher retirement was also compared before/after -on the real source: identical output. Its numeric builtin population stays -230/230. - -A temporary C host injected `INT64_MAX` into try-wrapped addition/comparison -and both iterator snapshot implementations. All four aborted via the -R1.3 diagnostic/SIGABRT; paired floats returned 6, true, 42, 42 (8/8). - -## Gates run - -- Default `make`: gcc -O2 warnings=0. -- `make build/server-db/eigenscript CFLAGS='-Wall -Wextra -Werror=implicit-function-declaration -Werror=switch -Werror=comment -Werror=misleading-indentation -O0 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE'`: - 35/35 translation units, warnings=0. -- `make -B build/server-db/eigenscript CFLAGS='-Wall -Wextra -Werror=implicit-function-declaration -Werror=switch -Werror=comment -Werror=misleading-indentation -O1 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE'`: - 35/35 translation units, warnings=0. -- `make -B build/server-db/eigenscript` (default -O2): - 35/35 translation units, warnings=0. -- `make jit-smoke`: `JIT smoke: all cases passed.` -- `make embed-smoke`: `embed_smoke: OK`. -- `make smi-trap` in the `ce66ede5` archive (runtime C identical to final HEAD): built. -- `python3 tools/phase2_inventory.py --check`: - `builtins: registered=311 numeric=230 classified=230 unclassified=0 stale=0`; - `examined=2014 classified=2014 unclassified=0`; `phase2-inventory: PASS`. -- `bash tools/num_read_check.sh`: - `num-read: examined=197 functions=81 allowlisted=81 violations=0 stale=0`; - `num-read: PASS`. -- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy bash tools/phase2_check.sh /tmp/eigs-oracle-anchor/v0.46.0/src/eigenscript /home/jon/src/wt/es-phase2/src/eigenscript --through R1.2 --baseline /tmp/phase2-r12/main/src/eigenscript --smi-trap /tmp/phase2-r12/trap/src/eigenscript`: - `phase2-check: PASS` (final checker artifact; 1351.09 seconds). Both corpus halves: - `examined=441 same=435 same_nonzero=31 same_under_replay=4 nondet=1 diff=0 new=14 deleted=0 crash_both=0 timeout_both=1 conditioned=15 incomplete=0 undeclared=0 stale=0 ledger_refused=0 unpinned=1 capped=13`. - Static int-source: `files=64 slot_from_int_defs=1 make_int_defs=0 calls=2 outside_writers=0 tag_homes=4/4 tag_spellings_outside=0`. - Inventory: `examined=2014 classified=2014 unclassified=0`; freshness PASS; - numeric builtins 230/230, dispositions 101 missing=0 stale=0, leaf 11/11. - Slot gate: `examined=33 calls=165 matrix_cells=396 arm_rows=32 failures=0`. -- `make test`: `RESULTS: 4268/4268 passed, 0 failed, 9 skipped`; child-script ledger: `0 nonzero exits`. -- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy - bash tools/jit_diff.sh`: - `jit_diff: OK (258 programs x {jit, osr} vs the interpreter; suite-env completed=15; OBS examined=630 denied=12; 30 arms adjudicated; 2 ledgered)`. -- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy bash tools/replay_diff.sh`: - `replay_diff: OK (258 programs record+replay; 21 at the documented boundary; 0 nondeterministic; 1 ledgered)`. -- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=x11 SDL_AUDIODRIVER=dummy - bash tools/strict_differential.sh /tmp/phase2-r12/main/src/eigenscript`: `OK`. - `identical-when-off: 156 differing: 0`; `unset-equals-strict: 156 / 156`; - `raises-under-strict: 156 silent: 0 misattributed: 0`; - `valid-input rows unchanged in all three modes: 252 / 252`. - Typed controls: `declared=139 examined=139 passed=130 failed=0 unavailable=9 backend_absent=0 pending=0 unrun=0`. - Pixels: `rows=37 (valid=14 wrong=23)`, `identical-when-off: 37 differing: 0`. - `bash tools/strict_differential.sh --selftest`: - `SHAPE_CAPTURE_SELFTEST: 88 passed, 0 failed, 88 declared`. -- `env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy make asan`: - build exits 0. Then `(cd tests && env -u XAUTHORITY DISPLAY=:99 SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy ASAN_OPTIONS=detect_leaks=1 bash run_all_tests.sh)`: - `RESULTS: 4259/4259 passed, 0 failed, 8 skipped`; - `PASS: every child .sh test ran to completion (0 nonzero exits)`. - LeakSanitizer nonzero-exit tally: 0. `RLIMIT_AS` was unlimited throughout. - The full suite took 2401.51 seconds; default `make` restored the release alias. -- `bash tools/suite_label_check.sh`: - `PASS: 294 labelled echo lines; labels and tallies carry no hand-typed counts; no two sections share a label`. -- `python3 /tmp/phase2-r12/build_committed_trees.py`: - `committed-tree-builds: examined=20 failures=0 target=build/server-db/eigenscript`. - This covers every implementation/tooling commit; the report-only commit - also receives its own default build. - -The first full release suite caught stale strict shape fingerprints: -`RESULTS: 4266/4268 passed, 2 failed, 9 skipped` and -`SHAPE_CONTRACT: candidates=190 guarded=139 exempt=51 errors=39`. -All 39 exemption roots and helper closures were reviewed, including an -independent pass; only fingerprint fields changed. The checker now reports -`SHAPE_CONTRACT: candidates=190 guarded=139 exempt=51 errors=0`. -The final suite rerun uses those reviewed fingerprints and the repaired bool -renderer probe. Earlier runs' no-renderer notes came from that stale probe; -they were not evidence of an unavailable renderer. - -The first `jit_diff` run inherited native X11 video and reported two extra -OBS rows (`ui_canvas_events.eigs`, `ui_dock.eigs`): JIT programs=258, -OBS examined=630 denied=12. The subsequent bounded X11 controls ran both -examples on candidate and `0740af03`, each in REF and OBS mode: all eight -were silent and timed out at 25 seconds (rc=124). The remaining gate train -uses explicit `SDL_VIDEODRIVER=dummy`; its full JIT verdict is green with -only the existing two ledger rows. The ledger is unchanged; the -initial failed run is retained as `logs/jit-diff-native-x11.log`. - -The first unforced -O1/-O2 requests reused objects; those logs are retained -as `warnings-*-unforced.log` and are not evidence. The forced builds above -count actual compiler invocations. - -An independent serial replay of all twenty committed trees builds the -server-db target from archived Git sources and exact successive Git blobs. -Intermediate trees retain the intentional deprecated-alias warnings; the -zero-warning requirement is measured on the final tree at all three levels. -The initial replay driver mistakenly required zero warnings on the first -intermediate tree: its actual make exited 0 with 340 warnings, all tagged -`-Wdeprecated-declarations`. That log is retained; the driver was narrowed -to successful builds and resumed from that successful first build. - -The sanitizer renderer note shared the obsolete `sdl-present: 1` spelling. -Its corrected helper was run with an available software renderer and an -unavailable video driver: `15 passed, 0 failed` in each profile, respectively -no false note and an accurate renderer-unavailable note. `RLIMIT_AS` was -unlimited. The initial invalid renderer hint fell back to a working renderer; -that attempt was not counted as a negative control. - -## Audio artifact - -`strace` identified `test_audio.eigs` using SDL's disk backend: it opened -`sdlaudio.raw` four times from src/. The shared per-program policy now sets -`SDL_AUDIODRIVER=dummy`; the same test completed 53/53 plus mixer checks and -left no raw artifact even with an inherited disk-driver setting. The stray -file was removed. - -The first full replay gate examined 258 programs and failed because -`test_audio.eigs` no longer diverged under the dummy-driver policy; no new -divergence was reported. The candidate and `0740af03` also matched on that -whole fixture when record and replay were separated by more than a second -(53/53 assertions plus mixer checks). Its noise assertions check length -and range, never sample values. The old CI log records a divergent row -without the underlying transcripts, so its cause remains unknown. - -A separate minimal program that prints the noise samples still diverges -across seconds on both binaries, with no `audio_noise` entry in either tape: -`NOISE_FIDELITY_PREEXISTING: candidate=divergent main0740=divergent`. -Retiring the whole-fixture row tightens the current gate's expectation; -it does not claim the sample-level issue is fixed on this branch. The -remaining untaped mixer-queue timing is another reason any future CI failure -needs actual record/replay transcripts before a cause is assigned. - -## Design deviations and caveats - -The header-reader follow-up completes arms missed by the earlier R1.2a -commit. Seven C fixtures needed an extra group. R1.2z also changes the two -mutually exclusive sort-key fields to a union to retain the old 16-byte -allocation footprint. These implement the behaviour-preserving scope. -After alias deletion, two stale P4 injection templates, 39 reviewed source -fingerprints and the renderer probe needed follow-up groups. The latter -restores pixel coverage that had silently disappeared with bool printing. -The sanitizer helper’s matching diagnostic and inert false control were -corrected in a separate group; its pass/fail predicate is unchanged. -The no-longer-reproducing audio-fixture replay row was retired after the -full gate failed on its absence and a fresh review checked the scope; -the replacement full run passes with one remaining fidelity row. -Runtime C source after `ce66ede5` is byte-identical; these follow-ups change -checker fixtures and machinery only. After the temporary pixel fault was -restored, the release binary SHA256 is -`9fa86d63826b385a2e21133ee78b7a292ba6665c45e379e6106532874be509c2`, -whose prefix matches the pre-plant SHA256 recorded by the completed R1.2 gate. - -The Git metadata import remains an orchestrator action because of sandbox -permissions. Raw logs and profiles are under /tmp/phase2-r12. -The global instructions mention failsoft_classify_check, which is absent -from this checkout; no result is claimed for that nonexistent command. - -## Distillation - -The cost table records why the VM's cold int refusals need measurement: -17 rejected source candidates changed the interpreter instruction count -beyond the round's tolerance despite leaving today's numeric semantics -unchanged. The existing performance skill already requires measuring this -effect; no new performance rule is needed. - -The real pixel fault exposed an untested capability assumption: the renderer -was available while a bool-printing change made the checker skip its rows. -The repaired probes use the actual `true`/`false` output. The one-time red -and restored green above document that repair without a permanent check of -the check, following PRINCIPLES §5. - -## Out of scope - -R1.3 int producers, arithmetic and tape v7; R1.6 bridge deletion and builtin -semantic changes; main integration, CI upload, and pushing. From 0c43ec88ca8915f9d365e3e63549cb1e322c76d3 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 18 Oct 2026 21:14:02 -0500 Subject: [PATCH 053/188] phase2: re-key the arm-refusal plant to NUM_CMP's per-operand refusal R1.2 (14471e2f) split NUM_CMP's combined SMI refusal into one slot_type(...) == VAL_INT check per operand. The arm-refusal plant still anchored on the combined text, which now occurs 0 times, so the self-test reported broken=1. The anchor now matches both checks exactly once, and the replacement still removes the refusal: on the planted tree the slot test's arm lt row fails with "arm lt with an int". Also correct the R1.2 verification note's retired-token count to files=89, as the gate prints. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 2 +- tools/phase2_plants.sh | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 4a9d9aebf..babbdb96c 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2769,7 +2769,7 @@ main baseline and a separately built SMI-trap binary. The trap corpus reported the same full 458-file summary as the candidate corpus, including `diff=0 incomplete=0 undeclared=0 stale=0` and 13 graphics-only caps. Both corpus halves passed; `mechanical smi-trap: PASS` and -`phase2-check: PASS`. The retired-token scan reported `tokens=9 files=90 +`phase2-check: PASS`. The retired-token scan reported `tokens=9 files=89 hits=0`; inventory `examined=2012 classified=2012 unclassified=0`; int source `make_int_defs=0 outside_writers=0`; slot matrix `examined=33 calls=165 matrix_cells=396 arm_rows=32 failures=0`. diff --git a/tools/phase2_plants.sh b/tools/phase2_plants.sh index 665387800..152ec420c 100755 --- a/tools/phase2_plants.sh +++ b/tools/phase2_plants.sh @@ -125,8 +125,10 @@ run_plant 1 src/value_slot.h \ # an SMI again (a `try` turns it into a wrong value). Named check: the slot # test's Part D row for `<`. run_plant arm-refusal src/vm.c \ - " if (slot_is_smi(_as) || slot_is_smi(_bs)) \\ - eigs_int_unwired(\"compare '\" OPNAME \"'\", (slot_is_smi(_as) ? _as : _bs).u); \\ + " if (slot_type(_as) == VAL_INT) \\ + eigs_int_unwired(\"compare '\" OPNAME \"'\", _as.u); \\ + if (slot_type(_bs) == VAL_INT) \\ + eigs_int_unwired(\"compare '\" OPNAME \"'\", _bs.u); \\ " \ "" \ tests/phase2/slot_layer.c \ From 05f7c2505e8bda27418f06f30d94a0ddbfcccf12 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:03:34 -0500 Subject: [PATCH 054/188] tests: copy every runner-sourced helper into the planner stub (main 0b25c741, #1819) Main's 0b25c741 (#1822) makes tools/section_plan.sh's self-test copy each file the runner sources with a literal `. "$TESTS_DIR/"` line, instead of a hand-kept list, and spells the binary_swap.sh source line in that form. This branch's R1.3 round changes tools/selftests.txt, which selects every self-test, so the planner's self-test needs the fix here before main is next merged. The content is byte-identical to 0b25c741's patch (applied with `git apply` to 0c43ec88); main's runtime sources are unchanged by it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/run_all_tests.sh | 2 +- tools/section_plan.sh | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh index 2a96b7049..fa3dc69fa 100755 --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -6998,7 +6998,7 @@ if [ ! -f "$EIGS_BIN" ]; then TOTAL=$((TOTAL - 1)) section_skip "no binary to fingerprint" else - source "$TESTS_DIR/binary_swap.sh" + . "$TESTS_DIR/binary_swap.sh" SELFTEST_OUT=$(eigs_binary_swap_selftest 2>&1) SELFTEST_RC=$? RESTORE_OUT=$(python3 "$TESTS_DIR/test_binary_swap_restore.py" 2>&1) diff --git a/tools/section_plan.sh b/tools/section_plan.sh index 43edf9fd9..eafdab97b 100755 --- a/tools/section_plan.sh +++ b/tools/section_plan.sh @@ -953,6 +953,36 @@ emit_plan() { # emit_plan bash -n "$out" || die "emitted runner is not syntactically valid: $out" echo "$planline" } + +# Copy every literal test support file sourced by the runner into a scratch +# tree. Keep the runner as the one source of truth: a hand-maintained list +# here is liable to miss the next helper added to its preamble (#1819). +copy_runner_support_files() { # + local runner_source="$1" scratch_tests="$2" rel src dst files unsupported + unsupported=$(awk ' + /^[[:space:]]*(\.|source)[[:space:]]/ && + $0 !~ /^[[:space:]]*\.[[:space:]][[:space:]]*"\$TESTS_DIR\/[^"]*".*$/ { + print NR ":" $0 + } + ' "$runner_source") + [ -z "$unsupported" ] || + die "runner source line is not the required literal . \"\$TESTS_DIR/\" form: $unsupported" + files=$(sed -n 's|^[[:space:]]*\.[[:space:]][[:space:]]*"\$TESTS_DIR/\([^"]*\)".*$|\1|p' \ + "$runner_source" | sort -u) + [ -n "$files" ] || die "no literal \$TESTS_DIR support files found in $runner_source" + while IFS= read -r rel; do + [ -n "$rel" ] || continue + src="$SP_ROOT/tests/$rel" + dst="$scratch_tests/$rel" + [ -f "$src" ] || die "runner-sourced support file was not copied because its source is missing: $rel" + mkdir -p "$(dirname "$dst")" || die "cannot create scratch directory for runner-sourced file: $rel" + cp "$src" "$dst" || die "could not copy runner-sourced support file: $rel" + [ -f "$dst" ] || die "runner-sourced support file was not copied: $rel" + done < "$stub/src/eigenscript" chmod +x "$stub/src/eigenscript" From f49576f876189488f6f3692b89069644b4cf0361 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:05:28 -0500 Subject: [PATCH 055/188] vm: DISPATCH drops its popped argument after binding it (#1838) OP_DISPATCH pops an owned argument slot. Both binding helpers, env_rebind_param_slot (recycled call env) and vm_bind_fresh_param (fresh env), retain their slot with slot_incref, but the opcode dropped its popped reference only when the callee had zero parameters. Every parameterized dispatch of a heap argument leaked one reference. Immediate numeric arguments hid it; R1.3's full leak-enabled ASan run exposed it (#1838). Fix: release the popped reference once, after either binding path, for every parameter count. The zero-parameter branches lose their own decref. Red then green, on this branch before the int flip (valgrind 3.26.0, --leak-check=full, release -O2), tests/test_dispatch_owned_arg.eigs: 0c43ec88: definitely lost: 240 bytes in 3 blocks (the string and list arguments), exit 9 this fix: All heap blocks were freed -- no leaks are possible, exit 0 control (the same values through a direct call, unfixed binary): no leaks. tests/test_dispatch.eigs stays 18/18. Section [0fn] runs the new test and requires it leak-clean (LSan classification `none`), as [87] does. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- .../fixed/1838-dispatch-argument-ownership.md | 1 + src/vm.c | 7 +++---- tests/sections/0fn-dispatch-owned-arg.sh | 17 +++++++++++++++++ tests/test_dispatch_owned_arg.eigs | 18 ++++++++++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 changes/fixed/1838-dispatch-argument-ownership.md create mode 100644 tests/sections/0fn-dispatch-owned-arg.sh create mode 100644 tests/test_dispatch_owned_arg.eigs diff --git a/changes/fixed/1838-dispatch-argument-ownership.md b/changes/fixed/1838-dispatch-argument-ownership.md new file mode 100644 index 000000000..312adfe4c --- /dev/null +++ b/changes/fixed/1838-dispatch-argument-ownership.md @@ -0,0 +1 @@ +- Fixed a leaked argument reference in `dispatch` calls using fresh or recycled function environments. ([#1838](https://github.com/InauguralSystems/EigenScript/issues/1838)) diff --git a/src/vm.c b/src/vm.c index 25dd64a58..f6d71440b 100644 --- a/src/vm.c +++ b/src/vm.c @@ -6545,8 +6545,6 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (call_env) { if (fn->data.fn.param_count > 0) { env_rebind_param_slot(call_env, 0, arg_s); - } else { - slot_decref(arg_s); } } else { call_env = env_new(fn->data.fn.closure); @@ -6556,8 +6554,6 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, : env_hash_name(fn->data.fn.params[0]); vm_bind_fresh_param(call_env, 0, fn->data.fn.params[0], fn->data.fn.param_intern_tbl, ph, arg_s); - } else { - slot_decref(arg_s); } /* DISPATCH always feeds argc=1; underfed tail slots * [1..param_count) get null placeholders, then @@ -6576,6 +6572,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (fn_chunk->local_count > dpc) env_reserve_slots(call_env, fn_chunk->local_count); } + /* Both binding helpers retain their slot. Drop DISPATCH's popped + * argument reference after binding, including the zero-param case. */ + slot_decref(arg_s); slot_decref(table_s); frame->ip = ip; diff --git a/tests/sections/0fn-dispatch-owned-arg.sh b/tests/sections/0fn-dispatch-owned-arg.sh new file mode 100644 index 000000000..e96a7c641 --- /dev/null +++ b/tests/sections/0fn-dispatch-owned-arg.sh @@ -0,0 +1,17 @@ +# #1838: an owned dispatch argument must be released after either binding +# path retains it. This regression is strictly leak-clean, like section [87]. +echo "[0fn] Dispatch argument ownership" +check_binary_fingerprint +TOTAL=$((TOTAL + 1)) +DARG_OUTPUT=$(suite_program_run test_dispatch_owned_arg.eigs $EIGS_TMO ./eigenscript "$TESTS_DIR/test_dispatch_owned_arg.eigs" &1); DARG_RC=$? +if [ "$DARG_RC" -eq 0 ] && + [ "$(lsan_classify_name "$DARG_OUTPUT")" = none ] && + grep -Fxq 'dispatch owned args: PASS' <<< "$DARG_OUTPUT"; then + PASS=$((PASS + 1)) + echo " PASS: dispatch preserves owned arguments through fresh and recycled envs (leak-clean)" +else + FAIL=$((FAIL + 1)) + echo " FAIL: dispatch argument ownership (rc=$DARG_RC — must be leak-clean)" + printf '%s\n' "$DARG_OUTPUT" | eigs_failure_output +fi +echo "" diff --git a/tests/test_dispatch_owned_arg.eigs b/tests/test_dispatch_owned_arg.eigs new file mode 100644 index 000000000..991fbfafd --- /dev/null +++ b/tests/test_dispatch_owned_arg.eigs @@ -0,0 +1,18 @@ +# A dispatch argument owns a popped stack reference. Binding must retain it, +# then release the popped reference, in both fresh and recycled call envs. +define echo(x) as: + return x + +define ignore() as: + return 0.5 + +table is [echo] +empty_params is [ignore] +for value in [9007199254740993, "owned dispatch argument", ["nested argument"]]: + first is dispatch of [table, 0, value] + second is dispatch of [table, 0, value] + assert of [first == value, "fresh dispatch preserves argument"] + assert of [second == value, "recycled dispatch preserves argument"] + assert of [(dispatch of [empty_params, 0, value]) == 0.5, "zero-param dispatch drops argument"] + +print of "dispatch owned args: PASS" From 5857540541248be2ec5f7dfb4d7684a17e7367ad Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:14:36 -0500 Subject: [PATCH 056/188] tests: cap the release examples' gfx runs at the 1,500,000 KiB machine setting Section [97] runs every gfx example under `ulimit -v` outside ASan. Its cap was 2,000,000 KiB; R1.2 moved the corpus graphics ceiling (jit_diff, replay_diff) to 1,500,000 KiB after a restricted real-VM probe failed its ceiling assertion at the 2 GiB setting on the 4 GB reference box. This aligns the suite's examples with that one machine setting. ASan runs keep no address-space cap, as before. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/run_all_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh index fa3dc69fa..d4bc61bd3 100755 --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -6554,7 +6554,7 @@ EIGS_ABS="$(pwd)/eigenscript" # RLIMIT_AS cannot coexist with ASan's multi-terabyte shadow mapping. Gfx is # now in the default sanitizer profile (#1415), so keep the runaway timeout # but omit only the address-space cap under ASan. -EX_GFX_ULIMIT='ulimit -v 2000000 2>/dev/null' +EX_GFX_ULIMIT='ulimit -v 1500000 2>/dev/null' if ASAN_OPTIONS=help=1 "$EIGS_ABS" --version 2>&1 | grep -q 'AddressSanitizer'; then EX_GFX_ULIMIT=':' fi From d599be7eaad34dec6e32f9cbe19958b448bbf5c2 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:21:25 -0500 Subject: [PATCH 057/188] phase2 R1.3a: the int semantics, before any int value exists (#1758) The arithmetic, comparison and negation arms get their final int behaviour while nothing can produce an int yet (the N1 literal commit comes later in this round), so every arm is in place before the first int reaches it: - N3 with (A): int + - * use checked int64 arithmetic (vm_int_arith, the INT_ARITH fast path for two exact int slots); overflow raises `value`, never wraps or rounds. Mixed int/float operands convert to float in the slow paths; `/` and `%` read ints through the bridge (today's semantics until R1.4). - N2: ordering compares int vs int and int vs float exactly (vm_number_compare, eigs_cmp_int_float); EQ/NE's only bit fast path is "both SMI" (the canonical form makes bit equality value equality). - N4b: `-x` and `abs of x` raise `value` at INT64_MIN. - N7: `num_type of x` answers "int", "float", or null for a non-number (registered, sandbox-allowed, in the bool-argument table and the LSP index). - Bitwise operands are exact int64 (vm_bit_operand, #1740's rule for floats); results stay floats until R1.5. - The JIT scanner refuses MOD, BAND, BOR, BXOR, SHL, SHR and BNOT (interpreted until the R5 int fast paths). The arms box results through the two SMI boxers, which get their final arms here because the slow paths depend on them: slot_to_value boxes an SMI with make_int, and slot_from_int boxes an int outside the SMI range. make_int is introduced here for that reason. The remaining placeholders, the tape and the literal producer follow in this round. The C slot test's Part A/B/C/D cover the new readers and boxers with hand-built SMIs (population 33 -> 35; every operator arm computes its value). The overflow row needs an int literal and lands with N1. Pre-flip smoke against 0c43ec88: identical output except the new builtin. The R1.1/R1.2 static int-source check now fails on this tree by design (make_int and slot_from_int have production callers), so the row checker's calibration runs its static int-source cases on the pinned last no-producer source, 0c43ec88, exported with `git archive` (tools/phase2_check.py). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/BUILTINS.md | 3 +- docs/design/phase2-inventory.txt | 1616 +++++++++++++++--------------- docs/design/phase2-numbers.md | 22 +- src/builtins.c | 20 +- src/eigenscript.c | 15 +- src/eigenscript.h | 1 + src/jit.c | 11 +- src/lsp_builtin_index.h | 1 + src/value_slot.h | 9 +- src/vm.c | 230 +++-- tests/bool_fuzz_anyvalue.txt | 3 + tests/phase2/slot_layer.c | 126 ++- tests/test_bitwise.eigs | 9 +- tools/num_read_allowlist.txt | 5 +- tools/phase2_check.py | 27 +- 15 files changed, 1103 insertions(+), 995 deletions(-) diff --git a/docs/BUILTINS.md b/docs/BUILTINS.md index 92fd36ef2..cab33e5ad 100644 --- a/docs/BUILTINS.md +++ b/docs/BUILTINS.md @@ -64,6 +64,7 @@ audio (`audio_open`, `audio_close`, `audio_pause`, `audio_play`, | `str` | `str of value` | Convert to string representation | | `num` | `num of value` | Convert to number (parse string or coerce). `num of "inf"` saturates to `1e308`; `num of "nan"` raises a `value` error naming `num` by default, while under `EIGS_STRICT=0` it is `0` and sets `math_flags.invalid` (#971). | | `type` | `type of value` | Return type name: "num", "str", "list", "dict", "buffer", "text_builder", "fn", "builtin", "none" (the null value — SPEC.md is normative and its gated example prints `none`; the string `"null"` is never produced) | +| `num_type` | `num_type of value` | Return "int" for an int64, "float" for a binary64, or `null` for any other value. Both numeric kinds still have `type of` "num" (#1758 N7). | | `assert` | `assert of [cond, msg]` | Raise catchable error `"ASSERT FAIL: "` if condition is false | | `exit` | `exit of N` | Terminate the program with exit code `N` (default 0). **Uncatchable** — a `try`/`catch` does not intercept it — and unwinds through normal teardown, so it is leak-clean even with live closures. Code after it does not run. The request is scoped to the evaluating thread and cleared at each host eval entry, so under the embedding API a script that calls `exit` does not disable `try`/`catch` for the host's *next* eval (#739). | | `coalesce` | `coalesce of [value, default]` | Return value unless empty/null, else default | @@ -419,7 +420,7 @@ automatically at exit. | Name | Signature | Description | |------|-----------|-------------| -| `abs` | `abs of x` | Absolute value | +| `abs` | `abs of x` | Absolute value, preserving int or float kind. `abs` of INT64_MIN raises `value` because its positive magnitude does not fit in int64 (#1758 N4b). | | `min` | `min of [n1, n2, ...]` | Smallest of a list of numbers (any length >= 1) | | `max` | `max of [n1, n2, ...]` | Largest of a list of numbers (any length >= 1) | | `floor` | `floor of x` | Round down to integer | diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 4e24a2f3d..be44a629b 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,64 +1,64 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2012 classified=2012 unclassified=0 +examined=2018 classified=2018 unclassified=0 files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 513 CASE=60 DATA=4 TEST=446 YIELD=3 -(b) payload reads 544 RAW=116 READ=428 -(c) producers 472 GUARD=71 PARSE=3 PRODUCE=371 TAGSET=4 WRITE=23 +(a) type tests 505 CASE=60 DATA=4 TEST=438 YIELD=3 +(b) payload reads 555 RAW=111 READ=444 +(c) producers 473 GUARD=73 PARSE=3 PRODUCE=371 TAGSET=5 WRITE=21 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 20 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=7 -(f) equality, ordering and hashing 51 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=21 +(f) equality, ordering and hashing 53 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=23 (g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 (h) JSON, store and db encoders 82 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=6 READ=24 TEST=21 (i) observer numeric paths 107 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=7 TEST=33 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token -make_num 363 -val_is_number 174 -eigs_num_arg 161 -VAL_INT 159 -VAL_FLOAT 156 +make_num 365 +val_is_number 184 +eigs_num_arg 172 +VAL_FLOAT 151 +VAL_INT 148 eigs_list_num 130 SLOT_F64_RAW 83 -VAL_F64_RAW 66 -num_guard 60 +num_guard 62 +VAL_F64_RAW 56 AST_NUM 52 slot_is_f64 50 eigs_value_as_num 48 eigs_slot_num 47 -VAL_I64_RAW 42 -slot_from_f64 41 +VAL_I64_RAW 44 buffer_read_num 37 -slot_is_smi 29 +slot_from_f64 37 +slot_is_smi 33 buffer_read_byte 22 list_set_num 22 -slot_f64_value 20 -slot_smi_val 18 +slot_f64_value 22 +slot_smi_val 19 strtod 16 -NUM_REUSE 15 +NUM_REUSE 12 eigs_slot_opt_num 12 eigs_num_arg_slow 9 EIGS_NUM_MAX 8 finite_num_to_byte 8 +slot_int_value 8 eigs_num_text 7 eigs_opt_num 6 eigs_slot_elem_num 6 num_guard_named 6 -num_to_i64_exact 6 num_val 5 +slot_from_int 5 VAL_F64_OFFSET 4 buf_num_arg 4 dict_value_rewrite_num 4 list_rewrite_num 3 -slot_from_int 3 +num_to_i64_exact 3 eigs_elem_num 2 f64_ 2 list_append_num 2 make_num_permanent 2 -slot_int_value 2 atof 1 d_ 1 dict_value_get_num 1 @@ -68,11 +68,11 @@ list_get_num 1 data.num (AST) 7 ## Per file (category counts) -builtins.c 346 a=81 b=103 c=111 e=6 f=13 h=21 i=11 -vm.c 300 a=85 b=88 c=67 e=2 f=8 i=50 +builtins.c 350 a=84 b=104 c=111 e=6 f=13 h=21 i=11 +vm.c 299 a=74 b=97 c=66 e=2 f=10 i=50 ext_gfx.c 298 a=104 b=124 c=70 builtins_tensor.c 200 a=55 b=59 c=86 -eigenscript.c 120 a=22 b=17 c=13 e=7 f=18 i=43 +eigenscript.c 123 a=22 b=18 c=15 e=7 f=18 i=43 builtins_buf.c 110 a=34 b=37 c=39 container.h 98 a=39 b=31 c=28 jit.c 96 d=96 @@ -104,10 +104,10 @@ model_io.c 1 h=1 ## Executors (arms per opcode; roles: interp jit_scan jit_emit leaf_scan leaf_exec) OP_ADD interp jit_scan jit_emit leaf_scan leaf_exec -OP_BAND interp jit_scan jit_emit - - -OP_BNOT interp jit_scan jit_emit - - -OP_BOR interp jit_scan jit_emit - - -OP_BXOR interp jit_scan jit_emit - - +OP_BAND interp - jit_emit - - +OP_BNOT interp - jit_emit - - +OP_BOR interp - jit_emit - - +OP_BXOR interp - jit_emit - - OP_CALL interp jit_scan jit_emit - - OP_CONST interp jit_scan jit_emit leaf_scan leaf_exec OP_DIV interp jit_scan jit_emit - - @@ -139,7 +139,7 @@ OP_LOCAL_IDX_GET interp jit_scan jit_emit - - OP_LOOP_CAP_CHECK interp jit_scan jit_emit - - OP_LOOP_STALL_CHECK interp jit_scan jit_emit - - OP_LT interp jit_scan jit_emit - - -OP_MOD interp jit_scan jit_emit - - +OP_MOD interp - jit_emit - - OP_MUL interp jit_scan jit_emit leaf_scan leaf_exec OP_NE interp jit_scan jit_emit - - OP_NEG interp jit_scan jit_emit - - @@ -158,8 +158,8 @@ OP_SET_FN_NAME_LOCAL interp jit_scan jit_emit - - OP_SET_LOCAL interp jit_scan jit_emit - - OP_SET_NAME interp jit_scan jit_emit - - OP_SET_NAME_LOCAL interp jit_scan jit_emit - - -OP_SHL interp jit_scan jit_emit - - -OP_SHR interp jit_scan jit_emit - - +OP_SHL interp - jit_emit - - +OP_SHR interp - jit_emit - - OP_SUB interp jit_scan jit_emit leaf_scan leaf_exec OP_TRUE interp jit_scan jit_emit - - OP_UNOBSERVED_BEGIN interp jit_scan jit_emit - - @@ -188,7 +188,7 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=58 D2=18 D3=26 T=66 dispositions=102 missing=0 stale=0 +D1=61 D2=18 D3=26 T=66 dispositions=105 missing=0 stale=0 D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 @@ -206,7 +206,7 @@ D1 container.h:slot_view smi-arm eigs_slot_ref=1 s D1 eigenscript.c:ent_child_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 eigenscript.c:module_ns_project guarded slot_is_f64=2 D1 eigenscript.c:observer_entropy_now smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 -D1 eigenscript.c:slot_to_value unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 +D1 eigenscript.c:slot_to_value smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 ext_store.c:store_json_encode_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 trace.c:write_slot unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 D1 value_slot.h:slot_f64_value guarded slot_as_ptr=1 slot_f64_value=1 slot_is_f64=1 slot_is_heap=1 @@ -216,8 +216,9 @@ D1 value_slot.h:slot_is_smi smi-arm SLOT_TAG_MASK=1 T D1 value_slot.h:slot_smi_val smi-arm SLOT_PAYLOAD_MASK=1 SLOT_SMI_SIGN=2 slot_smi_val=1 D1 value_slot.h:slot_truthy_immediate smi-arm SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 slot_is_f64=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:#define ARITH_FAST guarded slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 -D1 vm.c:#define INT_BINOP_R unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_type=2 -D1 vm.c:#define NUM_CMP unwired slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 slot_type=2 +D1 vm.c:#define INT_ARITH smi-arm slot_int_value=2 +D1 vm.c:#define INT_BINOP_R smi-arm slot_f64_value=1 +D1 vm.c:#define NUM_CMP smi-arm slot_as_ptr=2 slot_f64_value=2 slot_is_ptr=2 D1 vm.c:#define READ_SLICE_BOUND smi-arm slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:jit_helper_dot_set guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:jit_helper_index_get guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 @@ -232,19 +233,21 @@ D1 vm.c:obs_slot_observable refuse slot_is_bool=1 sl D1 vm.c:slot_bridge_unwrap smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_smi=1 D1 vm.c:slot_truthy smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:slot_type_name smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 +D1 vm.c:vm_bit_operand smi-arm slot_f64_value=1 slot_int_value=1 D1 vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL guarded slot_f64_value=2 D1 vm.c:vm_leaf_accessor_exec/OP_INDEX_GET guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(BNOT) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_type=1 +D1 vm.c:vm_number_compare smi-arm slot_f64_value=2 slot_int_value=2 +D1 vm.c:vm_run_ex/CASE(BNOT) smi-arm slot_f64_value=1 D1 vm.c:vm_run_ex/CASE(DISPATCH) smi-arm slot_as_ptr=8 slot_is_f64=1 slot_is_ptr=3 slot_is_smi=1 slot_smi_val=1 D1 vm.c:vm_run_ex/CASE(DOT_SET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(EQ) guarded slot_f64_value=2 +D1 vm.c:vm_run_ex/CASE(EQ) guarded slot_f64_value=2 slot_is_smi=2 D1 vm.c:vm_run_ex/CASE(INDEX_GET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(INDEX_SET) guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(ITER_NEXT) unwired slot_f64_value=2 slot_type=2 D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) guarded slot_is_f64=1 -D1 vm.c:vm_run_ex/CASE(NE) guarded slot_f64_value=2 -D1 vm.c:vm_run_ex/CASE(NEG) unwired slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 slot_type=1 +D1 vm.c:vm_run_ex/CASE(NE) guarded slot_f64_value=2 slot_is_smi=2 +D1 vm.c:vm_run_ex/CASE(NEG) smi-arm slot_as_ptr=1 slot_f64_value=1 slot_int_value=1 slot_is_ptr=1 D1 vm.c:vm_slot_lift smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_store_local_slot guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 D2 builtins.c:bool_gate_name guarded slot_as_ptr=1 slot_is_ptr=1 @@ -293,11 +296,11 @@ D3 vm.c:vm_run_ex/CASE(DOT_GET) guarded slot_is_null=1 D3 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET) guarded slot_is_null=1 ## Builtins -registered=311 numeric=230 classified=230 unclassified=0 stale=0 -classes: float-producing=57 int-preserving=37 int-requiring=85 other=51 +registered=312 numeric=231 classified=231 unclassified=0 stale=0 +classes: float-producing=57 int-preserving=37 int-requiring=85 other=52 LOSS (42): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_execute db_query_json db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed Q7: geometry=9 bounded=13 magnitude=13 -abs builtin_abs int-preserving LOSS - eigs_num_arg,make_num,val_is_number +abs builtin_abs int-preserving LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,val_is_number acos builtin_acos float-producing - - eigs_num_arg,make_num,val_is_number add builtin_tensor_add int-preserving LOSS - eigs_num_arg,make_num,num_guard,val_is_number append builtin_append other - - VAL_FLOAT @@ -440,6 +443,7 @@ net_send builtin_net_send int-requiring norm builtin_tensor_norm float-producing - - buffer_read_num,eigs_num_arg,make_num,num_guard,val_is_number num builtin_num other LOSS - make_num,num_guard_named,strtod,val_is_number num_copy builtin_num_copy int-preserving LOSS - eigs_num_arg,make_num,val_is_number +num_type builtin_num_type other - - VAL_FLOAT,VAL_INT numerical_grad builtin_numerical_grad float-producing - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num,val_is_number numerical_grad_cols builtin_numerical_grad_cols float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num,val_is_number numerical_grad_rows builtin_numerical_grad_rows float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_num_arg,eigs_slot_num,eigs_slot_opt_num,list_set_num,make_num,val_is_number @@ -576,305 +580,309 @@ builtins.c:784 builtin_observe make_num PRODUCE i builtins.c:785 builtin_observe make_num PRODUCE i builtins.c:867 builtin_type VAL_FLOAT CASE a builtins.c:868 builtin_type VAL_INT CASE a -builtins.c:915 eigs_json_encode_value VAL_FLOAT CASE h -builtins.c:922 eigs_json_encode_value eigs_num_arg READ h -builtins.c:922 eigs_json_encode_value eigs_num_text FORMAT h -builtins.c:926 eigs_json_encode_value VAL_INT CASE h -builtins.c:928 eigs_json_encode_value VAL_I64_RAW RAW h -builtins.c:1291 eigs_json_parse_number make_num PRODUCE h -builtins.c:1298 eigs_json_parse_number make_num PRODUCE h -builtins.c:1307 eigs_json_parse_number make_num PRODUCE h -builtins.c:1312 eigs_json_parse_number strtod PARSE h -builtins.c:1322 eigs_json_parse_number strtod PARSE h -builtins.c:1326 eigs_json_parse_number make_num PRODUCE h -builtins.c:1497 builtin_json_build val_is_number TEST h -builtins.c:1499 builtin_json_build VAL_I64_RAW RAW h -builtins.c:1499 builtin_json_build VAL_INT TEST h -builtins.c:1500 builtin_json_build eigs_num_arg READ h -builtins.c:1500 builtin_json_build eigs_num_text FORMAT h -builtins.c:1684 builtin_scan_ints make_num PRODUCE c -builtins.c:1798 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1799 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1800 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1801 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1802 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1803 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1906 builtin_char_at val_is_number TEST a -builtins.c:1908 builtin_char_at eigs_num_arg READ b -builtins.c:1942 builtin_substr val_is_number TEST a -builtins.c:1943 builtin_substr val_is_number TEST a -builtins.c:1945 builtin_substr eigs_num_arg READ b -builtins.c:1946 builtin_substr eigs_num_arg READ b -builtins.c:1976 builtin_index_of make_num PRODUCE c -builtins.c:1983 builtin_index_of make_num PRODUCE c -builtins.c:1988 builtin_index_of make_num PRODUCE c -builtins.c:1989 builtin_index_of make_num PRODUCE c -builtins.c:1997 builtin_sin make_num PRODUCE c -builtins.c:1997 builtin_sin val_is_number TEST a -builtins.c:1998 builtin_sin eigs_num_arg READ b -builtins.c:1998 builtin_sin make_num PRODUCE c -builtins.c:2002 builtin_cos make_num PRODUCE c -builtins.c:2002 builtin_cos val_is_number TEST a -builtins.c:2003 builtin_cos eigs_num_arg READ b -builtins.c:2003 builtin_cos make_num PRODUCE c -builtins.c:2007 builtin_tan make_num PRODUCE c -builtins.c:2007 builtin_tan val_is_number TEST a -builtins.c:2008 builtin_tan eigs_num_arg READ b -builtins.c:2008 builtin_tan make_num PRODUCE c -builtins.c:2012 builtin_asin make_num PRODUCE c -builtins.c:2012 builtin_asin val_is_number TEST a -builtins.c:2013 builtin_asin eigs_num_arg READ b -builtins.c:2018 builtin_asin make_num PRODUCE c -builtins.c:2022 builtin_asin make_num PRODUCE c -builtins.c:2026 builtin_acos make_num PRODUCE c -builtins.c:2026 builtin_acos val_is_number TEST a -builtins.c:2027 builtin_acos eigs_num_arg READ b -builtins.c:2032 builtin_acos make_num PRODUCE c -builtins.c:2036 builtin_acos make_num PRODUCE c -builtins.c:2040 builtin_atan make_num PRODUCE c -builtins.c:2040 builtin_atan val_is_number TEST a -builtins.c:2041 builtin_atan eigs_num_arg READ b -builtins.c:2041 builtin_atan make_num PRODUCE c -builtins.c:2046 builtin_atan2 make_num PRODUCE c -builtins.c:2049 builtin_atan2 make_num PRODUCE c -builtins.c:2049 builtin_atan2 val_is_number TEST a -builtins.c:2049 builtin_atan2 val_is_number TEST a -builtins.c:2050 builtin_atan2 eigs_num_arg READ b -builtins.c:2050 builtin_atan2 eigs_num_arg READ b -builtins.c:2050 builtin_atan2 make_num PRODUCE c -builtins.c:2054 builtin_floor make_num PRODUCE c -builtins.c:2054 builtin_floor val_is_number TEST a -builtins.c:2055 builtin_floor eigs_num_arg READ b -builtins.c:2055 builtin_floor make_num PRODUCE c -builtins.c:2059 builtin_ceil make_num PRODUCE c -builtins.c:2059 builtin_ceil val_is_number TEST a -builtins.c:2060 builtin_ceil eigs_num_arg READ b -builtins.c:2060 builtin_ceil make_num PRODUCE c -builtins.c:2064 builtin_round make_num PRODUCE c -builtins.c:2064 builtin_round val_is_number TEST a -builtins.c:2065 builtin_round eigs_num_arg READ b -builtins.c:2065 builtin_round make_num PRODUCE c -builtins.c:2069 builtin_abs make_num PRODUCE c -builtins.c:2069 builtin_abs val_is_number TEST a -builtins.c:2070 builtin_abs eigs_num_arg READ b -builtins.c:2070 builtin_abs make_num PRODUCE c -builtins.c:2079 minmax_reduce eigs_num_arg READ b -builtins.c:2079 minmax_reduce make_num PRODUCE c -builtins.c:2079 minmax_reduce val_is_number TEST a -builtins.c:2084 minmax_reduce make_num PRODUCE c -builtins.c:2087 minmax_reduce make_num PRODUCE c -builtins.c:2091 minmax_reduce make_num PRODUCE c -builtins.c:2091 minmax_reduce val_is_number TEST a -builtins.c:2092 minmax_reduce eigs_num_arg READ b -builtins.c:2092 minmax_reduce eigs_num_arg READ b -builtins.c:2093 minmax_reduce eigs_num_arg READ b +builtins.c:886 builtin_num_type VAL_INT TEST a +builtins.c:887 builtin_num_type VAL_FLOAT TEST a +builtins.c:923 eigs_json_encode_value VAL_FLOAT CASE h +builtins.c:930 eigs_json_encode_value eigs_num_arg READ h +builtins.c:930 eigs_json_encode_value eigs_num_text FORMAT h +builtins.c:934 eigs_json_encode_value VAL_INT CASE h +builtins.c:936 eigs_json_encode_value VAL_I64_RAW RAW h +builtins.c:1299 eigs_json_parse_number make_num PRODUCE h +builtins.c:1306 eigs_json_parse_number make_num PRODUCE h +builtins.c:1315 eigs_json_parse_number make_num PRODUCE h +builtins.c:1320 eigs_json_parse_number strtod PARSE h +builtins.c:1330 eigs_json_parse_number strtod PARSE h +builtins.c:1334 eigs_json_parse_number make_num PRODUCE h +builtins.c:1505 builtin_json_build val_is_number TEST h +builtins.c:1507 builtin_json_build VAL_I64_RAW RAW h +builtins.c:1507 builtin_json_build VAL_INT TEST h +builtins.c:1508 builtin_json_build eigs_num_arg READ h +builtins.c:1508 builtin_json_build eigs_num_text FORMAT h +builtins.c:1692 builtin_scan_ints make_num PRODUCE c +builtins.c:1806 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1807 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1808 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1809 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1810 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1811 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1914 builtin_char_at val_is_number TEST a +builtins.c:1916 builtin_char_at eigs_num_arg READ b +builtins.c:1950 builtin_substr val_is_number TEST a +builtins.c:1951 builtin_substr val_is_number TEST a +builtins.c:1953 builtin_substr eigs_num_arg READ b +builtins.c:1954 builtin_substr eigs_num_arg READ b +builtins.c:1984 builtin_index_of make_num PRODUCE c +builtins.c:1991 builtin_index_of make_num PRODUCE c +builtins.c:1996 builtin_index_of make_num PRODUCE c +builtins.c:1997 builtin_index_of make_num PRODUCE c +builtins.c:2005 builtin_sin make_num PRODUCE c +builtins.c:2005 builtin_sin val_is_number TEST a +builtins.c:2006 builtin_sin eigs_num_arg READ b +builtins.c:2006 builtin_sin make_num PRODUCE c +builtins.c:2010 builtin_cos make_num PRODUCE c +builtins.c:2010 builtin_cos val_is_number TEST a +builtins.c:2011 builtin_cos eigs_num_arg READ b +builtins.c:2011 builtin_cos make_num PRODUCE c +builtins.c:2015 builtin_tan make_num PRODUCE c +builtins.c:2015 builtin_tan val_is_number TEST a +builtins.c:2016 builtin_tan eigs_num_arg READ b +builtins.c:2016 builtin_tan make_num PRODUCE c +builtins.c:2020 builtin_asin make_num PRODUCE c +builtins.c:2020 builtin_asin val_is_number TEST a +builtins.c:2021 builtin_asin eigs_num_arg READ b +builtins.c:2026 builtin_asin make_num PRODUCE c +builtins.c:2030 builtin_asin make_num PRODUCE c +builtins.c:2034 builtin_acos make_num PRODUCE c +builtins.c:2034 builtin_acos val_is_number TEST a +builtins.c:2035 builtin_acos eigs_num_arg READ b +builtins.c:2040 builtin_acos make_num PRODUCE c +builtins.c:2044 builtin_acos make_num PRODUCE c +builtins.c:2048 builtin_atan make_num PRODUCE c +builtins.c:2048 builtin_atan val_is_number TEST a +builtins.c:2049 builtin_atan eigs_num_arg READ b +builtins.c:2049 builtin_atan make_num PRODUCE c +builtins.c:2054 builtin_atan2 make_num PRODUCE c +builtins.c:2057 builtin_atan2 make_num PRODUCE c +builtins.c:2057 builtin_atan2 val_is_number TEST a +builtins.c:2057 builtin_atan2 val_is_number TEST a +builtins.c:2058 builtin_atan2 eigs_num_arg READ b +builtins.c:2058 builtin_atan2 eigs_num_arg READ b +builtins.c:2058 builtin_atan2 make_num PRODUCE c +builtins.c:2062 builtin_floor make_num PRODUCE c +builtins.c:2062 builtin_floor val_is_number TEST a +builtins.c:2063 builtin_floor eigs_num_arg READ b +builtins.c:2063 builtin_floor make_num PRODUCE c +builtins.c:2067 builtin_ceil make_num PRODUCE c +builtins.c:2067 builtin_ceil val_is_number TEST a +builtins.c:2068 builtin_ceil eigs_num_arg READ b +builtins.c:2068 builtin_ceil make_num PRODUCE c +builtins.c:2072 builtin_round make_num PRODUCE c +builtins.c:2072 builtin_round val_is_number TEST a +builtins.c:2073 builtin_round eigs_num_arg READ b +builtins.c:2073 builtin_round make_num PRODUCE c +builtins.c:2077 builtin_abs make_num PRODUCE c +builtins.c:2077 builtin_abs val_is_number TEST a +builtins.c:2078 builtin_abs VAL_INT TEST a +builtins.c:2079 builtin_abs VAL_I64_RAW RAW b +builtins.c:2086 builtin_abs eigs_num_arg READ b +builtins.c:2086 builtin_abs make_num PRODUCE c +builtins.c:2095 minmax_reduce eigs_num_arg READ b builtins.c:2095 minmax_reduce make_num PRODUCE c -builtins.c:2104 builtin_pi make_num PRODUCE c -builtins.c:2160 builtin_random make_num PRODUCE c -builtins.c:2169 builtin_random_int make_num PRODUCE c -builtins.c:2172 builtin_random_int val_is_number TEST a -builtins.c:2172 builtin_random_int val_is_number TEST a -builtins.c:2173 builtin_random_int make_num PRODUCE c -builtins.c:2177 builtin_random_int eigs_num_arg READ b -builtins.c:2178 builtin_random_int eigs_num_arg READ b -builtins.c:2188 builtin_random_int make_num PRODUCE c -builtins.c:2200 builtin_random_int make_num PRODUCE c -builtins.c:2205 builtin_seed_random val_is_number TEST a -builtins.c:2207 builtin_seed_random eigs_num_arg READ b -builtins.c:2435 builtin_json_path val_is_number TEST h -builtins.c:2437 builtin_json_path VAL_I64_RAW RAW h -builtins.c:2437 builtin_json_path VAL_INT TEST h -builtins.c:2438 builtin_json_path eigs_num_arg READ h -builtins.c:2438 builtin_json_path eigs_num_text FORMAT h -builtins.c:2542 builtin_token_name val_is_number TEST a -builtins.c:2543 builtin_token_name eigs_num_arg READ b -builtins.c:2579 builtin_state_at val_is_number TEST i -builtins.c:2580 builtin_state_at eigs_num_arg READ i -builtins.c:2626 builtin_chr val_is_number TEST a -builtins.c:2630 builtin_chr eigs_num_arg READ b -builtins.c:2654 builtin_hex val_is_number TEST e -builtins.c:2655 builtin_hex eigs_num_arg READ e -builtins.c:2657 builtin_hex val_is_number TEST e -builtins.c:2658 builtin_hex val_is_number TEST e -builtins.c:2659 builtin_hex eigs_list_num READ e -builtins.c:2660 builtin_hex eigs_list_num READ e -builtins.c:2687 builtin_ord make_num PRODUCE c -builtins.c:2690 builtin_ord make_num PRODUCE c -builtins.c:2691 builtin_ord make_num PRODUCE c -builtins.c:2808 vm_desc_abi_error val_is_number TEST a -builtins.c:2816 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2821 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2917 desc_isolate_const VAL_FLOAT CASE a -builtins.c:2918 desc_isolate_const VAL_INT CASE a -builtins.c:3035 vm_build_chunk_desc_body val_is_number TEST a -builtins.c:3040 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3096 vm_build_chunk_desc_body val_is_number TEST a -builtins.c:3097 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3414 builtin_sandbox_run val_is_number TEST a -builtins.c:3415 builtin_sandbox_run eigs_list_num READ b -builtins.c:3421 builtin_sandbox_run val_is_number TEST a -builtins.c:3422 builtin_sandbox_run eigs_list_num READ b -builtins.c:3423 builtin_sandbox_run eigs_list_num READ b +builtins.c:2095 minmax_reduce val_is_number TEST a +builtins.c:2100 minmax_reduce make_num PRODUCE c +builtins.c:2103 minmax_reduce make_num PRODUCE c +builtins.c:2107 minmax_reduce make_num PRODUCE c +builtins.c:2107 minmax_reduce val_is_number TEST a +builtins.c:2108 minmax_reduce eigs_num_arg READ b +builtins.c:2108 minmax_reduce eigs_num_arg READ b +builtins.c:2109 minmax_reduce eigs_num_arg READ b +builtins.c:2111 minmax_reduce make_num PRODUCE c +builtins.c:2120 builtin_pi make_num PRODUCE c +builtins.c:2176 builtin_random make_num PRODUCE c +builtins.c:2185 builtin_random_int make_num PRODUCE c +builtins.c:2188 builtin_random_int val_is_number TEST a +builtins.c:2188 builtin_random_int val_is_number TEST a +builtins.c:2189 builtin_random_int make_num PRODUCE c +builtins.c:2193 builtin_random_int eigs_num_arg READ b +builtins.c:2194 builtin_random_int eigs_num_arg READ b +builtins.c:2204 builtin_random_int make_num PRODUCE c +builtins.c:2216 builtin_random_int make_num PRODUCE c +builtins.c:2221 builtin_seed_random val_is_number TEST a +builtins.c:2223 builtin_seed_random eigs_num_arg READ b +builtins.c:2451 builtin_json_path val_is_number TEST h +builtins.c:2453 builtin_json_path VAL_I64_RAW RAW h +builtins.c:2453 builtin_json_path VAL_INT TEST h +builtins.c:2454 builtin_json_path eigs_num_arg READ h +builtins.c:2454 builtin_json_path eigs_num_text FORMAT h +builtins.c:2558 builtin_token_name val_is_number TEST a +builtins.c:2559 builtin_token_name eigs_num_arg READ b +builtins.c:2595 builtin_state_at val_is_number TEST i +builtins.c:2596 builtin_state_at eigs_num_arg READ i +builtins.c:2642 builtin_chr val_is_number TEST a +builtins.c:2646 builtin_chr eigs_num_arg READ b +builtins.c:2670 builtin_hex val_is_number TEST e +builtins.c:2671 builtin_hex eigs_num_arg READ e +builtins.c:2673 builtin_hex val_is_number TEST e +builtins.c:2674 builtin_hex val_is_number TEST e +builtins.c:2675 builtin_hex eigs_list_num READ e +builtins.c:2676 builtin_hex eigs_list_num READ e +builtins.c:2703 builtin_ord make_num PRODUCE c +builtins.c:2706 builtin_ord make_num PRODUCE c +builtins.c:2707 builtin_ord make_num PRODUCE c +builtins.c:2824 vm_desc_abi_error val_is_number TEST a +builtins.c:2832 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2837 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2933 desc_isolate_const VAL_FLOAT CASE a +builtins.c:2934 desc_isolate_const VAL_INT CASE a +builtins.c:3051 vm_build_chunk_desc_body val_is_number TEST a +builtins.c:3056 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3112 vm_build_chunk_desc_body val_is_number TEST a +builtins.c:3113 vm_build_chunk_desc_body eigs_num_arg READ b builtins.c:3430 builtin_sandbox_run val_is_number TEST a builtins.c:3431 builtin_sandbox_run eigs_list_num READ b -builtins.c:3473 builtin_sandbox_run make_num PRODUCE c -builtins.c:3654 builtin_sandbox_run make_num PRODUCE c -builtins.c:3666 builtin_sandbox_run make_num PRODUCE c -builtins.c:3680 builtin_sandbox_run make_num PRODUCE c -builtins.c:3714 builtin_sandbox_run make_num PRODUCE c -builtins.c:3740 builtin_record_history val_is_number TEST i -builtins.c:3746 builtin_record_history eigs_num_arg READ i -builtins.c:3751 builtin_record_history make_num PRODUCE i -builtins.c:3779 builtin_copy_into val_is_number TEST a -builtins.c:3784 builtin_copy_into eigs_num_arg READ b -builtins.c:3796 builtin_copy_into val_is_number TEST a -builtins.c:3801 builtin_copy_into eigs_num_arg READ b -builtins.c:3834 builtin_list_slice val_is_number TEST a -builtins.c:3834 builtin_list_slice val_is_number TEST a -builtins.c:3837 builtin_list_slice eigs_num_arg READ b -builtins.c:3838 builtin_list_slice eigs_num_arg READ b -builtins.c:3860 builtin_num_copy val_is_number TEST a -builtins.c:3861 builtin_num_copy eigs_num_arg READ b -builtins.c:3861 builtin_num_copy make_num PRODUCE c -builtins.c:3905 builtin_range val_is_number TEST a -builtins.c:3907 builtin_range eigs_num_arg READ b -builtins.c:3914 builtin_range val_is_number TEST a -builtins.c:3922 builtin_range eigs_list_num READ b -builtins.c:3925 builtin_range eigs_list_num READ b -builtins.c:3929 builtin_range eigs_list_num READ b -builtins.c:3973 builtin_range make_num PRODUCE c -builtins.c:3989 builtin_fill eigs_list_num READ b -builtins.c:4011 at_index val_is_number TEST a -builtins.c:4015 at_index eigs_num_arg READ b -builtins.c:4019 at_index eigs_num_arg READ b -builtins.c:4030 buf_at_index val_is_number TEST a -builtins.c:4035 buf_at_index eigs_num_arg READ b -builtins.c:4039 buf_at_index eigs_num_arg READ b -builtins.c:4080 builtin_set_at val_is_number TEST a -builtins.c:4085 builtin_set_at eigs_num_arg READ b -builtins.c:4146 builtin_get_at buffer_read_num READ b -builtins.c:4146 builtin_get_at make_num PRODUCE c -builtins.c:4154 builtin_get_at buffer_read_num READ b -builtins.c:4154 builtin_get_at make_num PRODUCE c -builtins.c:4531 builtin_spawn make_num PRODUCE c -builtins.c:4537 builtin_spawn make_num PRODUCE c -builtins.c:4538 builtin_spawn make_num PRODUCE c -builtins.c:4563 builtin_thread_join val_is_number TEST a -builtins.c:4567 builtin_thread_join eigs_num_arg READ b -builtins.c:4568 builtin_thread_join eigs_num_arg READ b -builtins.c:4568 builtin_thread_join val_is_number TEST a -builtins.c:4671 get_channel_why val_is_number TEST a -builtins.c:4672 get_channel_why eigs_num_arg READ b -builtins.c:4674 get_channel_why eigs_num_arg READ b -builtins.c:4674 get_channel_why val_is_number TEST a -builtins.c:4739 builtin_channel make_num PRODUCE c -builtins.c:4740 builtin_channel make_num PRODUCE c -builtins.c:4842 builtin_recv_timeout val_is_number TEST a -builtins.c:4846 builtin_recv_timeout eigs_num_arg READ b -builtins.c:5028 builtin_task_spawn make_num PRODUCE c -builtins.c:5038 task_handle_resolve val_is_number TEST a -builtins.c:5039 task_handle_resolve eigs_num_arg READ b -builtins.c:5090 builtin_task_join val_is_number TEST a -builtins.c:5132 builtin_task_send val_is_number TEST a -builtins.c:5140 builtin_task_send eigs_num_arg READ b -builtins.c:5163 builtin_task_kill val_is_number TEST a -builtins.c:5175 builtin_task_alive val_is_number TEST a -builtins.c:5197 builtin_task_sleep val_is_number TEST a -builtins.c:5203 builtin_task_sleep eigs_num_arg READ b -builtins.c:5235 builtin_task_self make_num PRODUCE c -builtins.c:5249 builtin_task_detach val_is_number TEST a -builtins.c:5254 builtin_task_detach make_num PRODUCE c -builtins.c:5257 builtin_task_detach make_num PRODUCE c -builtins.c:5268 builtin_task_sched_seed val_is_number TEST a -builtins.c:5272 builtin_task_sched_seed eigs_num_arg READ b -builtins.c:5421 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5422 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5423 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5424 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5425 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5481 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5481 builtin_nearest_in_range val_is_number TEST a -builtins.c:5505 builtin_nearest_in_range eigs_num_arg_slow READ b -builtins.c:5508 builtin_nearest_in_range val_is_number TEST a -builtins.c:5508 builtin_nearest_in_range val_is_number TEST a -builtins.c:5510 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5511 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5525 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5526 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5527 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5528 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5553 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5554 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5555 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5610 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5610 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5630 builtin_nearest_in_range_all eigs_num_arg_slow READ b -builtins.c:5633 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5633 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5637 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5638 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5679 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5680 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5681 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5682 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5705 builtin_sign_extend make_num PRODUCE c -builtins.c:5715 builtin_sign_extend make_num PRODUCE c -builtins.c:5715 builtin_sign_extend val_is_number TEST a -builtins.c:5715 builtin_sign_extend val_is_number TEST a -builtins.c:5716 builtin_sign_extend eigs_num_arg READ b -builtins.c:5717 builtin_sign_extend eigs_num_arg READ b -builtins.c:5718 builtin_sign_extend make_num PRODUCE c +builtins.c:3437 builtin_sandbox_run val_is_number TEST a +builtins.c:3438 builtin_sandbox_run eigs_list_num READ b +builtins.c:3439 builtin_sandbox_run eigs_list_num READ b +builtins.c:3446 builtin_sandbox_run val_is_number TEST a +builtins.c:3447 builtin_sandbox_run eigs_list_num READ b +builtins.c:3489 builtin_sandbox_run make_num PRODUCE c +builtins.c:3670 builtin_sandbox_run make_num PRODUCE c +builtins.c:3682 builtin_sandbox_run make_num PRODUCE c +builtins.c:3696 builtin_sandbox_run make_num PRODUCE c +builtins.c:3730 builtin_sandbox_run make_num PRODUCE c +builtins.c:3756 builtin_record_history val_is_number TEST i +builtins.c:3762 builtin_record_history eigs_num_arg READ i +builtins.c:3767 builtin_record_history make_num PRODUCE i +builtins.c:3795 builtin_copy_into val_is_number TEST a +builtins.c:3800 builtin_copy_into eigs_num_arg READ b +builtins.c:3812 builtin_copy_into val_is_number TEST a +builtins.c:3817 builtin_copy_into eigs_num_arg READ b +builtins.c:3850 builtin_list_slice val_is_number TEST a +builtins.c:3850 builtin_list_slice val_is_number TEST a +builtins.c:3853 builtin_list_slice eigs_num_arg READ b +builtins.c:3854 builtin_list_slice eigs_num_arg READ b +builtins.c:3876 builtin_num_copy val_is_number TEST a +builtins.c:3877 builtin_num_copy eigs_num_arg READ b +builtins.c:3877 builtin_num_copy make_num PRODUCE c +builtins.c:3921 builtin_range val_is_number TEST a +builtins.c:3923 builtin_range eigs_num_arg READ b +builtins.c:3930 builtin_range val_is_number TEST a +builtins.c:3938 builtin_range eigs_list_num READ b +builtins.c:3941 builtin_range eigs_list_num READ b +builtins.c:3945 builtin_range eigs_list_num READ b +builtins.c:3989 builtin_range make_num PRODUCE c +builtins.c:4005 builtin_fill eigs_list_num READ b +builtins.c:4027 at_index val_is_number TEST a +builtins.c:4031 at_index eigs_num_arg READ b +builtins.c:4035 at_index eigs_num_arg READ b +builtins.c:4046 buf_at_index val_is_number TEST a +builtins.c:4051 buf_at_index eigs_num_arg READ b +builtins.c:4055 buf_at_index eigs_num_arg READ b +builtins.c:4096 builtin_set_at val_is_number TEST a +builtins.c:4101 builtin_set_at eigs_num_arg READ b +builtins.c:4162 builtin_get_at buffer_read_num READ b +builtins.c:4162 builtin_get_at make_num PRODUCE c +builtins.c:4170 builtin_get_at buffer_read_num READ b +builtins.c:4170 builtin_get_at make_num PRODUCE c +builtins.c:4547 builtin_spawn make_num PRODUCE c +builtins.c:4553 builtin_spawn make_num PRODUCE c +builtins.c:4554 builtin_spawn make_num PRODUCE c +builtins.c:4579 builtin_thread_join val_is_number TEST a +builtins.c:4583 builtin_thread_join eigs_num_arg READ b +builtins.c:4584 builtin_thread_join eigs_num_arg READ b +builtins.c:4584 builtin_thread_join val_is_number TEST a +builtins.c:4687 get_channel_why val_is_number TEST a +builtins.c:4688 get_channel_why eigs_num_arg READ b +builtins.c:4690 get_channel_why eigs_num_arg READ b +builtins.c:4690 get_channel_why val_is_number TEST a +builtins.c:4755 builtin_channel make_num PRODUCE c +builtins.c:4756 builtin_channel make_num PRODUCE c +builtins.c:4858 builtin_recv_timeout val_is_number TEST a +builtins.c:4862 builtin_recv_timeout eigs_num_arg READ b +builtins.c:5044 builtin_task_spawn make_num PRODUCE c +builtins.c:5054 task_handle_resolve val_is_number TEST a +builtins.c:5055 task_handle_resolve eigs_num_arg READ b +builtins.c:5106 builtin_task_join val_is_number TEST a +builtins.c:5148 builtin_task_send val_is_number TEST a +builtins.c:5156 builtin_task_send eigs_num_arg READ b +builtins.c:5179 builtin_task_kill val_is_number TEST a +builtins.c:5191 builtin_task_alive val_is_number TEST a +builtins.c:5213 builtin_task_sleep val_is_number TEST a +builtins.c:5219 builtin_task_sleep eigs_num_arg READ b +builtins.c:5251 builtin_task_self make_num PRODUCE c +builtins.c:5265 builtin_task_detach val_is_number TEST a +builtins.c:5270 builtin_task_detach make_num PRODUCE c +builtins.c:5273 builtin_task_detach make_num PRODUCE c +builtins.c:5284 builtin_task_sched_seed val_is_number TEST a +builtins.c:5288 builtin_task_sched_seed eigs_num_arg READ b +builtins.c:5437 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5438 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5439 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5440 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5441 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5497 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5497 builtin_nearest_in_range val_is_number TEST a +builtins.c:5521 builtin_nearest_in_range eigs_num_arg_slow READ b +builtins.c:5524 builtin_nearest_in_range val_is_number TEST a +builtins.c:5524 builtin_nearest_in_range val_is_number TEST a +builtins.c:5526 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5527 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5541 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5542 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5543 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5544 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5569 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5570 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5571 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5626 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5626 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5646 builtin_nearest_in_range_all eigs_num_arg_slow READ b +builtins.c:5649 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5649 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5653 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5654 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5695 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5696 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5697 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5698 builtin_nearest_in_range_all make_num PRODUCE c builtins.c:5721 builtin_sign_extend make_num PRODUCE c -builtins.c:5722 builtin_sign_extend make_num PRODUCE c -builtins.c:5739 builtin_list_truncate val_is_number TEST a -builtins.c:5743 builtin_list_truncate eigs_num_arg READ b -builtins.c:5769 builtin_list_remove_at val_is_number TEST a -builtins.c:5770 builtin_list_remove_at eigs_num_arg READ b -builtins.c:5791 builtin_list_insert_at val_is_number TEST a -builtins.c:5792 builtin_list_insert_at eigs_num_arg READ b -builtins.c:5819 builtin_list_index_of make_num PRODUCE f -builtins.c:5823 builtin_list_index_of make_num PRODUCE f -builtins.c:5829 builtin_list_index_of make_num PRODUCE f -builtins.c:5833 builtin_list_index_of make_num PRODUCE f -builtins.c:5904 builtin_sort_by val_is_number TEST f -builtins.c:5913 builtin_sort_by VAL_INT TEST f -builtins.c:5914 builtin_sort_by VAL_I64_RAW RAW f -builtins.c:5915 builtin_sort_by eigs_num_arg READ f -builtins.c:5937 sort_cmp_num VAL_INT TEST a -builtins.c:5937 sort_cmp_num VAL_INT TEST a -builtins.c:5938 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5938 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5938 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5938 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5939 sort_cmp_num VAL_INT TEST a -builtins.c:5940 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5940 sort_cmp_num eigs_num_arg READ b -builtins.c:5943 sort_cmp_num VAL_INT TEST a -builtins.c:5944 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5944 sort_cmp_num eigs_num_arg READ b -builtins.c:5947 sort_cmp_num eigs_num_arg READ b -builtins.c:5947 sort_cmp_num eigs_num_arg READ b -builtins.c:5965 builtin_sort VAL_FLOAT TEST f -builtins.c:5965 builtin_sort VAL_INT TEST f -builtins.c:5966 builtin_sort val_is_number TEST f -builtins.c:5973 builtin_sort VAL_FLOAT TEST f -builtins.c:5973 builtin_sort VAL_INT TEST f -builtins.c:5994 builtin_dispatch val_is_number TEST a -builtins.c:5998 builtin_dispatch eigs_num_arg READ b -builtins.c:5999 builtin_dispatch eigs_num_arg READ b -builtins.c:6001 builtin_dispatch eigs_num_arg READ b -builtins.c:6024 builtin_dispatch VAL_INT TEST a -builtins.c:6025 builtin_dispatch VAL_I64_RAW RAW b -builtins.c:6026 builtin_dispatch VAL_FLOAT TEST a -builtins.c:6027 builtin_dispatch eigs_num_arg READ b -builtins.c:6027 builtin_dispatch make_num PRODUCE c -builtins.c:6103 builtin_dot make_num PRODUCE c -builtins.c:6106 builtin_dot make_num PRODUCE c -builtins.c:6111 builtin_dot buffer_read_num READ b -builtins.c:6113 builtin_dot buffer_read_num READ b -builtins.c:6115 builtin_dot num_guard GUARD c -builtins.c:6115 builtin_dot num_guard GUARD c -builtins.c:6117 builtin_dot make_num PRODUCE c +builtins.c:5731 builtin_sign_extend make_num PRODUCE c +builtins.c:5731 builtin_sign_extend val_is_number TEST a +builtins.c:5731 builtin_sign_extend val_is_number TEST a +builtins.c:5732 builtin_sign_extend eigs_num_arg READ b +builtins.c:5733 builtin_sign_extend eigs_num_arg READ b +builtins.c:5734 builtin_sign_extend make_num PRODUCE c +builtins.c:5737 builtin_sign_extend make_num PRODUCE c +builtins.c:5738 builtin_sign_extend make_num PRODUCE c +builtins.c:5755 builtin_list_truncate val_is_number TEST a +builtins.c:5759 builtin_list_truncate eigs_num_arg READ b +builtins.c:5785 builtin_list_remove_at val_is_number TEST a +builtins.c:5786 builtin_list_remove_at eigs_num_arg READ b +builtins.c:5807 builtin_list_insert_at val_is_number TEST a +builtins.c:5808 builtin_list_insert_at eigs_num_arg READ b +builtins.c:5835 builtin_list_index_of make_num PRODUCE f +builtins.c:5839 builtin_list_index_of make_num PRODUCE f +builtins.c:5845 builtin_list_index_of make_num PRODUCE f +builtins.c:5849 builtin_list_index_of make_num PRODUCE f +builtins.c:5920 builtin_sort_by val_is_number TEST f +builtins.c:5929 builtin_sort_by VAL_INT TEST f +builtins.c:5930 builtin_sort_by VAL_I64_RAW RAW f +builtins.c:5931 builtin_sort_by eigs_num_arg READ f +builtins.c:5953 sort_cmp_num VAL_INT TEST a +builtins.c:5953 sort_cmp_num VAL_INT TEST a +builtins.c:5954 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5954 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5954 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5954 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5955 sort_cmp_num VAL_INT TEST a +builtins.c:5956 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5956 sort_cmp_num eigs_num_arg READ b +builtins.c:5959 sort_cmp_num VAL_INT TEST a +builtins.c:5960 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5960 sort_cmp_num eigs_num_arg READ b +builtins.c:5963 sort_cmp_num eigs_num_arg READ b +builtins.c:5963 sort_cmp_num eigs_num_arg READ b +builtins.c:5981 builtin_sort VAL_FLOAT TEST f +builtins.c:5981 builtin_sort VAL_INT TEST f +builtins.c:5982 builtin_sort val_is_number TEST f +builtins.c:5989 builtin_sort VAL_FLOAT TEST f +builtins.c:5989 builtin_sort VAL_INT TEST f +builtins.c:6010 builtin_dispatch val_is_number TEST a +builtins.c:6014 builtin_dispatch eigs_num_arg READ b +builtins.c:6015 builtin_dispatch eigs_num_arg READ b +builtins.c:6017 builtin_dispatch eigs_num_arg READ b +builtins.c:6040 builtin_dispatch VAL_INT TEST a +builtins.c:6041 builtin_dispatch VAL_I64_RAW RAW b +builtins.c:6042 builtin_dispatch VAL_FLOAT TEST a +builtins.c:6043 builtin_dispatch eigs_num_arg READ b +builtins.c:6043 builtin_dispatch make_num PRODUCE c +builtins.c:6119 builtin_dot make_num PRODUCE c +builtins.c:6122 builtin_dot make_num PRODUCE c +builtins.c:6127 builtin_dot buffer_read_num READ b +builtins.c:6129 builtin_dot buffer_read_num READ b +builtins.c:6131 builtin_dot num_guard GUARD c +builtins.c:6131 builtin_dot num_guard GUARD c +builtins.c:6133 builtin_dot make_num PRODUCE c builtins_buf.c:35 builtin_buffer VAL_FLOAT TEST a builtins_buf.c:35 builtin_buffer VAL_INT TEST a builtins_buf.c:36 builtin_buffer VAL_FLOAT TEST a @@ -1426,74 +1434,77 @@ eigenscript.c:1741 make_num make_num PRODUCE c eigenscript.c:1742 make_num num_guard GUARD c eigenscript.c:1758 make_num VAL_FLOAT TAGSET c eigenscript.c:1759 make_num VAL_F64_RAW WRITE c -eigenscript.c:1765 recycle_intermediate VAL_FLOAT TEST a -eigenscript.c:1787 make_num_permanent make_num_permanent PRODUCE c -eigenscript.c:1788 make_num_permanent num_guard GUARD c -eigenscript.c:1790 make_num_permanent VAL_FLOAT TAGSET c -eigenscript.c:1791 make_num_permanent VAL_F64_RAW WRITE c -eigenscript.c:1820 eigs_num_arg_slow eigs_num_arg_slow READ b -eigenscript.c:1821 eigs_num_arg_slow VAL_F64_RAW RAW b -eigenscript.c:1821 eigs_num_arg_slow VAL_FLOAT TEST a -eigenscript.c:1825 eigs_num_arg_slow VAL_I64_RAW RAW b -eigenscript.c:1825 eigs_num_arg_slow VAL_INT TEST a -eigenscript.c:1832 eigs_list_num eigs_list_num READ b -eigenscript.c:1839 eigs_list_num eigs_slot_num READ b -eigenscript.c:1842 eigs_elem_num eigs_elem_num READ b -eigenscript.c:1843 eigs_elem_num eigs_slot_elem_num READ b -eigenscript.c:1846 eigs_opt_num eigs_opt_num READ b -eigenscript.c:1847 eigs_opt_num eigs_slot_opt_num READ b -eigenscript.c:1883 slot_from_value VAL_FLOAT TEST a -eigenscript.c:1887 slot_from_value VAL_F64_RAW RAW b -eigenscript.c:1889 slot_from_value slot_from_f64 PRODUCE c -eigenscript.c:1893 slot_from_value VAL_INT TEST a -eigenscript.c:1894 slot_from_value VAL_I64_RAW RAW b -eigenscript.c:1897 slot_from_value slot_from_int PRODUCE c -eigenscript.c:1918 slot_to_value SLOT_F64_RAW RAW b -eigenscript.c:1918 slot_to_value make_num PRODUCE c -eigenscript.c:1918 slot_to_value slot_is_f64 TEST a -eigenscript.c:1926 slot_to_value slot_is_smi TEST a -eigenscript.c:2425 module_ns_project slot_is_f64 TEST a -eigenscript.c:2425 module_ns_project slot_is_f64 TEST a -eigenscript.c:2430 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2430 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2675 chan_clone_rec VAL_FLOAT TEST a -eigenscript.c:2675 chan_clone_rec VAL_INT TEST a -eigenscript.c:2678 chan_clone_rec VAL_F64_RAW RAW b -eigenscript.c:2678 chan_clone_rec VAL_FLOAT CASE a -eigenscript.c:2678 chan_clone_rec make_num PRODUCE c -eigenscript.c:2681 chan_clone_rec VAL_I64_RAW RAW b -eigenscript.c:2681 chan_clone_rec VAL_INT CASE a -eigenscript.c:2868 is_truthy VAL_F64_RAW RAW b -eigenscript.c:2868 is_truthy VAL_FLOAT CASE a -eigenscript.c:2869 is_truthy VAL_I64_RAW RAW b -eigenscript.c:2869 is_truthy VAL_INT CASE a -eigenscript.c:2908 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:2908 values_equal_impl VAL_INT TEST f -eigenscript.c:2909 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2909 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2910 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:2910 values_equal_impl VAL_INT TEST f -eigenscript.c:2911 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2911 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2912 values_equal_impl val_is_number TEST f -eigenscript.c:2913 values_equal_impl val_is_number TEST f -eigenscript.c:2927 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2927 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2927 values_equal_impl VAL_FLOAT CASE f -eigenscript.c:2928 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2928 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2928 values_equal_impl VAL_INT CASE f -eigenscript.c:2958 values_equal_impl buffer_read_num READ f -eigenscript.c:2960 values_equal_impl buffer_read_num READ f -eigenscript.c:3000 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3015 eigs_num_text strtod PARSE e -eigenscript.c:3025 value_to_string VAL_FLOAT CASE e -eigenscript.c:3026 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3026 value_to_string eigs_num_text FORMAT e -eigenscript.c:3029 value_to_string VAL_INT CASE e -eigenscript.c:3030 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4251 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4252 gc_value_is_node VAL_INT CASE a +eigenscript.c:1768 make_int VAL_INT TAGSET c +eigenscript.c:1769 make_int VAL_I64_RAW WRITE c +eigenscript.c:1775 recycle_intermediate VAL_FLOAT TEST a +eigenscript.c:1797 make_num_permanent make_num_permanent PRODUCE c +eigenscript.c:1798 make_num_permanent num_guard GUARD c +eigenscript.c:1800 make_num_permanent VAL_FLOAT TAGSET c +eigenscript.c:1801 make_num_permanent VAL_F64_RAW WRITE c +eigenscript.c:1830 eigs_num_arg_slow eigs_num_arg_slow READ b +eigenscript.c:1831 eigs_num_arg_slow VAL_F64_RAW RAW b +eigenscript.c:1831 eigs_num_arg_slow VAL_FLOAT TEST a +eigenscript.c:1835 eigs_num_arg_slow VAL_I64_RAW RAW b +eigenscript.c:1835 eigs_num_arg_slow VAL_INT TEST a +eigenscript.c:1842 eigs_list_num eigs_list_num READ b +eigenscript.c:1849 eigs_list_num eigs_slot_num READ b +eigenscript.c:1852 eigs_elem_num eigs_elem_num READ b +eigenscript.c:1853 eigs_elem_num eigs_slot_elem_num READ b +eigenscript.c:1856 eigs_opt_num eigs_opt_num READ b +eigenscript.c:1857 eigs_opt_num eigs_slot_opt_num READ b +eigenscript.c:1893 slot_from_value VAL_FLOAT TEST a +eigenscript.c:1897 slot_from_value VAL_F64_RAW RAW b +eigenscript.c:1899 slot_from_value slot_from_f64 PRODUCE c +eigenscript.c:1903 slot_from_value VAL_INT TEST a +eigenscript.c:1904 slot_from_value VAL_I64_RAW RAW b +eigenscript.c:1907 slot_from_value slot_from_int PRODUCE c +eigenscript.c:1927 slot_to_value SLOT_F64_RAW RAW b +eigenscript.c:1927 slot_to_value make_num PRODUCE c +eigenscript.c:1927 slot_to_value slot_is_f64 TEST a +eigenscript.c:1935 slot_to_value slot_is_smi TEST a +eigenscript.c:1935 slot_to_value slot_smi_val RAW b +eigenscript.c:2434 module_ns_project slot_is_f64 TEST a +eigenscript.c:2434 module_ns_project slot_is_f64 TEST a +eigenscript.c:2439 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2439 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2684 chan_clone_rec VAL_FLOAT TEST a +eigenscript.c:2684 chan_clone_rec VAL_INT TEST a +eigenscript.c:2687 chan_clone_rec VAL_F64_RAW RAW b +eigenscript.c:2687 chan_clone_rec VAL_FLOAT CASE a +eigenscript.c:2687 chan_clone_rec make_num PRODUCE c +eigenscript.c:2690 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:2690 chan_clone_rec VAL_INT CASE a +eigenscript.c:2877 is_truthy VAL_F64_RAW RAW b +eigenscript.c:2877 is_truthy VAL_FLOAT CASE a +eigenscript.c:2878 is_truthy VAL_I64_RAW RAW b +eigenscript.c:2878 is_truthy VAL_INT CASE a +eigenscript.c:2917 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2917 values_equal_impl VAL_INT TEST f +eigenscript.c:2918 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2918 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2919 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2919 values_equal_impl VAL_INT TEST f +eigenscript.c:2920 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2920 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2921 values_equal_impl val_is_number TEST f +eigenscript.c:2922 values_equal_impl val_is_number TEST f +eigenscript.c:2936 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2936 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2936 values_equal_impl VAL_FLOAT CASE f +eigenscript.c:2937 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2937 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2937 values_equal_impl VAL_INT CASE f +eigenscript.c:2967 values_equal_impl buffer_read_num READ f +eigenscript.c:2969 values_equal_impl buffer_read_num READ f +eigenscript.c:3009 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:3024 eigs_num_text strtod PARSE e +eigenscript.c:3034 value_to_string VAL_FLOAT CASE e +eigenscript.c:3035 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3035 value_to_string eigs_num_text FORMAT e +eigenscript.c:3038 value_to_string VAL_INT CASE e +eigenscript.c:3039 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4260 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4261 gc_value_is_node VAL_INT CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a eigenscript.h:272 VAL_FLOAT DATA a @@ -1516,23 +1527,23 @@ eigenscript.h:1392 eigs_list_num READ b eigenscript.h:1397 eigs_elem_num READ b eigenscript.h:1398 eigs_opt_num READ b eigenscript.h:1769 make_num PRODUCE c -eigenscript.h:1779 make_num_permanent PRODUCE c -eigenscript.h:1831 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1873 num_guard num_guard GUARD c -eigenscript.h:1881 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1881 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1780 make_num_permanent PRODUCE c +eigenscript.h:1832 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1874 num_guard num_guard GUARD c eigenscript.h:1882 num_guard EIGS_NUM_MAX GUARD c eigenscript.h:1882 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1891 buffer_read_num buffer_read_num READ b -eigenscript.h:1892 buffer_read_num num_guard GUARD c -eigenscript.h:1898 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1907 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1916 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1917 buffer_read_byte buffer_read_num READ b -eigenscript.h:1919 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1930 num_guard_named num_guard_named GUARD c -eigenscript.h:1936 num_guard_named num_guard GUARD c -eigenscript.h:2249 eigs_num_text FORMAT e +eigenscript.h:1883 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1883 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1892 buffer_read_num buffer_read_num READ b +eigenscript.h:1893 buffer_read_num num_guard GUARD c +eigenscript.h:1899 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1908 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1917 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1918 buffer_read_byte buffer_read_num READ b +eigenscript.h:1920 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1931 num_guard_named num_guard_named GUARD c +eigenscript.h:1937 num_guard_named num_guard GUARD c +eigenscript.h:2250 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j @@ -1992,102 +2003,102 @@ ext_store.c:1478 builtin_store_count make_num PRODUCE h ext_store.c:1512 builtin_store_update val_is_number TEST h ext_store.c:1513 builtin_store_update eigs_num_arg READ h ext_store.c:1654 builtin_store_drop eigs_num_arg READ h -jit.c:1282 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d -jit.c:1406 emit_addsd_xmm0_xmm1 emit_addsd_xmm0_xmm1 EMIT d -jit.c:1410 emit_subsd_xmm0_xmm1 emit_subsd_xmm0_xmm1 EMIT d -jit.c:1414 emit_mulsd_xmm0_xmm1 emit_mulsd_xmm0_xmm1 EMIT d -jit.c:1418 emit_divsd_xmm0_xmm1 emit_divsd_xmm0_xmm1 EMIT d -jit.c:1424 emit_cvttsd2si_xmm0_rax emit_cvttsd2si_xmm0_rax EMIT d -jit.c:1428 emit_cvttsd2si_xmm1_rdx emit_cvttsd2si_xmm1_rdx EMIT d -jit.c:1436 emit_cvtsi2sd_rax_xmm2 emit_cvtsi2sd_rax_xmm2 EMIT d -jit.c:1440 emit_cvtsi2sd_rdx_xmm2 emit_cvtsi2sd_rdx_xmm2 EMIT d -jit.c:1444 emit_ucomisd_xmm0_xmm2 emit_ucomisd_xmm0_xmm2 EMIT d -jit.c:1448 emit_ucomisd_xmm1_xmm2 emit_ucomisd_xmm1_xmm2 EMIT d -jit.c:1452 emit_cvtsi2sd_rdx_xmm0 emit_cvtsi2sd_rdx_xmm0 EMIT d -jit.c:1499 emit_btr_63_rax emit_btr_63_rax EMIT d -jit.c:1517 emit_cvtsi2sd_rax_xmm0 emit_cvtsi2sd_rax_xmm0 EMIT d -jit.c:1531 emit_ucomisd_xmm0_xmm1 emit_ucomisd_xmm0_xmm1 EMIT d -jit.c:1593 emit_btr_63_rdx emit_btr_63_rdx EMIT d -jit.c:1598 emit_btr_63_rsi emit_btr_63_rsi EMIT d -jit.c:1625 emit_immediate_num_check_rax emit_immediate_num_check_rax EMIT d -jit.c:1628 emit_immediate_num_check_rax TAG-IMM 0xFFF8 EMIT d -jit.c:1631 emit_immediate_num_check_rdx emit_immediate_num_check_rdx EMIT d -jit.c:1634 emit_immediate_num_check_rdx TAG-IMM 0xFFF8 EMIT d -jit.c:1640 emit_overflow_check_rax EMIT d -jit.c:1643 emit_overflow_check_rax emit_btr_63_rdx EMIT d -jit.c:1704 emit_cvttsd2si_xmm0_r8d emit_cvttsd2si_xmm0_r8d EMIT d -jit.c:1709 emit_cvtsi2sd_r8d_xmm1 emit_cvtsi2sd_r8d_xmm1 EMIT d -jit.c:1716 emit_cvttsd2si_xmm0_edx emit_cvttsd2si_xmm0_edx EMIT d -jit.c:1721 emit_cvtsi2sd_edx_xmm0 emit_cvtsi2sd_edx_xmm0 EMIT d -jit.c:1914 emit_jump_unless_bool_rax TAG-IMM 0xFFF9 EMIT d -jit.c:2032 emit_conditional_decref_rsi_hook TAG-IMM 0xFFFB EMIT d -jit.c:2178 emit_dict_cache_probe TAG-IMM 0xFFFB EMIT d -jit.c:2343 emit_load_numeric_operand EMIT d -jit.c:2348 emit_load_numeric_operand TAG-IMM 0xFFF8 EMIT d -jit.c:2353 emit_load_numeric_operand TAG-IMM 0xFFFB EMIT d -jit.c:2356 emit_load_numeric_operand TAG-IMM 0xFFFD EMIT d -jit.c:2363 emit_load_numeric_operand VAL_FLOAT EMIT d -jit.c:2367 emit_load_numeric_operand VAL_F64_OFFSET RAW d -jit.c:2368 emit_load_numeric_operand VAL_F64_OFFSET RAW d -jit.c:2397 emit_decref_binop_operands TAG-IMM 0xFFFB EMIT d -jit.c:2425 emit_commit_binop TAG-IMM 0xFFFB EMIT d -jit.c:2633 jit_compile_to_thunk max_normal_bits EMIT d -jit.c:2634 jit_compile_to_thunk EIGS_NUM_MAX GUARD d -jit.c:2634 jit_compile_to_thunk max_normal_bits EMIT d -jit.c:2801 jit_compile_to_thunk/OP_NULL TAG-IMM 0xFFF8 EMIT d -jit.c:2822 jit_compile_to_thunk/OP_CONST VAL_FLOAT TEST d -jit.c:2825 jit_compile_to_thunk/OP_CONST VAL_F64_RAW RAW d -jit.c:2828 jit_compile_to_thunk/OP_CONST TAG-IMM 0xFFFB EMIT d -jit.c:3024 jit_compile_to_thunk/OP_SET_NAME TAG-IMM 0xFFFB EMIT d -jit.c:3145 jit_compile_to_thunk/OP_LOCAL_DOT_GET emit_immediate_num_check_rax EMIT d -jit.c:3271 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rax EMIT d -jit.c:3274 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rdx EMIT d -jit.c:3452 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFF8 EMIT d -jit.c:3457 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFB EMIT d -jit.c:3459 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFD EMIT d -jit.c:3465 jit_compile_to_thunk/OP_SET_LOCAL VAL_FLOAT EMIT d -jit.c:3471 jit_compile_to_thunk/OP_SET_LOCAL VAL_F64_OFFSET RAW d -jit.c:3530 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d -jit.c:3534 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d -jit.c:3544 jit_compile_to_thunk/OP_MOD emit_btr_63_rsi EMIT d -jit.c:3558 jit_compile_to_thunk/OP_MOD fmod EMIT d -jit.c:3564 jit_compile_to_thunk/OP_MOD emit_overflow_check_rax EMIT d -jit.c:3564 jit_compile_to_thunk/OP_MOD max_normal_bits EMIT d -jit.c:3612 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d -jit.c:3616 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d -jit.c:3624 jit_compile_to_thunk/OP_ADD emit_addsd_xmm0_xmm1 EMIT d -jit.c:3625 jit_compile_to_thunk/OP_ADD emit_subsd_xmm0_xmm1 EMIT d -jit.c:3626 jit_compile_to_thunk/OP_ADD emit_mulsd_xmm0_xmm1 EMIT d -jit.c:3627 jit_compile_to_thunk/OP_ADD emit_divsd_xmm0_xmm1 EMIT d -jit.c:3634 jit_compile_to_thunk/OP_ADD emit_overflow_check_rax EMIT d -jit.c:3634 jit_compile_to_thunk/OP_ADD max_normal_bits EMIT d -jit.c:3673 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d -jit.c:3677 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d -jit.c:3690 jit_compile_to_thunk/OP_EQ emit_ucomisd_xmm0_xmm1 EMIT d -jit.c:3730 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rax EMIT d -jit.c:3732 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rdx EMIT d -jit.c:3738 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm0_rax EMIT d -jit.c:3739 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rax_xmm2 EMIT d -jit.c:3740 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm0_xmm2 EMIT d -jit.c:3743 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm1_rdx EMIT d -jit.c:3744 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm2 EMIT d -jit.c:3745 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm1_xmm2 EMIT d -jit.c:3765 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm0 EMIT d -jit.c:3795 jit_compile_to_thunk/OP_NOT emit_immediate_num_check_rax EMIT d -jit.c:3808 jit_compile_to_thunk/OP_NEG emit_btr_63_rax EMIT d -jit.c:3823 jit_compile_to_thunk/OP_NEG emit_cvttsd2si_xmm0_rax EMIT d -jit.c:3824 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm2 EMIT d -jit.c:3825 jit_compile_to_thunk/OP_NEG emit_ucomisd_xmm0_xmm2 EMIT d -jit.c:3829 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm0 EMIT d -jit.c:3948 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_immediate_num_check_rax EMIT d -jit.c:3951 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_btr_63_rax EMIT d -jit.c:4088 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rdx EMIT d -jit.c:4093 jit_compile_to_thunk/OP_INDEX_SET TAG-IMM 0xFFFB EMIT d -jit.c:4107 jit_compile_to_thunk/OP_INDEX_SET emit_cvttsd2si_xmm0_r8d EMIT d -jit.c:4108 jit_compile_to_thunk/OP_INDEX_SET emit_cvtsi2sd_r8d_xmm1 EMIT d -jit.c:4109 jit_compile_to_thunk/OP_INDEX_SET emit_ucomisd_xmm0_xmm1 EMIT d -jit.c:4117 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rax EMIT d -jit.c:4375 jit_compile_to_thunk/OP_POP VAL_FLOAT TEST d +jit.c:1275 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d +jit.c:1399 emit_addsd_xmm0_xmm1 emit_addsd_xmm0_xmm1 EMIT d +jit.c:1403 emit_subsd_xmm0_xmm1 emit_subsd_xmm0_xmm1 EMIT d +jit.c:1407 emit_mulsd_xmm0_xmm1 emit_mulsd_xmm0_xmm1 EMIT d +jit.c:1411 emit_divsd_xmm0_xmm1 emit_divsd_xmm0_xmm1 EMIT d +jit.c:1417 emit_cvttsd2si_xmm0_rax emit_cvttsd2si_xmm0_rax EMIT d +jit.c:1421 emit_cvttsd2si_xmm1_rdx emit_cvttsd2si_xmm1_rdx EMIT d +jit.c:1429 emit_cvtsi2sd_rax_xmm2 emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:1433 emit_cvtsi2sd_rdx_xmm2 emit_cvtsi2sd_rdx_xmm2 EMIT d +jit.c:1437 emit_ucomisd_xmm0_xmm2 emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:1441 emit_ucomisd_xmm1_xmm2 emit_ucomisd_xmm1_xmm2 EMIT d +jit.c:1445 emit_cvtsi2sd_rdx_xmm0 emit_cvtsi2sd_rdx_xmm0 EMIT d +jit.c:1492 emit_btr_63_rax emit_btr_63_rax EMIT d +jit.c:1510 emit_cvtsi2sd_rax_xmm0 emit_cvtsi2sd_rax_xmm0 EMIT d +jit.c:1524 emit_ucomisd_xmm0_xmm1 emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:1586 emit_btr_63_rdx emit_btr_63_rdx EMIT d +jit.c:1591 emit_btr_63_rsi emit_btr_63_rsi EMIT d +jit.c:1618 emit_immediate_num_check_rax emit_immediate_num_check_rax EMIT d +jit.c:1621 emit_immediate_num_check_rax TAG-IMM 0xFFF8 EMIT d +jit.c:1624 emit_immediate_num_check_rdx emit_immediate_num_check_rdx EMIT d +jit.c:1627 emit_immediate_num_check_rdx TAG-IMM 0xFFF8 EMIT d +jit.c:1633 emit_overflow_check_rax EMIT d +jit.c:1636 emit_overflow_check_rax emit_btr_63_rdx EMIT d +jit.c:1697 emit_cvttsd2si_xmm0_r8d emit_cvttsd2si_xmm0_r8d EMIT d +jit.c:1702 emit_cvtsi2sd_r8d_xmm1 emit_cvtsi2sd_r8d_xmm1 EMIT d +jit.c:1709 emit_cvttsd2si_xmm0_edx emit_cvttsd2si_xmm0_edx EMIT d +jit.c:1714 emit_cvtsi2sd_edx_xmm0 emit_cvtsi2sd_edx_xmm0 EMIT d +jit.c:1907 emit_jump_unless_bool_rax TAG-IMM 0xFFF9 EMIT d +jit.c:2025 emit_conditional_decref_rsi_hook TAG-IMM 0xFFFB EMIT d +jit.c:2171 emit_dict_cache_probe TAG-IMM 0xFFFB EMIT d +jit.c:2336 emit_load_numeric_operand EMIT d +jit.c:2341 emit_load_numeric_operand TAG-IMM 0xFFF8 EMIT d +jit.c:2346 emit_load_numeric_operand TAG-IMM 0xFFFB EMIT d +jit.c:2349 emit_load_numeric_operand TAG-IMM 0xFFFD EMIT d +jit.c:2356 emit_load_numeric_operand VAL_FLOAT EMIT d +jit.c:2360 emit_load_numeric_operand VAL_F64_OFFSET RAW d +jit.c:2361 emit_load_numeric_operand VAL_F64_OFFSET RAW d +jit.c:2390 emit_decref_binop_operands TAG-IMM 0xFFFB EMIT d +jit.c:2418 emit_commit_binop TAG-IMM 0xFFFB EMIT d +jit.c:2626 jit_compile_to_thunk max_normal_bits EMIT d +jit.c:2627 jit_compile_to_thunk EIGS_NUM_MAX GUARD d +jit.c:2627 jit_compile_to_thunk max_normal_bits EMIT d +jit.c:2794 jit_compile_to_thunk/OP_NULL TAG-IMM 0xFFF8 EMIT d +jit.c:2815 jit_compile_to_thunk/OP_CONST VAL_FLOAT TEST d +jit.c:2818 jit_compile_to_thunk/OP_CONST VAL_F64_RAW RAW d +jit.c:2821 jit_compile_to_thunk/OP_CONST TAG-IMM 0xFFFB EMIT d +jit.c:3017 jit_compile_to_thunk/OP_SET_NAME TAG-IMM 0xFFFB EMIT d +jit.c:3138 jit_compile_to_thunk/OP_LOCAL_DOT_GET emit_immediate_num_check_rax EMIT d +jit.c:3264 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rax EMIT d +jit.c:3267 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rdx EMIT d +jit.c:3445 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFF8 EMIT d +jit.c:3450 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFB EMIT d +jit.c:3452 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFD EMIT d +jit.c:3458 jit_compile_to_thunk/OP_SET_LOCAL VAL_FLOAT EMIT d +jit.c:3464 jit_compile_to_thunk/OP_SET_LOCAL VAL_F64_OFFSET RAW d +jit.c:3523 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d +jit.c:3527 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d +jit.c:3537 jit_compile_to_thunk/OP_MOD emit_btr_63_rsi EMIT d +jit.c:3551 jit_compile_to_thunk/OP_MOD fmod EMIT d +jit.c:3557 jit_compile_to_thunk/OP_MOD emit_overflow_check_rax EMIT d +jit.c:3557 jit_compile_to_thunk/OP_MOD max_normal_bits EMIT d +jit.c:3605 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d +jit.c:3609 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d +jit.c:3617 jit_compile_to_thunk/OP_ADD emit_addsd_xmm0_xmm1 EMIT d +jit.c:3618 jit_compile_to_thunk/OP_ADD emit_subsd_xmm0_xmm1 EMIT d +jit.c:3619 jit_compile_to_thunk/OP_ADD emit_mulsd_xmm0_xmm1 EMIT d +jit.c:3620 jit_compile_to_thunk/OP_ADD emit_divsd_xmm0_xmm1 EMIT d +jit.c:3627 jit_compile_to_thunk/OP_ADD emit_overflow_check_rax EMIT d +jit.c:3627 jit_compile_to_thunk/OP_ADD max_normal_bits EMIT d +jit.c:3666 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d +jit.c:3670 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d +jit.c:3683 jit_compile_to_thunk/OP_EQ emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:3723 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rax EMIT d +jit.c:3725 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rdx EMIT d +jit.c:3731 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm0_rax EMIT d +jit.c:3732 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:3733 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:3736 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm1_rdx EMIT d +jit.c:3737 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm2 EMIT d +jit.c:3738 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm1_xmm2 EMIT d +jit.c:3758 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm0 EMIT d +jit.c:3788 jit_compile_to_thunk/OP_NOT emit_immediate_num_check_rax EMIT d +jit.c:3801 jit_compile_to_thunk/OP_NEG emit_btr_63_rax EMIT d +jit.c:3816 jit_compile_to_thunk/OP_NEG emit_cvttsd2si_xmm0_rax EMIT d +jit.c:3817 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:3818 jit_compile_to_thunk/OP_NEG emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:3822 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm0 EMIT d +jit.c:3941 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_immediate_num_check_rax EMIT d +jit.c:3944 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_btr_63_rax EMIT d +jit.c:4081 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rdx EMIT d +jit.c:4086 jit_compile_to_thunk/OP_INDEX_SET TAG-IMM 0xFFFB EMIT d +jit.c:4100 jit_compile_to_thunk/OP_INDEX_SET emit_cvttsd2si_xmm0_r8d EMIT d +jit.c:4101 jit_compile_to_thunk/OP_INDEX_SET emit_cvtsi2sd_r8d_xmm1 EMIT d +jit.c:4102 jit_compile_to_thunk/OP_INDEX_SET emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:4110 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rax EMIT d +jit.c:4368 jit_compile_to_thunk/OP_POP VAL_FLOAT TEST d jit_smoke.c:103 jit_helper_local_idx_get slot_from_f64 PRODUCE d jit_smoke.c:138 jit_helper_iter_next SLOT_F64_RAW RAW d jit_smoke.c:142 jit_helper_iter_next slot_from_f64 PRODUCE d @@ -2226,21 +2237,21 @@ value_slot.h:123 #define SLOT_F64_RAW d_ RAW b value_slot.h:135 slot_smi_val slot_smi_val RAW b value_slot.h:143 slot_from_f64 SLOT_F64_RAW WRITE c value_slot.h:143 slot_from_f64 slot_from_f64 PRODUCE c -value_slot.h:148 slot_from_int slot_from_int PRODUCE c -value_slot.h:227 slot_truthy_immediate SLOT_F64_RAW RAW b -value_slot.h:227 slot_truthy_immediate slot_is_f64 TEST a -value_slot.h:230 slot_truthy_immediate slot_is_smi TEST a -value_slot.h:230 slot_truthy_immediate slot_smi_val RAW b -value_slot.h:244 slot_f64_value slot_f64_value READ b -value_slot.h:245 slot_f64_value SLOT_F64_RAW RAW b -value_slot.h:245 slot_f64_value slot_is_f64 TEST a -value_slot.h:248 slot_f64_value VAL_F64_RAW RAW b -value_slot.h:248 slot_f64_value VAL_FLOAT TEST a -value_slot.h:254 slot_int_value slot_int_value READ b -value_slot.h:255 slot_int_value slot_is_smi TEST a -value_slot.h:255 slot_int_value slot_smi_val RAW b -value_slot.h:258 slot_int_value VAL_I64_RAW RAW b -value_slot.h:258 slot_int_value VAL_INT TEST a +value_slot.h:147 slot_from_int slot_from_int PRODUCE c +value_slot.h:226 slot_truthy_immediate SLOT_F64_RAW RAW b +value_slot.h:226 slot_truthy_immediate slot_is_f64 TEST a +value_slot.h:229 slot_truthy_immediate slot_is_smi TEST a +value_slot.h:229 slot_truthy_immediate slot_smi_val RAW b +value_slot.h:243 slot_f64_value slot_f64_value READ b +value_slot.h:244 slot_f64_value SLOT_F64_RAW RAW b +value_slot.h:244 slot_f64_value slot_is_f64 TEST a +value_slot.h:247 slot_f64_value VAL_F64_RAW RAW b +value_slot.h:247 slot_f64_value VAL_FLOAT TEST a +value_slot.h:253 slot_int_value slot_int_value READ b +value_slot.h:254 slot_int_value slot_is_smi TEST a +value_slot.h:254 slot_int_value slot_smi_val RAW b +value_slot.h:257 slot_int_value VAL_I64_RAW RAW b +value_slot.h:257 slot_int_value VAL_INT TEST a vm.c:107 obs_dump_num eigs_num_text FORMAT i vm.c:118 obs_dump_value SLOT_F64_RAW RAW i vm.c:118 obs_dump_value slot_is_f64 TEST i @@ -2267,277 +2278,276 @@ vm.c:870 slot_truthy SLOT_F64_RAW RAW b vm.c:870 slot_truthy slot_is_f64 TEST a vm.c:874 slot_truthy slot_is_smi TEST a vm.c:874 slot_truthy slot_smi_val RAW b -vm.c:931 make_iter_state make_num PRODUCE c -vm.c:944 make_iter_state make_num PRODUCE c -vm.c:1163 vm_store_local_slot slot_is_f64 TEST a -vm.c:1167 vm_store_local_slot VAL_FLOAT TEST a -vm.c:1169 vm_store_local_slot SLOT_F64_RAW RAW b -vm.c:1169 vm_store_local_slot VAL_F64_RAW WRITE c -vm.c:1360 jit_helper_local_idx_get buffer_read_num READ b -vm.c:1360 jit_helper_local_idx_get slot_from_f64 PRODUCE c -vm.c:1521 jit_helper_dot_set slot_is_f64 TEST a -vm.c:1524 jit_helper_dot_set SLOT_F64_RAW RAW b -vm.c:1591 jit_helper_local_dot_set slot_is_f64 TEST a -vm.c:1592 jit_helper_local_dot_set SLOT_F64_RAW RAW b -vm.c:1642 obs_slot_observable slot_is_f64 TEST i -vm.c:1649 obs_slot_num SLOT_F64_RAW RAW i -vm.c:1649 obs_slot_num slot_is_f64 TEST i -vm.c:1650 obs_slot_num slot_is_smi TEST i -vm.c:1650 obs_slot_num slot_smi_val RAW i -vm.c:1798 jit_helper_iter_next slot_f64_value READ b -vm.c:1799 jit_helper_iter_next VAL_INT TEST a -vm.c:1814 jit_helper_iter_next slot_f64_value READ b -vm.c:1817 jit_helper_iter_next VAL_INT TEST a -vm.c:1819 jit_helper_iter_next slot_int_value READ b -vm.c:1826 jit_helper_iter_next buffer_read_num READ b -vm.c:1826 jit_helper_iter_next num_guard GUARD c -vm.c:1826 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1832 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1902 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b -vm.c:1902 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1906 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1909 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1948 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1962 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1962 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:1973 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1974 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:1992 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:1992 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2075 loop_iter_store make_num PRODUCE c -vm.c:2082 loop_iter_store slot_is_f64 TEST a -vm.c:2083 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2088 loop_iter_store make_num PRODUCE c -vm.c:2203 vm_value_index_is_int VAL_INT TEST a -vm.c:2204 vm_value_index_is_int VAL_I64_RAW RAW b -vm.c:2209 vm_value_index_is_int VAL_F64_RAW RAW b -vm.c:2222 jit_helper_index_set slot_is_f64 TEST a -vm.c:2227 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2228 jit_helper_index_set slot_is_f64 TEST a -vm.c:2230 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2232 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2242 jit_helper_index_set slot_is_f64 TEST a -vm.c:2244 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2245 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2247 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2259 jit_helper_index_set val_is_number TEST a -vm.c:2262 jit_helper_index_set eigs_num_arg READ b -vm.c:2269 jit_helper_index_set val_is_number TEST a -vm.c:2272 jit_helper_index_set eigs_num_arg READ b -vm.c:2275 jit_helper_index_set val_is_number TEST a -vm.c:2276 jit_helper_index_set eigs_num_arg READ b -vm.c:2295 jit_helper_index_get slot_is_f64 TEST a -vm.c:2297 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2304 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2315 jit_helper_index_get buffer_read_num READ b -vm.c:2317 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2319 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2335 jit_helper_index_get val_is_number TEST a -vm.c:2338 jit_helper_index_get eigs_num_arg READ b -vm.c:2350 jit_helper_index_get val_is_number TEST a -vm.c:2353 jit_helper_index_get eigs_num_arg READ b -vm.c:2362 jit_helper_index_get val_is_number TEST a -vm.c:2365 jit_helper_index_get eigs_num_arg READ b -vm.c:2367 jit_helper_index_get buffer_read_num READ b -vm.c:2367 jit_helper_index_get make_num PRODUCE c -vm.c:2953 vm_take_error_value make_num PRODUCE c -vm.c:3057 slot_type_name slot_is_f64 TEST e -vm.c:3058 slot_type_name slot_is_smi TEST e -vm.c:3298 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a -vm.c:3299 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b -vm.c:3299 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3313 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3318 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3338 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3338 #define NUM_REUSE VAL_FLOAT TEST a -vm.c:3349 #define ARITH_FAST slot_f64_value READ b -vm.c:3349 #define ARITH_FAST slot_f64_value READ b -vm.c:3350 #define ARITH_FAST num_guard GUARD c -vm.c:3355 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3356 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3364 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3365 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3373 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3383 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3383 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3384 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3384 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3384 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3385 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3385 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3386 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3386 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3387 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3410 vm_run_ex/CASE(ADD) VAL_INT TEST a -vm.c:3410 vm_run_ex/CASE(ADD) VAL_INT TEST a -vm.c:3438 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3438 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3439 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3439 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3439 #define NUM_BINOP num_guard GUARD c -vm.c:3440 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3440 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3442 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3442 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3443 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3443 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3444 #define NUM_BINOP make_num PRODUCE c -vm.c:3446 #define NUM_BINOP VAL_INT TEST a -vm.c:3446 #define NUM_BINOP VAL_INT TEST a -vm.c:3450 #define NUM_BINOP make_num PRODUCE c -vm.c:3468 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a -vm.c:3468 vm_run_ex/CASE(DIV) VAL_FLOAT TEST a -vm.c:3469 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3471 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3473 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3473 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3473 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3476 vm_run_ex/CASE(DIV) VAL_F64_RAW RAW b -vm.c:3478 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3478 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3479 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3479 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3480 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3483 vm_run_ex/CASE(DIV) VAL_INT TEST a -vm.c:3483 vm_run_ex/CASE(DIV) VAL_INT TEST a -vm.c:3487 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3495 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b -vm.c:3495 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3495 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3496 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b -vm.c:3496 vm_run_ex/CASE(MOD) VAL_F64_RAW RAW b -vm.c:3496 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3497 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3497 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3498 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3498 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3499 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3501 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3501 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3503 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3503 vm_run_ex/CASE(MOD) VAL_FLOAT TEST a -vm.c:3508 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3531 #define INT_BINOP_R slot_f64_value READ b -vm.c:3531 #define INT_BINOP_R slot_f64_value READ b -vm.c:3533 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3534 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3537 #define INT_BINOP_R num_to_i64_exact READ b -vm.c:3538 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3545 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3545 #define INT_BINOP_R VAL_F64_RAW WRITE c -vm.c:3549 #define INT_BINOP_R NUM_REUSE TEST a -vm.c:3549 #define INT_BINOP_R VAL_F64_RAW WRITE c -vm.c:3552 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3560 #define INT_BINOP_R VAL_INT TEST a -vm.c:3562 #define INT_BINOP_R VAL_INT TEST a -vm.c:3573 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3600 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3603 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3603 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3606 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3611 vm_run_ex/CASE(NEG) VAL_INT TEST a -vm.c:3615 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3630 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3632 vm_run_ex/CASE(BNOT) num_to_i64_exact READ b -vm.c:3635 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3641 vm_run_ex/CASE(BNOT) NUM_REUSE TEST a -vm.c:3641 vm_run_ex/CASE(BNOT) VAL_F64_RAW WRITE c -vm.c:3644 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3649 vm_run_ex/CASE(BNOT) VAL_INT TEST a -vm.c:3656 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3666 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3666 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3687 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3687 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3709 #define NUM_CMP slot_f64_value READ f -vm.c:3709 #define NUM_CMP slot_f64_value READ f -vm.c:3732 #define NUM_CMP VAL_INT TEST f -vm.c:3734 #define NUM_CMP VAL_INT TEST f -vm.c:4651 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4653 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4660 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4670 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4672 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4674 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4696 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4698 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4699 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4701 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4703 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4713 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4715 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4715 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:890 vm_int_arith slot_from_int PRODUCE c +vm.c:898 vm_bit_operand slot_int_value READ b +vm.c:899 vm_bit_operand num_to_i64_exact READ b +vm.c:899 vm_bit_operand slot_f64_value READ b +vm.c:907 vm_number_compare slot_int_value READ b +vm.c:907 vm_number_compare slot_int_value READ b +vm.c:909 vm_number_compare slot_f64_value READ b +vm.c:910 vm_number_compare slot_f64_value READ b +vm.c:962 make_iter_state make_num PRODUCE c +vm.c:975 make_iter_state make_num PRODUCE c +vm.c:1194 vm_store_local_slot slot_is_f64 TEST a +vm.c:1198 vm_store_local_slot VAL_FLOAT TEST a +vm.c:1200 vm_store_local_slot SLOT_F64_RAW RAW b +vm.c:1200 vm_store_local_slot VAL_F64_RAW WRITE c +vm.c:1391 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1391 jit_helper_local_idx_get slot_from_f64 PRODUCE c +vm.c:1552 jit_helper_dot_set slot_is_f64 TEST a +vm.c:1555 jit_helper_dot_set SLOT_F64_RAW RAW b +vm.c:1622 jit_helper_local_dot_set slot_is_f64 TEST a +vm.c:1623 jit_helper_local_dot_set SLOT_F64_RAW RAW b +vm.c:1673 obs_slot_observable slot_is_f64 TEST i +vm.c:1680 obs_slot_num SLOT_F64_RAW RAW i +vm.c:1680 obs_slot_num slot_is_f64 TEST i +vm.c:1681 obs_slot_num slot_is_smi TEST i +vm.c:1681 obs_slot_num slot_smi_val RAW i +vm.c:1829 jit_helper_iter_next slot_f64_value READ b +vm.c:1830 jit_helper_iter_next VAL_INT TEST a +vm.c:1845 jit_helper_iter_next slot_f64_value READ b +vm.c:1848 jit_helper_iter_next VAL_INT TEST a +vm.c:1850 jit_helper_iter_next slot_int_value READ b +vm.c:1857 jit_helper_iter_next buffer_read_num READ b +vm.c:1857 jit_helper_iter_next num_guard GUARD c +vm.c:1857 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1863 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1933 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b +vm.c:1933 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1937 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1940 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1979 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:1993 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:1993 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:2004 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2005 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2023 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:2023 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2106 loop_iter_store make_num PRODUCE c +vm.c:2113 loop_iter_store slot_is_f64 TEST a +vm.c:2114 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2119 loop_iter_store make_num PRODUCE c +vm.c:2234 vm_value_index_is_int VAL_INT TEST a +vm.c:2235 vm_value_index_is_int VAL_I64_RAW RAW b +vm.c:2240 vm_value_index_is_int VAL_F64_RAW RAW b +vm.c:2253 jit_helper_index_set slot_is_f64 TEST a +vm.c:2258 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2259 jit_helper_index_set slot_is_f64 TEST a +vm.c:2261 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2263 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2273 jit_helper_index_set slot_is_f64 TEST a +vm.c:2275 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2276 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2278 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2290 jit_helper_index_set val_is_number TEST a +vm.c:2293 jit_helper_index_set eigs_num_arg READ b +vm.c:2300 jit_helper_index_set val_is_number TEST a +vm.c:2303 jit_helper_index_set eigs_num_arg READ b +vm.c:2306 jit_helper_index_set val_is_number TEST a +vm.c:2307 jit_helper_index_set eigs_num_arg READ b +vm.c:2326 jit_helper_index_get slot_is_f64 TEST a +vm.c:2328 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2335 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2346 jit_helper_index_get buffer_read_num READ b +vm.c:2348 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2350 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2366 jit_helper_index_get val_is_number TEST a +vm.c:2369 jit_helper_index_get eigs_num_arg READ b +vm.c:2381 jit_helper_index_get val_is_number TEST a +vm.c:2384 jit_helper_index_get eigs_num_arg READ b +vm.c:2393 jit_helper_index_get val_is_number TEST a +vm.c:2396 jit_helper_index_get eigs_num_arg READ b +vm.c:2398 jit_helper_index_get buffer_read_num READ b +vm.c:2398 jit_helper_index_get make_num PRODUCE c +vm.c:2984 vm_take_error_value make_num PRODUCE c +vm.c:3088 slot_type_name slot_is_f64 TEST e +vm.c:3089 slot_type_name slot_is_smi TEST e +vm.c:3329 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3330 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3330 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3344 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3349 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3369 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3369 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3380 #define ARITH_FAST slot_f64_value READ b +vm.c:3380 #define ARITH_FAST slot_f64_value READ b +vm.c:3381 #define ARITH_FAST num_guard GUARD c +vm.c:3386 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3387 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3395 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3396 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3404 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3416 #define INT_ARITH slot_int_value READ b +vm.c:3416 #define INT_ARITH slot_int_value READ b +vm.c:3430 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3430 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3431 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3431 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3431 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3432 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3432 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3433 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3433 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3434 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3435 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3435 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3436 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3436 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3436 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3436 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3486 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3486 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3487 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3487 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3487 #define NUM_BINOP num_guard GUARD c +vm.c:3488 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3488 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3490 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3490 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3491 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3491 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3492 #define NUM_BINOP make_num PRODUCE c +vm.c:3493 #define NUM_BINOP val_is_number TEST a +vm.c:3493 #define NUM_BINOP val_is_number TEST a +vm.c:3494 #define NUM_BINOP eigs_num_arg READ b +vm.c:3494 #define NUM_BINOP eigs_num_arg READ b +vm.c:3495 #define NUM_BINOP num_guard GUARD c +vm.c:3498 #define NUM_BINOP make_num PRODUCE c +vm.c:3502 #define NUM_BINOP make_num PRODUCE c +vm.c:3520 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3520 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3521 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3523 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3525 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3525 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3525 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3528 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3530 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3530 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3531 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3531 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3532 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3537 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3545 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3545 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3545 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3546 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3546 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3546 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3547 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3547 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3548 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3548 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3549 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3551 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3551 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3556 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3584 #define INT_BINOP_R slot_f64_value READ b +vm.c:3588 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3615 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3618 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3618 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3621 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3625 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3630 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3635 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3657 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3661 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3670 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3670 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3676 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3676 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3696 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3696 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3702 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3702 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3724 #define NUM_CMP slot_f64_value READ f +vm.c:3724 #define NUM_CMP slot_f64_value READ f +vm.c:4667 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4669 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4676 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4686 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4688 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4690 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4712 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4714 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4715 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a vm.c:4717 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4729 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4732 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4739 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4742 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4719 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4729 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4731 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4731 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4733 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b vm.c:4745 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4746 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4802 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4805 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4866 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4867 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4893 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4893 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:4999 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5000 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5050 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b -vm.c:5051 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a -vm.c:5067 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b -vm.c:5070 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a -vm.c:5084 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5088 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5088 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5427 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5428 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5429 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5463 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5464 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5465 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5529 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5530 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5530 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5530 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5534 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5535 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5536 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5537 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5541 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5555 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5556 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5557 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5558 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5578 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5604 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5607 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5608 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5611 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5635 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5638 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5663 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5664 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5665 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5666 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5796 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5796 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5813 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5814 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5816 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5823 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5827 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5830 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5831 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5834 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5845 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5848 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6442 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6443 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6444 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6447 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6457 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6458 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6460 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6464 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:4748 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4755 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4758 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4761 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4762 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4818 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4821 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4882 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4883 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4909 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4909 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5015 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5016 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5066 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b +vm.c:5067 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a +vm.c:5083 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b +vm.c:5086 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a +vm.c:5100 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5104 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5104 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5443 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5444 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5445 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5479 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5480 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5481 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5545 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5546 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5552 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5553 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5557 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5571 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5572 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5573 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5574 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5594 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5620 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5623 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5624 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5651 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5654 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5659 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5679 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5680 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5681 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5682 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5829 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5830 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5832 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5839 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5843 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5846 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5847 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5850 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5861 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5864 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6458 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6459 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6460 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6463 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6473 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6474 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6476 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6480 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index babbdb96c..97e6bc1dd 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -682,7 +682,7 @@ result).** | `container.h:dict_value_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value`, the one SMI boxer (unwired until R1.3) (D1) | | `container.h:eigs_container_slot` | not-a-classifier | the canonicalizing Value-to-slot writer (R1.2): it reads a Value, not a slot, and writes the bits; a `VAL_INT` box becomes an SMI inside [-2^47, 2^47) and stays a heap slot outside it (2.1) (D3) | | `container.h:eigs_slot_adopt` | guarded | decides ownership from what `eigs_container_slot` returned (compile-forced); a small int comes back as an SMI and its box is released (D3) | -| `container.h:eigs_slot_box` | smi-arm | boxes an int through `slot_to_value`, kind-preserving (unwired until R1.3) (D1) | +| `container.h:eigs_slot_box` | smi-arm | an SMI is boxed as an owned int through `slot_to_value`; floats retain `make_num` (R1.3) (D1) | | `container.h:eigs_slot_elem_num` | smi-arm | bridge reader: an int converts to its double (D1) | | `container.h:eigs_slot_num` | smi-arm | bridge reader: an int converts to its double (D1) | | `container.h:eigs_slot_opt_num` | smi-arm | bridge reader: an int converts to its double and answers present (D1) | @@ -702,7 +702,7 @@ result).** | `eigenscript.c:module_ns_project` | guarded | an int skips the float-over-float rewrite: `slot_to_value` boxes it and the dict store re-canonicalizes it (D1) | | `eigenscript.c:observer_entropy_now` | smi-arm | an int is the numeric kind, as its double (D1) | | `eigenscript.c:slot_from_value` | not-a-classifier | the adopting Value-to-slot writer (R1.2): it reads a Value, not a slot, and writes the bits; a `VAL_INT` box becomes an SMI inside [-2^47, 2^47) (its box released) and stays a heap slot outside it (2.1) (D3) | -| `eigenscript.c:slot_to_value` | unwired | the one SMI boxer: a fresh int Value needs `make_int` (R1.3). Any other unknown tag now refuses; it used to read back as null (D1) | +| `eigenscript.c:slot_to_value` | smi-arm | the one SMI boxer: a fresh owned `make_int` preserves the exact value (R1.3); an unknown tag refuses (D1) | | `ext_store.c:store_json_encode_slot` | smi-arm | an int is written as its exact digits (design 7) (D1) | | `jit.c:jit_compile_to_thunk/OP_EQ` | not-a-classifier | writes the bool result bits (D3) | | `jit.c:jit_compile_to_thunk/OP_NEG` | not-a-classifier | the NOT arm writes bool result bits (D3) | @@ -718,7 +718,7 @@ result).** | `value_slot.h:slot_false` | not-a-classifier | constructor (D3) | | `value_slot.h:slot_from_bool` | not-a-classifier | constructor (D3) | | `value_slot.h:slot_from_heap` | guarded | maps null and bool Values to their immediates and every other Value to a heap slot, so a `VAL_INT` box stays a box: the lifts depend on that (§2.1) (D3) | -| `value_slot.h:slot_from_int` | not-a-classifier | the one int writer: an SMI inside [-2^47, 2^47); outside it the `VAL_INT` box is unwired until R1.3 (D3) | +| `value_slot.h:slot_from_int` | not-a-classifier | the one int writer: an SMI inside [-2^47, 2^47), otherwise an owned `VAL_INT` box with all int64 bits (R1.3) (D3) | | `value_slot.h:slot_incref` | guarded | as `slot_decref` (D3) | | `value_slot.h:slot_int_value` | smi-arm | an SMI's int, or a heap `VAL_INT`'s exact int64 (R1.2) (D1) | | `value_slot.h:slot_is_bool` | guarded | exact tag test (D3) | @@ -732,8 +732,9 @@ result).** | `value_slot.h:slot_true` | not-a-classifier | constructor (D3) | | `value_slot.h:slot_truthy_immediate` | smi-arm | an int is truthy when it is not 0, like a double (D1) | | `vm.c:#define ARITH_FAST` | guarded | an int is not a float (`slot_f64_value`): the arm's slow path pops it through `slot_bridge_unwrap`; R1.3 gives that path int arithmetic (D1) | -| `vm.c:#define INT_BINOP_R` | unwired | an int operand used to reach the type error naming `num`, which a `try` turned into a wrong value (the R1.1 critic). It now refuses through `eigs_int_unwired` until R1.3 gives the bitwise arms exact int64 operands (D1) | -| `vm.c:#define NUM_CMP` | unwired | an int operand used to reach the type error naming `num` (`r is xs[0] < 6` gave `false` inside a `try`). It now refuses through `eigs_int_unwired` until R1.3 adds N2's exact compare (D1) | +| `vm.c:#define INT_ARITH` | smi-arm | two exact integer slots use checked int64 arithmetic; the result is an SMI when it fits and an owned int box otherwise, and overflow raises (R1.3) (D1) | +| `vm.c:#define INT_BINOP_R` | smi-arm | both operands use `vm_bit_operand`, retaining exact int64 bits and the transitional shift rules (R1.3) (D1) | +| `vm.c:#define NUM_CMP` | smi-arm | the float fast path remains; integer and cross-kind operands use exact N2 comparison (R1.3) (D1) | | `vm.c:#define READ_SLICE_BOUND` | smi-arm | an int bound is its value when a C `int` holds it, else a value error (D1) | | `vm.c:jit_helper_dot_get` | guarded | a non-null field is pushed as its bits; an SMI is a valid stack slot (D3) | | `vm.c:jit_helper_dot_set` | guarded | an int value skips the immediate store: the slow path pops it through `slot_bridge_unwrap` (D1) | @@ -748,7 +749,9 @@ result).** | `vm.c:obs_slot_num` | smi-arm | the observer's numeric channel: a float, or an int as its exact double until round 3 (design 7) (D1) | | `vm.c:obs_slot_observable` | refuse | answered "pointer or bool", so an SMI was silently unobserved. R1.1 aborts on an SMI or a reserved tag; every caller routes a number to `obs_slot_num` first. A BOXED int is a pointer and goes to `observer_slot_update(Value *)`, whose number arm (eigenscript.c:785) R1.2's `VAL_NUM` rename forces (§7, O map) (D1 since R1.1: it names `slot_is_f64`) | | `vm.c:obs_slot_value` | guarded | called only after `obs_slot_observable` answered true (pointer or bool) (D2) | -| `vm.c:slot_bridge_unwrap` | smi-arm | an int materializes through `slot_to_value` (unwired until R1.3) (D1) | +| `vm.c:slot_bridge_unwrap` | smi-arm | an SMI materializes as an owned exact int through `slot_to_value` (R1.3) (D1) | +| `vm.c:vm_bit_operand` | smi-arm | an int64 operand is read exactly; float operands keep the #1740 conversion rule (R1.3) (D1) | +| `vm.c:vm_number_compare` | smi-arm | int and cross-kind comparisons use exact N2 order, without double rounding (R1.3) (D1) | | `vm.c:slot_truthy` | smi-arm | an int is truthy when it is not 0; a reserved tag refuses instead of being dereferenced (D1) | | `vm.c:slot_type_name` | smi-arm | an SMI reached the final `return "num"` by accident. R1.1 adds the explicit SMI arm ("num", (B)) and aborts on a reserved tag (D1 since R1.1) | | `vm.c:vm_borrow_scan` | guarded | compares heap slots with the result pointer; an SMI is not heap (D2) | @@ -758,7 +761,7 @@ result).** | `vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET` | guarded | a non-pointer target bails (`return 0`); a non-null field is borrowed as its bits, an SMI included (D2) | | `vm.c:vm_local_is_null` | guarded | exact null test (D3) | | `vm.c:vm_local_lift` | guarded | a non-pointer, non-null slot goes through `slot_to_value` (compile-forced) and is boxed on purpose (D2) | -| `vm.c:vm_run_ex/CASE(BNOT)` | unwired | an int used to reach the type error naming `num`. It now refuses through `eigs_int_unwired` until R1.3 gives the bitwise arms exact int64 operands (D1) | +| `vm.c:vm_run_ex/CASE(BNOT)` | smi-arm | an int64 operand is read exactly; the result retains the transitional float bridge until R1.5 (R1.3) (D1) | | `vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK)` | guarded | a non-pointer source takes the error path, which names the type through `slot_type_name` (D2) | | `vm.c:vm_run_ex/CASE(DISPATCH)` | smi-arm | an int key is its value when a C `int` holds it, else a value error; the result returns through `slot_bridge_unwrap` (D1) | | `vm.c:vm_run_ex/CASE(DOT_GET)` | guarded | exact null test of a field (D3) | @@ -770,9 +773,9 @@ result).** | `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET)` | guarded | exact null test of a field (D3) | | `vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET)` | guarded | an int value: `vm_slot_lift` boxes it (D1) | | `vm.c:vm_run_ex/CASE(NE)` | guarded | an int is not a float: the slow path; R1.3 adds N2 (D1) | -| `vm.c:vm_run_ex/CASE(NEG)` | unwired | an int used to reach the type error naming `num`. It now refuses through `eigs_int_unwired` until R1.3 adds N4b (D1) | +| `vm.c:vm_run_ex/CASE(NEG)` | smi-arm | an int is negated exactly and INT64_MIN raises value; floats keep their sign semantics (R1.3) (D1) | | `vm.c:vm_run_ex/CASE(SLICE_GET)` | guarded | as DESTRUCTURE_UNPACK (D2) | -| `vm.c:vm_slot_lift` | smi-arm | an int is boxed on purpose through `slot_to_value` (2.1; unwired until R1.3); a reserved tag refuses, where it became null (D1) | +| `vm.c:vm_slot_lift` | smi-arm | an SMI is boxed through `slot_to_value`; a reserved tag refuses (R1.3) (D1) | | `vm.c:vm_slot_value_opaque` | guarded | only a pointer can be a fn or builtin; an SMI answers "not opaque", which is right (D2) | | `vm.c:vm_store_local_slot` | guarded | an int skips the in-place float store; the generic swap stores the SMI (D1) | | `vm.c:vm_run_ex/CASE(ITER_NEXT)` | unwired | float-first index and snapshot readers; an int takes the existing R1.3 refusal only after the float reader fails (D1) | @@ -1580,6 +1583,7 @@ current state behind several rows: | `throw` | other | - | - | message via value_to_string | | `token_name` | int-requiring | - | - | token id | | `try_recv` | int-requiring | - | - | channel handle ids | +| `num_type` | other | - | - | N7: int/float kind, null for a non-number | | `type` | other | - | - | `type of` an int or a float is "num" ((B)) | | `usleep` | other | - | magnitude | the microseconds are a continuous duration: rounded; a sleep the C int cannot hold raises (Q7 magnitude) | | `vm_run_bytecode` | int-requiring | - | - | opcode bytes and ABI numbers | diff --git a/src/builtins.c b/src/builtins.c index 2d94d6e1d..b3b2afd56 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -880,6 +880,14 @@ Value* builtin_type(Value *arg) { return make_str("none"); } +/* #1758 N7: inspect numeric representation without splitting surface type + * "num". Every other value, including bool, answers null. */ +Value* builtin_num_type(Value *arg) { + if (arg && arg->type == VAL_INT) return make_str("int"); + if (arg && arg->type == VAL_FLOAT) return make_str("float"); + return make_null(); +} + /* Bound JSON nesting depth: each array/object descent is a C recursion, so * untrusted input like "[[[[...]]]]" would otherwise exhaust the C stack and * crash (SIGSEGV). 200 is far beyond any legitimate document. Shared by the @@ -2067,6 +2075,14 @@ Value* builtin_round(Value *arg) { Value* builtin_abs(Value *arg) { ARG_GUARD(!arg || !val_is_number(arg), "abs", "a number", make_num(0)); + if (arg && arg->type == VAL_INT) { + int64_t n = VAL_I64_RAW(arg); + if (n == INT64_MIN) { + rt_error(EK_VALUE, 0, "abs: int64 overflow"); + return make_null(); + } + return make_int(n < 0 ? -n : n); + } return make_num(fabs(eigs_num_arg(arg, __func__))); } @@ -3297,7 +3313,7 @@ static const char *SANDBOX_ALLOW[] = { /* path string manipulation (no fs access) */ "path_base", "path_dir", "path_ext", "path_join", /* type / value utilities */ - "type", "coalesce", "num_copy", "secure_equals", + "type", "num_type", "coalesce", "num_copy", "secure_equals", /* observer READS — touch only the sandbox's own values, never globals * (set_observer_thresholds / record_history are intentionally NOT here). * state_at is also excluded: temporal history belongs to the host thread, @@ -6148,6 +6164,7 @@ static const struct { const char *name; unsigned mask; const char *why; } k_bool {"write", BA_ANY, "renders any value"}, {"str", BA_ANY, "converts any value to text (\"true\"/\"false\")"}, {"type", BA_ANY, "names any value's type"}, + {"num_type", BA_ANY, "names a numeric kind or returns null for any other value"}, {"json_encode", BA_ANY, "JSON has true/false"}, {"observe", BA_ANY, "the observer measures bools (entropy 0/1)"}, {"classify", BA_ANY, "the observer classifies any value"}, @@ -6300,6 +6317,7 @@ void register_builtins(Env *env) { env_set_local_owned(env, "observe", make_builtin(builtin_observe)); env_set_local_owned(env, "classify", make_builtin(builtin_classify)); env_set_local_owned(env, "type", make_builtin(builtin_type)); + env_set_local_owned(env, "num_type", make_builtin(builtin_num_type)); env_set_local_owned(env, "math_flags", make_builtin(builtin_math_flags)); /* #865 */ env_set_local_owned(env, "json_encode", make_builtin(builtin_json_encode)); env_set_local_owned(env, "json_decode", make_builtin(builtin_json_decode)); diff --git a/src/eigenscript.c b/src/eigenscript.c index 633606dbd..7adb43362 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -1761,6 +1761,16 @@ Value* make_num(double n) { return v; } +/* #1758 R1.3: large int slots and Value API boundaries own ordinary heap + * Values. Int boxes never enter the float freelist and own no GC edges. */ +Value* make_int(int64_t n) { + Value *v = xcalloc(1, sizeof(Value)); + v->type = VAL_INT; + VAL_I64_RAW(v) = n; + v->refcount = 1; + return v; +} + void recycle_intermediate(Value *v) { if (!v || v->type != VAL_FLOAT || v->refcount > 1) return; #ifdef EIGS_POOL_OFF_NUM @@ -1909,8 +1919,7 @@ EigsSlot slot_from_value(Value *v) { * - heap/tracked pointer -> incref and return * - SMI (#1758) -> a fresh int Value. This is the ONE place that boxes an * SMI (the lifts, slot_bridge_unwrap, eigs_slot_box and the *_get_return - * readers all route here); the int Value kind lands in R1.2a/R1.3, so - * until then it is refused (eigs_int_unwired, deleted in R1.3). + * readers all route here). * - any other tag is a broken contract and aborts (it used to read back * as null, silently). */ @@ -1923,7 +1932,7 @@ Value* slot_to_value(EigsSlot s) { val_incref(v); return v; } - if (slot_is_smi(s)) eigs_int_unwired("slot_to_value", s.u); + if (slot_is_smi(s)) return make_int(slot_smi_val(s)); eigs_slot_refuse("slot_to_value", s); } diff --git a/src/eigenscript.h b/src/eigenscript.h index fc9386211..6d0b6c6e7 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -1767,6 +1767,7 @@ void strbuf_free(strbuf *b); /* ---- Value constructors ---- */ Value* make_num(double n); +Value* make_int(int64_t n); /* owned, unpooled int box; slots canonicalize small ints */ void recycle_intermediate(Value *v); Value* make_str(const char *s); Value* make_str_len(const char *s, size_t n); /* #1183: caller knows strlen(s) */ diff --git a/src/jit.c b/src/jit.c index 4d77f6d1f..9af7e0c65 100644 --- a/src/jit.c +++ b/src/jit.c @@ -744,8 +744,7 @@ static int jit_supported_prefix(const struct EigsChunk *chunk, } else if (op == OP_DUP2) { i += 1; ops++; non_line_ops++; } else if (op == OP_ADD || op == OP_SUB || - op == OP_MUL || op == OP_DIV || - op == OP_MOD) { + op == OP_MUL || op == OP_DIV) { i += 1; ops++; non_line_ops++; *has_bail_op = 1; /* Stage 5e: the tracked-operand loaders + commit decrefs @@ -760,13 +759,7 @@ static int jit_supported_prefix(const struct EigsChunk *chunk, *extra_size += 320; /* Stage 5e loaders + decrefs */ /* #1637: the result is the false/true TAG_BOOL immediate, so * OP_POP after a comparison remains a no-op peephole. */ - } else if (op == OP_BAND || op == OP_BOR || op == OP_BXOR || - op == OP_SHL || op == OP_SHR) { - i += 1; ops++; non_line_ops++; - *has_bail_op = 1; - /* Result is a double (whole-number-valued), so a subsequent - * OP_POP stays a no-op peephole. */ - } else if (op == OP_NEG || op == OP_NOT || op == OP_BNOT) { + } else if (op == OP_NEG || op == OP_NOT) { i += 1; ops++; non_line_ops++; *has_bail_op = 1; } else if (op == OP_JUMP || op == OP_JUMP_BACK) { diff --git a/src/lsp_builtin_index.h b/src/lsp_builtin_index.h index a1c931250..6f16f8a22 100644 --- a/src/lsp_builtin_index.h +++ b/src/lsp_builtin_index.h @@ -194,6 +194,7 @@ static const char *builtin_docs[][2] = { {"norm", "norm of a → L2 (Euclidean) norm = sqrt(sum_i a[i]^2). Buffers and tensors."}, {"num", "num — builtin; see docs/BUILTINS.md"}, {"num_copy", "num_copy of val → fresh heap-allocated copy of a numeric Value."}, + {"num_type", "num_type — builtin; see docs/BUILTINS.md"}, {"numerical_grad", "numerical_grad of [loss_fn, param, eps]"}, {"numerical_grad_cols", "numerical_grad_cols of [loss_fn, matrix, col_indices, eps]"}, {"numerical_grad_rows", "numerical_grad_rows of [loss_fn, matrix, row_indices, eps]"}, diff --git a/src/value_slot.h b/src/value_slot.h index a20b7cbb4..3b334bada 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -141,16 +141,15 @@ static inline int64_t slot_smi_val(EigsSlot s) { /* #1758: the ONE double writer. Round 2 canonicalizes a NaN here. */ static inline EigsSlot slot_from_f64(double d) { EigsSlot s; SLOT_F64_RAW(s) = d; return s; } -/* #1758: the ONE int writer: an SMI inside [-2^47, 2^47). Outside it the - * int needs a VAL_INT box, which cannot exist before R1.3 (make_int). Until - * R1.3 nothing in the runtime calls this (tools/phase2_check.sh, the - * int-source check); tests/phase2/slot_layer.c drives it. */ +static inline EigsSlot slot_from_heap(Value *v); +/* #1758: the ONE int writer: an SMI inside [-2^47, 2^47), otherwise an + * owned VAL_INT heap box. */ static inline EigsSlot slot_from_int(int64_t i) { #ifdef EIGS_SMI_TRAP eigs_int_unwired("slot_from_int under EIGS_SMI_TRAP", (uint64_t)i); #endif if (__builtin_expect(i < SLOT_SMI_MIN || i > SLOT_SMI_MAX, 0)) - eigs_int_unwired("slot_from_int", (uint64_t)i); + return slot_from_heap(make_int(i)); EigsSlot s; s.u = TAG_SMI | ((uint64_t)i & SLOT_PAYLOAD_MASK); return s; } static inline EigsSlot slot_null(void) { EigsSlot s; s.u = SLOT_NULL_BITS; return s; } diff --git a/src/vm.c b/src/vm.c index f6d71440b..596eda68c 100644 --- a/src/vm.c +++ b/src/vm.c @@ -875,14 +875,45 @@ static inline int slot_truthy(EigsSlot s) { eigs_slot_refuse("slot_truthy", s); } -/* #1758 R1.1: vm.c's slot_as_double is gone. Its readers now call - * slot_f64_value (value_slot.h), which answers only for a FLOAT; each one - * decided what an int does there: the arithmetic and equality arms send it to - * their slow path, which lifts it through slot_to_value; the ordering, - * bitwise, negation and `~` arms refuse it (eigs_int_unwired) where they used - * to raise a type error, which a `try` turned into a wrong value. R1.3 gives - * every one of them the int semantics and deletes eigs_int_unwired (design 8); - * the leaf evaluator bails, so the generic call computes it (design 4.5). */ +/* #1758 R1.3: floats keep the existing fast paths. Integer and mixed + * arithmetic is computed here, outside the JIT/leaf float executors. */ +static EigsSlot vm_int_arith(int64_t a, int64_t b, char op, int line) { + int64_t r; + int overflow; + if (op == '+') overflow = __builtin_add_overflow(a, b, &r); + else if (op == '-') overflow = __builtin_sub_overflow(a, b, &r); + else overflow = __builtin_mul_overflow(a, b, &r); + if (overflow) { + rt_error(EK_VALUE, line, "integer overflow in '%c'", op); + return slot_null(); + } + return slot_from_int(r); +} + +/* A number as an int64 for the transitional bitwise operators (#1740). + * An int never round-trips through double; float operands retain the exact + * integer-representation rule. Return -1 for a type error, 0 for value. */ +static int vm_bit_operand(EigsSlot s, int64_t *out) { + double f; + if (slot_int_value(s, out)) return 1; + if (slot_f64_value(s, &f)) return num_to_i64_exact(f, out); + return -1; +} + +/* Exact N2 ordering; 2 means unordered, and 0 return means not numbers. */ +static int vm_number_compare(EigsSlot a, EigsSlot b, int *out) { + int64_t ai, bi; + double af, bf; + int ia = slot_int_value(a, &ai), ib = slot_int_value(b, &bi); + if (ia && ib) { *out = (ai > bi) - (ai < bi); return 1; } + if (ia && slot_f64_value(b, &bf)) { *out = eigs_cmp_int_float(ai, bf); return 1; } + if (ib && slot_f64_value(a, &af)) { + int c = eigs_cmp_int_float(bi, af); + *out = c == 2 ? 2 : -c; + return 1; + } + return 0; +} static inline uint16_t read_u16(uint8_t *ip) { return ip[0] | (ip[1] << 8); @@ -3376,8 +3407,24 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } \ } while(0) + /* Float first, then exact integer slots. A small integer result is an + * SMI; only a result outside the SMI range allocates. This is the basic + * interpreter producer (§2.1); native JIT/leaf int paths remain R5. */ +#define INT_ARITH(OP) do { \ + EigsSlot _as = g_vm.stack[g_vm.sp - 2], _bs = g_vm.stack[g_vm.sp - 1]; \ + int64_t _ai, _bi; \ + if (slot_int_value(_as, &_ai) && slot_int_value(_bs, &_bi)) { \ + EigsSlot _r = vm_int_arith(_ai, _bi, (OP)[0], current_line); \ + slot_decref(_as); slot_decref(_bs); \ + g_vm.stack[g_vm.sp - 2] = _r; \ + g_vm.sp--; \ + DISPATCH(); \ + } \ +} while (0) + CASE(ADD): { ARITH_FAST(+, 0); + INT_ARITH("+"); /* Slow path: handles string concat etc */ Value *b = vm_pop(); Value *a = vm_pop(); if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) { @@ -3385,6 +3432,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } vm_push(make_num(r)); + } else if (val_is_number(a) && val_is_number(b)) { + vm_push(make_num(num_guard(eigs_num_arg(a, "addition") + eigs_num_arg(b, "addition")))); } else if (a->type == VAL_STR && b->type == VAL_STR) { int la = val_str_len(a), lb = val_str_len(b); /* #292's byte budget charged only the size-controlled builtins; @@ -3407,8 +3456,6 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, /* #1183: the length is already known — don't re-scan the result. */ vm_push(make_str_owned_len(s, (size_t)la + lb)); } else { - if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) - eigs_int_unwired("addition", 0); /* Strict: + adds two numbers or concatenates two strings; it does * not coerce across types ("3" + 4 was a footgun). For mixed * concatenation use an f-string — f"{a}{b}" — or str of. */ @@ -3434,6 +3481,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, #define NUM_BINOP(NAME, OP, OPNAME, UF) \ CASE(NAME): { \ ARITH_FAST(OP, UF); \ + INT_ARITH(OPNAME); \ Value *b = vm_pop(); Value *a = vm_pop(); \ if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) { \ double r = num_guard(VAL_F64_RAW(a) OP VAL_F64_RAW(b)); \ @@ -3442,9 +3490,13 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } \ if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } \ vm_push(make_num(r)); \ + } else if (val_is_number(a) && val_is_number(b)) { \ + double ad = eigs_num_arg(a, OPNAME), bd = eigs_num_arg(b, OPNAME); \ + double r = num_guard(ad OP bd); \ + if ((UF) && r == 0.0 && ad != 0.0 && bd != 0.0) \ + g_math_flags |= EIGS_MATH_UNDERFLOW; \ + vm_push(make_num(r)); \ } else { \ - if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) \ - eigs_int_unwired(OPNAME, 0); \ rt_error(EK_TYPE, current_line, "cannot apply '%s' to %s and %s", \ OPNAME, val_type_name(a->type), val_type_name(b->type)); \ vm_push(make_num(0)); \ @@ -3465,23 +3517,21 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(DIV): { Value *b = vm_pop(); Value *a = vm_pop(); - if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) { - if (VAL_F64_RAW(b) == 0.0) { + if (val_is_number(a) && val_is_number(b)) { + if (eigs_num_arg(b, "division") == 0.0) { rt_error(EK_VALUE, current_line, "division by zero"); vm_push(make_num(0)); } else { - double r = num_guard(VAL_F64_RAW(a) / VAL_F64_RAW(b)); + double r = num_guard(eigs_num_arg(a, "division") / eigs_num_arg(b, "division")); /* divisor already known nonzero (the raise above), so a zero * quotient from a nonzero dividend is underflow. */ - if (r == 0.0 && VAL_F64_RAW(a) != 0.0) + if (r == 0.0 && eigs_num_arg(a, "division") != 0.0) g_math_flags |= EIGS_MATH_UNDERFLOW; if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } vm_push(make_num(r)); } } else { - if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) - eigs_int_unwired("division", 0); rt_error(EK_TYPE, current_line, "cannot apply '/' to %s and %s", val_type_name(a->type), val_type_name(b->type)); vm_push(make_num(0)); @@ -3492,15 +3542,13 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(MOD): { Value *b = vm_pop(); Value *a = vm_pop(); - if (a->type == VAL_FLOAT && b->type == VAL_FLOAT && VAL_F64_RAW(b) != 0.0) { - double r = num_guard(fmod(VAL_F64_RAW(a), VAL_F64_RAW(b))); + if (val_is_number(a) && val_is_number(b) && eigs_num_arg(b, "modulo") != 0.0) { + double r = num_guard(fmod(eigs_num_arg(a, "modulo"), eigs_num_arg(b, "modulo"))); if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } vm_push(make_num(r)); } else { - if (__builtin_expect(a->type == VAL_INT || b->type == VAL_INT, 0)) - eigs_int_unwired("modulo", 0); - if (!(a->type == VAL_FLOAT && b->type == VAL_FLOAT)) + if (!(val_is_number(a) && val_is_number(b))) rt_error(EK_TYPE, current_line, "cannot apply '%%' to %s and %s", val_type_name(a->type), val_type_name(b->type)); else @@ -3523,54 +3571,21 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NAME): { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ - /* #1775: -O1 cannot see that the fast path's & of two successes \ - * wrote _ad before num_to_i64_exact reads it; initialised here \ - * only, where GCC warns (callgrind: no Ir cost; initialising the \ - * other arms' locals cost +2% on DMG). */ \ - double _ad = 0.0, _bd = 0.0; \ - if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { \ - int64_t _ai, _bi; \ - if (__builtin_expect(!num_to_i64_exact(_ad, &_ai) || \ - !num_to_i64_exact(_bd, &_bi), 0)) { \ - slot_decref(_as); slot_decref(_bs); \ - rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, OPNAME, \ - num_to_i64_exact(_ad, &_ai) ? _bd : _ad); \ - g_vm.stack[g_vm.sp - 2] = slot_from_f64(0.0); \ - g_vm.sp--; \ - DISPATCH(); \ - } \ - double _r = (double)(INT_OP_##NAME(_ai, (RHS))); \ - if (slot_is_ptr(_as)) { \ - Value *_a = slot_as_ptr(_as); \ - if (NUM_REUSE(_a)) { VAL_F64_RAW(_a) = _r; slot_decref(_bs); g_vm.sp--; DISPATCH(); } \ - } \ - if (slot_is_ptr(_bs)) { \ - Value *_b = slot_as_ptr(_bs); \ - if (NUM_REUSE(_b)) { VAL_F64_RAW(_b) = _r; g_vm.stack[g_vm.sp - 2] = _bs; slot_decref(_as); g_vm.sp--; DISPATCH(); } \ - } \ - slot_decref(_as); slot_decref(_bs); \ - g_vm.stack[g_vm.sp - 2] = slot_from_f64(_r); \ - g_vm.sp--; \ - DISPATCH(); \ - } \ - /* #1758 R1.1: an int operand is not a type error (inside a try \ - * it would become a wrong value). The arm refuses until R1.3 \ - * gives it exact int64 operands, and deleting eigs_int_unwired \ - * there forces that. */ \ - if (slot_type(_as) == VAL_INT) \ - eigs_int_unwired("bitwise '" OPNAME "'", _as.u); \ - if (slot_type(_bs) == VAL_INT) \ - eigs_int_unwired("bitwise '" OPNAME "'", _bs.u); \ - /* Mixed/non-numeric: error rather than silently returning 0, \ - * matching the arithmetic operators and the strict error model. \ - * Capture type names before decref (cf. NUM_CMP above). */ \ - { \ - const char *_tna = slot_type_name(_as), *_tnb = slot_type_name(_bs); \ - slot_decref(_as); slot_decref(_bs); \ + int64_t _ai, _bi; \ + int _ak = vm_bit_operand(_as, &_ai), _bk = vm_bit_operand(_bs, &_bi); \ + double _r = 0.0; \ + if (_ak == 1 && _bk == 1) { \ + _r = (double)(INT_OP_##NAME(_ai, (RHS))); \ + } else if (_ak < 0 || _bk < 0) { \ rt_error(EK_TYPE, current_line, "cannot apply '%s' to %s and %s", \ - OPNAME, _tna, _tnb); \ + OPNAME, slot_type_name(_as), slot_type_name(_bs)); \ + } else { \ + double _bad = 0.0; \ + slot_f64_value(_ak == 0 ? _as : _bs, &_bad); \ + rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, OPNAME, _bad); \ } \ - g_vm.stack[g_vm.sp - 2] = slot_from_f64(0.0); \ + slot_decref(_as); slot_decref(_bs); \ + g_vm.stack[g_vm.sp - 2] = slot_from_f64(_r); \ g_vm.sp--; \ DISPATCH(); \ } @@ -3606,10 +3621,15 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_vm.stack[g_vm.sp - 1] = slot_from_f64(-d); DISPATCH(); } - /* #1758 R1.1: an int is refused, not a type error, until R1.3 - * gives NEG its int arm (N4b) and deletes eigs_int_unwired. */ - if (slot_type(s) == VAL_INT) - eigs_int_unwired("negation", s.u); + int64_t i; + if (slot_int_value(s, &i)) { + slot_decref(s); + if (i == INT64_MIN) { + rt_error(EK_VALUE, current_line, "integer overflow in unary '-'"); + g_vm.stack[g_vm.sp - 1] = slot_null(); + } else g_vm.stack[g_vm.sp - 1] = slot_from_int(-i); + DISPATCH(); + } rt_error(EK_TYPE, current_line, "cannot negate %s", slot_type_name(s)); /* #1637: names bool */ slot_decref(s); g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); @@ -3626,34 +3646,19 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(BNOT): { EigsSlot s = g_vm.stack[g_vm.sp - 1]; - double d; - if (__builtin_expect(slot_f64_value(s, &d), 1)) { - int64_t i; - if (__builtin_expect(!num_to_i64_exact(d, &i), 0)) { /* #1740 */ - slot_decref(s); - rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, "~", d); - g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); - DISPATCH(); - } - double r = (double)(~i); - if (slot_is_ptr(s)) { - Value *v = slot_as_ptr(s); - if (NUM_REUSE(v)) { VAL_F64_RAW(v) = r; DISPATCH(); } - } - slot_decref(s); - g_vm.stack[g_vm.sp - 1] = slot_from_f64(r); - DISPATCH(); + int64_t i; + int k = vm_bit_operand(s, &i); + double r = 0.0; + if (k == 1) r = (double)(~i); + else if (k < 0) + rt_error(EK_TYPE, current_line, "cannot apply '~' to %s", slot_type_name(s)); + else { + double bad = 0.0; + slot_f64_value(s, &bad); + rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, "~", bad); } - /* #1758 R1.1: an int is refused, not a type error, until R1.3 - * gives the bitwise arms exact int64 operands. */ - if (slot_type(s) == VAL_INT) - eigs_int_unwired("bitwise '~'", s.u); - { - const char *_tn = slot_type_name(s); - slot_decref(s); - rt_error(EK_TYPE, current_line, "cannot apply '~' to %s", _tn); - } - g_vm.stack[g_vm.sp - 1] = slot_from_f64(0.0); + slot_decref(s); + g_vm.stack[g_vm.sp - 1] = slot_from_f64(r); DISPATCH(); } @@ -3662,6 +3667,11 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(EQ): { EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; + if (slot_is_smi(_as) && slot_is_smi(_bs)) { + g_vm.stack[g_vm.sp - 2] = slot_from_bool(_as.u == _bs.u); + g_vm.sp--; + DISPATCH(); + } double _ad, _bd; if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE @@ -3683,6 +3693,11 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(NE): { EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; EigsSlot _as = g_vm.stack[g_vm.sp - 2]; + if (slot_is_smi(_as) && slot_is_smi(_bs)) { + g_vm.stack[g_vm.sp - 2] = slot_from_bool(_as.u != _bs.u); + g_vm.sp--; + DISPATCH(); + } double _ad, _bd; if (__builtin_expect(slot_f64_value(_as, &_ad) & slot_f64_value(_bs, &_bd), 1)) { /* #1637: the result is a bool immediate. The old NUM_REUSE @@ -3726,13 +3741,14 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, DISPATCH(); \ } \ } \ - /* #1758 R1.1: an int operand is refused, not a type error (which \ - * a try would turn into a wrong `false`), until R1.3 gives this \ - * arm N2's exact compare and deletes eigs_int_unwired. */ \ - if (slot_type(_as) == VAL_INT) \ - eigs_int_unwired("compare '" OPNAME "'", _as.u); \ - if (slot_type(_bs) == VAL_INT) \ - eigs_int_unwired("compare '" OPNAME "'", _bs.u); \ + int _cmp; \ + if (vm_number_compare(_as, _bs, &_cmp)) { \ + int _r = _cmp != 2 && (_cmp OP 0); \ + slot_decref(_as); slot_decref(_bs); \ + g_vm.stack[g_vm.sp - 2] = slot_from_bool(_r); \ + g_vm.sp--; \ + DISPATCH(); \ + } \ /* Mixed/uncomparable types: error rather than silently returning \ * false (e.g. "3" < 4 used to be 0). Capture type names before \ * decref. ==/!= keep cross-type "not equal"; only ordering errors. */ \ diff --git a/tests/bool_fuzz_anyvalue.txt b/tests/bool_fuzz_anyvalue.txt index 84f5fc951..5f9df8467 100644 --- a/tests/bool_fuzz_anyvalue.txt +++ b/tests/bool_fuzz_anyvalue.txt @@ -20,6 +20,9 @@ str|e1|converts any value to text type|u|names any value's type type|e0|names any value's type type|e1|names any value's type +num_type|u|names a numeric kind or returns null for other values +num_type|e0|a list is a non-number so num_type returns null +num_type|e1|a list is a non-number so num_type returns null json_encode|u|JSON has true and false json_encode|e0|JSON has true and false json_encode|e1|JSON has true and false diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index e0bf2c014..a9e7f36c5 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -20,9 +20,9 @@ * tags and the sentinel; each cell runs in a forked child. * C slot_from_int, the one int writer (plant 1's named check, design 9.3): * inside [-2^47, 2^47) the tag is 0xFFFA and the int reads back exactly; - * outside, R1.1 refuses (the VAL_INT box lands in R1.3). + * outside, an owned VAL_INT box preserves every int64 bit. * D the VM's operator arms: a host builtin puts an SMI into a list and a - * program applies each operator to it. Every arm must refuse by name, + * program applies each operator to it. Every converted arm must compute its exact value, * inside a `try` too; the same program with a double is the control. * * Output, every line in one grammar (tests/phase2/slot_layer.sh refuses any @@ -178,11 +178,29 @@ static int r_slot_is_ptr(int64_t v) { return slot_is_ptr(smi(v)) != 0; } /* ---- Part A: ABORT calls ------------------------------------------------ */ -static void a_eigs_slot_box(EigsSlot s) { (void)eigs_slot_box(s); } -static void a_slot_to_value(EigsSlot s) { (void)slot_to_value(s); } +static int r_eigs_slot_box(int64_t v) { + Value *got = eigs_slot_box(smi(v)); + int bad = !got || got->type != VAL_INT || VAL_I64_RAW(got) != v; + val_decref(got); return bad; +} +static int r_slot_to_value(int64_t v) { + Value *got = slot_to_value(smi(v)); + int bad = !got || got->type != VAL_INT || VAL_I64_RAW(got) != v; + val_decref(got); return bad; +} static void a_write_slot(EigsSlot s) { write_slot(s); } +static int r_slot_bridge_unwrap(int64_t v) { + Value *got = slot_bridge_unwrap(smi(v)); + int bad = !got || got->type != VAL_INT || VAL_I64_RAW(got) != v; + val_decref(got); return bad; +} +static int r_vm_bit_operand(int64_t v) { + int64_t got = 7; return vm_bit_operand(smi(v), &got) != 1 || got != v; +} +static int r_vm_number_compare(int64_t v) { + int got = 7; return !vm_number_compare(smi(v), smi(v), &got) || got != 0; +} static void a_obs_slot_observable(EigsSlot s) { (void)obs_slot_observable(s); } -static void a_slot_bridge_unwrap(EigsSlot s) { (void)slot_bridge_unwrap(s); } static void a_eigs_slot_ref(EigsSlot s) { (void)eigs_slot_ref(s); } static void a_slot_as_ptr(EigsSlot s) { (void)slot_as_ptr(s); } static void a_obs_slot_value(EigsSlot s) { (void)obs_slot_value(s); } @@ -196,6 +214,8 @@ typedef struct { } Entry; static const Entry ENTRIES[] = { + {"vm.c:vm_bit_operand", r_vm_bit_operand, 0, 0, "exact int64 operand"}, + {"vm.c:vm_number_compare", r_vm_number_compare, 0, 0, "exact numeric comparison"}, {"container.h:eigs_slot_elem_num", r_eigs_slot_elem_num, 0, 0, "bridge: the int's double"}, {"container.h:eigs_slot_num", r_eigs_slot_num, 0, 0, "bridge: the int's double"}, {"container.h:eigs_slot_opt_num", r_eigs_slot_opt_num, 0, 0, "bridge: present, the int's double"}, @@ -219,13 +239,13 @@ static const Entry ENTRIES[] = { {"value_slot.h:slot_is_heap", r_slot_is_heap, 0, 0, "0"}, {"value_slot.h:slot_is_null", r_slot_is_null, 0, 0, "0"}, {"value_slot.h:slot_is_ptr", r_slot_is_ptr, 0, 0, "0"}, - {"container.h:eigs_slot_box", 0, a_eigs_slot_box, "slot_to_value", "unwired: an int Value (R1.3)"}, + {"container.h:eigs_slot_box", r_eigs_slot_box, 0, 0, "exact owned VAL_INT"}, {"container.h:slot_type", r_slot_type, 0, 0, "VAL_INT"}, {"container.h:slot_view", r_slot_view, 0, 0, "exact VAL_INT facade"}, - {"eigenscript.c:slot_to_value", 0, a_slot_to_value, "slot_to_value", "unwired: make_int (R1.3)"}, + {"eigenscript.c:slot_to_value", r_slot_to_value, 0, 0, "exact owned VAL_INT"}, {"trace.c:write_slot", 0, a_write_slot, "write_slot", "unwired: tape v7 (R1.3)"}, {"vm.c:obs_slot_observable", 0, a_obs_slot_observable, "obs_slot_observable", "refuse"}, - {"vm.c:slot_bridge_unwrap", 0, a_slot_bridge_unwrap, "slot_to_value", "routes to the one SMI boxer"}, + {"vm.c:slot_bridge_unwrap", r_slot_bridge_unwrap, 0, 0, "exact owned VAL_INT"}, {"container.h:eigs_slot_ref", 0, a_eigs_slot_ref, "eigs_slot_ref", "refuse"}, {"value_slot.h:slot_as_ptr", 0, a_slot_as_ptr, "slot_as_ptr", "refuse (checked builds)"}, {"vm.c:obs_slot_value", 0, a_obs_slot_value, "slot_as_ptr", "precondition: pointer or bool only"}, @@ -329,12 +349,14 @@ CELL(is_bool) { snprintf(b, n, "i:%d", slot_is_bool(s)); } CELL(is_heap) { snprintf(b, n, "i:%d", slot_is_heap(s)); } CELL(is_null) { snprintf(b, n, "i:%d", slot_is_null(s)); } CELL(is_ptr) { snprintf(b, n, "i:%d", slot_is_ptr(s)); } -CELL(slot_box) { Value *v = eigs_slot_box(s); r_v(b, n, v); if (v == g_str) val_decref(v); } +CELL(slot_box) { Value *v = eigs_slot_box(s); r_v(b, n, v); val_decref(v); } CELL(slot_type) { snprintf(b, n, "t:%s", val_type_name(slot_type(s))); } CELL(slot_view) { EIGS_VIEW_NOCHECK(view); r_v(b, n, slot_view(s, &view)); } -CELL(to_value) { Value *v = slot_to_value(s); r_v(b, n, v); if (v == g_str) val_decref(v); } +CELL(to_value) { Value *v = slot_to_value(s); r_v(b, n, v); val_decref(v); } CELL(observable) { snprintf(b, n, "i:%d", obs_slot_observable(s)); } -CELL(unwrap) { r_v(b, n, slot_bridge_unwrap(s)); } +CELL(unwrap) { Value *v = slot_bridge_unwrap(s); r_v(b, n, v); if (!slot_is_ptr(s)) val_decref(v); } +CELL(vm_bit_operand) { int64_t i = 7; int r = vm_bit_operand(s, &i); snprintf(b, n, "o:%d i:%lld", r, (long long)i); } +CELL(vm_number_compare) { int cmp = 7; int r = vm_number_compare(s, smi(1), &cmp); snprintf(b, n, "o:%d c:%d", r, cmp); } CELL(slot_ref) { r_v(b, n, eigs_slot_ref(s)); } CELL(as_ptr) { r_v(b, n, slot_as_ptr(s)); } CELL(obs_value) { r_v(b, n, obs_slot_value(s)); } @@ -468,7 +490,7 @@ EXP(slot_box) { case C_NULL: snprintf(b, n, "v:null"); break; case C_BOOL: e_bool(b, n, k); break; case C_HEAP: snprintf(b, n, "v:H"); break; - case C_SMI: ABORT("slot_to_value"); break; + case C_SMI: snprintf(b, n, "v:int:5"); break; default: ABORT("eigs_slot_ref"); } } @@ -493,6 +515,7 @@ EXP(to_value) { case C_NULL: snprintf(b, n, "v:null"); break; case C_BOOL: e_bool(b, n, k); break; case C_HEAP: snprintf(b, n, "v:H"); break; + case C_SMI: snprintf(b, n, "v:int:5"); break; default: ABORT("slot_to_value"); } } @@ -509,7 +532,7 @@ EXP(unwrap) { case C_NULL: snprintf(b, n, "v:null"); break; case C_BOOL: e_bool(b, n, k); break; case C_HEAP: snprintf(b, n, "v:H"); break; - case C_SMI: ABORT("slot_to_value"); break; + case C_SMI: snprintf(b, n, "v:int:5"); break; default: ABORT("slot_as_ptr"); } } @@ -533,7 +556,20 @@ typedef struct { void (*cell)(EigsSlot, char *, size_t); void (*expect)(int, char *, size_t); } MatrixEntry; +EXP(vm_bit_operand) { + if (k == K_SMI) snprintf(b, n, "o:1 i:5"); + else if (k == K_NZ) snprintf(b, n, "o:1 i:0"); + else snprintf(b, n, "o:%d i:7", kclass(k) == C_F64 ? 0 : -1); +} +EXP(vm_number_compare) { + if (k == K_SMI) snprintf(b, n, "o:1 c:1"); + else if (k == K_NAN) snprintf(b, n, "o:1 c:2"); + else if (kclass(k) == C_F64) snprintf(b, n, "o:1 c:%d", k == K_NZ ? -1 : 1); + else snprintf(b, n, "o:0 c:7"); +} static const MatrixEntry MATRIX[] = { + {"vm.c:vm_bit_operand", c_vm_bit_operand, e_vm_bit_operand}, + {"vm.c:vm_number_compare", c_vm_number_compare, e_vm_number_compare}, {"container.h:eigs_slot_elem_num", c_elem_num, e_elem_num}, {"container.h:eigs_slot_num", c_num, e_num}, {"container.h:eigs_slot_opt_num", c_opt_num, e_opt_num}, @@ -641,9 +677,6 @@ static int part_b(void) { /* ---- Part C: slot_from_int (plant 1's named check) ----------------------- */ -static int64_t g_from_int_arg; -static void c_from_int(EigsSlot s) { (void)s; (void)slot_from_int(g_from_int_arg); } - static int part_c(void) { static const int64_t inside[] = { 0, 1, -1, 12345, -12345, (INT64_C(1) << 47) - 1, -(INT64_C(1) << 47), @@ -664,21 +697,20 @@ static int part_c(void) { FAILF("slot_smi_val(SMI %lld) = %lld", (long long)v, (long long)slot_smi_val(smi(v))); } for (size_t k = 0; k < sizeof outside / sizeof outside[0]; k++, rows++) { - g_from_int_arg = outside[k]; - char what[64]; - snprintf(what, sizeof what, "slot_from_int(%lld)", (long long)outside[k]); - (void)aborts_naming(c_from_int, slot_null(), "slot_from_int", what); + EigsSlot boxed = slot_from_int(outside[k]); + int64_t got = 0; + if (!slot_is_heap(boxed) || !slot_int_value(boxed, &got) || got != outside[k] || + slot_as_ptr(boxed)->type != VAL_INT) + FAILF("slot_from_int(%lld): box loses exact int64", (long long)outside[k]); + slot_decref(boxed); } return rows; } /* ---- Part D: the VM's operator arms, with an int in a list ------------- */ -/* A host builtin puts a hand-built SMI (or, for the control run, the double - * of the same value) into a list element, the way no program can before - * R1.3. Each arm that met an int with a type error -- which a `try` turned - * into a wrong value (the R1.1 critic) -- must now refuse it by name, inside - * a `try` too; the control run proves the program reaches the arm. */ +/* A host builtin puts a hand-built SMI (or a float control) in a list. + * Every R1.3-converted arm computes its final value, including under try. */ static int g_poke_smi; static EigsValue *h_poke(EigsValue *arg) { Value *t = list_get_ref(arg, 0); @@ -688,24 +720,24 @@ static EigsValue *h_poke(EigsValue *arg) { slot_decref(old); return make_null(); } -typedef struct { const char *name, *expr, *f64_out, *aborts; int in_try; } Arm; +typedef struct { const char *name, *expr, *f64_out, *int_out; int in_try; } Arm; static const Arm ARMS[] = { - {"lt", "xs[0] < 6", "true", "compare '<'", 0}, - {"gt", "xs[0] > 6", "false", "compare '>'", 0}, - {"le", "xs[0] <= 6", "true", "compare '<='", 0}, - {"ge", "xs[0] >= 6", "false", "compare '>='", 0}, - {"lt_in_try", "xs[0] < 6", "true", "compare '<'", 1}, - {"band", "xs[0] & 3", "1", "bitwise '&'", 0}, - {"bor", "xs[0] | 3", "7", "bitwise '|'", 0}, - {"bxor", "xs[0] ^ 3", "6", "bitwise '^'", 0}, - {"shl", "xs[0] << 1", "10", "bitwise '<<'", 0}, - {"shr", "xs[0] >> 1", "2", "bitwise '>>'", 0}, - {"band_in_try", "xs[0] & 3", "1", "bitwise '&'", 1}, - {"neg", "-(xs[0])", "-5", "negation", 0}, - {"neg_in_try", "-(xs[0])", "-5", "negation", 1}, - {"bnot", "~(xs[0])", "-6", "bitwise '~'", 0}, - {"eq", "xs[0] == 5", "true", "slot_to_value", 0}, - {"add", "xs[0] + 1", "6", "slot_to_value", 0}, + {"lt", "xs[0] < 6", "true", "true", 0}, + {"gt", "xs[0] > 6", "false", "false", 0}, + {"le", "xs[0] <= 6", "true", "true", 0}, + {"ge", "xs[0] >= 6", "false", "false", 0}, + {"lt_in_try", "xs[0] < 6", "true", "true", 1}, + {"band", "xs[0] & 3", "1", "1", 0}, + {"bor", "xs[0] | 3", "7", "7", 0}, + {"bxor", "xs[0] ^ 3", "6", "6", 0}, + {"shl", "xs[0] << 1", "10", "10", 0}, + {"shr", "xs[0] >> 1", "2", "2", 0}, + {"band_in_try", "xs[0] & 3", "1", "1", 1}, + {"neg", "-(xs[0])", "-5", "-5", 0}, + {"neg_in_try", "-(xs[0])", "-5", "-5", 1}, + {"bnot", "~(xs[0])", "-6", "-6", 0}, + {"eq", "xs[0] == 5", "true", "true", 0}, + {"add", "xs[0] + 1", "6", "6", 0}, }; #define N_ARMS ((int)(sizeof ARMS / sizeof ARMS[0])) static const Arm *g_arm; @@ -720,6 +752,7 @@ static void c_arm(EigsSlot s, char *b, size_t n) { EigsValue *r = eigs_eval_string(prog); fflush(stdout); snprintf(b, n, "%s", r ? "ran" : "eval-error"); + eigs_value_release(r); } static int part_d(void) { eigs_register_function("phase2_poke", h_poke); @@ -729,9 +762,12 @@ static int part_d(void) { int bad = 0; char got[512], want[256], pre[512], wpre[64]; g_poke_smi = 1; - run_cell(c_arm, slot_null(), got, sizeof got, NULL, 0); - snprintf(want, sizeof want, "A:%s", g_arm->aborts); - if (strcmp(got, want) != 0) { FAILF("arm %s with an int: got %s, want %s", g_arm->name, got, want); bad++; } + run_cell(c_arm, slot_null(), got, sizeof got, pre, sizeof pre); + snprintf(want, sizeof want, "%s\n", g_arm->int_out); + if (strcmp(got, "ran") != 0 || strcmp(pre, want) != 0) { + FAILF("arm %s with an int: got %s printed %s, want ran and %s", g_arm->name, got, pre, want); + bad++; + } g_poke_smi = 0; run_cell(c_arm, slot_null(), got, sizeof got, pre, sizeof pre); snprintf(wpre, sizeof wpre, "%s\n", g_arm->f64_out); diff --git a/tests/test_bitwise.eigs b/tests/test_bitwise.eigs index bba438818..767cb3968 100644 --- a/tests/test_bitwise.eigs +++ b/tests/test_bitwise.eigs @@ -192,11 +192,10 @@ assert_eq of [(0 - 1) << 1, 0 - 2, "SHL of a negative is defined (unsigned shift assert_eq of [bit_shl of [0 - 1, 1], (0 - 1) << 1, "bit_shl matches infix on a negative"] assert_eq of [1 << (0 - 1), int64_min, "a negative exact count is masked & 63"] -# --- JIT tier: the native path must raise exactly where the VM does --- -# Each callee is called > EIGS_JIT_ENTRY_THRESHOLD (50) times with integers -# first, so its thunk exists before a non-integer operand arrives; the OSR -# loop runs past EIGS_JIT_OSR_THRESHOLD (5000) back-edges before its bad -# iteration. tools/jit_diff.sh runs this file JIT-off, default and forced OSR. +# --- All execution settings must raise exactly where the VM does --- +# R1.3 intentionally scanner-refuses these operators until R5. The hot +# entry/OSR scaffolds below verify interpreted fallback in each setting; +# Phase 2's ctl.scan.* rows independently witness the scanner refusals. define hot_or(a, b) as: return a | b define hot_shl(a, b) as: diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 9526fc263..39d7b9b55 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -65,7 +65,6 @@ value_slot.h|slot_f64_value|2|float reader (#1758: was vm.c slot_as_double): an value_slot.h|slot_from_f64|1|constructor: writes a double into a fresh slot (#1758: was slot_from_num) value_slot.h|slot_truthy_immediate|1|truthiness after slot_is_f64 vm.c|#define ARITH_FAST|2|arithmetic fast path after both operands tested VAL_FLOAT; NUM_REUSE writes -vm.c|#define INT_BINOP_R|2|integer op fast path after both slots slot_is_f64 vm.c|#define NUM_BINOP|6|arithmetic after a->type == VAL_FLOAT && b->type == VAL_FLOAT; NUM_REUSE writes vm.c|jit_helper_dot_set|1|JIT helper: number store after slot_is_f64 vm.c|jit_helper_index_get|3|JIT helper: index read after slot_is_f64 / VAL_FLOAT tests on index and element @@ -78,7 +77,7 @@ vm.c|obs_slot_num|1|observer numeric channel (#1758): reads an immediate after s vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 vm.c|slot_truthy|1|truthiness after slot_is_f64 vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_FLOAT (chunk_scan_leaf_accessor) and values behind VAL_FLOAT tests -vm.c|vm_run_ex|42|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_FLOAT dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built +vm.c|vm_run_ex|34|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_FLOAT dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 builtins.c|builtin_json_build|1|VAL_INT text is exact digits; float text retains the bridge (#1758 R1.2d) @@ -90,3 +89,5 @@ value_slot.h|slot_int_value|1|boxed VAL_INT payload after its type test (#1758 R container.h|slot_view|3|typed float or int facade, preserving exact payload and kind (#1758 R1.2i) ext_db.c|db_build_query|1|VAL_INT parameters encode as exact digits after the kind test (#1758 R1.2) vm.c|vm_value_index_is_int|2|Guarded exact VAL_INT-to-C-index conversion; the other numeric kind keeps the float integrality test (#1758 R1.2) +builtins.c|builtin_abs|1|N4b: proved VAL_INT payload, refuse INT64_MIN before negating +eigenscript.c|make_int|1|int constructor initializes the exact signed payload diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 3b1786348..a9b3e6fa2 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -71,6 +71,9 @@ sys.path.insert(0, os.path.join(ROOT, 'tools')) import phase2_inventory as inv # noqa: E402 (strip_c: one C-comment grammar) +# The no-int-source mechanism ended at R1.3. Its static calibration uses +# the exact last no-producer source; current runtime safety is the MAP/ASan gate. +STATIC_INT_SOURCE_REF = '0c43ec88ca8915f9d365e3e63549cb1e322c76d3' ROUNDS = ['R1.1', 'R1.2', 'R1.3', 'R1.4', 'R1.5', 'R1.6', 'R1.7', 'R1.8', 'R2.1', 'R2.2', 'R2.3', 'R2.4', 'R2.5', 'R2.6', 'R3'] # Gates every mode runs: the token gate (a landed round's deleted tokens stay @@ -688,6 +691,20 @@ def calibrate(args, out): cal = os.path.join(ROOT, 'tests/phase2/calib') map_rows, bad = parse_map(os.path.join(cal, 'MAP.md')) results = [] + # Keep early-round calibration meaningful after the first int producers + # exist. Export only tracked src bytes from the pinned R1.2 checkpoint. + historical = tempfile.mkdtemp(prefix='eigs-p2-int-source-r12-') + _PLANT_DIR.append(historical) + try: + archive = subprocess.run(['git', '-C', ROOT, 'archive', STATIC_INT_SOURCE_REF, 'src'], + capture_output=True, check=True) + subprocess.run(['tar', '-x', '-C', historical], input=archive.stdout, check=True) + except subprocess.CalledProcessError as error: + out('phase2-check: FAIL: historical R1.2 int-source export failed: %s' % error) + return 2 + historical_src = os.path.join(historical, 'src') + out('calibration: historical-int-source=%s (static only; dynamic no-SMI mode retired at R1.3)' % + STATIC_INT_SOURCE_REF) def case(name, got, want, detail=None): """One calibration case. An UNEXPECTED case prints the gate's own @@ -782,7 +799,7 @@ def stray(rd): case('a round with neither rows nor gates fails', any('round R2.3' in b for b in pb), True, detail=pb) # the int-source check against a planted production call with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: - shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src'), ignore=c_sources_only) + shutil.copytree(historical_src, os.path.join(d, 'src'), ignore=c_sources_only) p = os.path.join(d, 'src', 'trace.c') text = read_text(p) anchor = ' *out = slot_from_f64((double)count);' @@ -796,8 +813,8 @@ def stray(rd): lines = [] # at R1.2: from R1.2 the canonicalizing writers may convert a VAL_INT # (design 8), and the branch is past R1.1 - case('int-source on the real tree passes (at R1.2)', - int_source(os.path.join(ROOT, 'src'), lines.append, 'R1.2'), True, detail=lines) + case('int-source on pinned R1.2 source passes', + int_source(historical_src, lines.append, 'R1.2'), True, detail=lines) # the token gate against a reintroduced deleted token with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: os.mkdir(os.path.join(d, 'src')) @@ -810,10 +827,10 @@ def stray(rd): lines = [] case('token plant (slot_is_num reintroduced): the gate fails', (token_gate(d, 'R1.1', lines.append), any('slot_is_num' in l for l in lines)), (False, True), detail=lines) - # the int-source plants of the R1.1 critic, both halves + # the int-source plants of the R1.1 critic, static half on the historical source for name, edits in INTSRC_PLANTS: with tempfile.TemporaryDirectory(prefix='eigs-p2cal-') as d: - shutil.copytree(os.path.join(ROOT, 'src'), os.path.join(d, 'src'), ignore=c_sources_only) + shutil.copytree(historical_src, os.path.join(d, 'src'), ignore=c_sources_only) counts = [] for f, old, new in edits: p = os.path.join(d, 'src', f) From cad35731665872b1dd774a4d8635bf791dbba329 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:25:56 -0500 Subject: [PATCH 058/188] phase2 R1.3b: the remaining R1.1/R1.2 placeholders get their final int arms (#1758) Every `eigs_int_unwired` site outside the tape now does what an int needs, still before any int value can be produced: - chan_clone_rec copies an int into a fresh make_int box; - the `dispatch` builtin boxes a numeric argument by kind (make_int for an int, make_num for a float), so the callee never borrows a dead frame's view; - ITER_NEXT and jit_helper_iter_next read index and snapshot metadata through vm_iter_index / vm_iter_limit: an exact int in the C-int range is an index, a float keeps its reader, an out-of-range index exhausts without narrowing, a negative snapshot exhausts, an oversized one keeps the live length. The JIT helper now bounds the index with the interpreter's unsigned compare. The four iterator sites R1.2's cost fix moved (#1827) are pinned by the C slot test's new Part E: float, SMI and boxed-int metadata, range and malformed states, in the interpreter and the JIT helper (26 rows). The population grows by vm_iter_index and vm_iter_limit (35 -> 37 classifiers, 444 matrix cells). What still calls eigs_int_unwired is the tape writer, which converts with the v7 format in the N1 commit; that commit deletes the placeholder function. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 599 +++++++++++++++---------------- docs/design/phase2-numbers.md | 5 +- src/builtins.c | 8 +- src/eigenscript.c | 4 +- src/vm.c | 64 ++-- tests/phase2/slot_layer.c | 134 ++++++- tools/num_read_allowlist.txt | 6 +- 7 files changed, 469 insertions(+), 351 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index be44a629b..662f107df 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,11 +1,11 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2018 classified=2018 unclassified=0 +examined=2012 classified=2012 unclassified=0 files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 505 CASE=60 DATA=4 TEST=438 YIELD=3 -(b) payload reads 555 RAW=111 READ=444 +(a) type tests 501 CASE=60 DATA=4 TEST=434 YIELD=3 +(b) payload reads 553 RAW=111 READ=442 (c) producers 473 GUARD=73 PARSE=3 PRODUCE=371 TAGSET=5 WRITE=21 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 20 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=7 @@ -17,10 +17,10 @@ files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per token make_num 365 -val_is_number 184 +val_is_number 185 eigs_num_arg 172 -VAL_FLOAT 151 -VAL_INT 148 +VAL_FLOAT 150 +VAL_INT 144 eigs_list_num 130 SLOT_F64_RAW 83 num_guard 62 @@ -35,15 +35,15 @@ slot_from_f64 37 slot_is_smi 33 buffer_read_byte 22 list_set_num 22 -slot_f64_value 22 +slot_f64_value 19 slot_smi_val 19 strtod 16 NUM_REUSE 12 eigs_slot_opt_num 12 eigs_num_arg_slow 9 +slot_int_value 9 EIGS_NUM_MAX 8 finite_num_to_byte 8 -slot_int_value 8 eigs_num_text 7 eigs_opt_num 6 eigs_slot_elem_num 6 @@ -69,8 +69,8 @@ data.num (AST) 7 ## Per file (category counts) builtins.c 350 a=84 b=104 c=111 e=6 f=13 h=21 i=11 -vm.c 299 a=74 b=97 c=66 e=2 f=10 i=50 ext_gfx.c 298 a=104 b=124 c=70 +vm.c 293 a=70 b=95 c=66 e=2 f=10 i=50 builtins_tensor.c 200 a=55 b=59 c=86 eigenscript.c 123 a=22 b=18 c=15 e=7 f=18 i=43 builtins_buf.c 110 a=34 b=37 c=39 @@ -188,7 +188,7 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=61 D2=18 D3=26 T=66 dispositions=105 missing=0 stale=0 +D1=61 D2=19 D3=26 T=66 dispositions=106 missing=0 stale=0 D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 @@ -223,7 +223,6 @@ D1 vm.c:#define READ_SLICE_BOUND smi-arm slot_as_ptr=1 slo D1 vm.c:jit_helper_dot_set guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:jit_helper_index_get guarded slot_as_ptr=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 D1 vm.c:jit_helper_index_set guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 -D1 vm.c:jit_helper_iter_next unwired slot_as_ptr=1 slot_f64_value=2 slot_int_value=1 slot_is_ptr=1 slot_type=2 D1 vm.c:jit_helper_local_dot_set guarded slot_is_f64=1 D1 vm.c:loop_iter_store guarded slot_is_f64=1 D1 vm.c:obs_dump_scope smi-arm slot_as_ptr=3 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=3 slot_is_smi=1 slot_smi_val=1 @@ -234,6 +233,8 @@ D1 vm.c:slot_bridge_unwrap smi-arm slot_as_ptr=1 slo D1 vm.c:slot_truthy smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:slot_type_name smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 D1 vm.c:vm_bit_operand smi-arm slot_f64_value=1 slot_int_value=1 +D1 vm.c:vm_iter_index smi-arm slot_f64_value=1 slot_int_value=1 +D1 vm.c:vm_iter_limit smi-arm slot_int_value=1 D1 vm.c:vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL guarded slot_f64_value=2 D1 vm.c:vm_leaf_accessor_exec/OP_INDEX_GET guarded slot_as_ptr=1 slot_f64_value=1 slot_is_ptr=1 D1 vm.c:vm_number_compare smi-arm slot_f64_value=2 slot_int_value=2 @@ -243,7 +244,6 @@ D1 vm.c:vm_run_ex/CASE(DOT_SET) guarded slot_as_ptr=1 slo D1 vm.c:vm_run_ex/CASE(EQ) guarded slot_f64_value=2 slot_is_smi=2 D1 vm.c:vm_run_ex/CASE(INDEX_GET) guarded slot_as_ptr=1 slot_is_f64=1 slot_is_ptr=1 D1 vm.c:vm_run_ex/CASE(INDEX_SET) guarded slot_as_ptr=1 slot_is_f64=3 slot_is_ptr=1 -D1 vm.c:vm_run_ex/CASE(ITER_NEXT) unwired slot_f64_value=2 slot_type=2 D1 vm.c:vm_run_ex/CASE(LOCAL_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_SET) guarded slot_is_f64=1 D1 vm.c:vm_run_ex/CASE(NE) guarded slot_f64_value=2 slot_is_smi=2 @@ -260,6 +260,7 @@ D2 eigenscript.c:env_get_local_hashed guarded slot_as_ptr=1 slo D2 eigenscript.c:gc_collect_at_exit guarded slot_as_ptr=1 slot_is_ptr=1 D2 value_slot.h:#define slot_as_heap refuse slot_as_heap=1 slot_as_ptr=1 D2 value_slot.h:slot_as_ptr refuse SLOT_PAYLOAD_MASK=1 slot_as_ptr=1 slot_is_heap=1 +D2 vm.c:jit_helper_iter_next guarded slot_as_ptr=1 slot_is_ptr=1 D2 vm.c:obs_slot_value guarded slot_as_ptr=1 slot_is_bool=1 D2 vm.c:vm_borrow_scan guarded slot_as_ptr=2 slot_is_heap=2 D2 vm.c:vm_builtin_name_for guarded slot_as_ptr=1 slot_is_heap=1 @@ -363,7 +364,7 @@ cos builtin_cos float-producing db_execute builtin_db_execute other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg db_query_json builtin_db_query_json other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg db_query_value builtin_db_query_value other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,strtod -dispatch builtin_dispatch int-requiring - - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,val_is_number +dispatch builtin_dispatch int-requiring - - VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,val_is_number divide builtin_tensor_divide float-producing - - eigs_num_arg,make_num,num_guard,val_is_number dot builtin_dot float-producing - - buffer_read_num,make_num,num_guard eigen_eval_loss builtin_eigen_eval_loss float-producing - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_slot_num,make_num @@ -871,9 +872,9 @@ builtins.c:6010 builtin_dispatch val_is_number TEST a builtins.c:6014 builtin_dispatch eigs_num_arg READ b builtins.c:6015 builtin_dispatch eigs_num_arg READ b builtins.c:6017 builtin_dispatch eigs_num_arg READ b -builtins.c:6040 builtin_dispatch VAL_INT TEST a -builtins.c:6041 builtin_dispatch VAL_I64_RAW RAW b -builtins.c:6042 builtin_dispatch VAL_FLOAT TEST a +builtins.c:6040 builtin_dispatch val_is_number TEST a +builtins.c:6041 builtin_dispatch VAL_INT TEST a +builtins.c:6042 builtin_dispatch VAL_I64_RAW RAW b builtins.c:6043 builtin_dispatch eigs_num_arg READ b builtins.c:6043 builtin_dispatch make_num PRODUCE c builtins.c:6119 builtin_dot make_num PRODUCE c @@ -1472,39 +1473,39 @@ eigenscript.c:2684 chan_clone_rec VAL_INT TEST a eigenscript.c:2687 chan_clone_rec VAL_F64_RAW RAW b eigenscript.c:2687 chan_clone_rec VAL_FLOAT CASE a eigenscript.c:2687 chan_clone_rec make_num PRODUCE c -eigenscript.c:2690 chan_clone_rec VAL_I64_RAW RAW b -eigenscript.c:2690 chan_clone_rec VAL_INT CASE a -eigenscript.c:2877 is_truthy VAL_F64_RAW RAW b -eigenscript.c:2877 is_truthy VAL_FLOAT CASE a -eigenscript.c:2878 is_truthy VAL_I64_RAW RAW b -eigenscript.c:2878 is_truthy VAL_INT CASE a +eigenscript.c:2688 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:2688 chan_clone_rec VAL_INT CASE a +eigenscript.c:2875 is_truthy VAL_F64_RAW RAW b +eigenscript.c:2875 is_truthy VAL_FLOAT CASE a +eigenscript.c:2876 is_truthy VAL_I64_RAW RAW b +eigenscript.c:2876 is_truthy VAL_INT CASE a +eigenscript.c:2915 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2915 values_equal_impl VAL_INT TEST f +eigenscript.c:2916 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2916 values_equal_impl VAL_I64_RAW RAW f eigenscript.c:2917 values_equal_impl VAL_FLOAT TEST f eigenscript.c:2917 values_equal_impl VAL_INT TEST f eigenscript.c:2918 values_equal_impl VAL_F64_RAW RAW f eigenscript.c:2918 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2919 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:2919 values_equal_impl VAL_INT TEST f -eigenscript.c:2920 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2920 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2921 values_equal_impl val_is_number TEST f -eigenscript.c:2922 values_equal_impl val_is_number TEST f -eigenscript.c:2936 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2936 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2936 values_equal_impl VAL_FLOAT CASE f -eigenscript.c:2937 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2937 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2937 values_equal_impl VAL_INT CASE f +eigenscript.c:2919 values_equal_impl val_is_number TEST f +eigenscript.c:2920 values_equal_impl val_is_number TEST f +eigenscript.c:2934 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2934 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2934 values_equal_impl VAL_FLOAT CASE f +eigenscript.c:2935 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2935 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2935 values_equal_impl VAL_INT CASE f +eigenscript.c:2965 values_equal_impl buffer_read_num READ f eigenscript.c:2967 values_equal_impl buffer_read_num READ f -eigenscript.c:2969 values_equal_impl buffer_read_num READ f -eigenscript.c:3009 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3024 eigs_num_text strtod PARSE e -eigenscript.c:3034 value_to_string VAL_FLOAT CASE e -eigenscript.c:3035 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3035 value_to_string eigs_num_text FORMAT e -eigenscript.c:3038 value_to_string VAL_INT CASE e -eigenscript.c:3039 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4260 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4261 gc_value_is_node VAL_INT CASE a +eigenscript.c:3007 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:3022 eigs_num_text strtod PARSE e +eigenscript.c:3032 value_to_string VAL_FLOAT CASE e +eigenscript.c:3033 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3033 value_to_string eigs_num_text FORMAT e +eigenscript.c:3036 value_to_string VAL_INT CASE e +eigenscript.c:3037 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4258 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4259 gc_value_is_node VAL_INT CASE a eigenscript.h:188 num_val RAW b eigenscript.h:206 AST_NUM DATA a eigenscript.h:272 VAL_FLOAT DATA a @@ -2286,268 +2287,262 @@ vm.c:907 vm_number_compare slot_int_value READ b vm.c:907 vm_number_compare slot_int_value READ b vm.c:909 vm_number_compare slot_f64_value READ b vm.c:910 vm_number_compare slot_f64_value READ b -vm.c:962 make_iter_state make_num PRODUCE c -vm.c:975 make_iter_state make_num PRODUCE c -vm.c:1194 vm_store_local_slot slot_is_f64 TEST a -vm.c:1198 vm_store_local_slot VAL_FLOAT TEST a -vm.c:1200 vm_store_local_slot SLOT_F64_RAW RAW b -vm.c:1200 vm_store_local_slot VAL_F64_RAW WRITE c -vm.c:1391 jit_helper_local_idx_get buffer_read_num READ b -vm.c:1391 jit_helper_local_idx_get slot_from_f64 PRODUCE c -vm.c:1552 jit_helper_dot_set slot_is_f64 TEST a -vm.c:1555 jit_helper_dot_set SLOT_F64_RAW RAW b -vm.c:1622 jit_helper_local_dot_set slot_is_f64 TEST a -vm.c:1623 jit_helper_local_dot_set SLOT_F64_RAW RAW b -vm.c:1673 obs_slot_observable slot_is_f64 TEST i -vm.c:1680 obs_slot_num SLOT_F64_RAW RAW i -vm.c:1680 obs_slot_num slot_is_f64 TEST i -vm.c:1681 obs_slot_num slot_is_smi TEST i -vm.c:1681 obs_slot_num slot_smi_val RAW i -vm.c:1829 jit_helper_iter_next slot_f64_value READ b -vm.c:1830 jit_helper_iter_next VAL_INT TEST a -vm.c:1845 jit_helper_iter_next slot_f64_value READ b -vm.c:1848 jit_helper_iter_next VAL_INT TEST a -vm.c:1850 jit_helper_iter_next slot_int_value READ b -vm.c:1857 jit_helper_iter_next buffer_read_num READ b -vm.c:1857 jit_helper_iter_next num_guard GUARD c -vm.c:1857 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1863 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1933 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b -vm.c:1933 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1937 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1940 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1979 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1993 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1993 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:2004 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:2005 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:2023 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:2023 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2106 loop_iter_store make_num PRODUCE c -vm.c:2113 loop_iter_store slot_is_f64 TEST a -vm.c:2114 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2119 loop_iter_store make_num PRODUCE c -vm.c:2234 vm_value_index_is_int VAL_INT TEST a -vm.c:2235 vm_value_index_is_int VAL_I64_RAW RAW b -vm.c:2240 vm_value_index_is_int VAL_F64_RAW RAW b -vm.c:2253 jit_helper_index_set slot_is_f64 TEST a -vm.c:2258 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2259 jit_helper_index_set slot_is_f64 TEST a -vm.c:2261 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2263 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2273 jit_helper_index_set slot_is_f64 TEST a -vm.c:2275 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2276 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2278 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2290 jit_helper_index_set val_is_number TEST a -vm.c:2293 jit_helper_index_set eigs_num_arg READ b -vm.c:2300 jit_helper_index_set val_is_number TEST a -vm.c:2303 jit_helper_index_set eigs_num_arg READ b -vm.c:2306 jit_helper_index_set val_is_number TEST a -vm.c:2307 jit_helper_index_set eigs_num_arg READ b -vm.c:2326 jit_helper_index_get slot_is_f64 TEST a -vm.c:2328 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:922 vm_iter_index slot_f64_value READ b +vm.c:928 vm_iter_index slot_int_value READ b +vm.c:936 vm_iter_limit slot_int_value READ b +vm.c:984 make_iter_state make_num PRODUCE c +vm.c:997 make_iter_state make_num PRODUCE c +vm.c:1216 vm_store_local_slot slot_is_f64 TEST a +vm.c:1220 vm_store_local_slot VAL_FLOAT TEST a +vm.c:1222 vm_store_local_slot SLOT_F64_RAW RAW b +vm.c:1222 vm_store_local_slot VAL_F64_RAW WRITE c +vm.c:1413 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1413 jit_helper_local_idx_get slot_from_f64 PRODUCE c +vm.c:1574 jit_helper_dot_set slot_is_f64 TEST a +vm.c:1577 jit_helper_dot_set SLOT_F64_RAW RAW b +vm.c:1644 jit_helper_local_dot_set slot_is_f64 TEST a +vm.c:1645 jit_helper_local_dot_set SLOT_F64_RAW RAW b +vm.c:1695 obs_slot_observable slot_is_f64 TEST i +vm.c:1702 obs_slot_num SLOT_F64_RAW RAW i +vm.c:1702 obs_slot_num slot_is_f64 TEST i +vm.c:1703 obs_slot_num slot_is_smi TEST i +vm.c:1703 obs_slot_num slot_smi_val RAW i +vm.c:1864 jit_helper_iter_next buffer_read_num READ b +vm.c:1864 jit_helper_iter_next num_guard GUARD c +vm.c:1864 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1870 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1940 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b +vm.c:1940 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1944 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1947 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1986 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:2000 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:2000 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:2011 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2012 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2030 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:2030 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2113 loop_iter_store make_num PRODUCE c +vm.c:2120 loop_iter_store slot_is_f64 TEST a +vm.c:2121 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2126 loop_iter_store make_num PRODUCE c +vm.c:2241 vm_value_index_is_int VAL_INT TEST a +vm.c:2242 vm_value_index_is_int VAL_I64_RAW RAW b +vm.c:2247 vm_value_index_is_int VAL_F64_RAW RAW b +vm.c:2260 jit_helper_index_set slot_is_f64 TEST a +vm.c:2265 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2266 jit_helper_index_set slot_is_f64 TEST a +vm.c:2268 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2270 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2280 jit_helper_index_set slot_is_f64 TEST a +vm.c:2282 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2283 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2285 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2297 jit_helper_index_set val_is_number TEST a +vm.c:2300 jit_helper_index_set eigs_num_arg READ b +vm.c:2307 jit_helper_index_set val_is_number TEST a +vm.c:2310 jit_helper_index_set eigs_num_arg READ b +vm.c:2313 jit_helper_index_set val_is_number TEST a +vm.c:2314 jit_helper_index_set eigs_num_arg READ b +vm.c:2333 jit_helper_index_get slot_is_f64 TEST a vm.c:2335 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2346 jit_helper_index_get buffer_read_num READ b -vm.c:2348 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2350 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2366 jit_helper_index_get val_is_number TEST a -vm.c:2369 jit_helper_index_get eigs_num_arg READ b -vm.c:2381 jit_helper_index_get val_is_number TEST a -vm.c:2384 jit_helper_index_get eigs_num_arg READ b -vm.c:2393 jit_helper_index_get val_is_number TEST a -vm.c:2396 jit_helper_index_get eigs_num_arg READ b -vm.c:2398 jit_helper_index_get buffer_read_num READ b -vm.c:2398 jit_helper_index_get make_num PRODUCE c -vm.c:2984 vm_take_error_value make_num PRODUCE c -vm.c:3088 slot_type_name slot_is_f64 TEST e -vm.c:3089 slot_type_name slot_is_smi TEST e -vm.c:3329 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a -vm.c:3330 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b -vm.c:3330 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3344 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3349 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3369 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3369 #define NUM_REUSE VAL_FLOAT TEST a -vm.c:3380 #define ARITH_FAST slot_f64_value READ b -vm.c:3380 #define ARITH_FAST slot_f64_value READ b -vm.c:3381 #define ARITH_FAST num_guard GUARD c -vm.c:3386 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3387 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3395 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3396 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3404 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3416 #define INT_ARITH slot_int_value READ b -vm.c:3416 #define INT_ARITH slot_int_value READ b -vm.c:3430 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3430 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3431 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3431 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3431 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3432 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3432 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3433 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3433 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3434 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3435 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3435 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3436 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3436 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3436 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3436 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3486 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3486 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3487 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3487 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3487 #define NUM_BINOP num_guard GUARD c -vm.c:3488 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3488 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3490 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3490 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3491 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3491 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3492 #define NUM_BINOP make_num PRODUCE c -vm.c:3493 #define NUM_BINOP val_is_number TEST a -vm.c:3493 #define NUM_BINOP val_is_number TEST a -vm.c:3494 #define NUM_BINOP eigs_num_arg READ b -vm.c:3494 #define NUM_BINOP eigs_num_arg READ b -vm.c:3495 #define NUM_BINOP num_guard GUARD c -vm.c:3498 #define NUM_BINOP make_num PRODUCE c -vm.c:3502 #define NUM_BINOP make_num PRODUCE c -vm.c:3520 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3520 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3521 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3523 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3525 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3525 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3525 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:2342 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2353 jit_helper_index_get buffer_read_num READ b +vm.c:2355 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2357 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2373 jit_helper_index_get val_is_number TEST a +vm.c:2376 jit_helper_index_get eigs_num_arg READ b +vm.c:2388 jit_helper_index_get val_is_number TEST a +vm.c:2391 jit_helper_index_get eigs_num_arg READ b +vm.c:2400 jit_helper_index_get val_is_number TEST a +vm.c:2403 jit_helper_index_get eigs_num_arg READ b +vm.c:2405 jit_helper_index_get buffer_read_num READ b +vm.c:2405 jit_helper_index_get make_num PRODUCE c +vm.c:2991 vm_take_error_value make_num PRODUCE c +vm.c:3095 slot_type_name slot_is_f64 TEST e +vm.c:3096 slot_type_name slot_is_smi TEST e +vm.c:3336 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3337 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3337 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3351 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3356 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3376 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3376 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3387 #define ARITH_FAST slot_f64_value READ b +vm.c:3387 #define ARITH_FAST slot_f64_value READ b +vm.c:3388 #define ARITH_FAST num_guard GUARD c +vm.c:3393 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3394 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3402 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3403 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3411 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3423 #define INT_ARITH slot_int_value READ b +vm.c:3423 #define INT_ARITH slot_int_value READ b +vm.c:3437 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3437 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3438 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3438 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3438 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3439 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3439 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3440 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3440 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3441 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3442 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3442 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3443 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3443 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3443 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3443 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3493 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3493 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3494 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3494 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3494 #define NUM_BINOP num_guard GUARD c +vm.c:3495 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3495 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3497 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3497 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3498 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3498 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3499 #define NUM_BINOP make_num PRODUCE c +vm.c:3500 #define NUM_BINOP val_is_number TEST a +vm.c:3500 #define NUM_BINOP val_is_number TEST a +vm.c:3501 #define NUM_BINOP eigs_num_arg READ b +vm.c:3501 #define NUM_BINOP eigs_num_arg READ b +vm.c:3502 #define NUM_BINOP num_guard GUARD c +vm.c:3505 #define NUM_BINOP make_num PRODUCE c +vm.c:3509 #define NUM_BINOP make_num PRODUCE c +vm.c:3527 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3527 vm_run_ex/CASE(DIV) val_is_number TEST a vm.c:3528 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3530 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3530 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3531 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3531 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3532 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3537 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3545 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3545 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3545 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3546 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3546 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3546 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3547 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3547 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3548 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3548 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3549 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3551 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3551 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3530 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3532 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3532 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3532 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3535 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3537 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3537 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3538 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3538 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3539 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3544 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3552 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3552 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3552 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3553 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3553 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3553 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3554 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3554 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3555 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3555 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c vm.c:3556 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3584 #define INT_BINOP_R slot_f64_value READ b -vm.c:3588 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3615 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3618 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3618 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3621 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3625 vm_run_ex/CASE(NEG) slot_int_value READ b -vm.c:3630 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c -vm.c:3635 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3657 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3661 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3670 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3670 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3676 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3676 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3696 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3696 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3702 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3702 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3724 #define NUM_CMP slot_f64_value READ f -vm.c:3724 #define NUM_CMP slot_f64_value READ f -vm.c:4667 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4669 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:3558 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3558 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3563 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3591 #define INT_BINOP_R slot_f64_value READ b +vm.c:3595 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3622 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3625 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3625 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3628 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3632 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3637 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3642 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3664 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3668 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3677 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3677 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3683 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3683 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3703 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3703 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3709 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3709 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3731 #define NUM_CMP slot_f64_value READ f +vm.c:3731 #define NUM_CMP slot_f64_value READ f +vm.c:4674 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a vm.c:4676 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4686 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4688 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4690 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4712 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4714 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4715 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4717 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4719 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4729 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4731 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4731 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4733 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4745 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4748 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4755 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4758 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4761 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4762 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4818 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4821 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4882 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4883 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4909 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4909 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5015 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5016 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5066 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b -vm.c:5067 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a -vm.c:5083 vm_run_ex/CASE(ITER_NEXT) slot_f64_value READ b -vm.c:5086 vm_run_ex/CASE(ITER_NEXT) VAL_INT TEST a -vm.c:5100 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5104 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5104 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5443 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5444 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5445 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5479 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5480 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5481 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5545 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:4683 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4693 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4695 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4697 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4719 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4721 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4722 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4724 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4726 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4736 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4738 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4738 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4740 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4752 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4755 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4762 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4765 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4768 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4769 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4825 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4828 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4889 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4890 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4916 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4916 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5022 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5023 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5096 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5100 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5100 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5439 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5440 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5441 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5475 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5476 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5477 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5541 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5542 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5542 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5542 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5546 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5552 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5553 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5557 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5571 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5572 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5573 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5574 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5594 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5547 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5548 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5549 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5553 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5567 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5568 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5569 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5570 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5590 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5616 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5619 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5620 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5623 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5624 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5651 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5654 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5659 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5679 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5680 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5681 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5682 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5829 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5830 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5832 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5839 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5843 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5846 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5847 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5850 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5861 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5864 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6458 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6459 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6460 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6463 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6473 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6474 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6476 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6480 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:5639 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5647 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5650 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5655 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5675 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5676 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5677 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5678 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5808 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5808 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5825 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5826 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5828 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5835 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5839 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5842 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5843 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5846 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5857 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5860 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6454 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6455 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6456 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6459 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6469 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6470 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6472 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6476 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 97e6bc1dd..e9781c705 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -740,7 +740,7 @@ result).** | `vm.c:jit_helper_dot_set` | guarded | an int value skips the immediate store: the slow path pops it through `slot_bridge_unwrap` (D1) | | `vm.c:jit_helper_index_get` | guarded | an int index skips the fast path: the slow path lifts it through `slot_to_value` (D1) | | `vm.c:jit_helper_index_set` | guarded | an int index or value skips the fast path: the slow path pops it through `slot_bridge_unwrap` (D1) | -| `vm.c:jit_helper_iter_next` | unwired | float-first index and snapshot readers; an int takes the existing R1.3 refusal only after the float reader fails; a non-pointer state returns 1 (D1) | +| `vm.c:jit_helper_iter_next` | guarded | state must be a pointer; index and snapshot metadata use the exact checked iterator readers, matching CASE(ITER_NEXT) (R1.3) (D1) | | `vm.c:jit_helper_local_dot_set` | guarded | an int value skips the immediate store: `vm_slot_lift` boxes it (D1) | | `vm.c:jit_helper_local_idx_dot_get` | guarded | as `jit_helper_dot_get` (D3) | | `vm.c:loop_iter_store` | guarded | the loop counter is a float the VM makes; a non-float slot takes the `make_num` path (D1) | @@ -752,6 +752,8 @@ result).** | `vm.c:slot_bridge_unwrap` | smi-arm | an SMI materializes as an owned exact int through `slot_to_value` (R1.3) (D1) | | `vm.c:vm_bit_operand` | smi-arm | an int64 operand is read exactly; float operands keep the #1740 conversion rule (R1.3) (D1) | | `vm.c:vm_number_compare` | smi-arm | int and cross-kind comparisons use exact N2 order, without double rounding (R1.3) (D1) | +| `vm.c:vm_iter_index` | smi-arm | index metadata accepts an exact int in the C-int range, otherwise exhausts without narrowing (R1.3) (D1) | +| `vm.c:vm_iter_limit` | smi-arm | int snapshot metadata clamps the live length; negative snapshots exhaust and oversized positive snapshots keep the live length (R1.3) (D1) | | `vm.c:slot_truthy` | smi-arm | an int is truthy when it is not 0; a reserved tag refuses instead of being dereferenced (D1) | | `vm.c:slot_type_name` | smi-arm | an SMI reached the final `return "num"` by accident. R1.1 adds the explicit SMI arm ("num", (B)) and aborts on a reserved tag (D1 since R1.1) | | `vm.c:vm_borrow_scan` | guarded | compares heap slots with the result pointer; an SMI is not heap (D2) | @@ -778,7 +780,6 @@ result).** | `vm.c:vm_slot_lift` | smi-arm | an SMI is boxed through `slot_to_value`; a reserved tag refuses (R1.3) (D1) | | `vm.c:vm_slot_value_opaque` | guarded | only a pointer can be a fn or builtin; an SMI answers "not opaque", which is right (D2) | | `vm.c:vm_store_local_slot` | guarded | an int skips the in-place float store; the generic swap stores the SMI (D1) | -| `vm.c:vm_run_ex/CASE(ITER_NEXT)` | unwired | float-first index and snapshot readers; an int takes the existing R1.3 refusal only after the float reader fails (D1) | ### 2.6 The accessor API after round 1 (Alt 1R) diff --git a/src/builtins.c b/src/builtins.c index b3b2afd56..368a60e70 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -6037,10 +6037,10 @@ Value* builtin_dispatch(Value *arg) { /* #1665: a numeric fn_arg is a stack view in THIS frame. A builtin * that returns its argument (`num`) would hand our caller a pointer * into a dead frame, so a number goes in as a fresh box we own. */ - if (fn_arg && fn_arg->type == VAL_INT) - eigs_int_unwired("builtin_dispatch argument box", (uint64_t)VAL_I64_RAW(fn_arg)); - if (fn_arg && fn_arg->type == VAL_FLOAT) { - Value *boxed = make_num(eigs_num_arg(fn_arg, __func__)); + if (fn_arg && val_is_number(fn_arg)) { + Value *boxed = fn_arg->type == VAL_INT + ? make_int(VAL_I64_RAW(fn_arg)) + : make_num(eigs_num_arg(fn_arg, __func__)); Value *res = eigs_call_builtin(fn->data.builtin, boxed); if (res == boxed) return boxed; /* our ref transfers */ val_decref(boxed); diff --git a/src/eigenscript.c b/src/eigenscript.c index 7adb43362..30dd95444 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -2685,9 +2685,7 @@ static Value *chan_clone_rec(Value *v, int depth) { v->type != VAL_BOOL && v->type != VAL_STR) { val_incref(v); return v; } switch (v->type) { case VAL_FLOAT: return make_num(VAL_F64_RAW(v)); - /* #1758 R1.2a: a channel gets a fresh int box, which needs make_int - * (R1.3); no int exists before then. */ - case VAL_INT: eigs_int_unwired("chan_clone_rec", (uint64_t)VAL_I64_RAW(v)); + case VAL_INT: return make_int(VAL_I64_RAW(v)); case VAL_NULL: return make_null(); case VAL_BOOL: return make_bool(v->data.boolean); case VAL_STR: return make_str(v->data.str); diff --git a/src/vm.c b/src/vm.c index 596eda68c..65f63a4ed 100644 --- a/src/vm.c +++ b/src/vm.c @@ -915,6 +915,28 @@ static int vm_number_compare(EigsSlot a, EigsSlot b, int *out) { return 0; } +/* Iterator state is normally float metadata made by make_iter_state. Raw + * bytecode may supply ints too. Check the C index range BEFORE conversion. */ +static int vm_iter_index(EigsSlot s, int *out) { + double f; + if (slot_f64_value(s, &f)) { + if (!(f >= INT_MIN && f <= INT_MAX)) return 0; + *out = (int)f; + return 1; + } + int64_t i; + if (!slot_int_value(s, &i) || i < INT_MIN || i > INT_MAX) return 0; + *out = (int)i; + return 1; +} +static int vm_iter_limit(EigsSlot s, int len) { + int i; + if (vm_iter_index(s, &i)) return i < len ? (i < 0 ? 0 : i) : len; + int64_t big; + if (slot_int_value(s, &big) && big < 0) return 0; + return len; +} + static inline uint16_t read_u16(uint8_t *ip) { return ip[0] | (ip[1] << 8); } @@ -1824,14 +1846,8 @@ int jit_helper_iter_next(void) { return 1; /* Iterables are reference values; a numeric facade cannot be iterable. */ Value *iterable = list_get_ref(state, 0); - double idx_num; - EigsSlot idx_slot = list_slot(state, 1); - if (!slot_f64_value(idx_slot, &idx_num)) { - if (slot_type(idx_slot) == VAL_INT) - eigs_int_unwired("jit_helper_iter_next index", 0); - return 1; - } - int idx = (int)idx_num; + int idx; + if (!vm_iter_index(list_slot(state, 1), &idx)) return 1; if (!iterable) return 1; int len = 0; if (iterable->type == VAL_LIST) len = iterable->data.list.count; @@ -1840,18 +1856,9 @@ int jit_helper_iter_next(void) { /* #491: cap by the entry-time snapshot (items[2]) — see make_iter_state. * Mirrors CASE(ITER_NEXT). */ if (state->data.list.count >= 3) { - EigsSlot snap_slot = list_slot(state, 2); - double snap_num; - if (slot_f64_value(snap_slot, &snap_num)) { - int snap = (int)snap_num; - if (snap < len) len = snap; - } else if (slot_type(snap_slot) == VAL_INT) { - int64_t i = 0; - slot_int_value(snap_slot, &i); - eigs_int_unwired("jit_helper_iter_next snapshot", (uint64_t)i); - } - } - if (idx >= len) return 1; + len = vm_iter_limit(list_slot(state, 2), len); + } + if ((unsigned)idx >= (unsigned)len) return 1; EigsSlot elem; if (iterable->type == VAL_BUFFER) { elem = slot_from_f64(num_guard(buffer_read_num(iterable, idx))); @@ -5061,16 +5068,12 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, ip += exit_offset; DISPATCH(); } - double idx_num; - EigsSlot idx_slot = list_slot(state, 1); - if (!slot_f64_value(idx_slot, &idx_num)) { - if (slot_type(idx_slot) == VAL_INT) - eigs_int_unwired("ITER_NEXT index", 0); + int idx; + if (!vm_iter_index(list_slot(state, 1), &idx)) { ip += exit_offset; DISPATCH(); } Value *iterable = list_get_ref(state, 0); - int idx = (int)idx_num; int len = 0; if (iterable && iterable->type == VAL_LIST) len = iterable->data.list.count; else if (iterable && iterable->type == VAL_BUFFER) len = iterable->data.buffer.count; @@ -5078,14 +5081,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * appends can't extend the loop; min() with the live length keeps a * remove from reading past the end. See make_iter_state. */ if (state->data.list.count >= 3) { - EigsSlot snap_slot = list_slot(state, 2); - double snap_num; - if (slot_f64_value(snap_slot, &snap_num)) { - int snap = (int)snap_num; - if (snap < len) len = snap; - } else if (slot_type(snap_slot) == VAL_INT) { - eigs_int_unwired("ITER_NEXT snapshot", 0); - } + len = vm_iter_limit(list_slot(state, 2), len); } /* Unsigned compare bounds BOTH ends in one branch: a negative index diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index a9e7f36c5..31904abcb 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -24,6 +24,8 @@ * D the VM's operator arms: a host builtin puts an SMI into a list and a * program applies each operator to it. Every converted arm must compute its exact value, * inside a `try` too; the same program with a double is the control. + * E ITER_NEXT index and snapshot metadata in both executors, with float, + * SMI and boxed-int metadata, including range and malformed controls. * * Output, every line in one grammar (tests/phase2/slot_layer.sh refuses any * other line): `ENTRY : values= ok|FAIL` per Part A @@ -200,6 +202,14 @@ static int r_vm_bit_operand(int64_t v) { static int r_vm_number_compare(int64_t v) { int got = 7; return !vm_number_compare(smi(v), smi(v), &got) || got != 0; } +static int r_vm_iter_index(int64_t v) { + int got = 7, valid = v >= INT_MIN && v <= INT_MAX; + return vm_iter_index(smi(v), &got) != valid || got != (valid ? (int)v : 7); +} +static int r_vm_iter_limit(int64_t v) { + int want = v < 0 ? 0 : v < 10 ? (int)v : 10; + return vm_iter_limit(smi(v), 10) != want; +} static void a_obs_slot_observable(EigsSlot s) { (void)obs_slot_observable(s); } static void a_eigs_slot_ref(EigsSlot s) { (void)eigs_slot_ref(s); } static void a_slot_as_ptr(EigsSlot s) { (void)slot_as_ptr(s); } @@ -216,6 +226,8 @@ typedef struct { static const Entry ENTRIES[] = { {"vm.c:vm_bit_operand", r_vm_bit_operand, 0, 0, "exact int64 operand"}, {"vm.c:vm_number_compare", r_vm_number_compare, 0, 0, "exact numeric comparison"}, + {"vm.c:vm_iter_index", r_vm_iter_index, 0, 0, "checked C int metadata"}, + {"vm.c:vm_iter_limit", r_vm_iter_limit, 0, 0, "bounded snapshot"}, {"container.h:eigs_slot_elem_num", r_eigs_slot_elem_num, 0, 0, "bridge: the int's double"}, {"container.h:eigs_slot_num", r_eigs_slot_num, 0, 0, "bridge: the int's double"}, {"container.h:eigs_slot_opt_num", r_eigs_slot_opt_num, 0, 0, "bridge: present, the int's double"}, @@ -357,6 +369,8 @@ CELL(observable) { snprintf(b, n, "i:%d", obs_slot_observable(s)); } CELL(unwrap) { Value *v = slot_bridge_unwrap(s); r_v(b, n, v); if (!slot_is_ptr(s)) val_decref(v); } CELL(vm_bit_operand) { int64_t i = 7; int r = vm_bit_operand(s, &i); snprintf(b, n, "o:%d i:%lld", r, (long long)i); } CELL(vm_number_compare) { int cmp = 7; int r = vm_number_compare(s, smi(1), &cmp); snprintf(b, n, "o:%d c:%d", r, cmp); } +CELL(vm_iter_index) { int i = 7; int r = vm_iter_index(s, &i); snprintf(b, n, "o:%d i:%d", r, i); } +CELL(vm_iter_limit) { snprintf(b, n, "i:%d", vm_iter_limit(s, 10)); } CELL(slot_ref) { r_v(b, n, eigs_slot_ref(s)); } CELL(as_ptr) { r_v(b, n, slot_as_ptr(s)); } CELL(obs_value) { r_v(b, n, obs_slot_value(s)); } @@ -567,9 +581,18 @@ EXP(vm_number_compare) { else if (kclass(k) == C_F64) snprintf(b, n, "o:1 c:%d", k == K_NZ ? -1 : 1); else snprintf(b, n, "o:0 c:7"); } +EXP(vm_iter_index) { + if (k == K_SMI) snprintf(b, n, "o:1 i:5"); + else if (k == K_NZ) snprintf(b, n, "o:1 i:0"); + else if (k == K_F) snprintf(b, n, "o:1 i:1"); + else snprintf(b, n, "o:0 i:7"); +} +EXP(vm_iter_limit) { snprintf(b, n, "i:%d", k == K_SMI ? 5 : k == K_NZ ? 0 : k == K_F ? 1 : 10); } static const MatrixEntry MATRIX[] = { {"vm.c:vm_bit_operand", c_vm_bit_operand, e_vm_bit_operand}, {"vm.c:vm_number_compare", c_vm_number_compare, e_vm_number_compare}, + {"vm.c:vm_iter_index", c_vm_iter_index, e_vm_iter_index}, + {"vm.c:vm_iter_limit", c_vm_iter_limit, e_vm_iter_limit}, {"container.h:eigs_slot_elem_num", c_elem_num, e_elem_num}, {"container.h:eigs_slot_num", c_num, e_num}, {"container.h:eigs_slot_opt_num", c_opt_num, e_opt_num}, @@ -782,6 +805,110 @@ static int part_d(void) { return rows; } +/* ---- Part E: the four ITER_NEXT metadata sites (#1827) ------------------ */ +/* Construct a raw state because ordinary for loops deliberately keep float + * metadata until the builtin/iterator bridge round. Exercise the interpreter + * through an assembled chunk, and the actual JIT helper directly. */ +typedef struct { const char *name; int field, kind; int64_t value; int yields; } IterCase; +static const IterCase ITER_CASES[] = { + {"float_control", 1, 0, 0, 1}, + {"smi_index", 1, 1, 0, 1}, + {"boxed_index", 1, 2, 0, 1}, + {"smi_snapshot", 2, 1, 1, 1}, + {"boxed_snapshot", 2, 2, 1, 1}, + {"large_index", 1, 2, INT64_MAX, 0}, + {"negative_index", 1, 2, INT64_MIN, 0}, + {"large_snapshot", 2, 2, INT64_MAX, 1}, + {"negative_snapshot", 2, 2, INT64_MIN, 0}, + {"smi_negative_snapshot", 2, 1, -1, 0}, + {"malformed_index", 1, 3, 0, 0}, + {"malformed_snapshot", 2, 3, 0, 1}, + {"malformed_iterable", 0, 2, 42, 0}, +}; +#define N_ITER_CASES ((int)(sizeof ITER_CASES / sizeof ITER_CASES[0])) +static const IterCase *g_iter_case; +static int g_iter_helper; +static void c_iter(EigsSlot unused, char *b, size_t n) { + (void)unused; + const IterCase *t = g_iter_case; + Value *state = make_list(0), *items = make_list(0); + list_append_slot(items, slot_from_f64(42.0)); + list_append_slot(state, slot_from_heap(items)); + val_decref(items); + list_append_slot(state, slot_from_f64(0.0)); + list_append_slot(state, slot_from_f64(1.0)); + EigsSlot replacement = t->kind == 0 ? slot_from_f64((double)t->value) : + t->kind == 1 ? smi(t->value) : + t->kind == 2 ? slot_from_heap(make_int(t->value)) : + slot_from_heap(make_str("bad")); + /* Raw states can hold non-canonical small boxes. Bypass writers here + * deliberately, and prove which representation reaches each reader. */ + EigsSlot old_metadata = state->data.list.items[t->field]; + state->data.list.items[t->field] = replacement; + slot_decref(old_metadata); + EigsSlot stored_metadata = list_slot(state, t->field); + int representation_ok = t->kind == 0 ? slot_is_f64(stored_metadata) : + t->kind == 1 ? slot_is_smi(stored_metadata) : + t->kind == 2 ? (slot_is_heap(stored_metadata) && + slot_as_ptr(stored_metadata)->type == VAL_INT && + VAL_I64_RAW(slot_as_ptr(stored_metadata)) == t->value) : + (slot_is_heap(stored_metadata) && + slot_as_ptr(stored_metadata)->type == VAL_STR); + if (!representation_ok) { + snprintf(b, n, "wrong-metadata-representation"); + val_decref(state); + return; + } + Value *result; + if (g_iter_helper) { + vm_init(); /* direct helper calls need the VM allocated, as vm_execute does */ + val_incref(state); + vm_push(state); + int rc = jit_helper_iter_next(); + result = rc == 0 ? vm_pop() : make_null(); + Value *popped_state = vm_pop(); + val_decref(popped_state); + } else { + EigsChunk *chunk = chunk_new(""); + int ci = chunk_add_constant(chunk, state); + chunk_emit(chunk, OP_CONST, 1); + chunk_emit_u16(chunk, (uint16_t)ci, 1); + chunk_emit(chunk, OP_ITER_NEXT, 1); + chunk_emit_u16(chunk, 1, 1); /* exhausted: skip the element RETURN */ + chunk_emit(chunk, OP_RETURN, 1); + chunk_emit(chunk, OP_NULL, 1); + chunk_emit(chunk, OP_RETURN, 1); + result = vm_execute(chunk, g_global_env); + chunk_free(chunk); + } + if (result && result->type == VAL_FLOAT && VAL_F64_RAW(result) == 42.0) { + double next = -1; + int float_next = slot_f64_value(list_slot(state, 1), &next); + snprintf(b, n, "yield:42 float_next:%d", float_next && next == 1.0); + } else if (result && result->type == VAL_NULL) snprintf(b, n, "exhausted"); + else snprintf(b, n, "unexpected"); + val_decref(result); + val_decref(state); +} +static int part_e(void) { + int rows = 0; + for (int i = 0; i < N_ITER_CASES; i++) { + g_iter_case = &ITER_CASES[i]; + for (g_iter_helper = 0; g_iter_helper < 2; g_iter_helper++) { + char got[512]; + run_cell(c_iter, slot_null(), got, sizeof got, NULL, 0); + const char *want = g_iter_case->yields ? "yield:42 float_next:1" : "exhausted"; + int bad = strcmp(got, want) != 0; + if (bad) FAILF("ITER_NEXT %s %s: got %s, want %s", + g_iter_helper ? "jit_helper" : "interpreter", g_iter_case->name, got, want); + printf("ARM iter_%s_%s %s\n", g_iter_helper ? "jit" : "vm", + g_iter_case->name, bad ? "FAIL" : "ok"); + rows++; + } + } + return rows; +} + int main(void) { EigsState *st = eigs_open(); if (!st) { printf("slot-layer-test: FAIL eigs_open\n"); return 1; } @@ -804,13 +931,14 @@ int main(void) { int matrix_cells = part_b(); int from_int_rows = part_c(); int arm_rows = part_d(); + int iter_rows = part_e(); printf("slot-layer-test: examined=%d smi_values=%d calls=%d matrix=%d kinds=%d matrix_cells=%d " - "from_int_rows=%d arm_rows=%d failures=%d\n", N_ENTRIES, N_SMI, calls, N_MATRIX, N_KINDS, - matrix_cells, from_int_rows, arm_rows, failures); + "from_int_rows=%d arm_rows=%d iter_rows=%d failures=%d\n", N_ENTRIES, N_SMI, calls, N_MATRIX, N_KINDS, + matrix_cells, from_int_rows, arm_rows, iter_rows, failures); val_decref(g_str); eigs_close(st); int ok = failures == 0 && N_ENTRIES > 0 && calls > 0 && N_MATRIX == N_ENTRIES && - matrix_cells == N_MATRIX * N_KINDS && from_int_rows > 0 && arm_rows == 2 * N_ARMS; + matrix_cells == N_MATRIX * N_KINDS && from_int_rows > 0 && arm_rows == 2 * N_ARMS && iter_rows == 2 * N_ITER_CASES; printf("slot-layer-test: %s\n", ok ? "PASS" : "FAIL"); return ok ? 0 : 1; } diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 39d7b9b55..59e18650a 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -6,7 +6,7 @@ # Ordinary builtin argument reads use eigs_num_arg / eigs_list_num / # eigs_opt_num / eigs_elem_num, which raise on a bool. The explicitly reviewed # exceptions below preserve a numeric kind or exact int text (JSON and sorting), -# name an unwired int refusal (dispatch), or write a typed sentinel (matmul). +# box a typed dispatch argument, or write a typed sentinel (matmul). # A double bridge would lose int digits in the exact readers; each raw payload # read is behind its own kind test. Exceptions still need exact per-function # token counts and reasons; they do not exempt ordinary argument coercion. @@ -26,7 +26,7 @@ container.h|list_get_return|1|builtin-return read boxes an immediate only after chunk.c|chunk_disassemble|2|debug disassembly prints a constant behind its own type == VAL_FLOAT test chunk.c|const_equal|4|constant-pool dedup compares two constants after testing both are VAL_FLOAT chunk.c|const_hash_value|2|constant-pool hash of a constant inside its type == VAL_FLOAT branch -eigenscript.c|chan_clone_rec|2|channel deep-copy, switch case VAL_FLOAT; case VAL_INT names the int it refuses (unwired, R1.3) +eigenscript.c|chan_clone_rec|2|channel deep-copy, switch cases VAL_FLOAT and VAL_INT preserve the payload and numeric kind eigenscript.c|compute_entropy_impl|2|observer entropy, switch case VAL_FLOAT, and case VAL_INT (an int's entropy is its double's, design 7) eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_f64 eigenscript.c|eigs_num_arg_slow|2|checked reader slow path: reads only after type == VAL_FLOAT, or VAL_INT (the bridge converts an int, design 2.7) @@ -82,7 +82,7 @@ vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 builtins.c|builtin_json_build|1|VAL_INT text is exact digits; float text retains the bridge (#1758 R1.2d) builtins.c|builtin_json_path|1|VAL_INT scalar text is exact digits before releasing root (#1758 R1.2d) -builtins.c|builtin_dispatch|1|VAL_INT argument boxing refuses until make_int lands in R1.3 (#1758) +builtins.c|builtin_dispatch|1|typed dispatch argument boxing uses make_int after the VAL_INT kind test (#1758 R1.3) builtins.c|builtin_sort_by|1|numeric key kind retained for exact mixed sorting (#1758 N2) builtins.c|sort_cmp_num|6|validated numeric slots viewed through slot_view; int comparisons are exact (#1758 N2) value_slot.h|slot_int_value|1|boxed VAL_INT payload after its type test (#1758 R1.2i) From 3dd9f2b25526d98874c90bf109c9e1b76fe5cfe9 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:31:44 -0500 Subject: [PATCH 059/188] phase2 R1.3c: the observer routes a boxed int into the numeric channel (#1758) obs_slot_num already read an SMI as its double (R1.1). A heap VAL_INT box (an int outside the SMI range) now takes the same numeric channel instead of falling to the opaque path, so `where`, `why` and `how` see every int as its double until round 3's int readouts (design 7, O map). Precision rounds above 2^53 on that channel, as the allowlist row now says. The observer oracle follows the literal kinds the N1 commit introduces: - the required floor keeps measuring the binary64 observer: its scaffolding (counters, the OPS table, run_row's argument) and every recurrence operand are spelled as floats, so the native JIT/OSR witnesses it had on the pinned pre-int anchor still hold; - the int64 capability rows keep exact int literals. Until the R5 int fast paths, their JIT-enabled arms may report an interpreted int-opcode refusal instead of a native body, and only with evidence: an INT_* opcode before x's OBSERVE_ASSIGN, no function thunk, and no OSR thunk or one whose recorded prefix exit is exactly that opcode. Their readings stay scored. - the INT64_MIN literal control runs the spliced program directly. docs/OBSERVER.md states the rule. No int value exists before the N1 commit, so this arm and the int64 rows are inert here (the capability probe reads `num_type of 9223372036854775806` as "float" until then). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/OBSERVER.md | 9 +- docs/design/phase2-inventory.txt | 478 ++++++++++++++++--------------- src/vm.c | 4 + tools/num_read_allowlist.txt | 2 +- tools/observer_oracle/plants.py | 13 +- tools/observer_oracle/score.py | 67 +++-- 6 files changed, 308 insertions(+), 265 deletions(-) diff --git a/docs/OBSERVER.md b/docs/OBSERVER.md index ef8bb1e95..a7794705e 100644 --- a/docs/OBSERVER.md +++ b/docs/OBSERVER.md @@ -243,8 +243,13 @@ lies past the loop's back-edge and `bked` is 0, so every iteration ran natively, tier only the OSR thunk's last exit is recorded, so the witness covers the last iteration's body: OSR compiles at the first back-edge, so `x_0` is always assigned interpreted, and an earlier iteration that bailed goes unwitnessed until #1768. A run whose body stops computing `x` on an inf, NaN or clamped value (the JIT's designed bail) is reported as interpreted and -passes, so its readings grade the interpreter's observer for those iterations; any other run that does not witness fails as -vacuous. The predicate READS never run natively: the JIT compiles neither `PREDICATE_SLOT` nor `PREDICATE_NAME`. +passes, so its readings grade the interpreter's observer for those iterations. The non-capability floor uses float +scaffolding and float recurrence operands, preserving its binary64 inputs and native witnesses after integer literals +arrive. Exact int64 capability rows retain int literals; until the R5 int fast paths, their JIT-enabled arms may instead +report an interpreted int-opcode refusal, requiring `INT_*` before observing `x`, no function thunk, and either no OSR +thunk or its recorded prefix exit exactly at that int opcode. Their readings remain scored in every arm. Every other run that does not witness fails as vacuous, and both +native tiers must still witness a body. The predicate READS never run natively: the JIT compiles neither +`PREDICATE_SLOT` nor `PREDICATE_NAME`. A row's capability is derived from its values (IEEE inf/-inf/NaN; an int a double cannot hold exactly). Such a row runs only on a binary whose probe shows the capability (one probe checks that `1e308 * 10` overflows to inf AND that inf × 0 is diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 662f107df..5579eec4f 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2012 classified=2012 unclassified=0 +examined=2014 classified=2014 unclassified=0 files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category @@ -12,7 +12,7 @@ files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 (f) equality, ordering and hashing 53 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=23 (g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 (h) JSON, store and db encoders 82 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=6 READ=24 TEST=21 -(i) observer numeric paths 107 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=23 READ=7 TEST=33 +(i) observer numeric paths 109 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=24 READ=7 TEST=34 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token @@ -20,7 +20,7 @@ make_num 365 val_is_number 185 eigs_num_arg 172 VAL_FLOAT 150 -VAL_INT 144 +VAL_INT 145 eigs_list_num 130 SLOT_F64_RAW 83 num_guard 62 @@ -29,7 +29,7 @@ AST_NUM 52 slot_is_f64 50 eigs_value_as_num 48 eigs_slot_num 47 -VAL_I64_RAW 44 +VAL_I64_RAW 45 buffer_read_num 37 slot_from_f64 37 slot_is_smi 33 @@ -70,7 +70,7 @@ data.num (AST) 7 ## Per file (category counts) builtins.c 350 a=84 b=104 c=111 e=6 f=13 h=21 i=11 ext_gfx.c 298 a=104 b=124 c=70 -vm.c 293 a=70 b=95 c=66 e=2 f=10 i=50 +vm.c 295 a=70 b=95 c=66 e=2 f=10 i=52 builtins_tensor.c 200 a=55 b=59 c=86 eigenscript.c 123 a=22 b=18 c=15 e=7 f=18 i=43 builtins_buf.c 110 a=34 b=37 c=39 @@ -227,7 +227,7 @@ D1 vm.c:jit_helper_local_dot_set guarded slot_is_f64=1 D1 vm.c:loop_iter_store guarded slot_is_f64=1 D1 vm.c:obs_dump_scope smi-arm slot_as_ptr=3 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=3 slot_is_smi=1 slot_smi_val=1 D1 vm.c:obs_dump_value smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 -D1 vm.c:obs_slot_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 +D1 vm.c:obs_slot_num smi-arm slot_as_ptr=2 slot_is_f64=1 slot_is_heap=1 slot_is_smi=1 slot_smi_val=1 D1 vm.c:obs_slot_observable refuse slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_ptr=1 D1 vm.c:slot_bridge_unwrap smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_null=1 slot_is_smi=1 D1 vm.c:slot_truthy smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 @@ -2307,242 +2307,244 @@ vm.c:1702 obs_slot_num SLOT_F64_RAW RAW i vm.c:1702 obs_slot_num slot_is_f64 TEST i vm.c:1703 obs_slot_num slot_is_smi TEST i vm.c:1703 obs_slot_num slot_smi_val RAW i -vm.c:1864 jit_helper_iter_next buffer_read_num READ b -vm.c:1864 jit_helper_iter_next num_guard GUARD c -vm.c:1864 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1870 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1940 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b -vm.c:1940 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1944 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1947 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1986 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:2000 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:2000 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:2011 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:2012 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:2030 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:2030 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2113 loop_iter_store make_num PRODUCE c -vm.c:2120 loop_iter_store slot_is_f64 TEST a -vm.c:2121 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2126 loop_iter_store make_num PRODUCE c -vm.c:2241 vm_value_index_is_int VAL_INT TEST a -vm.c:2242 vm_value_index_is_int VAL_I64_RAW RAW b -vm.c:2247 vm_value_index_is_int VAL_F64_RAW RAW b -vm.c:2260 jit_helper_index_set slot_is_f64 TEST a -vm.c:2265 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2266 jit_helper_index_set slot_is_f64 TEST a -vm.c:2268 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2270 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2280 jit_helper_index_set slot_is_f64 TEST a -vm.c:2282 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2283 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2285 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2297 jit_helper_index_set val_is_number TEST a -vm.c:2300 jit_helper_index_set eigs_num_arg READ b -vm.c:2307 jit_helper_index_set val_is_number TEST a -vm.c:2310 jit_helper_index_set eigs_num_arg READ b -vm.c:2313 jit_helper_index_set val_is_number TEST a +vm.c:1704 obs_slot_num VAL_INT TEST i +vm.c:1705 obs_slot_num VAL_I64_RAW RAW i +vm.c:1868 jit_helper_iter_next buffer_read_num READ b +vm.c:1868 jit_helper_iter_next num_guard GUARD c +vm.c:1868 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1874 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1944 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b +vm.c:1944 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1948 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1951 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1990 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:2004 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:2004 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:2015 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2016 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2034 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:2034 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2117 loop_iter_store make_num PRODUCE c +vm.c:2124 loop_iter_store slot_is_f64 TEST a +vm.c:2125 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2130 loop_iter_store make_num PRODUCE c +vm.c:2245 vm_value_index_is_int VAL_INT TEST a +vm.c:2246 vm_value_index_is_int VAL_I64_RAW RAW b +vm.c:2251 vm_value_index_is_int VAL_F64_RAW RAW b +vm.c:2264 jit_helper_index_set slot_is_f64 TEST a +vm.c:2269 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2270 jit_helper_index_set slot_is_f64 TEST a +vm.c:2272 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2274 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2284 jit_helper_index_set slot_is_f64 TEST a +vm.c:2286 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2287 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2289 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2301 jit_helper_index_set val_is_number TEST a +vm.c:2304 jit_helper_index_set eigs_num_arg READ b +vm.c:2311 jit_helper_index_set val_is_number TEST a vm.c:2314 jit_helper_index_set eigs_num_arg READ b -vm.c:2333 jit_helper_index_get slot_is_f64 TEST a -vm.c:2335 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2342 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2353 jit_helper_index_get buffer_read_num READ b -vm.c:2355 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2357 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2373 jit_helper_index_get val_is_number TEST a -vm.c:2376 jit_helper_index_get eigs_num_arg READ b -vm.c:2388 jit_helper_index_get val_is_number TEST a -vm.c:2391 jit_helper_index_get eigs_num_arg READ b -vm.c:2400 jit_helper_index_get val_is_number TEST a -vm.c:2403 jit_helper_index_get eigs_num_arg READ b -vm.c:2405 jit_helper_index_get buffer_read_num READ b -vm.c:2405 jit_helper_index_get make_num PRODUCE c -vm.c:2991 vm_take_error_value make_num PRODUCE c -vm.c:3095 slot_type_name slot_is_f64 TEST e -vm.c:3096 slot_type_name slot_is_smi TEST e -vm.c:3336 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a -vm.c:3337 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b -vm.c:3337 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3351 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3356 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3376 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3376 #define NUM_REUSE VAL_FLOAT TEST a -vm.c:3387 #define ARITH_FAST slot_f64_value READ b -vm.c:3387 #define ARITH_FAST slot_f64_value READ b -vm.c:3388 #define ARITH_FAST num_guard GUARD c -vm.c:3393 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3394 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3402 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3403 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3411 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3423 #define INT_ARITH slot_int_value READ b -vm.c:3423 #define INT_ARITH slot_int_value READ b -vm.c:3437 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3437 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3438 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3438 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3438 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3439 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3439 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3440 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3440 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3441 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3442 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3442 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3443 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3443 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3443 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3443 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3493 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3493 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3494 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3494 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3494 #define NUM_BINOP num_guard GUARD c -vm.c:3495 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3495 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3497 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3497 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3498 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3498 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3499 #define NUM_BINOP make_num PRODUCE c -vm.c:3500 #define NUM_BINOP val_is_number TEST a -vm.c:3500 #define NUM_BINOP val_is_number TEST a -vm.c:3501 #define NUM_BINOP eigs_num_arg READ b -vm.c:3501 #define NUM_BINOP eigs_num_arg READ b -vm.c:3502 #define NUM_BINOP num_guard GUARD c -vm.c:3505 #define NUM_BINOP make_num PRODUCE c +vm.c:2317 jit_helper_index_set val_is_number TEST a +vm.c:2318 jit_helper_index_set eigs_num_arg READ b +vm.c:2337 jit_helper_index_get slot_is_f64 TEST a +vm.c:2339 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2346 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2357 jit_helper_index_get buffer_read_num READ b +vm.c:2359 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2361 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2377 jit_helper_index_get val_is_number TEST a +vm.c:2380 jit_helper_index_get eigs_num_arg READ b +vm.c:2392 jit_helper_index_get val_is_number TEST a +vm.c:2395 jit_helper_index_get eigs_num_arg READ b +vm.c:2404 jit_helper_index_get val_is_number TEST a +vm.c:2407 jit_helper_index_get eigs_num_arg READ b +vm.c:2409 jit_helper_index_get buffer_read_num READ b +vm.c:2409 jit_helper_index_get make_num PRODUCE c +vm.c:2995 vm_take_error_value make_num PRODUCE c +vm.c:3099 slot_type_name slot_is_f64 TEST e +vm.c:3100 slot_type_name slot_is_smi TEST e +vm.c:3340 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3341 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3341 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3355 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3360 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3380 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3380 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3391 #define ARITH_FAST slot_f64_value READ b +vm.c:3391 #define ARITH_FAST slot_f64_value READ b +vm.c:3392 #define ARITH_FAST num_guard GUARD c +vm.c:3397 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3398 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3406 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3407 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3415 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3427 #define INT_ARITH slot_int_value READ b +vm.c:3427 #define INT_ARITH slot_int_value READ b +vm.c:3441 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3441 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3442 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3442 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3442 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3443 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3443 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3444 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3444 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3445 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3446 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3446 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3447 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3447 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3447 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3447 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3497 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3497 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3498 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3498 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3498 #define NUM_BINOP num_guard GUARD c +vm.c:3499 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3499 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3501 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3501 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3502 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3502 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3503 #define NUM_BINOP make_num PRODUCE c +vm.c:3504 #define NUM_BINOP val_is_number TEST a +vm.c:3504 #define NUM_BINOP val_is_number TEST a +vm.c:3505 #define NUM_BINOP eigs_num_arg READ b +vm.c:3505 #define NUM_BINOP eigs_num_arg READ b +vm.c:3506 #define NUM_BINOP num_guard GUARD c vm.c:3509 #define NUM_BINOP make_num PRODUCE c -vm.c:3527 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3527 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3528 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3530 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3513 #define NUM_BINOP make_num PRODUCE c +vm.c:3531 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3531 vm_run_ex/CASE(DIV) val_is_number TEST a vm.c:3532 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3532 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3532 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3535 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3537 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3537 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3538 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3538 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3539 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3544 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3552 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3552 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3552 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3553 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3553 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3553 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3554 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3554 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3555 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3555 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3556 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3558 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3558 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3563 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3591 #define INT_BINOP_R slot_f64_value READ b -vm.c:3595 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3622 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3625 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3625 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3628 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3632 vm_run_ex/CASE(NEG) slot_int_value READ b -vm.c:3637 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c -vm.c:3642 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3664 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3668 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3677 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3677 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3683 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3683 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3703 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3703 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3709 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3709 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3731 #define NUM_CMP slot_f64_value READ f -vm.c:3731 #define NUM_CMP slot_f64_value READ f -vm.c:4674 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4676 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4683 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4693 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4695 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4697 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4719 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4721 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4722 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4724 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4726 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4736 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4738 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4738 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4740 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4752 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4755 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4762 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4765 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4768 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:3534 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3536 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3536 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3536 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3539 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3541 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3541 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3542 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3542 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3543 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3548 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3556 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3556 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3556 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3557 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3557 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3557 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3558 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3558 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3559 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3559 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3560 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3562 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3562 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3567 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3595 #define INT_BINOP_R slot_f64_value READ b +vm.c:3599 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3626 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3629 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3629 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3632 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3636 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3641 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3646 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3668 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3672 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3681 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3681 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3687 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3687 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3707 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3707 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3713 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3713 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3735 #define NUM_CMP slot_f64_value READ f +vm.c:3735 #define NUM_CMP slot_f64_value READ f +vm.c:4678 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4680 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4687 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4697 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4699 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4701 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4723 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4725 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4726 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4728 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4730 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4740 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4742 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4742 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4744 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4756 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4759 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4766 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a vm.c:4769 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4825 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4828 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4889 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4890 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4916 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4916 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5022 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5023 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5096 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5100 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5100 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5439 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5440 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5441 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5475 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5476 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5477 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5541 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5542 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5542 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5542 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:4772 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4773 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4829 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4832 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4893 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4894 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4920 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4920 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5026 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5027 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5100 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5104 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5104 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5443 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5444 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5445 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5479 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5480 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5481 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5545 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i vm.c:5546 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5547 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5548 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5549 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5553 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5567 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5568 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5569 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5570 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5590 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5616 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5619 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5552 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5553 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5557 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5571 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5572 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5573 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5574 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5594 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5620 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i vm.c:5623 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5639 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5647 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5650 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5655 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5675 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5676 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5677 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5678 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5808 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5808 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5825 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5826 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5828 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5835 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5839 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5842 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5843 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5846 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5857 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5860 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6454 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6455 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6456 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6459 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6469 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6470 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6472 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6476 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:5624 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5651 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5654 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5659 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5679 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5680 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5681 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5682 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5829 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5830 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5832 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5839 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5843 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5846 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5847 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5850 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5861 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5864 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6458 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6459 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6460 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6463 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6473 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6474 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6476 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6480 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/src/vm.c b/src/vm.c index 65f63a4ed..f01e59f59 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1701,6 +1701,10 @@ static inline int obs_slot_observable(EigsSlot s) { static inline int obs_slot_num(EigsSlot s, double *out) { if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } + if (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_INT) { + *out = (double)VAL_I64_RAW(slot_as_ptr(s)); + return 1; + } return 0; } static inline Value *obs_slot_value(EigsSlot s) { diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 59e18650a..862d6a36a 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -73,7 +73,7 @@ vm.c|jit_helper_local_dot_set|1|JIT helper: number store after slot_is_f64 vm.c|loop_iter_store|1|writes the loop counter slot after slot_is_f64 vm.c|obs_dump_scope|1|SIGUSR1 observer dump after slot_is_f64 vm.c|obs_dump_value|3|SIGUSR1 observer dump after slot_is_f64 / case VAL_FLOAT / case VAL_INT (exact digits) -vm.c|obs_slot_num|1|observer numeric channel (#1758): reads an immediate after slot_is_f64; an int converts exactly +vm.c|obs_slot_num|2|observer numeric channel (#1758): reads an immediate after slot_is_f64; an int explicitly converts to the observer double channel (precision can round above 2^53) vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 vm.c|slot_truthy|1|truthiness after slot_is_f64 vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_FLOAT (chunk_scan_leaf_accessor) and values behind VAL_FLOAT tests diff --git a/tools/observer_oracle/plants.py b/tools/observer_oracle/plants.py index 8016080c9..78c5cb74e 100644 --- a/tools/observer_oracle/plants.py +++ b/tools/observer_oracle/plants.py @@ -56,7 +56,7 @@ HERE = os.path.dirname(os.path.abspath(__file__)) VENV = os.path.expanduser("~/.local/venvs/oracle/bin/python") -LOOP_HEAD, GUARD = " loop while true:\n", " if m > 0:\n" +LOOP_HEAD, GUARD = " loop while true:\n", " if m > 0.0:\n" INJECT = {"osr_bail": ("osr", "cw is CW_S + CW_S"), "jit_bail_body": ("jit", "cw is CW_S + CW_S"), "num_body": (None, "cw is 1.0 + 2.0")} PROBE_ANSWERS = {"int64_fake": {"9223372036854775806": "true", "num_type": "int"}, @@ -375,6 +375,7 @@ def counts(): # --- the plants ----------------------------------------------------------------- def plants(tag, ieee): + from score import literal F = ["--floor", "{d}/floor.json"] sc = lambda *a: ["python3", "{d}/score.py", *a] cf = ["{venv}", "{d}/certify.py"] @@ -513,13 +514,9 @@ def plants(tag, ieee): ("zero-sign", "the runtime's zero sign lines flipped (it would hold -0.0 where the generator holds 0.0)", lambda d: shim(d, "zero_sign", tag), sc("{d}/obs_zero_sign"), 2, r"runtime=0 \(sign bit True\) generator=0.0 \(values must agree in every bit\).*"), - ("intmin-literal", "CONTROL: an int row x <- x * INT64_MIN + 0 from 0: the spliced INT64_MIN literal" + ("intmin-literal", "CONTROL: x <- x * INT64_MIN + 0 from 0: the spliced INT64_MIN literal" " must keep its parentheses (x_1 = 0, not -1)", - lambda d: (edit_json(d, "corpus.json", keep_rows(extra=extra_row(d, "int_counter", id="intmin_a", - gen={"kind": "affine", "x0": 0, "a": -2 ** 63, "b": 0, "int": True}, n=10, checkpoints=[10], - props={"limit": 0.0, "tends_to": None, "bounded": True, "deterministic": True}))), - certify_in(d), subprocess.run(["python3", f"{d}/derive.py", "--write"], check=True)), - sc(tag), 0, r"observer oracle exit 0: no gate failed.*"), + None, [tag, "-e", "x is 0\nx is x * " + literal(-2 ** 63) + " + 0\nprint of x"], 0, r"^0$"), ("double-scored", "converged scored against MATH and CONVENTION (the reported flag removed)", lambda d: edit_json(d, "corpus.json", lambda c: [x.pop("reported", None) for x in c["definitions"]]), sc(tag), 2, r"two scored definitions.*"), @@ -567,7 +564,7 @@ def plants(tag, ieee): sc(tag), 2, r"\S+: checkpoint \d+ read after \['\d+'\] assignments,\s+not \d+.*"), ("late-read-loop", "loop-form read after one assignment too many", lambda d: (edit_text(d, "score.py", "st = steps(row, xs, c)", "st = steps(row, generate(row[\"gen\"], c + 1), c + 1)"), - edit_text(d, "score.py", 'f"r is run_row of {c + 1}"', 'f"r is run_row of {c + 2}"')), + edit_text(d, "score.py", 'f"r is run_row of {float(c + 1)!r}"', 'f"r is run_row of {float(c + 2)!r}"')), sc(tag), 2, r"\S+: checkpoint \d+ read after \['\d+'\] assignments,\s+not \d+.*"), ("L1", "a label flipped by hand in labels.json", lambda d: edit_text(d, "labels.json", '"geo_decay_0.5@60": {"converged": ["CONVENTION", true', diff --git a/tools/observer_oracle/score.py b/tools/observer_oracle/score.py index 1c351cc66..621ed8803 100644 --- a/tools/observer_oracle/score.py +++ b/tools/observer_oracle/score.py @@ -29,7 +29,12 @@ computing x (from the body's MUL to its OBSERVE_ASSIGN) on an inf, NaN or clamped value (the JIT's designed bail, #1758 N12) is reported as interpreted and passes, so its readings grade the interpreted observer for -the bailed iterations; any other non-native run is VACUOUS (exit 2). No +the bailed iterations. Int64 capability rows retain exact int literals; +until R5 their JIT-enabled runs may explicitly witness an interpreted int +opcode refusal (INT_* before observing x; no function thunk, and OSR +absent or its actual prefix exit at that int opcode). +All floor rows use float scaffolding and float recurrence operands, as on +the pinned pre-int anchor; every other non-native run is VACUOUS (exit 2). No aggregate. Predicate reads always run interpreted: the JIT compiles neither PREDICATE_SLOT nor PREDICATE_NAME. Values are compared with the generator's exactly (a zero's sign through atan2, since the runtime prints -0.0 as 0), @@ -140,8 +145,15 @@ def literal(v): def steps(row, xs, upto): """x_0..x_upto as the runtime assigns them: a literal, or x * a + b.""" if row["gen"]["kind"] in IN_PROGRAM: - return program(row["gen"], upto) - return [("set", v) for v in xs[:upto + 1]] + out = program(row["gen"], upto) + else: + out = [("set", v) for v in xs[:upto + 1]] + # The non-capability floor measures the original binary64 observer. + # Python ints in its corpus JSON are exact mathematical values, not a + # request to change the measured execution tier after the int flip. + if row.get("capability") != "int64": + out = [(s[0], *(float(v) for v in s[1:])) for s in out] + return out def ck_line(at, ys, form): @@ -204,18 +216,19 @@ def emit_loop(row, xs, ys, c, warm): observer state is its own.""" st = steps(row, xs, c) aff = [s for s in st if s[0] == "aff"] - zero = 0 if row["gen"].get("int") else 0.0 - out = table("OPS", [0 if s[0] == "set" else 1 for s in st]) + integer = row.get("capability") == "int64" + zero, one = (0, 1) if integer else (0.0, 1.0) + out = table("OPS", [zero if s[0] == "set" else one for s in st]) out += table("A", [zero if s[0] == "set" else s[1] for s in st] if aff else []) out += table("B", [s[1] if s[0] == "set" else s[2] for s in st]) out += table("YB", ys[:c + 1]) if ys is not None else [] - out += ["OUT is []", "OUTY is []", "define run_row(m) as:", " i is 0", " if m > 0:", - " loop while true:", " if OPS[i] == 0:", " x is B[i]", + out += ["OUT is []", "OUTY is []", "define run_row(m) as:", f" i is {literal(zero)}", " if m > 0.0:", + " loop while true:", f" if OPS[i] == {literal(zero)}:", " x is B[i]", " else:", " x is x * A[i] + B[i]", " append of [OUT, x]"] out += [" y is YB[i]", " append of [OUTY, y]"] if ys is not None else [] - out += [" i is i + 1", " if i >= m:", " break", - " " + ck_line(c, ys, "loop"), " return 0", - f"for k in range of {warm}:", " r is run_row of 0", f"r is run_row of {c + 1}", + out += [f" i is i + {literal(one)}", " if i >= m:", " break", + " " + ck_line(c, ys, "loop"), " return 0.0", + f"for k in range of {warm}:", " r is run_row of 0.0", f"r is run_row of {float(c + 1)!r}", "for k in range of (len of OUT):", ' print of f"V {k} {OUT[k]}"', "for k in range of (len of OUTY):", ' print of f"Y {k} {OUTY[k]}"'] out += [sign_line("V", k, f"OUT[{k}]") for k in range(c + 1) if is_zero(xs[k])] @@ -346,8 +359,8 @@ def grades(rid, tier, form, err, cks): f" {sorted({o[0] for o in ops if o[0].startswith('OBSERVE_ASSIGN')})}") -def witness(tier, rid, err, hot, held, c): - """("native" | "value bail" | "VACUOUS", detail) for the measured call's +def witness(tier, rid, err, hot, held, c, integer=False, int64=False): + """("native" | "value bail" | "int refusal" | "VACUOUS", detail) for the measured call's loop. The thunk's last exit must lie past the loop's back-edge (the body ran to its `break` natively). jit: the function thunk, with bked = 0 (after a bail the rest of the call runs interpreted), so every iteration ran @@ -377,6 +390,25 @@ def witness(tier, rid, err, hot, held, c): stop = f"{ops[at][0]}@{at}" if at in ops else f"the end of run_row ({at})" if at >= 0 else "no thunk" if ok: return "native", f"exits at {stop}, past the back-edge at {jb}" + # R1.3 through R5: exact int capability rows intentionally contain int + # opcodes which both JIT scanners refuse by default. Keep all their + # JIT-enabled verdicts scored, but name the actual interpreted tier. + # A float row or an int opcode after x's assignment cannot claim this + # witness. An OSR prefix may run the float indexing/control before the + # refusal; its recorded exit must be AT the int opcode, before observing + # x. Disabling the JIT globally still reds the native float rows. + head = jb + 3 - int(ops[jb][1]) + observed = min((o for o, (op, _arg) in ops.items() + if o >= head and op.startswith("OBSERVE_ASSIGN")), default=head) + intstops = {o: op for o, (op, _arg) in ops.items() + if head <= o < observed and op in ("INT_ZERO", "INT_ONE", "INT_CONST")} + osr_at = int(hrow[10]) + int(hrow[9]) if hrow[8] == "yes" and int(hrow[10]) == head else -1 + absent = tier == "jit" and hrow[8] in ("?", "no") + function_absent = hrow[2] == "no" if tier == "jit" else hrow[2] in ("?", "no") + refused = (absent and hrow[11] in intstops.values()) or osr_at in intstops + if integer and int64 and intstops and function_absent and refused: + detail = "no OSR thunk" if absent else f"OSR prefix exits at {intstops[osr_at]}@{osr_at}, before x's observe@{observed}" + return "int refusal", f"x observed interpreted: no function thunk; {detail} (R5)" mul = min((o for o, (op, _a) in ops.items() if op == "MUL" and o < jb), default=jb) asg = min((o for o, (op, _a) in ops.items() if op.startswith("OBSERVE_ASSIGN") and o > mul), default=mul) bad = [v for v in held[max(0, k - 1):k + 1] if not math.isfinite(v) or abs(v) >= CLAMP] @@ -441,7 +473,9 @@ def measure(binary, corpus, caps): grades(rid, tier, form, err, cks) res["runs"] += 1 if tier != "interp": - res["wit"][(tier, rid, cks[0])] = witness(tier, rid, err, hot, xs, cks[0]) + res["wit"][(tier, rid, cks[0])] = witness( + tier, rid, err, hot, xs, cks[0], + integer=row.get("capability") == "int64", int64=caps["int64"]) for at in cks: for p in PREDS: res["read"][(tier, form, rid, at, p)] = got[at][p] @@ -595,7 +629,8 @@ def report(v, res, corpus, numbers, caps, probes, labels, reported, expect): print(f" {'EXPECTED ' if cap in expect else 'WARNING: '}{line}ABSENT, {n} row(s) SKIPPED") print(f"PATHS, checked in each of the {res['runs']} programs' EIGS_DUMP_BC listing: " + "; ".join(f"the {form} form observes x through {a} and reads it through {r}" for form, (a, r) in GRADES.items())) - print("\nTIER WITNESS, per run (n native, v interpreted: a value bail on a non-finite or clamped value, V VACUOUS;" + print("\nTIER WITNESS, per run (n native, v interpreted: a value bail on a non-finite or clamped value," + " i interpreted int opcode refusal until R5, V VACUOUS;" " jit: every iteration, x_0 included; osr: the last iteration only, #1768):") for row in corpus["rows"]: if row["id"] in res["held"]: @@ -605,10 +640,10 @@ def report(v, res, corpus, numbers, caps, probes, labels, reported, expect): for t in ("jit", "osr"): w = {k[1:]: x for k, x in res["wit"].items() if k[0] == t} print(f" {t}: {sum(1 for x in w.values() if x[0] == 'native')} of {len(w)} runs witness a native body;" - f" minimum: every run that is not a value bail, and at least one") + f" minimum: every run except a value bail or witnessed int opcode refusal, and at least one") for (rid, c), (status, detail) in w.items(): if status != "native": - print(f" {status.upper() if status == 'VACUOUS' else 'interpreted (value bail)'} {t}" + print(f" {status.upper() if status == 'VACUOUS' else 'interpreted (' + status + ')'} {t}" f" {rid}@{c}: {detail}") print(" predicate reads run interpreted in every tier: the JIT compiles neither PREDICATE_SLOT nor PREDICATE_NAME") print("\nSCORED VERDICTS, one question per predicate: TP FP FN TN right/total") From 4ee4885188138c8a0f1ad2c3f2fb04d2494e22ef Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:52:01 -0500 Subject: [PATCH 060/188] phase2 R1.3d: N1 int literals with tape v7, the first int values (#1758) N1, with its token changes in this commit (design 2.7): - the lexer produces an int for a decimal literal within int64 (parsed exactly, never through a double) and for hex (wrapping modulo 2^64); `3.0`, `1e3` and a decimal past int64 stay floats; - the token's `num_val` and the AST payload `num` become `EigsNum number` (AST_BOOL now has its own `boolean`), so every payload site stopped compiling here and was converted; - OP_INT_ZERO, OP_INT_ONE and OP_INT_CONST are appended (97, 98, 99; pinned in tests/test_opcode_abi.c, no ABI bump): dispatch table and interpreter CASEs, op_name, the verifier (an INT_CONST operand must be a VAL_INT constant), both stack-effect tables and the disassembler. The JIT and leaf scanners refuse them by their default arms. OP_NUM_ZERO/ONE/CONST keep their float meaning in all three executors (vm_run_bytecode rows pin both kinds). Tape v7 lands in this same commit (design 8). After it, a v6 writer would print `3` for both kinds and replay would turn ints into floats; landed earlier, v7 would spell every integral literal `2.0` for one commit, and test_trace_mt.sh's exact `A 0 q=2` record would go red until N1. - floats always carry a point or exponent (`3.0`, `-0.0`, %.17g digits); - ints are exact signed digits, parsed back without a double (INT64_MIN included); an out-of-range digit token is malformed; - TRACE_FORMAT_VERSION 7; a v6 tape is refused by the version check. eigs_int_unwired is deleted with its last callers, the tape writers. The EIGS_SMI_TRAP source trap is retired (the smi-trap target keeps its spelling and checked slots); the row checker's calibration drops the two dynamic no-SMI plants (P4, B2), so its self-test pin is now 49 cases. The slot test gains the write_slot digits row and the N3 overflow row (Part D, `9223372036854775807 + xs[0]` raises `value`); phase2_plants.sh replaces the arm-refusal plant, whose anchor is gone, with an overflow that wraps. Test expectations that move because ints now exist, each by the decision it follows: - JIT/OSR/leaf fixtures and the doubling-loop fixtures spell float literals, keeping their native coverage and runaway semantics (int opcodes interpret until R5; int overflow raises under (A)); - C tests whose `return 42`/`7`/`8` now return exact ints expect VAL_INT; - tape tests expect `V 7`, v7 in messages and `5.0` for integral floats; - `~INT64_MIN` stays a float until N8 (R1.5), so its expectation is a float; - SPEC's executed example: 9007199254740992 + 1 is exact, and 9007199254740993 == 9007199254740992 is false (N2); - jit_env_flags_float.eigs replaces bench_idxset.eigs as the compile probe in test_env_flags.sh and jit_diff's self-check (its int loops interpret now); - the SIGUSR1 dump test waits for 5,000 post-arm assignments before its second signal (the interpreted int loop is slower under ASan). Checks at this commit: release build 0 warnings; inventory fresh; num-read 189 tokens; slot test 37 classifiers, 444 cells, 34 arm rows, 26 iter rows; static precheck 18/18; jit-smoke; test_replay.sh 35/35, test_trace_mt.sh 21/21, trace context 53/53. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 17 +- docs/SPEC.md | 6 +- docs/design/phase2-inventory.txt | 731 +++++++++++----------- docs/design/phase2-numbers.md | 4 +- src/builtins_host.c | 14 +- src/chunk.c | 12 +- src/compiler.c | 58 +- src/eigenscript.c | 8 +- src/eigenscript.h | 23 +- src/lexer.c | 123 ++-- src/parser.c | 4 +- src/trace.c | 78 ++- src/trace.h | 2 +- src/value_slot.h | 31 +- src/vm.c | 19 + src/vm.h | 5 + tests/jit_env_flags_float.eigs | 8 + tests/line_after_callback_halt.eigs | 14 +- tests/line_after_callback_tape.eigs | 12 +- tests/line_after_return_fn.eigs | 12 +- tests/line_after_return_module.eigs | 10 +- tests/line_after_return_null.eigs | 12 +- tests/phase2/calib/cal.osr-fill-plant.out | 2 +- tests/phase2/calib/cal.osr-fill.out | 2 +- tests/phase2/slot_layer.c | 26 +- tests/roads/native_alternate.eigs | 18 +- tests/roads/native_catch.eigs | 16 +- tests/roads/native_inline.eigs | 14 +- tests/roads/native_late.eigs | 18 +- tests/roads/native_match.eigs | 18 +- tests/roads/native_outer.eigs | 20 +- tests/run_all_tests.sh | 2 +- tests/sections/0f5-trace-context.sh | 2 +- tests/sections/0fb-bool-type.sh | 8 +- tests/strict_shape_descriptor.c | 2 +- tests/test_bitwise.eigs | 6 +- tests/test_env_flags.sh | 2 +- tests/test_error_line_fallback.c | 4 +- tests/test_halting_descent.eigs | 6 +- tests/test_jit_andor_leak.eigs | 14 +- tests/test_jit_cycle_root.eigs | 34 +- tests/test_jit_hot_osr.eigs | 8 +- tests/test_jit_paths.eigs | 431 +++++++------ tests/test_jit_temporal_osr.eigs | 14 +- tests/test_loop_cap_772.eigs | 11 +- tests/test_loop_exit.eigs | 4 +- tests/test_opcode_abi.c | 4 + tests/test_osr_observe_assign.eigs | 20 +- tests/test_pool_poison.c | 3 +- tests/test_replay.sh | 6 +- tests/test_sandbox_work_budget.c | 10 +- tests/test_sigusr1_dump.sh | 36 +- tests/test_temporal_param.eigs | 32 +- tests/test_trace_context.c | 56 +- tests/test_trace_context.sh | 4 +- tests/test_trace_history_boundary.c | 10 +- tests/test_trace_mt.sh | 2 +- tests/test_tsan.sh | 2 +- tests/test_vm_run_bytecode.eigs | 14 + tools/jit_diff.sh | 2 +- tools/num_read_allowlist.txt | 6 +- tools/phase2_check.py | 41 +- tools/phase2_inventory.py | 10 +- tools/phase2_plants.sh | 27 +- tools/selftests.txt | 2 +- 65 files changed, 1181 insertions(+), 991 deletions(-) create mode 100644 tests/jit_env_flags_float.eigs diff --git a/Makefile b/Makefile index bbf13c0a3..e7a7c3305 100644 --- a/Makefile +++ b/Makefile @@ -183,17 +183,12 @@ SRC_V_jit-checked := $(HOSTED_SOURCES) FLAGS_jit-checked := $(CFLAGS) $(DEFS_OFF) -DEIGENSCRIPT_EXT_GFX=1 -DEIGS_JIT_CHECKED $(VERDEF) LIBS_jit-checked := $(LDFLAGS) -ldl -# #1758 R1.1: the dynamic half of the int-source check. Every slot classifier -# aborts when it reads an SMI and slot_from_int aborts on any call -# (value_slot.h EIGS_SMI_TRAP); slot_as_ptr checks its tag too. Until R1.3 no -# program may make an int, so this build must run the corpus exactly as -# release does: tools/phase2_check.sh --through R1.1 --smi-trap . -# -Wno-maybe-uninitialized: the trap's noreturn refusal inside every slot -# predicate defeats GCC's flow analysis in vm_run_ex's four compare arms -# (false positives on _ad, read only after both reads succeeded). Release -# compiles the same source with the warning on and has none (#1775). +# #1758: compatibility target for the pre-R1.3 int-source gate. R1.3 retires +# EIGS_SMI_TRAP now that integer literals are producers; slot_as_ptr still +# checks tags through EIGS_SLOT_CHECKED. Historical R1.1/R1.2 calibrations +# build their pinned pre-flip source rather than treating this as a trap. SRC_V_smi-trap := $(HOSTED_SOURCES) -FLAGS_smi-trap := $(CFLAGS) $(DEFS_OFF) -DEIGENSCRIPT_EXT_GFX=1 -DEIGS_SMI_TRAP -DEIGS_SLOT_CHECKED -Wno-maybe-uninitialized $(VERDEF) +FLAGS_smi-trap := $(CFLAGS) $(DEFS_OFF) -DEIGENSCRIPT_EXT_GFX=1 -DEIGS_SMI_TRAP -DEIGS_SLOT_CHECKED $(VERDEF) LIBS_smi-trap := $(LDFLAGS) -ldl VARIANTS := release server server-db zlib asan asan-server tsan tsan-server valgrind poison pool-off asan-pool-off pool-off-num pool-off-callenv jit-checked smi-trap @@ -739,7 +734,7 @@ jit-checked: build/jit-checked/eigenscript # tools/phase2_check.sh --through R1.1 --smi-trap /src/eigenscript ... smi-trap: build/smi-trap/eigenscript $(call RELINK,smi-trap) - @echo "EigenScript $(VERSION) (smi-trap: an int before #1758 R1.3 aborts) built. Binary: $(BINARY)" + @echo "EigenScript $(VERSION) (smi-trap compatibility: checked slots; source trap retired in R1.3) built. Binary: $(BINARY)" # Profile-guided optimization. Builds an instrumented binary, runs the diff --git a/docs/SPEC.md b/docs/SPEC.md index 9833ef7d8..021316599 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -344,15 +344,15 @@ consequences are contracts you can rely on: seam for checksums, hashing, and byte protocols (see docs/BUILTINS.md). ```eigenscript -print of (9007199254740992 + 1) # +1 is invisible past 2^53 +print of (9007199254740992 + 1) # exact int64 addition print of (9007199254740993 == 9007199254740992) print of (1e308 * 10) # saturates, never Infinity print of (bit_and of [0xFFFFFFFF, 0xFF]) # int64 bitwise print of (bit_shl of [1, 40]) # exact past 2^32 ``` ```output -9007199254740992 -true +9007199254740993 +false 1e+308 255 1099511627776 diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 5579eec4f..2e4d9b9aa 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,16 +1,16 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2014 classified=2014 unclassified=0 +examined=2037 classified=2037 unclassified=0 files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 501 CASE=60 DATA=4 TEST=434 YIELD=3 -(b) payload reads 553 RAW=111 READ=442 -(c) producers 473 GUARD=73 PARSE=3 PRODUCE=371 TAGSET=5 WRITE=21 +(a) type tests 502 CASE=60 DATA=4 TEST=435 YIELD=3 +(b) payload reads 572 RAW=130 READ=442 +(c) producers 475 GUARD=73 PARSE=3 PRODUCE=374 TAGSET=5 WRITE=20 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 20 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=7 (f) equality, ordering and hashing 53 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=23 -(g) tape encode and decode 28 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=5 TEST=2 +(g) tape encode and decode 29 CASE=4 DATA=5 PARSE=7 PRODUCE=5 RAW=6 TEST=2 (h) JSON, store and db encoders 82 CASE=4 FORMAT=3 PARSE=5 PRODUCE=19 RAW=6 READ=24 TEST=21 (i) observer numeric paths 109 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=24 READ=7 TEST=34 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 @@ -20,7 +20,7 @@ make_num 365 val_is_number 185 eigs_num_arg 172 VAL_FLOAT 150 -VAL_INT 145 +VAL_INT 146 eigs_list_num 130 SLOT_F64_RAW 83 num_guard 62 @@ -29,14 +29,15 @@ AST_NUM 52 slot_is_f64 50 eigs_value_as_num 48 eigs_slot_num 47 -VAL_I64_RAW 45 +VAL_I64_RAW 46 buffer_read_num 37 slot_from_f64 37 slot_is_smi 33 +number 26 buffer_read_byte 22 list_set_num 22 +slot_smi_val 20 slot_f64_value 19 -slot_smi_val 19 strtod 16 NUM_REUSE 12 eigs_slot_opt_num 12 @@ -44,12 +45,11 @@ eigs_num_arg_slow 9 slot_int_value 9 EIGS_NUM_MAX 8 finite_num_to_byte 8 +slot_from_int 8 eigs_num_text 7 eigs_opt_num 6 eigs_slot_elem_num 6 num_guard_named 6 -num_val 5 -slot_from_int 5 VAL_F64_OFFSET 4 buf_num_arg 4 dict_value_rewrite_num 4 @@ -65,38 +65,38 @@ dict_value_get_num 1 dict_value_set_num 1 i64_ 1 list_get_num 1 -data.num (AST) 7 +data.number (AST) 3 ## Per file (category counts) builtins.c 350 a=84 b=104 c=111 e=6 f=13 h=21 i=11 +vm.c 299 a=70 b=96 c=69 e=2 f=10 i=52 ext_gfx.c 298 a=104 b=124 c=70 -vm.c 295 a=70 b=95 c=66 e=2 f=10 i=52 builtins_tensor.c 200 a=55 b=59 c=86 eigenscript.c 123 a=22 b=18 c=15 e=7 f=18 i=43 builtins_buf.c 110 a=34 b=37 c=39 container.h 98 a=39 b=31 c=28 jit.c 96 d=96 +builtins_host.c 54 a=13 b=29 c=12 ext_store.c 54 h=54 embed_smoke.c 50 j=50 -builtins_host.c 49 a=13 b=24 c=12 -eigenscript.h 39 a=7 b=20 c=11 e=1 +eigenscript.h 40 a=7 b=21 c=11 e=1 jit_smoke.c 31 d=31 lint.c 29 a=29 -trace.c 23 g=23 +compiler.c 24 a=13 b=8 c=1 i=2 +trace.c 24 g=24 value_slot.h 22 a=8 b=11 c=3 -compiler.c 21 a=13 b=5 c=1 i=2 -chunk.c 19 a=3 e=4 f=12 +chunk.c 20 a=4 e=4 f=12 ext_net.c 19 a=5 b=7 c=7 model_infer.c 17 a=2 b=6 c=9 ext_http.c 14 a=3 b=4 c=7 eigs_embed.c 11 j=11 +lexer.c 11 b=10 c=1 model_train.c 8 a=2 b=4 c=1 i=1 embed_concurrent.c 6 j=6 ext_db.c 6 h=6 task.c 6 a=1 b=1 c=4 -parser.c 5 a=2 b=1 c=2 +parser.c 5 a=2 b=2 c=1 tape_read.c 5 g=5 -lexer.c 3 b=2 c=1 lint_host.c 3 a=3 eigenlsp.c 2 a=2 eigs_embed.h 1 j=1 @@ -208,7 +208,7 @@ D1 eigenscript.c:module_ns_project guarded slot_is_f64=2 D1 eigenscript.c:observer_entropy_now smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 D1 eigenscript.c:slot_to_value smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 ext_store.c:store_json_encode_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 -D1 trace.c:write_slot unwired slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 +D1 trace.c:write_slot smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 value_slot.h:slot_f64_value guarded slot_as_ptr=1 slot_f64_value=1 slot_is_f64=1 slot_is_heap=1 D1 value_slot.h:slot_int_value smi-arm slot_as_ptr=1 slot_int_value=1 slot_is_heap=1 slot_is_smi=1 slot_smi_val=1 D1 value_slot.h:slot_is_f64 guarded SLOT_QNAN_MASK=2 slot_is_f64=1 @@ -277,7 +277,6 @@ D3 jit.c:jit_compile_to_thunk/OP_NEG not-a-classifier SLOT_FALSE_BITS=1 D3 jit.c:jit_compile_to_thunk/OP_NULL not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 D3 jit_smoke.c:run_bool_cases not-a-classifier SLOT_FALSE_BITS=2 SLOT_TRUE_BITS=3 D3 jit_smoke.c:run_index_bail_cases guarded slot_is_null=1 -D3 value_slot.h:#define SLOT_SMI_TRAP refuse SLOT_TAG_MASK=1 TAG_SMI=1 D3 value_slot.h:slot_decref guarded SLOT_PAYLOAD_MASK=1 SLOT_QNAN_MASK=2 SLOT_TAG_MASK=1 TAG_HEAP=1 D3 value_slot.h:slot_false not-a-classifier SLOT_FALSE_BITS=1 D3 value_slot.h:slot_from_bool not-a-classifier TAG_BOOL=1 @@ -294,6 +293,7 @@ D3 vm.c:jit_helper_dot_get guarded slot_is_null=1 D3 vm.c:jit_helper_local_idx_dot_get guarded slot_is_null=1 D3 vm.c:vm_local_is_null guarded slot_is_null=1 D3 vm.c:vm_run_ex/CASE(DOT_GET) guarded slot_is_null=1 +D3 vm.c:vm_run_ex/CASE(INT_CONST) not-a-classifier SLOT_SMI_MAX=1 SLOT_SMI_MIN=1 D3 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET) guarded slot_is_null=1 ## Builtins @@ -351,7 +351,7 @@ buf_scale_range builtin_buf_scale_range float-producing buf_set builtin_buf_set int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num buf_to_pcm16le builtin_buf_to_pcm16le other - bounded VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,num_guard buffer builtin_buffer int-requiring - - VAL_FLOAT,VAL_INT,eigs_list_num,eigs_num_arg,val_is_number -build_corpus builtin_build_corpus int-requiring - - eigs_num_arg,eigs_opt_num,make_num,num_val,val_is_number +build_corpus builtin_build_corpus int-requiring - - eigs_num_arg,eigs_opt_num,make_num,number,val_is_number ceil builtin_ceil int-preserving LOSS - eigs_num_arg,make_num,val_is_number channel builtin_channel int-preserving - - make_num channel_closed builtin_channel_closed int-requiring - - eigs_num_arg,val_is_number @@ -1007,7 +1007,12 @@ builtins_host.c:413 builtin_build_corpus val_is_number TEST a builtins_host.c:417 builtin_build_corpus eigs_num_arg READ b builtins_host.c:449 builtin_build_corpus eigs_opt_num READ b builtins_host.c:478 builtin_build_corpus eigs_opt_num READ b -builtins_host.c:707 builtin_build_corpus num_val RAW b +builtins_host.c:706 builtin_build_corpus number RAW b +builtins_host.c:706 builtin_build_corpus number RAW b +builtins_host.c:707 builtin_build_corpus number RAW b +builtins_host.c:707 builtin_build_corpus number RAW b +builtins_host.c:708 builtin_build_corpus number RAW b +builtins_host.c:709 builtin_build_corpus number RAW b builtins_host.c:808 builtin_build_corpus make_num PRODUCE c builtins_host.c:809 builtin_build_corpus make_num PRODUCE c builtins_host.c:810 builtin_build_corpus make_num PRODUCE c @@ -1257,32 +1262,36 @@ chunk.c:223 const_equal VAL_I64_RAW RAW f chunk.c:223 const_equal VAL_I64_RAW RAW f chunk.c:243 const_dedup_grow val_is_number TEST a chunk.c:252 chunk_add_constant_ex val_is_number TEST a -chunk.c:430 chunk_disassemble VAL_FLOAT TEST e -chunk.c:431 chunk_disassemble VAL_F64_RAW RAW e -chunk.c:432 chunk_disassemble VAL_INT TEST e -chunk.c:433 chunk_disassemble VAL_I64_RAW RAW e -chunk.c:1101 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a -compiler.c:582 add_num_constant make_num PRODUCE c -compiler.c:791 collect_referenced_names_skip AST_NUM CASE a -compiler.c:935 collect_referenced_names AST_NUM CASE a -compiler.c:1074 scan_for_captures AST_NUM CASE a -compiler.c:1181 ast_has_closure AST_NUM CASE a -compiler.c:1259 subtree_overwrite_safe AST_NUM CASE a -compiler.c:1469 scan_for_interrogated AST_NUM CASE a -compiler.c:1591 scan_for_env_bound AST_NUM CASE a -compiler.c:1658 collect_module_names_walk AST_NUM CASE a -compiler.c:1796 scan_dispatch_rebind AST_NUM CASE a -compiler.c:1983 cond_is_observer_based AST_NUM CASE i -compiler.c:2071 compile_node_inner AST_NUM CASE a -compiler.c:2072 compile_node_inner data.num RAW b -compiler.c:2090 compile_node_inner data.num RAW b -compiler.c:2929 compile_node_inner AST_NUM TEST a -compiler.c:2930 compile_node_inner data.num RAW b -compiler.c:2985 compile_node_inner AST_NUM TEST a -compiler.c:2986 compile_node_inner data.num RAW b -compiler.c:3030 compile_node_inner AST_NUM TEST a -compiler.c:3031 compile_node_inner data.num RAW b -compiler.c:3844 obs_ast_scan_d AST_NUM CASE i +chunk.c:431 chunk_disassemble VAL_FLOAT TEST e +chunk.c:432 chunk_disassemble VAL_F64_RAW RAW e +chunk.c:433 chunk_disassemble VAL_INT TEST e +chunk.c:434 chunk_disassemble VAL_I64_RAW RAW e +chunk.c:800 chunk_verify_impl VAL_INT TEST a +chunk.c:1107 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a +compiler.c:583 add_num_constant make_num PRODUCE c +compiler.c:599 literal_index_u16 data.number RAW b +compiler.c:599 literal_index_u16 number RAW b +compiler.c:814 collect_referenced_names_skip AST_NUM CASE a +compiler.c:958 collect_referenced_names AST_NUM CASE a +compiler.c:1097 scan_for_captures AST_NUM CASE a +compiler.c:1204 ast_has_closure AST_NUM CASE a +compiler.c:1282 subtree_overwrite_safe AST_NUM CASE a +compiler.c:1492 scan_for_interrogated AST_NUM CASE a +compiler.c:1614 scan_for_env_bound AST_NUM CASE a +compiler.c:1681 collect_module_names_walk AST_NUM CASE a +compiler.c:1819 scan_dispatch_rebind AST_NUM CASE a +compiler.c:2006 cond_is_observer_based AST_NUM CASE i +compiler.c:2094 compile_node_inner AST_NUM CASE a +compiler.c:2095 compile_node_inner data.number RAW b +compiler.c:2095 compile_node_inner number RAW b +compiler.c:2095 compile_node_inner number RAW b +compiler.c:2096 compile_node_inner number RAW b +compiler.c:2097 compile_node_inner number RAW b +compiler.c:2103 compile_node_inner number RAW b +compiler.c:2962 compile_node_inner AST_NUM TEST a +compiler.c:3017 compile_node_inner AST_NUM TEST a +compiler.c:3061 compile_node_inner AST_NUM TEST a +compiler.c:3874 obs_ast_scan_d AST_NUM CASE i container.h:26 eigs_container_slot VAL_F64_RAW RAW b container.h:26 eigs_container_slot VAL_FLOAT TEST a container.h:26 eigs_container_slot num_guard GUARD c @@ -1464,87 +1473,88 @@ eigenscript.c:1927 slot_to_value make_num PRODUCE c eigenscript.c:1927 slot_to_value slot_is_f64 TEST a eigenscript.c:1935 slot_to_value slot_is_smi TEST a eigenscript.c:1935 slot_to_value slot_smi_val RAW b -eigenscript.c:2434 module_ns_project slot_is_f64 TEST a -eigenscript.c:2434 module_ns_project slot_is_f64 TEST a -eigenscript.c:2439 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2439 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2684 chan_clone_rec VAL_FLOAT TEST a -eigenscript.c:2684 chan_clone_rec VAL_INT TEST a -eigenscript.c:2687 chan_clone_rec VAL_F64_RAW RAW b -eigenscript.c:2687 chan_clone_rec VAL_FLOAT CASE a -eigenscript.c:2687 chan_clone_rec make_num PRODUCE c -eigenscript.c:2688 chan_clone_rec VAL_I64_RAW RAW b -eigenscript.c:2688 chan_clone_rec VAL_INT CASE a -eigenscript.c:2875 is_truthy VAL_F64_RAW RAW b -eigenscript.c:2875 is_truthy VAL_FLOAT CASE a -eigenscript.c:2876 is_truthy VAL_I64_RAW RAW b -eigenscript.c:2876 is_truthy VAL_INT CASE a -eigenscript.c:2915 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:2915 values_equal_impl VAL_INT TEST f -eigenscript.c:2916 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2916 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2917 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:2917 values_equal_impl VAL_INT TEST f -eigenscript.c:2918 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2918 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2919 values_equal_impl val_is_number TEST f -eigenscript.c:2920 values_equal_impl val_is_number TEST f -eigenscript.c:2934 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2934 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2934 values_equal_impl VAL_FLOAT CASE f -eigenscript.c:2935 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2935 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2935 values_equal_impl VAL_INT CASE f -eigenscript.c:2965 values_equal_impl buffer_read_num READ f -eigenscript.c:2967 values_equal_impl buffer_read_num READ f -eigenscript.c:3007 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3022 eigs_num_text strtod PARSE e -eigenscript.c:3032 value_to_string VAL_FLOAT CASE e -eigenscript.c:3033 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3033 value_to_string eigs_num_text FORMAT e -eigenscript.c:3036 value_to_string VAL_INT CASE e -eigenscript.c:3037 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4258 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4259 gc_value_is_node VAL_INT CASE a -eigenscript.h:188 num_val RAW b -eigenscript.h:206 AST_NUM DATA a -eigenscript.h:272 VAL_FLOAT DATA a -eigenscript.h:282 VAL_INT DATA a -eigenscript.h:290 #define val_is_number VAL_FLOAT TEST a -eigenscript.h:290 #define val_is_number VAL_INT TEST a -eigenscript.h:290 #define val_is_number val_is_number TEST a -eigenscript.h:311 #define VAL_F64_RAW VAL_F64_RAW RAW b -eigenscript.h:311 #define VAL_F64_RAW f64_ RAW b -eigenscript.h:312 #define VAL_I64_RAW VAL_I64_RAW RAW b -eigenscript.h:312 #define VAL_I64_RAW i64_ RAW b -eigenscript.h:313 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b -eigenscript.h:313 #define VAL_F64_OFFSET f64_ RAW b -eigenscript.h:1387 eigs_num_arg_slow READ b -eigenscript.h:1388 eigs_num_arg eigs_num_arg READ b -eigenscript.h:1389 eigs_num_arg VAL_F64_RAW RAW b -eigenscript.h:1389 eigs_num_arg VAL_FLOAT TEST a -eigenscript.h:1390 eigs_num_arg eigs_num_arg_slow READ b -eigenscript.h:1392 eigs_list_num READ b -eigenscript.h:1397 eigs_elem_num READ b -eigenscript.h:1398 eigs_opt_num READ b -eigenscript.h:1769 make_num PRODUCE c -eigenscript.h:1780 make_num_permanent PRODUCE c -eigenscript.h:1832 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1874 num_guard num_guard GUARD c -eigenscript.h:1882 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1882 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1883 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1883 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1892 buffer_read_num buffer_read_num READ b -eigenscript.h:1893 buffer_read_num num_guard GUARD c -eigenscript.h:1899 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1908 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1917 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1918 buffer_read_byte buffer_read_num READ b -eigenscript.h:1920 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1931 num_guard_named num_guard_named GUARD c -eigenscript.h:1937 num_guard_named num_guard GUARD c -eigenscript.h:2250 eigs_num_text FORMAT e +eigenscript.c:2428 module_ns_project slot_is_f64 TEST a +eigenscript.c:2428 module_ns_project slot_is_f64 TEST a +eigenscript.c:2433 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2433 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2678 chan_clone_rec VAL_FLOAT TEST a +eigenscript.c:2678 chan_clone_rec VAL_INT TEST a +eigenscript.c:2681 chan_clone_rec VAL_F64_RAW RAW b +eigenscript.c:2681 chan_clone_rec VAL_FLOAT CASE a +eigenscript.c:2681 chan_clone_rec make_num PRODUCE c +eigenscript.c:2682 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:2682 chan_clone_rec VAL_INT CASE a +eigenscript.c:2869 is_truthy VAL_F64_RAW RAW b +eigenscript.c:2869 is_truthy VAL_FLOAT CASE a +eigenscript.c:2870 is_truthy VAL_I64_RAW RAW b +eigenscript.c:2870 is_truthy VAL_INT CASE a +eigenscript.c:2909 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2909 values_equal_impl VAL_INT TEST f +eigenscript.c:2910 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2910 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2911 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2911 values_equal_impl VAL_INT TEST f +eigenscript.c:2912 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2912 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2913 values_equal_impl val_is_number TEST f +eigenscript.c:2914 values_equal_impl val_is_number TEST f +eigenscript.c:2928 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2928 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2928 values_equal_impl VAL_FLOAT CASE f +eigenscript.c:2929 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2929 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2929 values_equal_impl VAL_INT CASE f +eigenscript.c:2959 values_equal_impl buffer_read_num READ f +eigenscript.c:2961 values_equal_impl buffer_read_num READ f +eigenscript.c:3001 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:3016 eigs_num_text strtod PARSE e +eigenscript.c:3026 value_to_string VAL_FLOAT CASE e +eigenscript.c:3027 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3027 value_to_string eigs_num_text FORMAT e +eigenscript.c:3030 value_to_string VAL_INT CASE e +eigenscript.c:3031 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4252 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4253 gc_value_is_node VAL_INT CASE a +eigenscript.h:195 number RAW b +eigenscript.h:213 AST_NUM DATA a +eigenscript.h:239 number RAW b +eigenscript.h:280 VAL_FLOAT DATA a +eigenscript.h:289 VAL_INT DATA a +eigenscript.h:297 #define val_is_number VAL_FLOAT TEST a +eigenscript.h:297 #define val_is_number VAL_INT TEST a +eigenscript.h:297 #define val_is_number val_is_number TEST a +eigenscript.h:318 #define VAL_F64_RAW VAL_F64_RAW RAW b +eigenscript.h:318 #define VAL_F64_RAW f64_ RAW b +eigenscript.h:319 #define VAL_I64_RAW VAL_I64_RAW RAW b +eigenscript.h:319 #define VAL_I64_RAW i64_ RAW b +eigenscript.h:320 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b +eigenscript.h:320 #define VAL_F64_OFFSET f64_ RAW b +eigenscript.h:1394 eigs_num_arg_slow READ b +eigenscript.h:1395 eigs_num_arg eigs_num_arg READ b +eigenscript.h:1396 eigs_num_arg VAL_F64_RAW RAW b +eigenscript.h:1396 eigs_num_arg VAL_FLOAT TEST a +eigenscript.h:1397 eigs_num_arg eigs_num_arg_slow READ b +eigenscript.h:1399 eigs_list_num READ b +eigenscript.h:1404 eigs_elem_num READ b +eigenscript.h:1405 eigs_opt_num READ b +eigenscript.h:1776 make_num PRODUCE c +eigenscript.h:1787 make_num_permanent PRODUCE c +eigenscript.h:1839 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1881 num_guard num_guard GUARD c +eigenscript.h:1889 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1889 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1890 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1890 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1899 buffer_read_num buffer_read_num READ b +eigenscript.h:1900 buffer_read_num num_guard GUARD c +eigenscript.h:1906 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1915 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1924 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1925 buffer_read_byte buffer_read_num READ b +eigenscript.h:1927 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1938 num_guard_named num_guard_named GUARD c +eigenscript.h:1944 num_guard_named num_guard GUARD c +eigenscript.h:2257 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j @@ -2131,9 +2141,17 @@ jit_smoke.c:602 run_exit_cases VAL_F64_RAW WRITE d jit_smoke.c:628 run_exit_cases slot_from_f64 PRODUCE d jit_smoke.c:637 run_exit_cases SLOT_F64_RAW RAW d jit_smoke.c:642 run_exit_cases SLOT_F64_RAW RAW d -lexer.c:42 tok_add num_val RAW b -lexer.c:647 tokenize_at_line num_val RAW b -lexer.c:750 tokenize_at_line strtod PARSE c +lexer.c:35 tok_add number RAW b +lexer.c:42 tok_add number RAW b +lexer.c:42 tok_add number RAW b +lexer.c:647 tokenize_at_line number RAW b +lexer.c:734 tokenize_at_line number RAW b +lexer.c:735 tokenize_at_line number RAW b +lexer.c:748 tokenize_at_line strtod PARSE c +lexer.c:749 tokenize_at_line number RAW b +lexer.c:765 tokenize_at_line number RAW b +lexer.c:766 tokenize_at_line number RAW b +lexer.c:770 tokenize_at_line number RAW b lint.c:247 collect_refs AST_NUM CASE a lint.c:311 collect_assigns AST_NUM CASE a lint.c:369 cond_has_bare_predicate AST_NUM CASE a @@ -2194,9 +2212,9 @@ model_train.c:1474 builtin_native_train_step eigs_slot_num READ b model_train.c:1477 builtin_native_train_step eigs_slot_num READ b parser.c:524 free_ast AST_NUM CASE a parser.c:806 parse_primary AST_NUM DATA a -parser.c:807 parse_primary data.num WRITE c -parser.c:807 parse_primary num_val RAW b -parser.c:834 parse_primary data.num WRITE c +parser.c:807 parse_primary data.number WRITE c +parser.c:807 parse_primary number RAW b +parser.c:807 parse_primary number RAW b tape_read.c:368 tape_parse strtod PARSE g tape_read.c:387 tape_parse strtod PARSE g tape_read.c:388 tape_parse strtod PARSE g @@ -2217,42 +2235,43 @@ trace.c:1927 #define TK_NUM_ VAL_INT DATA g trace.c:2020 kinds_text VAL_FLOAT DATA g trace.c:2020 kinds_text VAL_INT DATA g trace.c:2021 kinds_text VAL_FLOAT DATA g -trace.c:2327 parse_value_p strtod PARSE g -trace.c:2410 parse_value_p strtod PARSE g -trace.c:2413 parse_value_p make_num PRODUCE g -trace.c:2823 write_value_ptr VAL_F64_RAW RAW g -trace.c:2823 write_value_ptr VAL_FLOAT CASE g -trace.c:2826 write_value_ptr VAL_I64_RAW RAW g -trace.c:2826 write_value_ptr VAL_INT CASE g -trace.c:2842 write_slot SLOT_F64_RAW RAW g -trace.c:2842 write_slot slot_is_f64 TEST g -trace.c:2849 write_slot slot_is_smi TEST g -trace.c:2963 write_value_ptr_full VAL_F64_RAW RAW g -trace.c:2963 write_value_ptr_full VAL_FLOAT CASE g -trace.c:2964 write_value_ptr_full VAL_I64_RAW RAW g -trace.c:2964 write_value_ptr_full VAL_INT CASE g -value_slot.h:106 slot_is_f64 slot_is_f64 TEST a -value_slot.h:112 slot_is_smi slot_is_smi TEST a -value_slot.h:123 #define SLOT_F64_RAW SLOT_F64_RAW RAW b -value_slot.h:123 #define SLOT_F64_RAW d_ RAW b -value_slot.h:135 slot_smi_val slot_smi_val RAW b -value_slot.h:143 slot_from_f64 SLOT_F64_RAW WRITE c -value_slot.h:143 slot_from_f64 slot_from_f64 PRODUCE c -value_slot.h:147 slot_from_int slot_from_int PRODUCE c -value_slot.h:226 slot_truthy_immediate SLOT_F64_RAW RAW b -value_slot.h:226 slot_truthy_immediate slot_is_f64 TEST a -value_slot.h:229 slot_truthy_immediate slot_is_smi TEST a -value_slot.h:229 slot_truthy_immediate slot_smi_val RAW b -value_slot.h:243 slot_f64_value slot_f64_value READ b -value_slot.h:244 slot_f64_value SLOT_F64_RAW RAW b -value_slot.h:244 slot_f64_value slot_is_f64 TEST a -value_slot.h:247 slot_f64_value VAL_F64_RAW RAW b -value_slot.h:247 slot_f64_value VAL_FLOAT TEST a -value_slot.h:253 slot_int_value slot_int_value READ b -value_slot.h:254 slot_int_value slot_is_smi TEST a -value_slot.h:254 slot_int_value slot_smi_val RAW b -value_slot.h:257 slot_int_value VAL_I64_RAW RAW b -value_slot.h:257 slot_int_value VAL_INT TEST a +trace.c:2328 parse_value_p strtod PARSE g +trace.c:2434 parse_value_p strtod PARSE g +trace.c:2437 parse_value_p make_num PRODUCE g +trace.c:2870 write_value_ptr VAL_F64_RAW RAW g +trace.c:2870 write_value_ptr VAL_FLOAT CASE g +trace.c:2871 write_value_ptr VAL_I64_RAW RAW g +trace.c:2871 write_value_ptr VAL_INT CASE g +trace.c:2887 write_slot SLOT_F64_RAW RAW g +trace.c:2887 write_slot slot_is_f64 TEST g +trace.c:2891 write_slot slot_is_smi TEST g +trace.c:2891 write_slot slot_smi_val RAW g +trace.c:3005 write_value_ptr_full VAL_FLOAT CASE g +trace.c:3007 write_value_ptr_full VAL_F64_RAW RAW g +trace.c:3011 write_value_ptr_full VAL_INT CASE g +trace.c:3013 write_value_ptr_full VAL_I64_RAW RAW g +value_slot.h:84 slot_is_f64 slot_is_f64 TEST a +value_slot.h:90 slot_is_smi slot_is_smi TEST a +value_slot.h:101 #define SLOT_F64_RAW SLOT_F64_RAW RAW b +value_slot.h:101 #define SLOT_F64_RAW d_ RAW b +value_slot.h:113 slot_smi_val slot_smi_val RAW b +value_slot.h:121 slot_from_f64 SLOT_F64_RAW WRITE c +value_slot.h:121 slot_from_f64 slot_from_f64 PRODUCE c +value_slot.h:125 slot_from_int slot_from_int PRODUCE c +value_slot.h:201 slot_truthy_immediate SLOT_F64_RAW RAW b +value_slot.h:201 slot_truthy_immediate slot_is_f64 TEST a +value_slot.h:204 slot_truthy_immediate slot_is_smi TEST a +value_slot.h:204 slot_truthy_immediate slot_smi_val RAW b +value_slot.h:218 slot_f64_value slot_f64_value READ b +value_slot.h:219 slot_f64_value SLOT_F64_RAW RAW b +value_slot.h:219 slot_f64_value slot_is_f64 TEST a +value_slot.h:222 slot_f64_value VAL_F64_RAW RAW b +value_slot.h:222 slot_f64_value VAL_FLOAT TEST a +value_slot.h:228 slot_int_value slot_int_value READ b +value_slot.h:229 slot_int_value slot_is_smi TEST a +value_slot.h:229 slot_int_value slot_smi_val RAW b +value_slot.h:232 slot_int_value VAL_I64_RAW RAW b +value_slot.h:232 slot_int_value VAL_INT TEST a vm.c:107 obs_dump_num eigs_num_text FORMAT i vm.c:118 obs_dump_value SLOT_F64_RAW RAW i vm.c:118 obs_dump_value slot_is_f64 TEST i @@ -2363,188 +2382,192 @@ vm.c:2409 jit_helper_index_get make_num PRODUCE c vm.c:2995 vm_take_error_value make_num PRODUCE c vm.c:3099 slot_type_name slot_is_f64 TEST e vm.c:3100 slot_type_name slot_is_smi TEST e -vm.c:3340 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a -vm.c:3341 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b -vm.c:3341 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3355 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3360 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3380 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3380 #define NUM_REUSE VAL_FLOAT TEST a -vm.c:3391 #define ARITH_FAST slot_f64_value READ b -vm.c:3391 #define ARITH_FAST slot_f64_value READ b -vm.c:3392 #define ARITH_FAST num_guard GUARD c -vm.c:3397 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3398 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3406 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3407 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3415 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3427 #define INT_ARITH slot_int_value READ b -vm.c:3427 #define INT_ARITH slot_int_value READ b -vm.c:3441 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3441 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3442 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3442 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3442 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3443 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3443 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3444 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3444 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3445 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3446 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3446 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3447 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3447 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3447 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3447 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3497 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3497 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3498 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3498 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3498 #define NUM_BINOP num_guard GUARD c -vm.c:3499 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3499 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3501 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3501 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3502 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3502 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3503 #define NUM_BINOP make_num PRODUCE c -vm.c:3504 #define NUM_BINOP val_is_number TEST a -vm.c:3504 #define NUM_BINOP val_is_number TEST a -vm.c:3505 #define NUM_BINOP eigs_num_arg READ b -vm.c:3505 #define NUM_BINOP eigs_num_arg READ b -vm.c:3506 #define NUM_BINOP num_guard GUARD c -vm.c:3509 #define NUM_BINOP make_num PRODUCE c -vm.c:3513 #define NUM_BINOP make_num PRODUCE c -vm.c:3531 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3531 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3532 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3534 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3536 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3536 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3536 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3539 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3541 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3541 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3542 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3542 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3543 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3548 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3556 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3556 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3556 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3557 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3557 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3557 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3558 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3558 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3559 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3559 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3560 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3562 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3562 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3567 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3595 #define INT_BINOP_R slot_f64_value READ b -vm.c:3599 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3626 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3629 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3629 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3632 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3636 vm_run_ex/CASE(NEG) slot_int_value READ b -vm.c:3641 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c -vm.c:3646 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3668 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3672 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3681 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3681 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3687 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3687 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3707 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3707 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3713 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3713 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3735 #define NUM_CMP slot_f64_value READ f -vm.c:3735 #define NUM_CMP slot_f64_value READ f -vm.c:4678 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4680 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4687 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4697 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4699 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4701 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4723 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4725 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4726 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4728 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4730 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4740 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4742 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4742 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:3342 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3343 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3343 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3352 vm_run_ex/CASE(INT_ZERO) slot_from_int PRODUCE c +vm.c:3356 vm_run_ex/CASE(INT_ONE) slot_from_int PRODUCE c +vm.c:3362 vm_run_ex/CASE(INT_CONST) VAL_I64_RAW RAW b +vm.c:3363 vm_run_ex/CASE(INT_CONST) slot_from_int PRODUCE c +vm.c:3374 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3379 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3399 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3399 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3410 #define ARITH_FAST slot_f64_value READ b +vm.c:3410 #define ARITH_FAST slot_f64_value READ b +vm.c:3411 #define ARITH_FAST num_guard GUARD c +vm.c:3416 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3417 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3425 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3426 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3434 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3446 #define INT_ARITH slot_int_value READ b +vm.c:3446 #define INT_ARITH slot_int_value READ b +vm.c:3460 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3460 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3461 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3461 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3461 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3462 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3462 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3463 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3463 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3464 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3465 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3465 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3466 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3466 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3466 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3466 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3516 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3516 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3517 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3517 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3517 #define NUM_BINOP num_guard GUARD c +vm.c:3518 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3518 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3520 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3520 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3521 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3521 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3522 #define NUM_BINOP make_num PRODUCE c +vm.c:3523 #define NUM_BINOP val_is_number TEST a +vm.c:3523 #define NUM_BINOP val_is_number TEST a +vm.c:3524 #define NUM_BINOP eigs_num_arg READ b +vm.c:3524 #define NUM_BINOP eigs_num_arg READ b +vm.c:3525 #define NUM_BINOP num_guard GUARD c +vm.c:3528 #define NUM_BINOP make_num PRODUCE c +vm.c:3532 #define NUM_BINOP make_num PRODUCE c +vm.c:3550 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3550 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3551 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3553 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3555 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3555 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3555 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3558 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3560 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3560 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3561 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3561 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3562 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3567 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3575 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3575 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3575 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3576 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3576 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3576 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3577 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3577 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3578 vm_run_ex/CASE(MOD) NUM_REUSE TEST a +vm.c:3578 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c +vm.c:3579 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3581 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3581 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3586 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3614 #define INT_BINOP_R slot_f64_value READ b +vm.c:3618 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3645 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3648 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3648 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3651 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3655 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3660 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3665 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3687 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3691 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3700 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3700 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3706 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3706 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3726 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3726 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3732 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3732 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3754 #define NUM_CMP slot_f64_value READ f +vm.c:3754 #define NUM_CMP slot_f64_value READ f +vm.c:4697 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4699 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4706 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4716 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4718 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4720 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4742 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a vm.c:4744 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4756 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4759 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4766 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4769 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4772 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4773 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4829 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4832 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4893 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4894 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4920 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4920 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5026 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5027 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5100 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5104 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5104 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5443 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5444 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5445 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5479 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5480 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5481 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5545 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5546 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5546 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5550 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5551 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5552 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5553 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5557 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:4745 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4747 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4749 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4759 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4761 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4761 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4763 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4775 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4778 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4785 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4788 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4791 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4792 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4848 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4851 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4912 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4913 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:4939 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:4939 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5045 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5046 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5119 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5123 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5123 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5462 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5463 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5464 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5498 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5499 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5500 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5564 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5565 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5565 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5565 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5569 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5570 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5571 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i vm.c:5572 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5573 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5574 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5594 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5620 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5623 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5624 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5627 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5651 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5654 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5659 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5679 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5680 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5681 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5682 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5812 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5829 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5830 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5832 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5839 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5843 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5846 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5847 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5850 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5861 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5864 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6458 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6459 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6460 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6463 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6473 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6474 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6476 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6480 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:5576 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5590 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5591 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5592 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5593 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5613 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5639 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5642 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5643 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5646 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5662 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5670 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5673 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5678 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5698 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5699 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5700 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5701 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5831 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5831 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5848 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5849 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5851 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5858 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5862 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5865 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5866 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5869 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5880 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5883 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6477 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6478 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6479 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6482 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6492 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6493 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6495 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6499 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index e9781c705..f1463d144 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -709,8 +709,7 @@ result).** | `jit.c:jit_compile_to_thunk/OP_NULL` | not-a-classifier | the constant arm writes null and bool bits (D3) | | `jit_smoke.c:run_bool_cases` | not-a-classifier | test harness: expected bool bits (D3) | | `jit_smoke.c:run_index_bail_cases` | guarded | test harness: an exact null test of a result (D3) | -| `trace.c:write_slot` | unwired | an int needs tape v7 (ints as digits, floats marked), R1.3; a v6 tape would replay it as a float. Any other tag refuses; it was written as `` (D1) | -| `value_slot.h:#define SLOT_SMI_TRAP` | refuse | the smi-trap build's check (`-DEIGS_SMI_TRAP`): every slot classifier aborts on an SMI before R1.3; nothing in other builds (D3) | +| `trace.c:write_slot` | smi-arm | v7 writes an int as exact digits and marks floats with a point or exponent; an unknown tag refuses (R1.3) (D1) | | `value_slot.h:#define slot_as_heap` | refuse | alias of `slot_as_ptr` (D2) | | `value_slot.h:slot_as_ptr` | refuse | the raw dereference: R1.1 refuses a non-heap slot in ASan builds and under `-DEIGS_SLOT_CHECKED` (the C slot test) (D2) | | `value_slot.h:slot_decref` | guarded | acts only on tag `0xFFFB`; an SMI has no refcount (D3) | @@ -769,6 +768,7 @@ result).** | `vm.c:vm_run_ex/CASE(DOT_GET)` | guarded | exact null test of a field (D3) | | `vm.c:vm_run_ex/CASE(DOT_SET)` | guarded | an int value skips the immediate store: the slow path pops it (D1) | | `vm.c:vm_run_ex/CASE(EQ)` | guarded | an int is not a float: the slow path (`values_equal_op` on the lifted Values); R1.3 adds N2 (D1) | +| `vm.c:vm_run_ex/CASE(INT_CONST)` | not-a-classifier | int literal producer: a constant in the SMI range is emitted through `slot_from_int`; an out-of-range int borrows its constant-pool box into the stack with an owned reference (R1.3) (D3) | | `vm.c:vm_run_ex/CASE(INDEX_GET)` | guarded | an int index skips the fast path: the slow path lifts it through `slot_to_value` (D1) | | `vm.c:vm_run_ex/CASE(INDEX_SET)` | guarded | an int index or value skips the fast path: the slow path pops it (D1) | | `vm.c:vm_run_ex/CASE(LOCAL_DOT_SET)` | guarded | an int value: `vm_slot_lift` boxes it (D1) | diff --git a/src/builtins_host.c b/src/builtins_host.c index 42f942f39..39bb656cc 100644 --- a/src/builtins_host.c +++ b/src/builtins_host.c @@ -700,13 +700,13 @@ Value* builtin_build_corpus(Value *arg) { tid = FIRST_IDENT + actual_top + hit; } } else if (int_count > 0 && tid == TOK_NUM) { - /* Give small non-negative integer literals exact tokens; the - * region sits directly after the slots. floor==value rejects - * 3.5 etc.; the lexer emits '-' as its own token so num_val is - * never negative for a literal, but guard anyway. */ - double nv = tl.tokens[i].num_val; - if (nv >= 0.0 && nv < (double)int_count && nv == (double)(long)nv) - tid = FIRST_IDENT + actual_top + slot_count + (int)nv; + /* Only int literals receive the compact integer token. + * Preserve literal kinds: `3.0` remains TOK_NUM. Hex literals + * can wrap negative, so check the range before the cast. */ + EigsNum number = tl.tokens[i].number; + if (number.is_int && number.value.i64 >= 0 && + number.value.i64 < int_count) + tid = FIRST_IDENT + actual_top + slot_count + (int)number.value.i64; } double d = (double)tid; fwrite(&d, sizeof(double), 1, stream_file); diff --git a/src/chunk.c b/src/chunk.c index 531d2aa38..50e4c63b3 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -346,6 +346,7 @@ const char *op_name(uint8_t op) { switch ((OpCode)op) { #define N(o) case o: return #o + 3; N(OP_CONST) N(OP_NULL) N(OP_NUM_ZERO) N(OP_NUM_ONE) N(OP_TRUE) N(OP_FALSE) + N(OP_INT_ZERO) N(OP_INT_ONE) N(OP_INT_CONST) N(OP_ADD) N(OP_SUB) N(OP_MUL) N(OP_DIV) N(OP_MOD) N(OP_BAND) N(OP_BOR) N(OP_BXOR) N(OP_SHL) N(OP_SHR) N(OP_NEG) N(OP_NOT) N(OP_BNOT) @@ -392,7 +393,7 @@ const char *op_name(uint8_t op) { * desynchronized on 15 opcodes). */ typedef enum { VR_RAW = 0, /* count / kind / line / runtime-guarded slot — no bound */ - VR_CONST, /* constant-pool index — any value type (OP_CONST push) */ + VR_CONST, /* constant-pool index (OP_CONST or OP_INT_CONST push) */ VR_NAME, /* constant-pool index that MUST be a string: the VM derefs it * as an interned name (const_interns[idx]), which is NULL for * a non-string constant → NULL deref. Bound AND type-check. */ @@ -425,7 +426,7 @@ void chunk_disassemble(EigsChunk *chunk, const char *label) { for (int k = 0; k < nops && i + 1 < chunk->code_len; k++) { uint16_t arg = chunk->code[i] | (chunk->code[i + 1] << 8); fprintf(stderr, " %d", arg); - if (op == OP_CONST && arg < (uint16_t)chunk->const_count) { + if ((op == OP_CONST || op == OP_INT_CONST) && arg < (uint16_t)chunk->const_count) { Value *v = chunk->constants[arg]; if (v->type == VAL_FLOAT) fprintf(stderr, " (%.6g)", VAL_F64_RAW(v)); @@ -475,7 +476,7 @@ void chunk_disassemble(EigsChunk *chunk, const char *label) { * the disassembler's stepping table — one layout source, not two. */ static int op_verify_operands(uint8_t op8, VerifyRole roles[3]) { switch ((OpCode)op8) { - case OP_CONST: + case OP_CONST: case OP_INT_CONST: roles[0] = VR_CONST; return 1; case OP_GET_NAME: case OP_SET_NAME: case OP_SET_NAME_LOCAL: case OP_SET_FN_NAME_LOCAL: case OP_DOT_GET: case OP_DOT_SET: @@ -519,6 +520,7 @@ static int op_verify_operands(uint8_t op8, VerifyRole roles[3]) { /* Operand-free opcodes — every one listed, so a new opcode cannot * silently walk wrong. */ case OP_NULL: case OP_NUM_ZERO: case OP_NUM_ONE: case OP_TRUE: case OP_FALSE: + case OP_INT_ZERO: case OP_INT_ONE: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: case OP_NEG: case OP_NOT: case OP_BNOT: @@ -626,6 +628,7 @@ static StackEffect op_verify_stack_effect(uint8_t op8, int operand0) { switch ((OpCode)op8) { /* Pushes, consuming nothing. */ case OP_CONST: case OP_NULL: case OP_NUM_ZERO: case OP_NUM_ONE: + case OP_INT_ZERO: case OP_INT_ONE: case OP_INT_CONST: case OP_TRUE: case OP_FALSE: case OP_GET_LOCAL: case OP_GET_NAME: case OP_CLOSURE: case OP_LOCAL_DOT_GET: case OP_LOCAL_IDX_GET: case OP_LOCAL_IDX_DOT_GET: @@ -794,6 +797,9 @@ static int chunk_verify_impl(EigsChunk *chunk, char *why, size_t whyn) { if (operand >= chunk->const_count) { WHY("constant index %d out of range at offset %d", operand, i); ok = 0; + } else if (op == OP_INT_CONST && chunk->constants[operand]->type != VAL_INT) { + WHY("integer constant index %d is not an int at offset %d", operand, i); + ok = 0; } break; case VR_NAME: if (operand >= chunk->const_count) { diff --git a/src/compiler.c b/src/compiler.c index 0976cd065..bc2d5ca89 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -305,6 +305,7 @@ static int op_stack_effect(uint8_t op8) { switch ((OpCode)op8) { /* Push 1 */ case OP_CONST: case OP_NULL: case OP_NUM_ZERO: case OP_NUM_ONE: + case OP_INT_ZERO: case OP_INT_ONE: case OP_INT_CONST: case OP_TRUE: case OP_FALSE: case OP_GET_LOCAL: case OP_GET_NAME: case OP_DUP: case OP_PREDICATE: case OP_LISTCOMP_BEGIN: @@ -585,6 +586,28 @@ static int add_num_constant(Compiler *c, double num) { return check_const_index(idx); } +static int add_int_constant(Compiler *c, int64_t integer) { + Value *v = make_int(integer); + int idx = chunk_add_constant(c->chunk, v); + val_decref(v); + return check_const_index(idx); +} + +/* A fused literal index is an exact u16 for either numeric kind. Check + * before casting: large int/float literals must take the generic path. */ +static int literal_index_u16(const ASTNode *node, int *out) { + EigsNum n = node->data.number; + if (n.is_int) { + if (n.value.i64 < 0 || n.value.i64 > 0xFFFF) return 0; + *out = (int)n.value.i64; + return 1; + } + double d = n.value.f64; + if (!(d >= 0.0 && d <= 65535.0) || floor(d) != d) return 0; + *out = (int)d; + return 1; +} + /* ---- Local variable tracking ---- */ static int resolve_local(Compiler *c, const char *name, uint32_t hash) { @@ -2069,10 +2092,20 @@ static void compile_node_inner(Compiler *c, ASTNode *node) { switch (node->type) { case AST_NUM: { - double v = node->data.num; - if (v == 0.0) { emit(c, OP_NUM_ZERO, node->line); } - else if (v == 1.0) { emit(c, OP_NUM_ONE, node->line); } - else { emit_op_u16(c, OP_CONST, (uint16_t)add_num_constant(c, v), node->line); } + EigsNum number = node->data.number; + if (number.is_int) { + int64_t i = number.value.i64; + if (i == 0) emit(c, OP_INT_ZERO, node->line); + else if (i == 1) emit(c, OP_INT_ONE, node->line); + else emit_op_u16(c, OP_INT_CONST, + (uint16_t)add_int_constant(c, i), node->line); + } else { + double f = number.value.f64; + if (f == 0.0) emit(c, OP_NUM_ZERO, node->line); + else if (f == 1.0) emit(c, OP_NUM_ONE, node->line); + else emit_op_u16(c, OP_CONST, + (uint16_t)add_num_constant(c, f), node->line); + } break; } @@ -2087,7 +2120,7 @@ static void compile_node_inner(Compiler *c, ASTNode *node) { break; case AST_BOOL: /* #1637 */ - emit(c, node->data.num != 0.0 ? OP_TRUE : OP_FALSE, node->line); + emit(c, node->data.boolean ? OP_TRUE : OP_FALSE, node->line); break; case AST_IDENT: { @@ -2927,9 +2960,8 @@ static void compile_node_inner(Compiler *c, ASTNode *node) { if (c->enclosing && node->data.index.target->type == AST_IDENT && node->data.index.index->type == AST_NUM) { - double dv = node->data.index.index->data.num; - int iv = (int)dv; - if (iv == dv && iv >= 0 && iv <= 0xFFFF) { + int iv; + if (literal_index_u16(node->data.index.index, &iv)) { const char *tname = node->data.index.target->data.ident.name; uint32_t th = node->data.index.target->name_hash; if (th == 0) th = env_hash_name(tname); @@ -2983,9 +3015,8 @@ static void compile_node_inner(Compiler *c, ASTNode *node) { ASTNode *idx_node = node->data.dot.target; if (idx_node->data.index.target->type == AST_IDENT && idx_node->data.index.index->type == AST_NUM) { - double dv = idx_node->data.index.index->data.num; - int iv = (int)dv; - if (iv == dv && iv >= 0 && iv <= 0xFFFF) { + int iv; + if (literal_index_u16(idx_node->data.index.index, &iv)) { const char *tname = idx_node->data.index.target->data.ident.name; uint32_t th = idx_node->data.index.target->name_hash; if (th == 0) th = env_hash_name(tname); @@ -3028,9 +3059,8 @@ static void compile_node_inner(Compiler *c, ASTNode *node) { ASTNode *idx_node = node->data.dot_assign.target; if (idx_node->data.index.target->type == AST_IDENT && idx_node->data.index.index->type == AST_NUM) { - double dv = idx_node->data.index.index->data.num; - int iv = (int)dv; - if (iv == dv && iv >= 0 && iv <= 0xFFFF) { + int iv; + if (literal_index_u16(idx_node->data.index.index, &iv)) { const char *tname = idx_node->data.index.target->data.ident.name; uint32_t th = idx_node->data.index.target->name_hash; if (th == 0) th = env_hash_name(tname); diff --git a/src/eigenscript.c b/src/eigenscript.c index 30dd95444..2c572ad22 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -1943,12 +1943,6 @@ void eigs_slot_refuse(const char *who, EigsSlot s) { abort(); } -void eigs_int_unwired(const char *who, uint64_t bits) { - fprintf(stderr, "EigenScript FATAL: %s: int 0x%016llx reached an arm whose " - "int handling lands in #1758 R1.3\n", who, (unsigned long long)bits); - abort(); -} - Value* make_str(const char *s) { /* #965: the copying string constructor is the sandbox chokepoint for the * pure string transforms (str_lower/str_upper/trim/substr/ @@ -2911,7 +2905,7 @@ static int values_equal_impl(Value *a, Value *b, int depth, const char *op) { if (a->type != b->type) { /* #1758 N2 (design 7): an int and a float are both numbers and are * equal exactly when their values are; no conversion rounds either - * side. Dead until R1.3, when the first int Value exists. */ + * side. */ if (a->type == VAL_INT && b->type == VAL_FLOAT) return eigs_cmp_int_float(VAL_I64_RAW(a), VAL_F64_RAW(b)) == 0; if (a->type == VAL_FLOAT && b->type == VAL_INT) diff --git a/src/eigenscript.h b/src/eigenscript.h index 6d0b6c6e7..fa70f900c 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -152,6 +152,13 @@ static inline int eigs_name_is_reserved(const char *name) { #define MAX_PARAMS 16 #define MAX_MATCH_CASES 64 +/* #1758 R1.3: a source number retains its literal kind through lexing and + * parsing. Decimal integers outside int64 are floats; hex integers wrap. */ +typedef struct { + int is_int; + union { int64_t i64; double f64; } value; +} EigsNum; + /* ---- Tokenizer ---- */ typedef enum { @@ -185,7 +192,7 @@ typedef enum { typedef struct { TokType type; - double num_val; + EigsNum number; char *str_val; int line; int col; /* 0-based column offset */ @@ -212,7 +219,7 @@ typedef enum { AST_TRY, AST_DICT, AST_DOT, AST_BREAK, AST_CONTINUE, AST_DOT_ASSIGN, AST_IMPORT, AST_MATCH, AST_LAMBDA, AST_UNOBSERVED, AST_INDEX_ASSIGN, AST_LIST_PATTERN_ASSIGN, AST_SLICE, - AST_BOOL /* #1637: `true`/`false`; the value is data.num (1 or 0) */ + AST_BOOL /* #1637: `true`/`false`; the value is data.boolean (1 or 0) */ } ASTType; typedef struct ASTNode ASTNode; @@ -229,7 +236,8 @@ struct ASTNode { * parenthesized literal list is a single call * argument, never spread (#355) */ union { - double num; + EigsNum number; + int boolean; char *str; struct { char *name; } ident; struct { char op[4]; ASTNode *left; ASTNode *right; } binop; @@ -276,9 +284,8 @@ typedef enum { * slot layer carries it as the TAG_BOOL immediate. Arithmetic on it and * `==` against a number raise. */ VAL_BOOL, - /* #1758 R1.2a: an exact int64, boxed only outside the SMI range (design - * 2.1). Nothing produces one before R1.3 (make_int does not exist yet): - * every arm that handles it is dead code until then. */ + /* #1758: an exact int64. Stack/container slots use an SMI when it fits; + * the Value API and out-of-SMI values use make_int (design 2.1). */ VAL_INT, } ValType; @@ -291,7 +298,7 @@ typedef Value* (*BuiltinFn)(Value* arg); /* #1758 N2 (design 7): an int and a float compare exactly, by value. Returns * -1, 0 or 1 for i < f, i == f, i > f, and 2 when f is NaN (unordered: every * comparison is false except !=). Lua's LTintfloat/EQintfloat give the same - * answers. Pure; no int Value exists before R1.3. */ + * answers. Pure; neither operand is rounded through the other kind. */ static inline int eigs_cmp_int_float(int64_t i, double f) { if (f != f) return 2; if (f >= 9223372036854775808.0) return -1; /* f above every int64 */ @@ -450,7 +457,7 @@ struct Value { * reviewed list tools/num_read_allowlist.txt, pinned by count * (tools/num_read_check.sh). */ double f64_; /* VAL_FLOAT (#1758 R1.2a) */ - int64_t i64_; /* VAL_INT (#1758 R1.2a; no producer before R1.3) */ + int64_t i64_; /* VAL_INT (#1758) */ int boolean; /* VAL_BOOL: 0 or 1 (only the two singletons exist) */ /* VAL_STR payload: NUL-terminated bytes. * diff --git a/src/lexer.c b/src/lexer.c index 57b5fa223..7f9233b61 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -32,14 +32,14 @@ static void lexer_error_at(const char *caret_source, int line, int col, eigs_print_caret_src(stderr, caret_source, line, col); } -static void tok_add(TokenList *tl, TokType type, double num, const char *str, int line, int col) { +static void tok_add(TokenList *tl, TokType type, EigsNum number, const char *str, int line, int col) { if (tl->count >= tl->capacity) { tl->capacity *= 2; tl->tokens = xrealloc_array(tl->tokens, tl->capacity, sizeof(Token)); } Token *t = &tl->tokens[tl->count++]; t->type = type; - t->num_val = num; + t->number = number; t->str_val = str ? xstrdup(str) : NULL; t->line = line; t->col = col; @@ -131,7 +131,7 @@ static const char *fstr_interp_end(const char *p, int nesting, int *too_deep) { * reports the post-`}` column, since a zero length would read as * "column unknown" to the error recorder. */ static void tok_add_synth(TokenList *tl, TokType type, const char *str, int line, int col) { - tok_add(tl, type, 0, str, line, col); + tok_add(tl, type, (EigsNum){0}, str, line, col); tl->tokens[tl->count - 1].synth = 1; } @@ -434,7 +434,7 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init snprintf(msg, sizeof(msg), "f-string nesting too deep (max %d levels)", MAX_TOKENIZE_DEPTH); lexer_error_at(caret_source, initial_line, initial_col, msg); - tok_add(&tl, TOK_EOF, 0, NULL, initial_line, initial_col); + tok_add(&tl, TOK_EOF, (EigsNum){0}, NULL, initial_line, initial_col); return tl; } g_tokenize_depth++; @@ -483,12 +483,12 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init } else { indent_top++; indent_stack[indent_top] = spaces; - tok_add(&tl, TOK_INDENT, 0, NULL, line, col); + tok_add(&tl, TOK_INDENT, (EigsNum){0}, NULL, line, col); } } else { while (indent_top > 0 && spaces < indent_stack[indent_top]) { indent_top--; - tok_add(&tl, TOK_DEDENT, 0, NULL, line, col); + tok_add(&tl, TOK_DEDENT, (EigsNum){0}, NULL, line, col); } if (spaces != indent_stack[indent_top]) { fprintf(stderr, "Syntax error line %d: indentation does not match any outer level\n", line); @@ -522,7 +522,7 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init if (tl.count > 0 && tl.tokens[tl.count-1].type != TOK_NEWLINE && tl.tokens[tl.count-1].type != TOK_INDENT && tl.tokens[tl.count-1].type != TOK_DEDENT) { - tok_add(&tl, TOK_NEWLINE, 0, NULL, line, col); + tok_add(&tl, TOK_NEWLINE, (EigsNum){0}, NULL, line, col); } at_line_start = 1; } @@ -644,7 +644,7 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init * the post-`}` column sent LSP rename edits onto * the closing quote). */ Token *it = &inner.tokens[ti]; - tok_add(&tl, it->type, it->num_val, it->str_val, it->line, it->col); + tok_add(&tl, it->type, it->number, it->str_val, it->line, it->col); tl.tokens[tl.count - 1].len = it->len; tl.tokens[tl.count - 1].synth = it->synth; } @@ -708,7 +708,7 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init fprintf(stderr, "Syntax error line %d: unterminated string\n", tok_line); lexer_error_at(caret_source, tok_line, tok_col, "unterminated string"); } - tok_add(&tl, TOK_STR, 0, buf.data, tok_line, tok_col); + tok_add(&tl, TOK_STR, (EigsNum){0}, buf.data, tok_line, tok_col); tl.tokens[tl.count - 1].len = (int)(p - str_start); /* true source span */ strbuf_free(&buf); continue; @@ -716,41 +716,58 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init if (isdigit(*p) || (*p == '.' && isdigit(*(p+1)))) { const char *num_start = p; - /* Hex integer literals are lexed HERE, not via strtod: the - * freestanding mini_strtod has no hex path (documented - * divergence — hex used to break on EigenOS), and C99 strtod - * also accepts hex-FLOAT forms (0x1p4, 0xA.8) the language - * does not mean. Digits accumulate in a double, so values - * past 2^53 round exactly like long decimal literals do. */ + /* Hex is parsed here rather than by strtod, whose hex-float + * grammar is wider than ours and absent from mini_strtod. N1: + * accumulate modulo 2^64, then interpret the signed int64 value + * without an implementation-defined uint64-to-int64 cast. */ if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { if (isxdigit((unsigned char)p[2])) { - double num = 0; + uint64_t bits = 0; p += 2; col += 2; while (isxdigit((unsigned char)*p)) { int d = *p <= '9' ? *p - '0' : (*p | 32) - 'a' + 10; - num = num * 16 + d; + bits = bits * UINT64_C(16) + (uint64_t)d; p++; col++; } - tok_add(&tl, TOK_NUM, num, NULL, line, tok_col); + int64_t value = bits <= INT64_MAX ? (int64_t)bits + : -1 - (int64_t)(UINT64_MAX - bits); + EigsNum number = { .is_int = 1, .value.i64 = value }; + tok_add(&tl, TOK_NUM, number, NULL, line, tok_col); tl.tokens[tl.count - 1].len = (int)(p - num_start); continue; } - /* A 0x prefix with no hex digit (bare `0x`, or the - * hex-FLOAT fraction form `0x.8`): lex just the `0` so - * the rest re-lexes as an identifier/dot and the parse - * fails loudly. strtod must NEVER see a hex prefix — - * glibc would parse `0x.8` as 0.5 while mini_strtod - * (no hex) reads 0, a silent profile divergence. */ - tok_add(&tl, TOK_NUM, 0, NULL, line, tok_col); + /* A hex prefix without a digit lexes as `0` followed by + * invalid suffix tokens, on hosted and freestanding builds. */ + EigsNum zero = { .is_int = 1, .value.i64 = 0 }; + tok_add(&tl, TOK_NUM, zero, NULL, line, tok_col); tl.tokens[tl.count - 1].len = 1; p++; col++; continue; } char *end; - double num = strtod(p, &end); + double f = strtod(p, &end); + EigsNum number = { .is_int = 0, .value.f64 = f }; + /* strtod determines the existing decimal grammar/span. Only a + * digits-only token can be an int: `3.0` and `1e3` stay floats. + * Parse the integer independently, so no double rounding occurs + * above 2^53, and fall back to the float on decimal overflow. */ + int64_t integer = 0; + int fits = 1; + for (const char *q = p; q < end; q++) { + if (*q < '0' || *q > '9' || + integer > (INT64_MAX - (*q - '0')) / 10) { + fits = 0; + break; + } + integer = integer * 10 + (*q - '0'); + } + if (fits) { + number.is_int = 1; + number.value.i64 = integer; + } col += (int)(end - p); p = end; - tok_add(&tl, TOK_NUM, num, NULL, line, tok_col); + tok_add(&tl, TOK_NUM, number, NULL, line, tok_col); tl.tokens[tl.count - 1].len = (int)(end - num_start); continue; } @@ -768,7 +785,7 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init col++; } TokType tt = keyword_type(buf.data); - tok_add(&tl, tt, 0, buf.data, line, tok_col); + tok_add(&tl, tt, (EigsNum){0}, buf.data, line, tok_col); strbuf_free(&buf); continue; } @@ -778,7 +795,7 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init TokType op_ty = 0; int op_n = lexer_operator_len(p, &op_ty); if (op_n > 1) { - tok_add(&tl, op_ty, 0, NULL, line, tok_col); + tok_add(&tl, op_ty, (EigsNum){0}, NULL, line, tok_col); p += op_n; col += op_n; continue; @@ -786,32 +803,32 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init } switch (*p) { - case '+': tok_add(&tl, TOK_PLUS, 0, NULL, line, tok_col); p++; col++; break; - case '-': tok_add(&tl, TOK_MINUS, 0, NULL, line, tok_col); p++; col++; break; - case '*': tok_add(&tl, TOK_STAR, 0, NULL, line, tok_col); p++; col++; break; - case '/': tok_add(&tl, TOK_SLASH, 0, NULL, line, tok_col); p++; col++; break; - case '%': tok_add(&tl, TOK_PERCENT, 0, NULL, line, tok_col); p++; col++; break; - case '(': tok_add(&tl, TOK_LPAREN, 0, NULL, line, tok_col); p++; col++; bracket_depth++; break; - case ')': tok_add(&tl, TOK_RPAREN, 0, NULL, line, tok_col); p++; col++; if (bracket_depth > 0) bracket_depth--; break; - case '[': tok_add(&tl, TOK_LBRACKET, 0, NULL, line, tok_col); p++; col++; bracket_depth++; break; - case ']': tok_add(&tl, TOK_RBRACKET, 0, NULL, line, tok_col); p++; col++; if (bracket_depth > 0) bracket_depth--; break; - case '{': tok_add(&tl, TOK_LBRACE, 0, NULL, line, tok_col); p++; col++; bracket_depth++; break; - case '}': tok_add(&tl, TOK_RBRACE, 0, NULL, line, tok_col); p++; col++; if (bracket_depth > 0) bracket_depth--; break; - case ',': tok_add(&tl, TOK_COMMA, 0, NULL, line, tok_col); p++; col++; break; - case ':': tok_add(&tl, TOK_COLON, 0, NULL, line, tok_col); p++; col++; break; - case '.': tok_add(&tl, TOK_DOT, 0, NULL, line, tok_col); p++; col++; break; - case '<': tok_add(&tl, TOK_LT, 0, NULL, line, tok_col); p++; col++; break; - case '>': tok_add(&tl, TOK_GT, 0, NULL, line, tok_col); p++; col++; break; + case '+': tok_add(&tl, TOK_PLUS, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '-': tok_add(&tl, TOK_MINUS, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '*': tok_add(&tl, TOK_STAR, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '/': tok_add(&tl, TOK_SLASH, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '%': tok_add(&tl, TOK_PERCENT, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '(': tok_add(&tl, TOK_LPAREN, (EigsNum){0}, NULL, line, tok_col); p++; col++; bracket_depth++; break; + case ')': tok_add(&tl, TOK_RPAREN, (EigsNum){0}, NULL, line, tok_col); p++; col++; if (bracket_depth > 0) bracket_depth--; break; + case '[': tok_add(&tl, TOK_LBRACKET, (EigsNum){0}, NULL, line, tok_col); p++; col++; bracket_depth++; break; + case ']': tok_add(&tl, TOK_RBRACKET, (EigsNum){0}, NULL, line, tok_col); p++; col++; if (bracket_depth > 0) bracket_depth--; break; + case '{': tok_add(&tl, TOK_LBRACE, (EigsNum){0}, NULL, line, tok_col); p++; col++; bracket_depth++; break; + case '}': tok_add(&tl, TOK_RBRACE, (EigsNum){0}, NULL, line, tok_col); p++; col++; if (bracket_depth > 0) bracket_depth--; break; + case ',': tok_add(&tl, TOK_COMMA, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case ':': tok_add(&tl, TOK_COLON, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '.': tok_add(&tl, TOK_DOT, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '<': tok_add(&tl, TOK_LT, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '>': tok_add(&tl, TOK_GT, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; case '!': fprintf(stderr, "Syntax error line %d: expected '!=' after '!'\n", line); lexer_error_at(caret_source, line, tok_col, "expected '!=' after '!'"); p++; col++; break; - case '=': tok_add(&tl, TOK_ASSIGN, 0, NULL, line, tok_col); p++; col++; break; - case '|': tok_add(&tl, TOK_BITOR, 0, NULL, line, tok_col); p++; col++; break; - case '&': tok_add(&tl, TOK_AMP, 0, NULL, line, tok_col); p++; col++; break; - case '^': tok_add(&tl, TOK_CARET, 0, NULL, line, tok_col); p++; col++; break; - case '~': tok_add(&tl, TOK_TILDE, 0, NULL, line, tok_col); p++; col++; break; + case '=': tok_add(&tl, TOK_ASSIGN, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '|': tok_add(&tl, TOK_BITOR, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '&': tok_add(&tl, TOK_AMP, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '^': tok_add(&tl, TOK_CARET, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; + case '~': tok_add(&tl, TOK_TILDE, (EigsNum){0}, NULL, line, tok_col); p++; col++; break; default: { /* Spell the offending byte, never echo it (#1048). A byte @@ -838,14 +855,14 @@ static TokenList tokenize_at_line(const char *source, int initial_line, int init } while (indent_top > 0) { - tok_add(&tl, TOK_DEDENT, 0, NULL, line, col); + tok_add(&tl, TOK_DEDENT, (EigsNum){0}, NULL, line, col); indent_top--; } if (tl.count > 0 && tl.tokens[tl.count-1].type != TOK_NEWLINE) { - tok_add(&tl, TOK_NEWLINE, 0, NULL, line, col); + tok_add(&tl, TOK_NEWLINE, (EigsNum){0}, NULL, line, col); } - tok_add(&tl, TOK_EOF, 0, NULL, line, col); + tok_add(&tl, TOK_EOF, (EigsNum){0}, NULL, line, col); g_tokenize_depth--; return tl; diff --git a/src/parser.c b/src/parser.c index 2d5933c5b..1cb5a83f3 100644 --- a/src/parser.c +++ b/src/parser.c @@ -804,7 +804,7 @@ static ASTNode* parse_primary(Parser *p) { if (t->type == TOK_NUM) { p_advance(p); ASTNode *n = make_node(AST_NUM, t->line); - n->data.num = t->num_val; + n->data.number = t->number; while (p_cur(p)->type == TOK_LBRACKET) { if (chain_too_deep(p)) break; n = parse_subscript_suffix(p, n); @@ -831,7 +831,7 @@ static ASTNode* parse_primary(Parser *p) { if (t->type == TOK_TRUE || t->type == TOK_FALSE) { /* #1637 */ p_advance(p); ASTNode *b = make_node(AST_BOOL, t->line); - b->data.num = (t->type == TOK_TRUE) ? 1.0 : 0.0; + b->data.boolean = (t->type == TOK_TRUE); return b; } diff --git a/src/trace.c b/src/trace.c index 79f6c2b21..93ebeab5a 100644 --- a/src/trace.c +++ b/src/trace.c @@ -2269,7 +2269,8 @@ static int unescape_string(const char **p, char *out, int out_cap) { * * Recognized shapes: * null | true | false immediates - * strtod-parseable + * exact signed int64, no decimal point + * decimal point or exponent marks its kind * "" escapes per unescape_string * [v, v, …] list * b[num, num, …] buffer (the leading 'b' disambiguates @@ -2406,9 +2407,32 @@ static Value *parse_value_p(const char **p) { * not replayable. Caller falls back to live source. */ if (c == '<' || (unsigned char)c == 0xE2) return NULL; + /* v7: a decimal digit token without a point/exponent is an int. Parse + * its magnitude exactly, including INT64_MIN, without routing through a + * double (9007199254740993 must retain its low bit on replay). */ + const char *digits = *p; + int negative = *digits == '-'; + if (negative) digits++; + const char *end_digits = digits; + while (*end_digits >= '0' && *end_digits <= '9') end_digits++; + if (end_digits != digits && at_token_boundary(*end_digits)) { + uint64_t limit = negative ? UINT64_C(9223372036854775808) + : UINT64_C(9223372036854775807); + uint64_t magnitude = 0; + for (const char *q = digits; q != end_digits; q++) { + unsigned digit = (unsigned)(*q - '0'); + if (magnitude > (limit - digit) / 10) return NULL; + magnitude = magnitude * 10 + digit; + } + int64_t i = negative + ? -(int64_t)(magnitude - (magnitude != 0)) - (magnitude != 0) + : (int64_t)magnitude; + *p = end_digits; + return make_int(i); + } char *end = NULL; double d = strtod(*p, &end); - if (end == *p) return NULL; + if (end == *p || !at_token_boundary(*end)) return NULL; *p = end; return make_num(d); } @@ -2815,15 +2839,36 @@ static void write_string(const char *s) { tp_putc('"'); } +/* Tape float spelling is independent of ordinary display (N6, R1.7). The + * point/exponent is the v7 kind marker: integral floats, including negative + * zero, must never replay as ints. %.17g preserves the exact double bits. */ +static void tape_float_text(char *buf, size_t nbuf, double n) { + snprintf(buf, nbuf, "%.17g", n); + if (isfinite(n) && !strchr(buf, '.') && !strchr(buf, 'e') && !strchr(buf, 'E')) { + size_t used = strlen(buf); + if (used + 2 < nbuf) memcpy(buf + used, ".0", 3); + } +} + +static void write_float(double n) { + char buf[32]; + tape_float_text(buf, sizeof buf, n); + tp_puts(buf); +} + +static void write_int(int64_t n) { + char buf[32]; + eigs_int_text(buf, sizeof buf, n); + tp_puts(buf); +} + /* Format a heap or tracked Value*. Numeric heap values unwrap to their * number; collections show their size for at-a-glance scanning. */ static void write_value_ptr(Value *v) { if (!v) { tp_puts("null"); return; } switch (v->type) { - case VAL_FLOAT: tp_printf("%.17g", VAL_F64_RAW(v)); break; - /* #1758 R1.2a: an int is written as digits by tape v7 (R1.3); a v6 - * tape cannot tell it from a float, so it is refused until then. */ - case VAL_INT: eigs_int_unwired("write_value_ptr", (uint64_t)VAL_I64_RAW(v)); + case VAL_FLOAT: write_float(VAL_F64_RAW(v)); break; + case VAL_INT: write_int(VAL_I64_RAW(v)); break; case VAL_NULL: tp_puts("null"); break; case VAL_STR: write_string(v->data.str); break; case VAL_LIST: tp_printf("", v->data.list.count); break; @@ -2839,14 +2884,11 @@ static void write_value_ptr(Value *v) { } static void write_slot(EigsSlot s) { - if (slot_is_f64(s)) { tp_printf("%.17g", SLOT_F64_RAW(s)); return; } + if (slot_is_f64(s)) { write_float(SLOT_F64_RAW(s)); return; } if (slot_is_null(s)) { tp_puts("null"); return; } if (slot_is_bool(s)) { tp_puts(slot_as_bool(s) ? "true" : "false"); return; } if (slot_is_heap(s)) { write_value_ptr(slot_as_ptr(s)); return; } - /* #1758: an int needs tape v7 (ints as digits, floats marked), which - * lands with the first int value in R1.3; a v6 tape would replay it as a - * float. Any other tag used to be written as ``, unreplayable. */ - if (slot_is_smi(s)) eigs_int_unwired("write_slot", s.u); + if (slot_is_smi(s)) { write_int(slot_smi_val(s)); return; } eigs_slot_refuse("write_slot", s); } @@ -2960,8 +3002,18 @@ static void write_value_ptr_full(Value *v, int *budget) { if (*budget <= 0) return; if (!v) { wf_puts("null", budget); return; } switch (v->type) { - case VAL_FLOAT: wf_printf(budget, "%.17g", VAL_F64_RAW(v)); break; - case VAL_INT: eigs_int_unwired("write_value_ptr_full", (uint64_t)VAL_I64_RAW(v)); /* #1758: tape v7, R1.3 */ + case VAL_FLOAT: { + char buf[32]; + tape_float_text(buf, sizeof buf, VAL_F64_RAW(v)); + wf_puts(buf, budget); + break; + } + case VAL_INT: { + char buf[32]; + eigs_int_text(buf, sizeof buf, VAL_I64_RAW(v)); + wf_puts(buf, budget); + break; + } case VAL_NULL: wf_puts("null", budget); break; case VAL_BOOL: wf_puts(v->data.boolean ? "true" : "false", budget); break; case VAL_STR: write_string_full(v->data.str, budget); break; diff --git a/src/trace.h b/src/trace.h index bac5174b1..ff35bac28 100644 --- a/src/trace.h +++ b/src/trace.h @@ -29,7 +29,7 @@ typedef union { double d_; uint64_t u; } EigsSlot; /* d_: read via SLOT_F64_RA * value serialization, escaping, truncation markers, the header itself. * Replay refuses a tape whose format or runtime version differs from the * running binary: version-and-reject, never migrate (docs/TRACE.md). */ -#define TRACE_FORMAT_VERSION 6 /* v6: true/false are bool values (#1637) */ +#define TRACE_FORMAT_VERSION 7 /* v7: int digits; float tokens retain their kind (#1758) */ #define TRACE_STREAM_KEY_MAX 1024 /* B payload parser shared with the non-executing tape reader. key_hex points diff --git a/src/value_slot.h b/src/value_slot.h index 3b334bada..676138870 100644 --- a/src/value_slot.h +++ b/src/value_slot.h @@ -11,8 +11,7 @@ * 0xFFF8 tag 0 : NULL (payload ignored) * 0xFFF9 tag 1 : BOOL (low bit = value) * 0xFFFA tag 2 : SMI (an int in [-2^47, 2^47): 48-bit two's - * complement payload; #1758. Nothing - * produces one before R1.3) + * complement payload; #1758) * 0xFFFB tag 3 : HEAP pointer (str/list/dict/fn/builtin/buffer/tb) * 0xFFFC tag 4 : reserved (#262 Step E: was TRACKED — removed) * 0xFFFD tag 5 : reserved @@ -63,14 +62,6 @@ typedef union { double d_; uint64_t u; } EigsSlot; /* d_: read via SLOT_F64_RA #define EIGS_SLOT_NORETURN #endif EIGS_SLOT_NORETURN void eigs_slot_refuse(const char *who, EigsSlot s); -/* #1758 R1.1: an int exists as an encoding (the SMI) before any int Value - * kind does (VAL_INT lands in R1.2a, make_int in R1.3). A reader whose int - * arm needs an int Value, the int's ValType or tape v7 calls this instead - * of guessing; nothing produces an int before R1.3, so it never runs. - * R1.3 DELETES it, so every caller stops compiling in the commit that makes - * ints reachable and gets its real arm there (design 2.7). */ -EIGS_SLOT_NORETURN void eigs_int_unwired(const char *who, uint64_t bits); - /* slot_as_ptr refuses a slot that is not a heap pointer in sanitizer builds * and under -DEIGS_SLOT_CHECKED (#1758 R1.1: an SMI must never be read as a * pointer). Release keeps the bare mask: it is on every hot path. */ @@ -82,22 +73,9 @@ EIGS_SLOT_NORETURN void eigs_int_unwired(const char *who, uint64_t bits); # endif #endif -/* #1758 R1.1, the dynamic half of the int-source check: built with - * -DEIGS_SMI_TRAP (`make smi-trap`), every slot classifier below aborts the - * moment it reads an SMI, and slot_from_int aborts on any call. Nothing may - * make an int before R1.3, so the corpus must run on that build exactly as on - * release; a producer that writes the tag bits itself, which no scan of names - * sees, dies at its first reader. R1.3 retires the mode with eigs_int_unwired. - * In every other build SLOT_SMI_TRAP is nothing. */ -#ifdef EIGS_SMI_TRAP -#define SLOT_SMI_TRAP(s) \ - do { \ - if (__builtin_expect(((s).u & SLOT_TAG_MASK) == TAG_SMI, 0)) \ - eigs_slot_refuse("EIGS_SMI_TRAP: an int before #1758 R1.3", (s)); \ - } while (0) -#else +/* #1758 R1.3: the pre-flip source trap is retired now that SMI values are + * valid. Keep its build spelling for through-round gate invocations. */ #define SLOT_SMI_TRAP(s) ((void)0) -#endif /* Predicates */ @@ -145,9 +123,6 @@ static inline EigsSlot slot_from_heap(Value *v); /* #1758: the ONE int writer: an SMI inside [-2^47, 2^47), otherwise an * owned VAL_INT heap box. */ static inline EigsSlot slot_from_int(int64_t i) { -#ifdef EIGS_SMI_TRAP - eigs_int_unwired("slot_from_int under EIGS_SMI_TRAP", (uint64_t)i); -#endif if (__builtin_expect(i < SLOT_SMI_MIN || i > SLOT_SMI_MAX, 0)) return slot_from_heap(make_int(i)); EigsSlot s; s.u = TAG_SMI | ((uint64_t)i & SLOT_PAYLOAD_MASK); return s; diff --git a/src/vm.c b/src/vm.c index f01e59f59..8580ff217 100644 --- a/src/vm.c +++ b/src/vm.c @@ -3188,6 +3188,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, static void *dispatch_table[OP_COUNT] = { [OP_CONST] = &&lbl_CONST, [OP_NULL] = &&lbl_NULL, [OP_NUM_ZERO] = &&lbl_NUM_ZERO, [OP_NUM_ONE] = &&lbl_NUM_ONE, + [OP_INT_ZERO] = &&lbl_INT_ZERO, [OP_INT_ONE] = &&lbl_INT_ONE, + [OP_INT_CONST] = &&lbl_INT_CONST, [OP_TRUE] = &&lbl_TRUE, [OP_FALSE] = &&lbl_FALSE, [OP_ADD] = &&lbl_ADD, [OP_SUB] = &&lbl_SUB, [OP_MUL] = &&lbl_MUL, [OP_DIV] = &&lbl_DIV, [OP_MOD] = &&lbl_MOD, @@ -3346,6 +3348,23 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, DISPATCH(); } + CASE(INT_ZERO): { + vm_push_slot(slot_from_int(0)); + DISPATCH(); + } + CASE(INT_ONE): { + vm_push_slot(slot_from_int(1)); + DISPATCH(); + } + CASE(INT_CONST): { + uint16_t idx = read_u16(ip); ip += 2; + Value *v = chunk->constants[idx]; + int64_t i = VAL_I64_RAW(v); /* verifier: OP_INT_CONST requires VAL_INT */ + if (i >= SLOT_SMI_MIN && i <= SLOT_SMI_MAX) vm_push_slot(slot_from_int(i)); + else { val_incref(v); vm_push(v); } + DISPATCH(); + } + CASE(NULL): { vm_push_slot(slot_null()); DISPATCH(); diff --git a/src/vm.h b/src/vm.h index 50d19863d..c9e6941b0 100644 --- a/src/vm.h +++ b/src/vm.h @@ -222,6 +222,11 @@ typedef enum { * Appended to preserve the public bytecode ABI. */ OP_TRUE, /*obs:NONE*/ /* #1637: push the bool true immediate. Appended. */ OP_FALSE, /*obs:NONE*/ /* #1637: push the bool false immediate. Appended. */ + /* #1758 R1.3: int literal opcodes append to preserve the bytecode ABI. + * The float literal opcodes above retain their original meanings. */ + OP_INT_ZERO, /*obs:NONE*/ /* push int 0 */ + OP_INT_ONE, /*obs:NONE*/ /* push int 1 */ + OP_INT_CONST, /*obs:NONE*/ /* [idx:16] push int constant pool entry */ OP_COUNT /* sentinel — number of opcodes */ } OpCode; diff --git a/tests/jit_env_flags_float.eigs b/tests/jit_env_flags_float.eigs new file mode 100644 index 000000000..340e51635 --- /dev/null +++ b/tests/jit_env_flags_float.eigs @@ -0,0 +1,8 @@ +# R1.3: native env-flag witnesses use explicit float literals until the +# JIT int fast-path round. Keep cost benchmarks unchanged. +i is 0.0 +total is 0.0 +loop while i < 20000.0: + total is total + i + i is i + 1.0 +print of total diff --git a/tests/line_after_callback_halt.eigs b/tests/line_after_callback_halt.eigs index 077987bfa..5f57dcbfb 100644 --- a/tests/line_after_callback_halt.eigs +++ b/tests/line_after_callback_halt.eigs @@ -3,13 +3,13 @@ # error-halts (sandbox_run swallows the error), then sqrt raises in hot_sb's # own expression on line 9. Pre-fix: "Error line 77: sqrt: ..." and # "at hot_sb (line 77)". LINE-NUMBER SENSITIVE ([0g] greps these numbers). -ok77 is [1, [68,77,0,0,0, 3, 40], []] -halt77 is [1, [68,77,0,0,0, 3, 2, 7, 40], []] +ok77 is [1.0, [68.0,77.0,0.0,0.0,0.0, 3.0, 40.0], []] +halt77 is [1.0, [68.0,77.0,0.0,0.0,0.0, 3.0, 2.0, 7.0, 40.0], []] define hot_sb(d, k) as: - r is sqrt of (k - (len of (sandbox_run of [d, 100]))) + r is sqrt of (k - (len of (sandbox_run of [d, 100.0]))) return r -k is 60 -loop while k > 1: +k is 60.0 +loop while k > 1.0: w is hot_sb of [ok77, k] - k is k - 1 -w is hot_sb of [halt77, 1] + k is k - 1.0 +w is hot_sb of [halt77, 1.0] diff --git a/tests/line_after_callback_tape.eigs b/tests/line_after_callback_tape.eigs index a599856e4..e4cdc5cbf 100644 --- a/tests/line_after_callback_tape.eigs +++ b/tests/line_after_callback_tape.eigs @@ -5,13 +5,13 @@ # the statement's line 15. [0g] steps the tape: after the last stop at line 9 # the next stop must be 15. LINE-NUMBER SENSITIVE. define key(v) as: - w is 0 - v + w is 0.0 - v return w define mk(n) as: - q is [[n, 2], key] + q is [[n, 2.0], key] return q -k is 60 -loop while k > 0: +k is 60.0 +loop while k > 0.0: x is len of (sort_by of (mk of k)) - k is k - 1 -print of (what is x at 15) + k is k - 1.0 +print of (what is x at 15.0) diff --git a/tests/line_after_return_fn.eigs b/tests/line_after_return_fn.eigs index 8ee4903e5..4474d93ad 100644 --- a/tests/line_after_return_fn.eigs +++ b/tests/line_after_return_fn.eigs @@ -4,13 +4,13 @@ # Pre-fix: "Error line 8" and "at outer (line 8)". # LINE-NUMBER SENSITIVE (the [0g] runner section greps these numbers). define dec(x) as: - y is x - 1 + y is x - 1.0 return y define outer(x) as: - q is x + 1 - r is 1 / (dec of x) + q is x + 1.0 + r is 1.0 / (dec of x) return r -k is 6001 -loop while k > 0: +k is 6001.0 +loop while k > 0.0: w is outer of k - k is k - 1 + k is k - 1.0 diff --git a/tests/line_after_return_module.eigs b/tests/line_after_return_module.eigs index c2111239b..88e54a7c4 100644 --- a/tests/line_after_return_module.eigs +++ b/tests/line_after_return_module.eigs @@ -3,9 +3,9 @@ # last iteration. Pre-fix: "Error line 7" and "at (line 7)". # LINE-NUMBER SENSITIVE (the [0g] runner section greps these numbers). define dec(x) as: - y is x - 1 + y is x - 1.0 return y -k is 6001 -loop while k > 0: - r is 1 / (dec of k) - k is k - 1 +k is 6001.0 +loop while k > 0.0: + r is 1.0 / (dec of k) + k is k - 1.0 diff --git a/tests/line_after_return_null.eigs b/tests/line_after_return_null.eigs index 2e42a9186..891c7b5b6 100644 --- a/tests/line_after_return_null.eigs +++ b/tests/line_after_return_null.eigs @@ -7,14 +7,14 @@ define nothing(x) as: y is x define one(x) as: y is x - return 1 + return 1.0 define hot_null(g, x) as: - q is x + 1 + q is x + 1.0 r is x / (g of x) return r -k is 0 -loop while k < 6000: +k is 0.0 +loop while k < 6000.0: w is nothing of k w is hot_null of [one, k] - k is k + 1 -w is hot_null of [nothing, 4] + k is k + 1.0 +w is hot_null of [nothing, 4.0] diff --git a/tests/phase2/calib/cal.osr-fill-plant.out b/tests/phase2/calib/cal.osr-fill-plant.out index 4600611f9..bc522ed18 100644 --- a/tests/phase2/calib/cal.osr-fill-plant.out +++ b/tests/phase2/calib/cal.osr-fill-plant.out @@ -1,2 +1,2 @@ -[9007199254740992, 9007199254740992, 9007199254740992, 9007199254740992] +[9007199254740993, 9007199254740993, 9007199254740993, 9007199254740993] value diff --git a/tests/phase2/calib/cal.osr-fill.out b/tests/phase2/calib/cal.osr-fill.out index 4600611f9..bc522ed18 100644 --- a/tests/phase2/calib/cal.osr-fill.out +++ b/tests/phase2/calib/cal.osr-fill.out @@ -1,2 +1,2 @@ -[9007199254740992, 9007199254740992, 9007199254740992, 9007199254740992] +[9007199254740993, 9007199254740993, 9007199254740993, 9007199254740993] value diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index 31904abcb..f1187b186 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -1,7 +1,7 @@ /* tests/phase2/slot_layer.c -- #1758 R1.1, the C slot test (design 2.5). * - * Nothing in the runtime produces an SMI before R1.3, so no program can show - * what a slot reader does with one. This test builds SMI slots BY HAND (the + * The classifier matrix exercises canonical and non-canonical states directly. + * This test builds SMI slots BY HAND (the * literal tag 0xFFFA, never slot_from_int) and drives every slot classifier * whose first parameter is an EigsSlot -- the population * `tools/phase2_inventory.py --slot-population` derives -- with the SMI @@ -12,8 +12,7 @@ * A every population entry x every SMI boundary value. An entry either * RETURNS the int's answer (its truthiness, type name, double, digits, * the slot unchanged), or ABORTS through a named refusal: the permanent - * ones (eigs_slot_refuse) and the R1.1 placeholders whose int arm needs - * the int Value kind (eigs_int_unwired, deleted in R1.3). An abort runs + * reference-reader refusals (eigs_slot_refuse). An abort runs * in a forked child, and its FATAL line must name the expected reader. * B every population entry x twelve slot kinds: a double, the canonical * NaN, -0.0, null, both bools, an SMI, a heap pointer, the reserved @@ -190,7 +189,14 @@ static int r_slot_to_value(int64_t v) { int bad = !got || got->type != VAL_INT || VAL_I64_RAW(got) != v; val_decref(got); return bad; } -static void a_write_slot(EigsSlot s) { write_slot(s); } +static int r_write_slot(int64_t v) { + size_t before = g_out_len; + write_slot(smi(v)); + char want[32], got[32]; + snprintf(want, sizeof want, "%lld", (long long)v); + snprintf(got, sizeof got, "%.*s", (int)(g_out_len - before), g_out + before); + return strcmp(want, got) != 0; +} static int r_slot_bridge_unwrap(int64_t v) { Value *got = slot_bridge_unwrap(smi(v)); int bad = !got || got->type != VAL_INT || VAL_I64_RAW(got) != v; @@ -255,7 +261,7 @@ static const Entry ENTRIES[] = { {"container.h:slot_type", r_slot_type, 0, 0, "VAL_INT"}, {"container.h:slot_view", r_slot_view, 0, 0, "exact VAL_INT facade"}, {"eigenscript.c:slot_to_value", r_slot_to_value, 0, 0, "exact owned VAL_INT"}, - {"trace.c:write_slot", 0, a_write_slot, "write_slot", "unwired: tape v7 (R1.3)"}, + {"trace.c:write_slot", r_write_slot, 0, 0, "v7 exact int digits"}, {"vm.c:obs_slot_observable", 0, a_obs_slot_observable, "obs_slot_observable", "refuse"}, {"vm.c:slot_bridge_unwrap", r_slot_bridge_unwrap, 0, 0, "exact owned VAL_INT"}, {"container.h:eigs_slot_ref", 0, a_eigs_slot_ref, "eigs_slot_ref", "refuse"}, @@ -435,11 +441,12 @@ EXP(store_json) { static char g_heap_tape[64]; /* what the tape writer prints for g_str */ EXP(write_slot) { switch (kclass(k)) { - case C_F64: snprintf(b, n, "w:%.17g", KD(k)); break; + case C_F64: snprintf(b, n, "w:%s", k == K_NAN ? "nan" : k == K_NZ ? "-0.0" : "1.5"); break; + case C_SMI: snprintf(b, n, "w:5"); break; case C_NULL: snprintf(b, n, "w:null"); break; case C_BOOL: snprintf(b, n, "w:%s", k == K_TRUE ? "true" : "false"); break; case C_HEAP: snprintf(b, n, "w:%s", g_heap_tape); break; - default: ABORT("write_slot"); /* an SMI: tape v7 is R1.3's; a reserved tag refuses */ + default: ABORT("write_slot"); /* a reserved tag refuses */ } } EXP(f64_value) { @@ -761,6 +768,7 @@ static const Arm ARMS[] = { {"bnot", "~(xs[0])", "-6", "-6", 0}, {"eq", "xs[0] == 5", "true", "true", 0}, {"add", "xs[0] + 1", "6", "6", 0}, + {"overflow_add", "9223372036854775807 + xs[0]", "9.223372036854776e+18", "value", 1}, }; #define N_ARMS ((int)(sizeof ARMS / sizeof ARMS[0])) static const Arm *g_arm; @@ -769,7 +777,7 @@ static void c_arm(EigsSlot s, char *b, size_t n) { char prog[512]; if (g_arm->in_try) snprintf(prog, sizeof prog, "xs is [7.5]\nphase2_poke of ([xs])\ntry:\n print of (%s)\n" - "catch e:\n print of \"caught\"\n", g_arm->expr); + "catch e:\n print of e.kind\n", g_arm->expr); else snprintf(prog, sizeof prog, "xs is [7.5]\nphase2_poke of ([xs])\nprint of (%s)\n", g_arm->expr); EigsValue *r = eigs_eval_string(prog); diff --git a/tests/roads/native_alternate.eigs b/tests/roads/native_alternate.eigs index 422afbc35..95c141942 100644 --- a/tests/roads/native_alternate.eigs +++ b/tests/roads/native_alternate.eigs @@ -1,13 +1,13 @@ # road-bind: v total # road-native: required -v is 100 -total is 0 -for i in range of 1200: - if i % 2 == 0: - local v is 10 - j is 0 - loop while j < 12: - v is v + 1 +v is 100.0 +total is 0.0 +for i in range of 1200.0: + if i % 2.0 == 0.0: + local v is 10.0 + j is 0.0 + loop while j < 12.0: + v is v + 1.0 total is total + v - j is j + 1 + j is j + 1.0 print of [v, total] diff --git a/tests/roads/native_catch.eigs b/tests/roads/native_catch.eigs index 811943c1a..750d301e1 100644 --- a/tests/roads/native_catch.eigs +++ b/tests/roads/native_catch.eigs @@ -1,14 +1,14 @@ # road-bind: v total # road-native: required -v is 100 -total is 0 -for i in range of 1200: +v is 100.0 +total is 0.0 +for i in range of 1200.0: try: - throw of 10 + throw of 10.0 catch v: - k is 0 - loop while k < 12: - v is v + 1 + k is 0.0 + loop while k < 12.0: + v is v + 1.0 total is total + v - k is k + 1 + k is k + 1.0 print of [v, total] diff --git a/tests/roads/native_inline.eigs b/tests/roads/native_inline.eigs index 473b53533..c2bbdc480 100644 --- a/tests/roads/native_inline.eigs +++ b/tests/roads/native_inline.eigs @@ -1,11 +1,11 @@ # road-bind: v # road-native: required -v is 100 -for i in [1]: - j is 0 - loop while j < 20000: - if j == 15000: - eval of "local v is 10" +v is 100.0 +for i in [1.0]: + j is 0.0 + loop while j < 20000.0: + if j == 15000.0: + eval of "local v is 10.0" v is j - j is j + 1 + j is j + 1.0 print of v diff --git a/tests/roads/native_late.eigs b/tests/roads/native_late.eigs index fb728a2b5..d7f0fbace 100644 --- a/tests/roads/native_late.eigs +++ b/tests/roads/native_late.eigs @@ -1,13 +1,13 @@ # road-bind: v total # road-native: required -v is 100 -total is 0 -for i in range of 1200: - if i > 500: - local v is 10 - j is 0 - loop while j < 12: - v is v + 1 +v is 100.0 +total is 0.0 +for i in range of 1200.0: + if i > 500.0: + local v is 10.0 + j is 0.0 + loop while j < 12.0: + v is v + 1.0 total is total + v - j is j + 1 + j is j + 1.0 print of [v, total] diff --git a/tests/roads/native_match.eigs b/tests/roads/native_match.eigs index d1f97d3fd..6492c6b55 100644 --- a/tests/roads/native_match.eigs +++ b/tests/roads/native_match.eigs @@ -1,14 +1,14 @@ # road-bind: v total # road-native: required -v is 100 -total is 0 -for i in range of 1200: - local v is 10 - match 10: +v is 100.0 +total is 0.0 +for i in range of 1200.0: + local v is 10.0 + match 10.0: case v: - k is 0 - loop while k < 12: - v is v + 1 + k is 0.0 + loop while k < 12.0: + v is v + 1.0 total is total + v - k is k + 1 + k is k + 1.0 print of [v, total] diff --git a/tests/roads/native_outer.eigs b/tests/roads/native_outer.eigs index c63abc7c8..60ac5381a 100644 --- a/tests/roads/native_outer.eigs +++ b/tests/roads/native_outer.eigs @@ -1,14 +1,14 @@ # road-bind: v total # road-native: required -v is 100 -total is 0 -for i in range of 1200: - if i % 2 == 0: - local v is 10 - for b in [0, 1]: - k is 0 - loop while k < 12: - v is v + 1 +v is 100.0 +total is 0.0 +for i in range of 1200.0: + if i % 2.0 == 0.0: + local v is 10.0 + for b in [0.0, 1.0]: + k is 0.0 + loop while k < 12.0: + v is v + 1.0 total is total + v - k is k + 1 + k is k + 1.0 print of [v, total] diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh index d4bc61bd3..f1d1fbabb 100755 --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -599,7 +599,7 @@ else # follows the store). EL_LIVE=$(sed -n 's/^LIVE: errline_1434=2 line \([0-9]*\)$/\1/p' <<< "$ERRLINE_OUT") EL_STEP=$(printf 'j 95\nt errline_1434\nq\n' | $EIGS_TMO ./eigenscript --step "$EL_TAPE" 2>&1 | - sed -n 's/^ #[0-9]* *line \([0-9]*\) *2 .*/\1/p') + sed -n 's/^ #[0-9]* *line \([0-9]*\) *2[.]0 .*/\1/p') rm -f "$EL_TAPE" TOTAL=$((TOTAL + 1)) if [ -n "$EL_LIVE" ] && [ "$EL_LIVE" = "$EL_STEP" ]; then diff --git a/tests/sections/0f5-trace-context.sh b/tests/sections/0f5-trace-context.sh index f67da13f0..5616c6fd9 100644 --- a/tests/sections/0f5-trace-context.sh +++ b/tests/sections/0f5-trace-context.sh @@ -2,7 +2,7 @@ echo "[0f5] Owned replay contexts and explicit host session advance (#1286)" check_binary_fingerprint TOTAL=$((TOTAL + 1)) TRACE_CONTEXT_OUT=$(bash "$TESTS_DIR/test_trace_context.sh" 2>&1); TRACE_CONTEXT_RC=$? -if rc_ok "$TRACE_CONTEXT_RC" "$TRACE_CONTEXT_OUT" && grep -qx 'trace context: 44 passed, 0 failed (44 declared)' <<< "$TRACE_CONTEXT_OUT"; then +if rc_ok "$TRACE_CONTEXT_RC" "$TRACE_CONTEXT_OUT" && grep -qx 'trace context: 53 passed, 0 failed (53 declared)' <<< "$TRACE_CONTEXT_OUT"; then PASS=$((PASS + 1)); echo " PASS: replay source/session ownership" else FAIL=$((FAIL + 1)); echo " FAIL: stream context contract (rc=$TRACE_CONTEXT_RC)" diff --git a/tests/sections/0fb-bool-type.sh b/tests/sections/0fb-bool-type.sh index caf0bed2b..2d8b12d58 100644 --- a/tests/sections/0fb-bool-type.sh +++ b/tests/sections/0fb-bool-type.sh @@ -66,16 +66,16 @@ if [ "$BOOL_TP_RC" = 0 ] && [ "$BOOL_TP_REC" = '[true, "bool", false]' ] && else FAIL=$((FAIL + 1)); echo " FAIL: a recorded bool replays as a bool (rc=$BOOL_TP_RC rec='$BOOL_TP_REC' rep='$BOOL_TP_REP')" fi -sed '1s/^V 6 /V 5 /' "$BOOL_TP_DIR/p.tape" > "$BOOL_TP_DIR/p5.tape" +sed '1s/^V 7 /V 5 /' "$BOOL_TP_DIR/p.tape" > "$BOOL_TP_DIR/p5.tape" BOOL_TP_OUT=$(EIGS_REPLAY="$BOOL_TP_DIR/p5.tape" $EIGS_TMO ./eigenscript "$BOOL_TP_DIR/p.eigs" &1); BOOL_TP_RC=$? TOTAL=$((TOTAL + 1)) -if [ "$BOOL_TP_RC" = 3 ] && grep -q "tape format v5, this binary reads v6" <<< "$BOOL_TP_OUT"; then +if [ "$BOOL_TP_RC" = 3 ] && grep -q "tape format v5, this binary reads v7" <<< "$BOOL_TP_OUT"; then PASS=$((PASS + 1)); echo " PASS: a v5 (pre-bool) tape is refused with exit 3" else FAIL=$((FAIL + 1)); echo " FAIL: a v5 (pre-bool) tape is refused with exit 3 (rc=$BOOL_TP_RC)" printf '%s\n' "$BOOL_TP_OUT" | eigs_failure_output fi -# Tamper: a v6 tape whose bool record was hand-edited to a number (and a +# Tamper: a v7 tape whose bool record was hand-edited to a number (and a # number record edited to a bool) is refused with exit 3, naming the builtin, # the record and the tape version -- never replayed as the other kind. printf 'x is file_exists of "%s"\nr is random of null\nn is random_normal of [2, 1.0]\nprint of [x, type of x, type of r, type of n]\n' \ @@ -90,7 +90,7 @@ for BOOL_TP_CASE in "t1:file_exists returns a bool, the tape holds a num" "t2:ra BOOL_TP_T=${BOOL_TP_CASE%%:*}; BOOL_TP_WANT=${BOOL_TP_CASE#*:} BOOL_TP_OUT=$(EIGS_REPLAY="$BOOL_TP_DIR/$BOOL_TP_T.tape" $EIGS_TMO ./eigenscript "$BOOL_TP_DIR/t.eigs" &1); BOOL_TP_RC=$? if ! cmp -s "$BOOL_TP_DIR/t.tape" "$BOOL_TP_DIR/$BOOL_TP_T.tape" && [ "$BOOL_TP_RC" = 3 ] && - grep -q "tape format v6 record 'N [0-9]* .*': $BOOL_TP_WANT; refusing to replay" <<< "$BOOL_TP_OUT"; then + grep -q "tape format v7 record 'N [0-9]* .*': $BOOL_TP_WANT; refusing to replay" <<< "$BOOL_TP_OUT"; then PASS=$((PASS + 1)); echo " PASS: a tampered tape is refused: $BOOL_TP_WANT" else FAIL=$((FAIL + 1)); echo " FAIL: a tampered tape is refused: $BOOL_TP_WANT (rc=$BOOL_TP_RC)" diff --git a/tests/strict_shape_descriptor.c b/tests/strict_shape_descriptor.c index 653b7317d..29ed5eb36 100644 --- a/tests/strict_shape_descriptor.c +++ b/tests/strict_shape_descriptor.c @@ -7,7 +7,7 @@ #include "vm.h" int main(void) { - const char *source = "return 42\n"; + const char *source = "return 42.0\n"; EigsState *state = eigs_open(); if (!state) return 1; TokenList tokens = tokenize(source); diff --git a/tests/test_bitwise.eigs b/tests/test_bitwise.eigs index 767cb3968..233e1a005 100644 --- a/tests/test_bitwise.eigs +++ b/tests/test_bitwise.eigs @@ -181,12 +181,14 @@ assert_eq of [bw_raise of ["bit_shr", 1, big], "value", "bit_shr of [1, 1e30] ra assert_eq of [bw_raise of ["bit_not", 1.5, 0], "value", "bit_not of 1.5 raises value"] assert_eq of [bw_raise of ["bit_not", 9223372036854775808, 0], "value", "bit_not of 2^63 raises value"] # Exact integers at the edges stay valid, unchanged from #1739. -int64_min is -9223372036854775808 +int64_min is -9223372036854775808.0 assert_eq of [bw_raise of ["|", int64_min, 0], "no raise", "-2^63 | 0 is valid"] assert_eq of [int64_min | 0, int64_min, "-2^63 | 0 returns itself"] assert_eq of [bit_or of [int64_min, 0], int64_min, "bit_or of [-2^63, 0] returns itself"] assert_eq of [9223372036854774784 | 0, 9223372036854774784, "largest double below 2^63 is valid"] -assert_eq of [~int64_min, 9223372036854775807, "~(-2^63) is INT64_MAX"] +# R1.3: bitwise results remain floats until N8 (R1.5); N2 compares the +# rounded float result exactly, so its expected value is explicitly float. +assert_eq of [~int64_min, 9223372036854775808.0, "~(-2^63) retains the transitional float result"] assert_eq of [(0 - 0) | 0, 0, "zero is valid"] assert_eq of [(0 - 1) << 1, 0 - 2, "SHL of a negative is defined (unsigned shift)"] assert_eq of [bit_shl of [0 - 1, 1], (0 - 1) << 1, "bit_shl matches infix on a negative"] diff --git a/tests/test_env_flags.sh b/tests/test_env_flags.sh index 5f342606a..c956de700 100755 --- a/tests/test_env_flags.sh +++ b/tests/test_env_flags.sh @@ -9,7 +9,7 @@ set -u TESTS_DIR="$(cd "$(dirname "$0")" && pwd)" EIGS="$TESTS_DIR/../src/eigenscript" -PROG="$TESTS_DIR/bench_idxset.eigs" +PROG="$TESTS_DIR/jit_env_flags_float.eigs" compiled() { env "$@" EIGS_JIT_STATS=1 "$EIGS" "$PROG" 2>&1 >/dev/null | grep -o 'compiled=[0-9]*' | head -1; } c_on=$(compiled -u EIGS_JIT_OFF) c_zero=$(compiled EIGS_JIT_OFF=0) diff --git a/tests/test_error_line_fallback.c b/tests/test_error_line_fallback.c index 48124e83c..8e4059890 100644 --- a/tests/test_error_line_fallback.c +++ b/tests/test_error_line_fallback.c @@ -111,8 +111,8 @@ int main(void) { * 6001 calls make it hot for the JIT. The last element returns a string, * so sort_by raises after its final callback. */ EigsValue *defs = eigs_eval_string( - "define ekey(x) as:\n y is 0\n i is 0\n loop while i < 3:\n" - " y is y + x\n i is i + 1\n if x < 0:\n" + "define ekey(x) as:\n y is 0.0\n i is 0.0\n loop while i < 3.0:\n" + " y is y + x\n i is i + 1.0\n if x < 0.0:\n" " return \"s\"\n return y\n"); if (defs) eigs_value_release(defs); Value *ekey = eigs_get_global("ekey"); diff --git a/tests/test_halting_descent.eigs b/tests/test_halting_descent.eigs index bf1953b01..0b554693e 100644 --- a/tests/test_halting_descent.eigs +++ b/tests/test_halting_descent.eigs @@ -8,12 +8,12 @@ print of "--- HD1: bare-predicate loop around a runaway exits via STALL ---" # honest exit reason. counter is 0 -x is 10 -x is 10 +x is 10.0 +x is 10.0 loop while not converged: counter is counter + 1 - x is x * 2 + x is x * 2.0 print of counter print of report of x diff --git a/tests/test_jit_andor_leak.eigs b/tests/test_jit_andor_leak.eigs index 050612544..8839f5ab4 100644 --- a/tests/test_jit_andor_leak.eigs +++ b/tests/test_jit_andor_leak.eigs @@ -6,17 +6,17 @@ # Run well past the OSR threshold so the JIT thunk is exercised; the ASan leak # gate (run_all_tests.sh under detect_leaks=1) catches a regression. h is "a-heap-string" -i is 0 -acc is 0 -loop while i < 12000: +i is 0.0 +acc is 0.0 +loop while i < 12000.0: r is h and i acc is acc + r - i is i + 1 + i is i + 1.0 # also exercise `or` with a heap left operand that short-circuits (truthy -> returns h) -j is 0 -loop while j < 12000: +j is 0.0 +loop while j < 12000.0: s is h or j - j is j + 1 + j is j + 1.0 print of "jit-and-or-ok" diff --git a/tests/test_jit_cycle_root.eigs b/tests/test_jit_cycle_root.eigs index 031349180..3d2bbb13b 100644 --- a/tests/test_jit_cycle_root.eigs +++ b/tests/test_jit_cycle_root.eigs @@ -17,34 +17,34 @@ define mk() as: return l define churn() as: - local i is 0 - loop while i < 1200: + local i is 0.0 + loop while i < 1200.0: local t is mk of [] - t is 0 - i is i + 1 - return 0 + t is 0.0 + i is i + 1.0 + return 0.0 define spin(c) as: churn of [] - local i is 0 - local dropped is 0 - loop while i < 6000: - if i == 5990: - c is 0 - dropped is 1 - i is i + 1 + local i is 0.0 + local dropped is 0.0 + loop while i < 6000.0: + if i == 5990.0: + c is 0.0 + dropped is 1.0 + i is i + 1.0 return dropped -checks is 0 -passed is 0 +checks is 0.0 +passed is 0.0 define check(label, got, want) as: - checks is checks + 1 + checks is checks + 1.0 if got == want: - passed is passed + 1 + passed is passed + 1.0 else: print of ("MISMATCH " + label + ": got=" + str of got + " want=" + str of want) -check of ["native drop executed", spin of (mk of []), 1] +check of ["native drop executed", spin of (mk of []), 1.0] if passed == checks: print of "All tests passed" diff --git a/tests/test_jit_hot_osr.eigs b/tests/test_jit_hot_osr.eigs index 8ad9bbe4c..de4d6cb65 100644 --- a/tests/test_jit_hot_osr.eigs +++ b/tests/test_jit_hot_osr.eigs @@ -1,7 +1,7 @@ # One frame entry with enough loop back-edges to enter an OSR thunk. The # EIGS_JIT_HOT suite row derives the expected aggregate from this chunk's row. -i is 0 -total is 0 -loop while i < 20000: +i is 0.0 +total is 0.0 +loop while i < 20000.0: total is total + i - i is i + 1 + i is i + 1.0 diff --git a/tests/test_jit_paths.eigs b/tests/test_jit_paths.eigs index 54c50a5ce..e6ba9c740 100644 --- a/tests/test_jit_paths.eigs +++ b/tests/test_jit_paths.eigs @@ -12,16 +12,16 @@ # The suite runs this file with EIGS_JIT_STATS=1 and (on x86-64) asserts # compiled > 0, so it cannot silently pass interpreted. -pass_count is 0 -fail_count is 0 +pass_count is 0.0 +fail_count is 0.0 define check(args) as: - label is args[0] - cond is args[1] + label is args[0.0] + cond is args[1.0] if cond: - pass_count is pass_count + 1 + pass_count is pass_count + 1.0 else: - fail_count is fail_count + 1 + fail_count is fail_count + 1.0 print of ("FAIL: " + label) # ---------------------------------------------------------------- @@ -31,109 +31,109 @@ define check(args) as: # the entry and cumulative-iteration thresholds. # ---------------------------------------------------------------- define fused_regs(seed) as: - regs is [{"a": seed, "b": 0}, {"a": 0, "b": 0}] - k is 0 - loop while k < 80: - regs[0].a is regs[0].a + 1 - regs[1].b is regs[1].b + regs[0].a - regs[1].a is regs[0].a & 255 - k is k + 1 - return regs[1].b + regs[1].a + regs is [{"a": seed, "b": 0.0}, {"a": 0.0, "b": 0.0}] + k is 0.0 + loop while k < 80.0: + regs[0.0].a is regs[0.0].a + 1.0 + regs[1.0].b is regs[1.0].b + regs[0.0].a + regs[1.0].a is regs[0.0].a & 255.0 + k is k + 1.0 + return regs[1.0].b + regs[1.0].a # 80 calls x 80 iterations: the chunk's from-zero thunk stops at the # dict/list literals, so the fused ops only run natively via the loop's # OSR thunk — 6400 cumulative back-edges crosses the 5000 OSR threshold. -fr_total is 0 -n is 0 -loop while n < 80: - fr_total is fr_total + (fused_regs of (n % 4)) - n is n + 1 +fr_total is 0.0 +n is 0.0 +loop while n < 80.0: + fr_total is fr_total + (fused_regs of (n % 4.0)) + n is n + 1.0 # per call with seed s: regs[1].b = 80s + 3240, regs[1].a = s + 80, # so 81s + 3320; seeds cycle 0..3, 20 calls each: 20*(81*6 + 4*3320) -check of ["fused local[idx].field checksum", fr_total == 275320] +check of ["fused local[idx].field checksum", fr_total == 275320.0] # ---------------------------------------------------------------- # 2) Dict-dot get/set through the 2-way inline cache (bench_dmg_shape # op-handler shape: mutate fields of a dict parameter). # ---------------------------------------------------------------- define op_inc(c) as: - c.a is c.a + 1 - c.cycles is c.cycles + 4 - return 4 + c.a is c.a + 1.0 + c.cycles is c.cycles + 4.0 + return 4.0 define op_mix(c) as: - c.b is (c.b ^ c.a) & 255 - c.cycles is c.cycles + 8 - return 8 + c.b is (c.b ^ c.a) & 255.0 + c.cycles is c.cycles + 8.0 + return 8.0 -ctx is {"a": 0, "b": 0, "cycles": 0} -n is 0 +ctx is {"a": 0.0, "b": 0.0, "cycles": 0.0} +n is 0.0 unobserved: - loop while n < 600: + loop while n < 600.0: r1 is op_inc of ctx r2 is op_mix of ctx - n is n + 1 -check of ["dict-dot IC a", ctx.a == 600] -check of ["dict-dot IC cycles", ctx.cycles == 7200] -check of ["dict-dot IC b", ctx.b == 88] + n is n + 1.0 +check of ["dict-dot IC a", ctx.a == 600.0] +check of ["dict-dot IC cycles", ctx.cycles == 7200.0] +check of ["dict-dot IC b", ctx.b == 88.0] # Polymorphic dict shapes through the same hot accessor: the 2-way # inline cache must miss, exercising the jit_helper_dot_get/dot_set # out-of-line fallbacks with identical semantics. define poly_bump(c) as: - c.v is c.v + 1 + c.v is c.v + 1.0 return c.v -pa is {"v": 0} -pb is {"pad1": 0, "v": 100} -pc_d is {"pad1": 0, "pad2": 0, "v": 200} -pd is {"pad1": 0, "pad2": 0, "pad3": 0, "v": 300} -n is 0 +pa is {"v": 0.0} +pb is {"pad1": 0.0, "v": 100.0} +pc_d is {"pad1": 0.0, "pad2": 0.0, "v": 200.0} +pd is {"pad1": 0.0, "pad2": 0.0, "pad3": 0.0, "v": 300.0} +n is 0.0 unobserved: - loop while n < 200: + loop while n < 200.0: r1 is poly_bump of pa r2 is poly_bump of pb r3 is poly_bump of pc_d r4 is poly_bump of pd - n is n + 1 -check of ["poly dot IC a", pa.v == 200] -check of ["poly dot IC b", pb.v == 300] -check of ["poly dot IC c", pc_d.v == 400] -check of ["poly dot IC d", pd.v == 500] + n is n + 1.0 +check of ["poly dot IC a", pa.v == 200.0] +check of ["poly dot IC b", pb.v == 300.0] +check of ["poly dot IC c", pc_d.v == 400.0] +check of ["poly dot IC d", pd.v == 500.0] # Dot access on a *global* dict inside a hot fn: the target isn't a # resolvable local slot, so this compiles to plain OP_DOT_GET/DOT_SET — # in a thunk those are the jit_helper_dot_get/dot_set out-of-line calls. -gdict is {"v": 0, "tag": ""} +gdict is {"v": 0.0, "tag": ""} define bump_global(amount) as: - k is 0 - loop while k < 50: + k is 0.0 + loop while k < 50.0: gdict.v is gdict.v + amount - k is k + 1 + k is k + 1.0 return gdict.v -n is 0 -loop while n < 60: - r is bump_global of 1 - n is n + 1 -check of ["global dict dot in thunk", gdict.v == 3000] +n is 0.0 +loop while n < 60.0: + r is bump_global of 1.0 + n is n + 1.0 +check of ["global dict dot in thunk", gdict.v == 3000.0] # Non-num stores through local dot: the inline LOCAL_DOT_SET fast path # only handles in-place num writes, so a string store takes the # jit_helper_local_dot_set slow path every iteration. define tag_local(t) as: d is {"name": ""} - k is 0 - loop while k < 80: + k is 0.0 + loop while k < 80.0: d.name is t + "!" - k is k + 1 + k is k + 1.0 return d.name -n is 0 +n is 0.0 last_tag is "" -loop while n < 80: +loop while n < 80.0: last_tag is tag_local of "z" - n is n + 1 + n is n + 1.0 check of ["local dot string store slow path", last_tag == "z!"] # Num store into a dict slot currently holding a string: the inline @@ -141,20 +141,20 @@ check of ["local dot string store slow path", last_tag == "z!"] # exclusive num, so the first store of each call is a guard miss into # jit_helper_local_dot_set; subsequent iterations re-take the fast path. define renum(d2) as: - k is 0 - loop while k < 60: + k is 0.0 + loop while k < 60.0: d2.x is k - k is k + 1 + k is k + 1.0 return d2.x rd is {"x": "start"} -n is 0 -rlast is 0 -loop while n < 80: +n is 0.0 +rlast is 0.0 +loop while n < 80.0: rd.x is "again" rlast is renum of rd - n is n + 1 -check of ["local dot guard-miss store", rlast == 59] + n is n + 1.0 +check of ["local dot guard-miss store", rlast == 59.0] # #1665 arm D B10: dict values are EigsSlot storage, so the inline # LOCAL_DOT_GET probe pushes the field's slot bits. A 0 field is all-zero @@ -162,156 +162,156 @@ check of ["local dot guard-miss store", rlast == 59] # numbers and must take the helper, and a number store over a number field # is the inline bit store. define dot_mix(z) as: - d is {"zero": 0, "s": "str", "n": null, "t": true, "neg": -0.5} - k is 0 - acc is 0 + d is {"zero": 0.0, "s": "str", "n": null, "t": true, "neg": -0.5} + k is 0.0 + acc is 0.0 seen is "" - loop while k < 80: + loop while k < 80.0: acc is acc + d.zero + d.neg if d.t: seen is d.s if d.n == null: - acc is acc + 1 + acc is acc + 1.0 d.zero is d.zero + z - k is k + 1 + k is k + 1.0 return [acc, seen, d.zero] -n is 0 +n is 0.0 dm is null -loop while n < 80: - dm is dot_mix of 1 - n is n + 1 +loop while n < 80.0: + dm is dot_mix of 1.0 + n is n + 1.0 # acc = sum_{k<80} (k - 0.5 + 1) = 3160 + 40 -check of ["local dot slot reads (0 field, ref fields)", dm[0] == 3200 and dm[1] == "str" and dm[2] == 80] +check of ["local dot slot reads (0 field, ref fields)", dm[0.0] == 3200.0 and dm[1.0] == "str" and dm[2.0] == 80.0] # ---------------------------------------------------------------- # 3) Buffer + list index writes in a fn-local loop (bench_idxset # shape: INDEX_SET inline fast path), plus the helper slow path # via non-num stores into list slots. # ---------------------------------------------------------------- -buf is buffer of 256 -lst is [0, 0, 0, 0] +buf is buffer of 256.0 +lst is [0.0, 0.0, 0.0, 0.0] define idx_fill(base) as: - k is 0 - loop while k < 100: - buf[(base + k) % 256] is k - lst[k % 4] is k - k is k + 1 - return lst[3] - -n is 0 -acc is 0 -loop while n < 60: + k is 0.0 + loop while k < 100.0: + buf[(base + k) % 256.0] is k + lst[k % 4.0] is k + k is k + 1.0 + return lst[3.0] + +n is 0.0 +acc is 0.0 +loop while n < 60.0: acc is acc + (idx_fill of n) - n is n + 1 -check of ["idx fill list tail", acc == 60 * 99] + n is n + 1.0 +check of ["idx fill list tail", acc == 60.0 * 99.0] # Fractional stores through the hot inline INDEX_SET path must keep # the full double (the JIT used to round-trip through cvttsd2si, # truncating to int — divergent from buf_set and the double[] storage). -fb is buffer of 8 +fb is buffer of 8.0 define frac_fill(base) as: - k is 0 - loop while k < 80: - fb[k % 8] is base + (k % 8) + 0.5 - k is k + 1 - return fb[3] - -n is 0 -fsum is 0 -loop while n < 60: - fsum is fsum + (frac_fill of 0) - n is n + 1 -check of ["fractional store in thunk", fsum == 60 * 3.5] + k is 0.0 + loop while k < 80.0: + fb[k % 8.0] is base + (k % 8.0) + 0.5 + k is k + 1.0 + return fb[3.0] + +n is 0.0 +fsum is 0.0 +loop while n < 60.0: + fsum is fsum + (frac_fill of 0.0) + n is n + 1.0 +check of ["fractional store in thunk", fsum == 60.0 * 3.5] # Last call ran with base=59, so its final write was buf[(59+99)%256]=99. -check of ["idx fill buffer", buf[158] == 99] +check of ["idx fill buffer", buf[158.0] == 99.0] # Slow path: storing strings (non-num) into list slots in a hot fn. strs is ["", "", "", ""] define str_fill(tag) as: - k is 0 - loop while k < 60: - strs[k % 4] is tag + "!" - k is k + 1 - return strs[1] + k is 0.0 + loop while k < 60.0: + strs[k % 4.0] is tag + "!" + k is k + 1.0 + return strs[1.0] -n is 0 +n is 0.0 last is "" -loop while n < 60: +loop while n < 60.0: last is str_fill of "t" - n is n + 1 + n is n + 1.0 check of ["index_set non-num slow path", last == "t!"] # ---------------------------------------------------------------- # 4) for-in iteration in a hot function (jit_helper_iter_next), # over both a list and a buffer. # ---------------------------------------------------------------- -xs is [1, 2, 3, 4, 5, 6, 7, 8] -bxs is buffer of 8 -k is 0 -loop while k < 8: - bxs[k] is k * 2 - k is k + 1 +xs is [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] +bxs is buffer of 8.0 +k is 0.0 +loop while k < 8.0: + bxs[k] is k * 2.0 + k is k + 1.0 define sum_list(dummy) as: - s is 0 + s is 0.0 for v in xs: s is s + v return s define sum_buf(dummy) as: - s is 0 + s is 0.0 for v in bxs: s is s + v return s -n is 0 -sl is 0 -sb is 0 -loop while n < 80: +n is 0.0 +sl is 0.0 +sb is 0.0 +loop while n < 80.0: sl is sl + (sum_list of null) sb is sb + (sum_buf of null) - n is n + 1 -check of ["for-in list in thunk", sl == 80 * 36] -check of ["for-in buffer in thunk", sb == 80 * 56] + n is n + 1.0 +check of ["for-in list in thunk", sl == 80.0 * 36.0] +check of ["for-in buffer in thunk", sb == 80.0 * 56.0] # ---------------------------------------------------------------- # 5) Native VAL_FN call inside a thunk (hot fn calling another fn). # ---------------------------------------------------------------- define leaf(x) as: - return x * 2 + 1 + return x * 2.0 + 1.0 define trunk(x) as: - s is 0 - k is 0 - loop while k < 40: + s is 0.0 + k is 0.0 + loop while k < 40.0: s is s + (leaf of k) - k is k + 1 + k is k + 1.0 return s + x -n is 0 -nc is 0 -loop while n < 60: +n is 0.0 +nc is 0.0 +loop while n < 60.0: nc is nc + (trunk of n) - n is n + 1 + n is n + 1.0 # sum_{k=0..39}(2k+1) = 1600; plus n each call: 60*1600 + 1770 -check of ["native call in thunk", nc == 97770] +check of ["native call in thunk", nc == 97770.0] # ---------------------------------------------------------------- # 6) OSR: a single long-running loop (>5000 back-edges) inside one # call gets a per-loop OSR thunk mid-flight. # ---------------------------------------------------------------- define osr_loop(dummy) as: - s is 0 - k is 0 - loop while k < 7000: - s is s + (k & 7) - k is k + 1 + s is 0.0 + k is 0.0 + loop while k < 7000.0: + s is s + (k & 7.0) + k is k + 1.0 return s osr_r is osr_loop of null # 7000/8 = 875 full cycles of 0..7 (sum 28) -check of ["OSR long loop checksum", osr_r == 875 * 28] +check of ["OSR long loop checksum", osr_r == 875.0 * 28.0] # ---------------------------------------------------------------- # 7) Error semantics from hot code: an out-of-range index raised @@ -319,20 +319,20 @@ check of ["OSR long loop checksum", osr_r == 875 * 28] # with the interpreter's message/behavior. # ---------------------------------------------------------------- define maybe_oob(i) as: - small is [10, 20] + small is [10.0, 20.0] return small[i] -n is 0 -loop while n < 60: - r is maybe_oob of (n % 2) - n is n + 1 +n is 0.0 +loop while n < 60.0: + r is maybe_oob of (n % 2.0) + n is n + 1.0 -caught is 0 +caught is 0.0 try: - r is maybe_oob of 5 + r is maybe_oob of 5.0 catch e: - caught is 1 -check of ["hot fn OOB still raises catchably", caught == 1] + caught is 1.0 +check of ["hot fn OOB still raises catchably", caught == 1.0] # ---------------------------------------------------------------- # 8) SET_FN_NAME_LOCAL in hot code (jit_helper_set_fn_name_local): @@ -342,66 +342,61 @@ check of ["hot fn OOB still raises catchably", caught == 1] # and falls back to the helper. # ---------------------------------------------------------------- define obs_sum(n) as: - total is 0 - k is 0 - loop while k < 100: - total is total + (k & 3) - k is k + 1 + total is 0.0 + k is 0.0 + loop while k < 100.0: + total is total + (k & 3.0) + k is k + 1.0 return what is total define cap_sum(n) as: - total is 0 + total is 0.0 define get as: return total - k is 0 - loop while k < 100: - total is total + (k & 3) - k is k + 1 + k is 0.0 + loop while k < 100.0: + total is total + (k & 3.0) + k is k + 1.0 return get of null -fns1 is 0 -fns2 is 0 -m is 0 -loop while m < 70: +fns1 is 0.0 +fns2 is 0.0 +m is 0.0 +loop while m < 70.0: fns1 is fns1 + (obs_sum of m) fns2 is fns2 + (cap_sum of m) - m is m + 1 + m is m + 1.0 # per call: 25 cycles of 0+1+2+3 = 150; 70 calls = 10500 -check of ["interrogated-name hot assign", fns1 == 10500] -check of ["captured-name hot assign", fns2 == 10500] +check of ["interrogated-name hot assign", fns1 == 10500.0] +check of ["captured-name hot assign", fns2 == 10500.0] # ---------------------------------------------------------------- -# Bitwise operators in a hot fn-local loop. The interpreter bitwise -# paths are covered by test_bitwise.eigs, but the JIT *emitters* for -# OR/XOR/shift-left/shift-right/NOT (emit_or_rax_rdx, emit_xor_rdx_rax, -# emit_shl_cl_rdx, emit_sar_cl_rdx, emit_not_rax) only fire on hot code -# and were unhit by the suite — only AND (`& mask`) appeared above. This -# loop is hot enough to JIT-compile and exercises all six operators with -# zero bailouts; the checksum is identical interpreted vs JIT-compiled -# (verified with EIGS_JIT_OFF=1), so a miscompiled bitwise emitter fails -# here loudly. +# Bitwise operators in a hot fn-local loop. R1.3 deliberately refuses +# bitwise opcodes in the JIT scanner until the int fast-path round. +# These checks retain interpreter/fallback coverage while the other +# float-shaped sections continue to exercise the admitted JIT paths. # ---------------------------------------------------------------- define bitwise_mix(seed) as: a is seed - acc is 0 - k is 0 - loop while k < 200: - a is (a | 1) - a is (a ^ 3) - a is (a << 2) - a is (a >> 1) + acc is 0.0 + k is 0.0 + loop while k < 200.0: + a is (a | 1.0) + a is (a ^ 3.0) + a is (a << 2.0) + a is (a >> 1.0) a is (~a) - a is (a & 1023) + a is (a & 1023.0) acc is acc + a - k is k + 1 + k is k + 1.0 return acc -bw_total is 0 -b is 0 -loop while b < 80: +bw_total is 0.0 +b is 0.0 +loop while b < 80.0: bw_total is bw_total + (bitwise_mix of b) - b is b + 1 -check of ["bitwise emitters hot loop", bw_total == 5621472] + b is b + 1.0 +check of ["bitwise hot loop fallback", bw_total == 5621472.0] # ---------------------------------------------------------------- # 9) #908: the emitted assign_counts bump, inside `unobserved:`. @@ -413,66 +408,66 @@ check of ["bitwise emitters hot loop", bw_total == 5621472] # takes over, silently stops counting. Restoring the old emitted # sequence makes this check report 5001 instead of 20001. # ---------------------------------------------------------------- -hot908 is 0 +hot908 is 0.0 unobserved: - q908 is 0 - loop while q908 < 20000: + q908 is 0.0 + loop while q908 < 20000.0: hot908 is q908 - q908 is q908 + 1 -check of ["unobserved assigns counted in JIT thunk", (when is hot908) == 20001] + q908 is q908 + 1.0 +check of ["unobserved assigns counted in JIT thunk", (when is hot908) == 20001.0] # ---------------------------------------------------------------- # 10) A raising fused local-read helper must leave its native thunk # immediately. Continuing in the thunk would run the counter increment # before the interpreter gets a chance to dispatch to the catch handler. # ---------------------------------------------------------------- -null_read_side_effects is {"count": 0} +null_read_side_effects is {"count": 0.0} define null_field_bail(x) as: value is x.foo - null_read_side_effects.count is null_read_side_effects.count + 1 + null_read_side_effects.count is null_read_side_effects.count + 1.0 return value define null_index_bail(x) as: - value is x[0] - null_read_side_effects.count is null_read_side_effects.count + 1 + value is x[0.0] + null_read_side_effects.count is null_read_side_effects.count + 1.0 return value define null_index_field_bail(x) as: - value is x[0].foo - null_read_side_effects.count is null_read_side_effects.count + 1 + value is x[0.0].foo + null_read_side_effects.count is null_read_side_effects.count + 1.0 return value # Keep this short warmup's back-edge count separate from the module's # earlier OSR loops; the cache diagnostic displays one OSR slot per chunk. define warm_null_reads(dummy) as: - local warm_i is 0 - loop while warm_i < 60: - null_field_bail of {"foo": 1} - null_index_bail of [[1]] - null_index_field_bail of [[{"foo": 1}]] - warm_i is warm_i + 1 + local warm_i is 0.0 + loop while warm_i < 60.0: + null_field_bail of {"foo": 1.0} + null_index_bail of [[1.0]] + null_index_field_bail of [[{"foo": 1.0}]] + warm_i is warm_i + 1.0 warm_null_reads of null before_null_errors is null_read_side_effects.count -null_errors_caught is 0 +null_errors_caught is 0.0 try: null_field_bail of null catch e: - null_errors_caught is null_errors_caught + 1 + null_errors_caught is null_errors_caught + 1.0 try: null_index_bail of null catch e: - null_errors_caught is null_errors_caught + 1 + null_errors_caught is null_errors_caught + 1.0 try: null_index_field_bail of null catch e: - null_errors_caught is null_errors_caught + 1 -check of ["hot null local reads remain catchable", null_errors_caught == 3] + null_errors_caught is null_errors_caught + 1.0 +check of ["hot null local reads remain catchable", null_errors_caught == 3.0] check of ["hot null local reads bail before side effects", null_read_side_effects.count == before_null_errors] # ---------------------------------------------------------------- print of f"jit paths: {pass_count} passed, {fail_count} failed" -if fail_count == 0: +if fail_count == 0.0: print of "All tests passed" diff --git a/tests/test_jit_temporal_osr.eigs b/tests/test_jit_temporal_osr.eigs index 4901c4ca9..fb40af47d 100644 --- a/tests/test_jit_temporal_osr.eigs +++ b/tests/test_jit_temporal_osr.eigs @@ -5,12 +5,12 @@ # written there, not the value frozen at the point the OSR thunk took over. # Pre-fix the JIT skipped the stamp and these queries froze (e.g. 4999). load_file of "lib/test.eigs" -x is 0 -k is 0 -loop while k < 20000: +x is 0.0 +k is 0.0 +loop while k < 20000.0: x is k - k is k + 1 -assert_eq of [what is x at 11, 19999, "JIT temporal: at-line correct under OSR"] -sa is state_at of 11 -assert_eq of [sa["x"], 19999, "JIT temporal: state_at correct under OSR"] + k is k + 1.0 +assert_eq of [what is x at 11.0, 19999.0, "JIT temporal: at-line correct under OSR"] +sa is state_at of 11.0 +assert_eq of [sa["x"], 19999.0, "JIT temporal: state_at correct under OSR"] test_summary of null diff --git a/tests/test_loop_cap_772.eigs b/tests/test_loop_cap_772.eigs index 6e1d3a2c7..28c6a5959 100644 --- a/tests/test_loop_cap_772.eigs +++ b/tests/test_loop_cap_772.eigs @@ -4,12 +4,13 @@ # in-frame iterations — wrong results with exit 0. Found by polymethod's # brute-force differential oracle (4 corrupted outputs in 524,288 at n=19). # This loop crosses the old boundary; the armed sandbox cap keeps its own -# coverage in test_vm_run_bytecode.eigs. -i is 0 +# coverage in test_vm_run_bytecode.eigs. R1.3 spells this legacy float +# probe explicitly; integer native-loop recovery is measured by phase2_cost. +i is 0.0 unobserved: - loop while i < 105000000: - i is i + 1 -if i == 105000000: + loop while i < 105000000.0: + i is i + 1.0 +if i == 105000000.0: print of "cap772: loop crossed 1e8 uncapped PASS" else: print of f"cap772 FAIL: loop stopped at {i}" diff --git a/tests/test_loop_exit.eigs b/tests/test_loop_exit.eigs index e2e6ec220..4b97560ad 100644 --- a/tests/test_loop_exit.eigs +++ b/tests/test_loop_exit.eigs @@ -5,9 +5,9 @@ print of "=== LOOP EXIT TEST ===" # converged). The constant loop in LE2 is the one that exits normally now. print of "--- LE1: Runaway exits via stall ---" x is 1 -x is 100 +x is 100.0 loop while not converged: - x is x * 2 + x is x * 2.0 print of __loop_exit__ print of __loop_iterations__ diff --git a/tests/test_opcode_abi.c b/tests/test_opcode_abi.c index 9eed0e096..77ca2af75 100644 --- a/tests/test_opcode_abi.c +++ b/tests/test_opcode_abi.c @@ -35,6 +35,10 @@ ABI_ASSERT(OP_LINE, 68); ABI_ASSERT(OP_SET_LOCAL_INTERNAL, 94); ABI_ASSERT(OP_TRUE, 95); ABI_ASSERT(OP_FALSE, 96); +/* #1758 N1: int literals append; old float producer numbers do not move. */ +ABI_ASSERT(OP_INT_ZERO, 97); +ABI_ASSERT(OP_INT_ONE, 98); +ABI_ASSERT(OP_INT_CONST, 99); /* #704: the revision the ABI-stamped descriptors in the .eigs fixtures under * tests/ declare. Those diff --git a/tests/test_osr_observe_assign.eigs b/tests/test_osr_observe_assign.eigs index 03b464c60..00e6f12ee 100644 --- a/tests/test_osr_observe_assign.eigs +++ b/tests/test_osr_observe_assign.eigs @@ -15,22 +15,22 @@ load_file of "lib/test.eigs" define run(rounds) as: items is [] - for i in range of 20: - v is (i + 1) * 1.0 + for i in range of 20.0: + v is (i + 1.0) * 1.0 append of [items, v] - total is 0 + total is 0.0 for k in range of rounds: - for i in range of 20: + for i in range of 20.0: a is items[i] - b is items[19] + b is items[19.0] pick is a - if i > 10: + if i > 10.0: pick is b total is total + pick # Rebuild items each round so the picked values are fresh heap # objects (the leak only bites when the rebound value is a pointer). new_items is [] - for i in range of 20: + for i in range of 20.0: w is items[i] + 0.0 append of [new_items, w] items is new_items @@ -40,10 +40,10 @@ define run(rounds) as: # threshold. Per round: i=0..10 -> pick=items[i]=i+1 (sum 1..11 = 66); # i=11..19 -> pick=items[19]=20 (9 * 20 = 180); round total 246. # 300 rounds -> 73800. -r1 is run of 300 -assert of [r1 == 73800, "OSR conditional observed-assign result correct"] +r1 is run of 300.0 +assert of [r1 == 73800.0, "OSR conditional observed-assign result correct"] -r2 is run of 300 +r2 is run of 300.0 assert of [r1 == r2, "OSR result is deterministic across repeated runs"] print of "osr observe-assign: all passed" diff --git a/tests/test_pool_poison.c b/tests/test_pool_poison.c index 769e93a1b..00ca7f291 100644 --- a/tests/test_pool_poison.c +++ b/tests/test_pool_poison.c @@ -143,7 +143,8 @@ static int control(void) { if (!r) { puts("control take: eval failed"); return 1; } eigs_value_release(r); Value *res = eigs_get_global("pool_poison_r"); - int ok = res && res->type == VAL_FLOAT && VAL_F64_RAW(res) == 8.0; + /* #1758 N1/N3: this natural integer program returns the exact int 8. */ + int ok = res && res->type == VAL_INT && VAL_I64_RAW(res) == 8; if (res) eigs_value_release(res); int same = c->env_cache == first; printf("control env take: %s (re-parked same env: %s)\n", diff --git a/tests/test_replay.sh b/tests/test_replay.sh index c4d11fb32..a207dc3c9 100755 --- a/tests/test_replay.sh +++ b/tests/test_replay.sh @@ -534,8 +534,8 @@ print of x EOF CONTRACT_TAPE="$TMPDIR/contract.tape" EIGS_TRACE="$CONTRACT_TAPE" "$EIGS" "$TMPDIR/p_tape_contract.eigs" >/dev/null 2>&1 -if head -1 "$CONTRACT_TAPE" | grep -q '^V 6 '; then - ok "tapes written by this build stamp format v6" +if head -1 "$CONTRACT_TAPE" | grep -q '^V 7 '; then + ok "tapes written by this build stamp format v7" else fail "format stamp" "$(head -1 "$CONTRACT_TAPE")" fi @@ -560,7 +560,7 @@ else fail "pre-v3 replay refusal" "rc=$OLD_REPLAY_RC $(cat "$TMPDIR/old-replay.err")" fi -# O records remain part of v6 tapes and the stepper still folds them. Bound the +# O records remain part of v7 tapes and the stepper still folds them. Bound the # multiplicative configuration-record x binding work even though programs can # no longer create those records through observer setter builtins. WORK_TAPE="$TMPDIR/observer-work-limit.tape" diff --git a/tests/test_sandbox_work_budget.c b/tests/test_sandbox_work_budget.c index 6a5d8b8ab..7ebe90b76 100644 --- a/tests/test_sandbox_work_budget.c +++ b/tests/test_sandbox_work_budget.c @@ -21,7 +21,7 @@ static Value *ordinary_descriptor(void) { if (chunk && !g_has_error && !g_parse_errors && chunk->code_len > 0 && chunk->code_len <= 64 && !chunk->fn_count && !chunk->local_count && !chunk->param_count && chunk->const_count == 1 && - chunk->constants[0]->type == VAL_FLOAT && VAL_F64_RAW(chunk->constants[0]) == 42) { + chunk->constants[0]->type == VAL_INT && VAL_I64_RAW(chunk->constants[0]) == 42) { Value *code = make_list(chunk->code_len); Value *constants = make_list(1); for (int i = 0; i < chunk->code_len; i++) @@ -63,14 +63,14 @@ int main(void) { Value *ok = out ? dict_get_view(out, "ok", &ok_view) : NULL; Value *result = out ? dict_get_view(out, "result", &result_view) : NULL; REQUIRE(ok && ok->type == VAL_BOOL && ok->data.boolean == 1 && - result && result->type == VAL_FLOAT && VAL_F64_RAW(result) == 42, + result && result->type == VAL_INT && VAL_I64_RAW(result) == 42, "ordinary sandbox result"); REQUIRE(!g_sandbox_active && g_sandbox_work_used == 13 && g_sandbox_work_max == 77, "sandbox restores caller accounting"); val_decref(out); val_decref(args); Value *host = eigs_eval_string("return 7\n"); - REQUIRE(host && host->type == VAL_FLOAT && VAL_F64_RAW(host) == 7, + REQUIRE(host && host->type == VAL_INT && VAL_I64_RAW(host) == 7, "host work between sandbox calls"); val_decref(host); REQUIRE(g_sandbox_work_used == 13 && g_sandbox_work_max == 77, @@ -85,13 +85,13 @@ int main(void) { g_sandbox_work_max = 10000; g_sandbox_work_used = 0; Value *ordinary = eigs_eval_string("return 42\n"); - REQUIRE(ordinary && ordinary->type == VAL_FLOAT && VAL_F64_RAW(ordinary) == 42, + REQUIRE(ordinary && ordinary->type == VAL_INT && VAL_I64_RAW(ordinary) == 42, "ordinary arithmetic result"); val_decref(ordinary); REQUIRE(g_sandbox_work_used > 0, "ordinary dispatch charges shared account"); uint64_t previous_work = g_sandbox_work_used; ordinary = eigs_eval_string("define work_identity(x) as:\n return x\nreturn work_identity of 42\n"); - REQUIRE(ordinary && ordinary->type == VAL_FLOAT && VAL_F64_RAW(ordinary) == 42, + REQUIRE(ordinary && ordinary->type == VAL_INT && VAL_I64_RAW(ordinary) == 42, "ordinary function result"); val_decref(ordinary); REQUIRE(g_sandbox_work_used > previous_work, "re-entry preserves accounting"); diff --git a/tests/test_sigusr1_dump.sh b/tests/test_sigusr1_dump.sh index c16356695..b1b5e2c92 100644 --- a/tests/test_sigusr1_dump.sh +++ b/tests/test_sigusr1_dump.sh @@ -9,6 +9,9 @@ # we poll for that line, then `kill -USR1`. The dump's own "# end dump" # trailer on stderr acknowledges the safepoint fired. Then we release the # child through a SENTINEL FILE and require the DONE marker + exit 0. +# If the first dump arms observation, a separate ARM file is created only +# after that dump's trailer. The child sees it, performs 5000 further loop +# assignments, and prints POST_ARM_READY before we send the second signal. # # The sentinel is load-bearing, and the reason is worth keeping. The child's # loop used to be bounded by a fixed iteration count (2,000,000) chosen so the @@ -47,6 +50,7 @@ FIX2=/tmp/eigs_sigusr1_b_$$.eigs # Release files: the child polls for these and winds down once the harness has # collected its dumps (see the header). SENT1=/tmp/eigs_sigusr1_a_$$.go +ARM1=/tmp/eigs_sigusr1_a_$$.arm SENT2=/tmp/eigs_sigusr1_b_$$.go OUT1=/tmp/eigs_sigusr1_a_$$.out ERR1=/tmp/eigs_sigusr1_a_$$.err @@ -61,7 +65,7 @@ cleanup() { for p in $PIDS; do sigusr1_stop "$p" || status=1 done - rm -f "$FIX1" "$FIX2" "$OUT1" "$ERR1" "$OUT2" "$ERR2" "$SENT1" "$SENT2" "$FIX1.bak" "$FIX2.bak" + rm -f "$FIX1" "$FIX2" "$OUT1" "$ERR1" "$OUT2" "$ERR2" "$SENT1" "$SENT2" "$ARM1" "$FIX1.bak" "$FIX2.bak" exit "$status" } trap cleanup EXIT @@ -90,10 +94,19 @@ epsilon is 1.0 define train(n) as: loss is 5.0 scale is 0.999 + post_arm_samples is -1 loop while step_count < n: step_count is step_count + 1 loss is loss * scale + 0.001 epsilon is epsilon * 0.99999 + if post_arm_samples < 0: + if file_exists of "@ARM1@": + post_arm_samples is 0 + else: + if post_arm_samples < 5000: + post_arm_samples is post_arm_samples + 1 + if post_arm_samples == 5000: + print of "POST_ARM_READY" if step_count == 5000: print of "READY" if step_count % 200000 == 0: @@ -104,9 +117,12 @@ r is train of 2000000000 print of "DONE" EOF sigusr1_replace_sentinel "$FIX1" "@SENT1@" "$SENT1" || exit 1 +sigusr1_replace_sentinel "$FIX1" "@ARM1@" "$ARM1" || exit 1 # ---- Subtest 1: single-thread dump shape ------------------------------- +# The ARM sentinel must be absent until the first gated dump acknowledges it. +rm -f "$ARM1" "$EIGS" "$FIX1" > "$OUT1" 2> "$ERR1" & PID=$! PIDS="$PIDS $PID" @@ -138,9 +154,16 @@ fi # capability is preserved across two signals instead of being dropped. if grep -q "observer gate CLOSED" "$ERR1"; then pass "sigusr1: gated first dump declares absence of data (not equilibrium)" - # Second signal: observation was armed by the first, so this one carries - # real trajectories. The row assertions below grep the whole file and so - # match this dump. + # A signal arriving immediately after arming may see too few observed + # assignments, especially under ASan. Wait for the child to acknowledge + # 5000 actual iterations after seeing this post-dump sentinel. + : > "$ARM1" + if ! poll_file "$OUT1" "^POST_ARM_READY$" 600; then + fail "sigusr1: child never completed 5000 assignments after the gate armed" + exit 1 + fi + # The second dump now carries real trajectories. The row assertions below + # grep the whole file and match this dump. DUMPS_BEFORE=$(grep -c '^# end dump$' "$ERR1") kill -USR1 "$PID" 2>/dev/null || true for _ in $(seq 1 600); do @@ -156,8 +179,9 @@ if grep -q "observer gate CLOSED" "$ERR1"; then fi # Row shape: name | value | when= | entropy= | dH= | word. -# when must have 4+ digits (READY is printed at assignment 5000 of -# step_count, the signal lands strictly after) — a settled long-lived +# when must have 4+ digits: READY follows 5000 step_count assignments; +# a gated second dump additionally waits for 5000 post-arm assignments. +# This is a settled long-lived # binding, visibly distinct from a fresh per-call one. if grep -qE '^step_count \| [0-9]+ \| when=[0-9]{4,} \| entropy=[^ ]+ \| dH=[^ ]+ \| [a-z]+$' "$ERR1"; then pass "sigusr1: module row shape (name|value|when|entropy|dH|trajectory) with settled when" diff --git a/tests/test_temporal_param.eigs b/tests/test_temporal_param.eigs index c77bf35ad..3eb311bb0 100644 --- a/tests/test_temporal_param.eigs +++ b/tests/test_temporal_param.eigs @@ -116,32 +116,32 @@ assert_true of [(plain of 1) == 1, "no interrogation: same restore (#1064)"] # the tape. Before the fix the inline SET_LOCAL recorded nothing, so history # froze at the OSR threshold: prev of t answered 4999, not 199999. define hot(t) as: - for i in range of 200000: - t is t + 1 + for i in range of 200000.0: + t is t + 1.0 return prev of t define hot_local(q) as: local t is q - for i in range of 200000: - t is t + 1 + for i in range of 200000.0: + t is t + 1.0 return prev of t -assert_true of [(hot of 0) == 199999, "OSR-compiled slot writes reach the tape (param)"] -assert_true of [(hot_local of 0) == 199999, "local twin of (6)"] +assert_true of [(hot of 0.0) == 199999.0, "OSR-compiled slot writes reach the tape (param)"] +assert_true of [(hot_local of 0.0) == 199999.0, "local twin of (6)"] define hot_what(t) as: - for i in range of 20000: - t is t + 1 - return what is t at 131 -assert_true of [(hot_what of 0) == 20000, "what is at reads the LAST write, past OSR"] + for i in range of 20000.0: + t is t + 1.0 + return what is t at 131.0 +assert_true of [(hot_what of 0.0) == 20000.0, "what is at reads the LAST write, past OSR"] define hot_bind(p) as: - for p in range of 20000: - p is p + 0 + for p in range of 20000.0: + p is p + 0.0 return prev of p define hot_bind_local(q) as: local p is q - for p in range of 20000: - p is p + 0 + for p in range of 20000.0: + p is p + 0.0 return prev of p -assert_true of [(hot_bind of 1) == (hot_bind_local of 1), "hot binder over a param == its local twin"] -assert_true of [(hot_bind of 1) == 19999, "...and the value itself (main froze the tape at OSR: 19998)"] +assert_true of [(hot_bind of 1.0) == (hot_bind_local of 1.0), "hot binder over a param == its local twin"] +assert_true of [(hot_bind of 1.0) == 19999.0, "...and the value itself (main froze the tape at OSR: 19998)"] # ---- (6b) the history table is keyed by NAME across all frames. A callee's # same-named SLOT local must not rewrite the caller's `prev` -- only a chunk diff --git a/tests/test_trace_context.c b/tests/test_trace_context.c index fee0f3f33..b15d18e8c 100644 --- a/tests/test_trace_context.c +++ b/tests/test_trace_context.c @@ -29,20 +29,20 @@ static EigsValue *advance_callback(EigsValue *arg) { } static const char file_tape[] = - "V 6 " EIGENSCRIPT_VERSION "\n" + "V 7 " EIGENSCRIPT_VERSION "\n" "B 0 1 1 0 root -\nB 1 2 2 0 host 70656572\n" "N 1 peer=12\nN 0 root=11\nN 0 root=13\n" - "V 6 " EIGENSCRIPT_VERSION "\n" + "V 7 " EIGENSCRIPT_VERSION "\n" "B 0 1 1 0 root -\nB 1 2 2 0 host 70656572\n" "N 0 root=21\nN 1 peer=22\n"; static const char memory_tape[] = - "V 6 " EIGENSCRIPT_VERSION "\n" + "V 7 " EIGENSCRIPT_VERSION "\n" "B 0 101 11 0 root -\nB 1 102 12 0 host 70656572\n" "N 1 peer=102\nN 0 root=101\nN 0 root=103\n" - "V 6 " EIGENSCRIPT_VERSION "\n" + "V 7 " EIGENSCRIPT_VERSION "\n" "B 0 101 11 0 root -\nN 0 root=201\n"; static const char replacement[] = - "V 6 " EIGENSCRIPT_VERSION "\n" + "V 7 " EIGENSCRIPT_VERSION "\n" "B 0 201 21 0 root -\nB 1 202 22 0 host 70656572\n" "N 1 peer=302\nN 0 root=301\n"; static const char refused[] = "V 5 " EIGENSCRIPT_VERSION "\n"; /* #1637: v5 predates bool values */ @@ -51,10 +51,10 @@ static const char refused[] = "V 5 " EIGENSCRIPT_VERSION "\n"; /* #1637: v5 pr * installs `tape` and takes `name`; the refusal is _exit(3) with `want` on * stderr, so it runs in a forked child. */ static const char host_kind_tape[] = - "V 6 " EIGENSCRIPT_VERSION "\n" + "V 7 " EIGENSCRIPT_VERSION "\n" "B 0 401 41 0 root -\nN 0 root=true\n"; static const char host_undeclared_tape[] = - "V 6 " EIGENSCRIPT_VERSION "\n" + "V 7 " EIGENSCRIPT_VERSION "\n" "B 0 501 51 0 root -\nN 0 ghost=7\n"; static int child_refuses(const char *tape, size_t len, const char *name, const char *want) { int fds[2]; @@ -237,10 +237,48 @@ int main(void) { !eigs_trace_declare_kind("fnval", EIGS_KIND(EIGS_TYPE_FN)) && !eigs_trace_declare_kind("nokind", 0), "a runtime name, an empty name, a FN kind and no kind are refused"); + + /* #1758 v7: unlike the bridge builtins, a host can supply actual int + * N values now. Exercise the production writer AND parser, with values + * whose low bits would be lost by a double intermediate. */ + used = 0; journal[0] = 0; bad_sink = 0; + eigs_set_trace_sink(sink, NULL); + Value *numbers[] = {make_int(3), make_int(INT64_C(9007199254740993)), + make_int(INT64_MIN), make_int(INT64_MAX), + make_num(3.0), make_num(-0.0)}; + for (size_t i = 0; i < sizeof numbers / sizeof numbers[0]; i++) { + trace_nondet_value("sample", numbers[i]); + val_decref(numbers[i]); + } + eigs_set_trace_sink(NULL, NULL); + check(!bad_sink && strstr(journal, " sample=9007199254740993\n") && + strstr(journal, " sample=-9223372036854775808\n") && + strstr(journal, " sample=9223372036854775807\n") && + strstr(journal, " sample=3.0\n") && strstr(journal, " sample=-0.0\n"), + "v7 writer spells exact int digits and marks integral floats"); + check(eigs_set_replay_tape(journal, used, 1), "v7 numeric-kind journal installs"); + const int64_t exact[] = {3, INT64_C(9007199254740993), INT64_MIN, INT64_MAX}; + for (size_t i = 0; i < sizeof exact / sizeof exact[0]; i++) { + EigsValue *v = NULL; + int got = eigs_replay_take("sample", &v); + check(got && v && v->type == VAL_INT && VAL_I64_RAW(v) == exact[i], + "v7 int replay retains exact kind and int64 payload"); + eigs_value_release(v); + } + for (int i = 0; i < 2; i++) { + EigsValue *v = NULL; + int got = eigs_replay_take("sample", &v); + check(got && v && v->type == VAL_FLOAT && + VAL_F64_RAW(v) == (i ? -0.0 : 3.0) && + (!!signbit(VAL_F64_RAW(v)) == i), + "v7 float replay retains kind and signed zero"); + eigs_value_release(v); + } + check(eigs_set_replay_tape(NULL, 0, 0), "v7 numeric-kind replay releases its source"); if (!eigs_thread_switch(peer)) return 2; eigs_thread_detach(); eigs_state_destroy(peer); if (!eigs_thread_switch(root)) return 2; eigs_close(root); - printf("trace context: %d passed, %d failed (44 declared)\n", passed, failed); - return failed || total != 44; + printf("trace context: %d passed, %d failed (53 declared)\n", passed, failed); + return failed || total != 53; } diff --git a/tests/test_trace_context.sh b/tests/test_trace_context.sh index b32a734b3..bc95dbfaf 100644 --- a/tests/test_trace_context.sh +++ b/tests/test_trace_context.sh @@ -37,10 +37,10 @@ if [[ "$rc" -ne 0 || "$classification" -ne 2 ]]; then echo "FAIL: trace context child rc=$rc sanitizer=$classification" exit 1 fi -summaries=$(grep -Fxc 'trace context: 44 passed, 0 failed (44 declared)' "$out" || true) +summaries=$(grep -Fxc 'trace context: 53 passed, 0 failed (53 declared)' "$out" || true) [[ "$summaries" -eq 1 ]] || exit 1 passes=$(grep -c '^PASS:' "$out" || true) -[[ "$passes" -eq 44 ]] || exit 1 +[[ "$passes" -eq 53 ]] || exit 1 if grep -q '^FAIL:' "$out"; then exit 1 fi diff --git a/tests/test_trace_history_boundary.c b/tests/test_trace_history_boundary.c index 7cf5424e0..0f86004f6 100644 --- a/tests/test_trace_history_boundary.c +++ b/tests/test_trace_history_boundary.c @@ -161,10 +161,10 @@ int main(void) { trace_record_obs(host, 9, 8, 7); g_sandbox_active = 0; check(!tape.overflow && tape.assignments == 4 && - strstr(tape.bytes, "A 0 boundary_fresh=5\n") && - strstr(tape.bytes, "A 0 boundary_fresh=6\n") && - strstr(tape.bytes, "A 0 boundary_fresh=7\n") && - strstr(tape.bytes, "A 0 boundary_fresh=8\n"), + strstr(tape.bytes, "A 0 boundary_fresh=5.0\n") && + strstr(tape.bytes, "A 0 boundary_fresh=6.0\n") && + strstr(tape.bytes, "A 0 boundary_fresh=7.0\n") && + strstr(tape.bytes, "A 0 boundary_fresh=8.0\n"), "all assignment routes retain exact ordinary tape records"); check(g_arm_all && g_prev_tab == table && g_prev_count == count && g_prev_cap == capacity, @@ -189,7 +189,7 @@ int main(void) { e->occ[2].entropy == .75 && e->occ[2].dH == .5, "host occurrence observer recording resumes"); trace_assign_tape_only(fresh, slot_from_f64(9)); - check(tape.assignments == 6 && strstr(tape.bytes, "A 0 boundary_fresh=9\n") && + check(tape.assignments == 6 && strstr(tape.bytes, "A 0 boundary_fresh=9.0\n") && g_prev_count == count, "explicit tape-only producer remains tape-only outside boundary"); diff --git a/tests/test_trace_mt.sh b/tests/test_trace_mt.sh index 2607288bc..be63236f5 100755 --- a/tests/test_trace_mt.sh +++ b/tests/test_trace_mt.sh @@ -326,7 +326,7 @@ for bad in 'N random=0.5' 'N -1 random=0.5' 'N 18446744073709551616 random=0.5' { printf '%s\n' "$vline" 'B 0 1 1 0 root -'; printf '%s\n' "$bad"; } > "$TMPDIR/bad-id.tape" EIGS_REPLAY="$TMPDIR/bad-id.tape" "$EIGS" "$TMPDIR/take.eigs" >/dev/null 2>"$TMPDIR/bad-id.err" brc=$? - if [ "$brc" -eq 3 ] && grep -q 'malformed v6 stream id' "$TMPDIR/bad-id.err"; then + if [ "$brc" -eq 3 ] && grep -q 'malformed v7 stream id' "$TMPDIR/bad-id.err"; then ok "parser rejects malformed stream tag: $bad" else fail "parser rejects malformed stream tag: $bad" "rc=$brc" diff --git a/tests/test_tsan.sh b/tests/test_tsan.sh index 8cb152ad5..42c6cd6fb 100755 --- a/tests/test_tsan.sh +++ b/tests/test_tsan.sh @@ -209,7 +209,7 @@ if [ -f "$RP_EIGS" ]; then EIGS_TRACE="$RP_HDR" timeout "$TSAN_RUN_TIMEOUT" setarch -R "$EIGS" \ "$TESTS_DIR/../build/tsan_one.eigs" >/dev/null 2>&1 || header_rc=$? vline=$(head -1 "$RP_HDR" 2>/dev/null || true) - if [ "$header_rc" -ne 0 ] || ! printf '%s\n' "$vline" | grep -q '^V 6 '; then + if [ "$header_rc" -ne 0 ] || ! printf '%s\n' "$vline" | grep -q '^V 7 '; then echo " FAIL: replay-workers header setup rc=$header_rc" FAIL=$((FAIL + 1)) else diff --git a/tests/test_vm_run_bytecode.eigs b/tests/test_vm_run_bytecode.eigs index 9e850f119..b2c4c642f 100644 --- a/tests/test_vm_run_bytecode.eigs +++ b/tests/test_vm_run_bytecode.eigs @@ -50,6 +50,20 @@ define assert_bad_descriptor(desc, reason, label) as: # 2 + 3 -> 5 assert_eq of [vm_run_bytecode of [ABI, [CONST,0,0, CONST,1,0, ADD, RETURN], [2, 3]], 5, "arith add"] +# #1758 R1.3: new int opcodes append to the ABI; INT_CONST validates its +# pool entry before execution, while the old numeric zero/one remain floats. +INT_ZERO is 97 +INT_ONE is 98 +INT_CONST is 99 +assert_eq of [num_type of (vm_run_bytecode of [ABI, [2, RETURN], []]), "float", "#1758: legacy NUM_ZERO remains float"] +assert_eq of [num_type of (vm_run_bytecode of [ABI, [3, RETURN], []]), "float", "#1758: legacy NUM_ONE remains float"] +assert_eq of [num_type of (vm_run_bytecode of [ABI, [CONST,0,0, RETURN], [3.0]]), "float", "#1758: legacy CONST preserves a float constant"] +assert_eq of [num_type of (vm_run_bytecode of [ABI, [INT_ZERO, RETURN], []]), "int", "#1758: appended INT_ZERO produces int"] +assert_eq of [num_type of (vm_run_bytecode of [ABI, [INT_ONE, RETURN], []]), "int", "#1758: appended INT_ONE produces int"] +assert_eq of [vm_run_bytecode of [ABI, [INT_CONST,0,0, RETURN], [9007199254740993]], 9007199254740993, "#1758: INT_CONST preserves exact large int"] +assert_bad_descriptor of [[ABI, [INT_CONST,0,0, RETURN], [3.0]], "not an int", "#1758: INT_CONST rejects a float pool entry"] +assert_bad_descriptor of [[ABI, [INT_CONST,0,0, RETURN], ["3"]], "not an int", "#1758: INT_CONST rejects a string pool entry"] + # string concat "a" + "b" -> "ab" assert_eq of [vm_run_bytecode of [ABI, [CONST,0,0, CONST,1,0, ADD, RETURN], ["a", "b"]], "ab", "string concat via ADD"] diff --git a/tools/jit_diff.sh b/tools/jit_diff.sh index 3b948c8c8..3fc065cb7 100755 --- a/tools/jit_diff.sh +++ b/tools/jit_diff.sh @@ -47,7 +47,7 @@ row_of() { case "$1" in tests/*/*) printf '%s' "$1" ;; tests/*) basename "$1" ;; # '#' lines and blank lines are reasons. Data rows are what the diff sees. ledger_data() { awk 'NF && substr($0,1,1) != "#" { print }' "$1" | sort; } ledger_count() { ledger_data "$1" | wc -l | tr -d ' '; } -b=bench_idxset.eigs +b=jit_env_flags_float.eigs selfcheck() { # $1 arm name, $2.. env args local arm="$1"; shift local st; st=$(env "$@" EIGS_JIT_STATS=1 timeout 60 "$EIG" "../tests/$b" 2>&1 >/dev/null | grep -o 'compiled=[0-9]*') diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 862d6a36a..9a2216195 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -58,8 +58,8 @@ jit_smoke.c|run_index_bail_cases|2|JIT smoke test program (stubbed helpers over jit_smoke.c|run_reader_bail_cases|8|JIT smoke test program (stubbed helpers over slots it built as numbers) jit_smoke.c|run_store_cases|4|JIT smoke test program (stubbed helpers over slots it built as numbers) trace.c|write_slot|1|tape writer after slot_is_f64 -trace.c|write_value_ptr|2|tape writer, switch case VAL_FLOAT; case VAL_INT names the int it refuses (tape v7, R1.3) -trace.c|write_value_ptr_full|2|tape writer, switch case VAL_FLOAT; case VAL_INT names the int it refuses (tape v7, R1.3) +trace.c|write_value_ptr|2|v7 tape writer, switch cases VAL_FLOAT and VAL_INT mark floats and preserve exact integer digits +trace.c|write_value_ptr_full|2|full v7 tape writer, switch cases VAL_FLOAT and VAL_INT mark floats and preserve exact integer digits value_slot.h|#define SLOT_F64_RAW|1|the raw slot read definition (#1758: was SLOT_NUM_RAW) value_slot.h|slot_f64_value|2|float reader (#1758: was vm.c slot_as_double): an immediate after slot_is_f64, a box after type == VAL_FLOAT; 0 for an int value_slot.h|slot_from_f64|1|constructor: writes a double into a fresh slot (#1758: was slot_from_num) @@ -77,7 +77,7 @@ vm.c|obs_slot_num|2|observer numeric channel (#1758): reads an immediate after s vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 vm.c|slot_truthy|1|truthiness after slot_is_f64 vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_FLOAT (chunk_scan_leaf_accessor) and values behind VAL_FLOAT tests -vm.c|vm_run_ex|34|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_FLOAT dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built +vm.c|vm_run_ex|35|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_FLOAT dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 builtins.c|builtin_json_build|1|VAL_INT text is exact digits; float text retains the bridge (#1758 R1.2d) diff --git a/tools/phase2_check.py b/tools/phase2_check.py index a9b3e6fa2..5e7186f0f 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -926,15 +926,10 @@ def stray(rd): args.planted_leaf_scan = build_plant('leaf-scan', out) args.planted_leaf_mul = build_plant('leaf-mul', out) args.planted_random_int = build_plant('random-int', out) - args.planted_p4_trap = build_plant('p4-trap', out) args.planted_value_eq = build_plant('value-eq-raw', out) - args.planted_b2_trap = build_plant('b2-trap', out) for label, b, files, want in ( ('plant C (buffer equality reads raw elements), release build', args.planted_value_eq, - ['tests/test_numeric_guard.eigs', 'tests/test_bool.eigs'], ('DIFF', 'same')), - ('plant B2 (an int from spelled tag bits) on the smi-trap build', args.planted_b2_trap, - ['tests/test_buffer_nonfinite_read.eigs', 'tests/test_numeric_guard.eigs', 'tests/test_bool.eigs'], - ('DIFF', 'DIFF', 'same'))): + ['tests/test_numeric_guard.eigs', 'tests/test_bool.eigs'], ('DIFF', 'same')),): if not b: out('CAL %-58s NOT RUN (no binary; --build-plants builds it)' % label) results.append(False) @@ -955,17 +950,9 @@ def stray(rd): else: out('CAL %-58s NOT RUN (no --planted-random-int binary; --build-plants builds it)' % 'plant D') results.append(False) - if args.planted_p4_trap: - # both files bind 1 through slot_from_value (loop_iter_store -> - # env_set_local_hashed), where P4 makes an int - files = ['tests/test_bool.eigs', 'tests/test_system.eigs'] - rc, text, v = diff_restricted(base, args.planted_p4_trap, files) - case('P4 on the smi-trap build (the dynamic half): each file DIFF, aborting at the int', - (rc,) + tuple(v.get(f) for f in files) + (v.get(''), 'slot_from_int under EIGS_SMI_TRAP' in text), - (3, 'DIFF', 'DIFF', None, True), detail=text.splitlines()) - else: - out('CAL %-58s NOT RUN (no --planted-p4-trap binary; --build-plants builds it)' % 'P4 dynamic') - results.append(False) + # P4/B2's dynamic no-SMI plants are retired: ints are legitimate at + # R1.3 and the trap mode is intentionally no-op. Their static source + # plants above still calibrate the historical R1.1/R1.2 mechanism. for label, flag, b in (('leaf-scanner-early-return', '--planted-leaf-scan', args.planted_leaf_scan), ('leaf-mul-plus-one', '--planted-leaf-mul', args.planted_leaf_mul)): if not b: @@ -1001,15 +988,7 @@ def stray(rd): # elements (no read normalisation); the suite's [42c] goes red on it 'value-eq-raw': ('src/eigenscript.c', ' case VAL_BUFFER: {\n if (a->data.buffer.count != b->data.buffer.count) return 0;\n for (int i = 0; i < a->data.buffer.count; i++) {\n double av = buffer_read_num(a, i);\n if (g_has_error) return 0;\n double bv = buffer_read_num(b, i);\n', ' case VAL_BUFFER: {\n if (a->data.buffer.count != b->data.buffer.count) return 0;\n for (int i = 0; i < a->data.buffer.count; i++) {\n double av = a->data.buffer.data[i]; /* CRITIC PLANT C: raw element, no read normalisation */\n if (g_has_error) return 0;\n double bv = b->data.buffer.data[i];\n', 'build'), - # the second critic's plant B2: an int produced by spelling the tag's bits - # (no TAG_SMI, so the static half cannot see it), on the smi-trap build - 'b2-trap': ('src/vm.c', ' if (target->type == VAL_BUFFER) {\n if (_ok && vm_index_resolve(&i, target->data.buffer.count)) {\n double v = buffer_read_num(target, i);\n slot_decref(tgt_s);\n vm_push_slot(slot_from_f64(v));\n } else {\n if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s));\n else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)",\n', - ' if (target->type == VAL_BUFFER) {\n if (_ok && vm_index_resolve(&i, target->data.buffer.count)) {\n double v = buffer_read_num(target, i);\n slot_decref(tgt_s);\n if (isnan(target->data.buffer.data[i])) { /* CRITIC PLANT B2: an int producer, bits spelled */\n EigsSlot p; p.u = (SLOT_QNAN_MASK | (UINT64_C(2) << 48)) | 7u;\n vm_push_slot(p);\n } else {\n vm_push_slot(slot_from_f64(v));\n }\n } else {\n if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s));\n else rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)",\n', 'smi-trap'), - # the critic's P4 (an int produced inside an allowed writer) on the smi-trap build - 'p4-trap': ('src/eigenscript.c', ' double n = VAL_F64_RAW(v);\n val_decref(v);\n return slot_from_f64(n);', - ' double n = VAL_F64_RAW(v);\n val_decref(v);\n' - ' if (n == 1.0) return slot_from_int(1); /* PLANT P4 */\n return slot_from_f64(n);', - 'smi-trap'), + } _PLANT_DIR = [] @@ -1143,8 +1122,7 @@ def selftest(out): out(' TAG %s built in %s' % (TAG, d)) args = argparse.Namespace(tag=os.path.abspath(tag), branch=branch, build_plants=True, planted_leaf_scan=None, planted_leaf_mul=None, - planted_random_int=None, planted_p4_trap=None, - planted_value_eq=None, planted_b2_trap=None) + planted_random_int=None, planted_value_eq=None) return calibrate(args, out) @@ -1170,18 +1148,15 @@ def main(): ap.add_argument('--planted-leaf-scan', help='calibration: a build whose leaf scanner returns early') ap.add_argument('--planted-leaf-mul', help='calibration: a build whose leaf MUL computes a*b+1') ap.add_argument('--planted-random-int', help='calibration: a build whose random_int answers lo+1..hi+1') - ap.add_argument('--planted-p4-trap', help='calibration: a smi-trap build with the P4 producer planted') ap.add_argument('--planted-value-eq', help='calibration: a build whose buffer equality reads raw elements (C)') - ap.add_argument('--planted-b2-trap', help='calibration: a smi-trap build with the B2 producer planted') ap.add_argument('--build-plants', action='store_true', - help='calibration: build the six planted binaries from HEAD') + help='calibration: build the four active planted binaries from HEAD') args = ap.parse_args() if args.selftest: print('phase2-check: FAIL: --selftest takes no other argument') return 2 for b in (args.tag, args.branch, args.baseline, args.smi_trap, args.planted_leaf_scan, - args.planted_leaf_mul, args.planted_random_int, args.planted_p4_trap, - args.planted_value_eq, args.planted_b2_trap): + args.planted_leaf_mul, args.planted_random_int, args.planted_value_eq): if b and not os.access(b, os.X_OK): print('phase2-check: FAIL: %s is not an executable' % b) return 2 diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index f51746fdb..c70ea1cb7 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -88,7 +88,7 @@ 'buffer_read_byte': 'READ', # a buffer element as a byte (Q1: N5, no wrap) 'buf_num_arg': 'READ', # builtins_buf.c wrapper of eigs_list_num 'eigs_value_as_num': 'READ', # embed API accessor - 'num_val': 'RAW', # lexer token payload (double) + 'number': 'RAW', # lexer/AST EigsNum payload (#1758 R1.3) # (c) producers 'make_num': 'PRODUCE', 'make_num_permanent': 'PRODUCE', @@ -118,9 +118,9 @@ r'emit_(?:add|sub|mul|div)sd_xmm0_xmm1|emit_ucomisd_\w+|emit_cvttsd2si_\w+|' r'emit_cvtsi2sd_\w+|emit_btr_63_\w+|fmod)\b') -# `data.num` is the AST literal's double (`data.f64_` is the Value member, +# `data.number` is the AST literal's EigsNum (`data.f64_` is the Value member, # reached only through VAL_F64_RAW); matched as a member access, below. -AST_NUM_FIELD = re.compile(r'(?:->|\.)data\.num\b(?!_)') +AST_NUM_FIELD = re.compile(r'(?:->|\.)data\.number\b(?!_)') KIND_CATEGORY = { 'TEST': 'a', 'CASE': 'a', 'YIELD': 'a', 'DATA': 'a', @@ -432,7 +432,7 @@ def scan_file(path, rel): for m in AST_NUM_FIELD.finditer(line): rest = line[m.end():].lstrip() kind = 'WRITE' if re.match(r'=(?!=)', rest) else 'RAW' - sites.append((rel, ln, scope[ln], 'data.num', kind)) + sites.append((rel, ln, scope[ln], 'data.number', kind)) return sites, stripped, scope, sigs @@ -893,7 +893,7 @@ def main(): out.append('## Per token') for t in sorted(token_hits, key=lambda t: (-token_hits[t], t)): out.append('%-24s %5d' % (t, token_hits[t])) - out.append('%-24s %5d' % ('data.num (AST)', sum(1 for s in sites if s[3] == 'data.num'))) + out.append('%-24s %5d' % ('data.number (AST)', sum(1 for s in sites if s[3] == 'data.number'))) out.append('') out.append('## Per file (category counts)') for rel in sorted(per_file, key=lambda r: (-per_file[r], r)): diff --git a/tools/phase2_plants.sh b/tools/phase2_plants.sh index 152ec420c..717054ab4 100755 --- a/tools/phase2_plants.sh +++ b/tools/phase2_plants.sh @@ -18,8 +18,8 @@ # # Plants land with their named checks: plant 1 with R1.1 (the C slot test); # 2-7 name MAP rows that land in R1.3-R2.2 and join this table then. The R1.1 -# fix round added three instrument plants on the slot test: an operator arm -# that lost its int refusal (Part D), and a population scan that writes noise +# fix round added three instrument plants on the slot test: an integer overflow +# that wraps instead of raising (Part D), and a population scan that writes noise # to stderr or an unparsed line to stdout (the critic's class); and #1775's # plant, the missing return that makes the -O0 amalgamation warn. # Prints one line per plant and `plants=N killed=N survived=0 broken=0 @@ -121,20 +121,17 @@ run_plant 1 src/value_slot.h \ '^slot-layer-test: FAIL slot_from_int\(0\): bits 0x' \ bash tests/phase2/slot_layer.sh release -# An operator arm that lost its int refusal: NUM_CMP raises a type error for -# an SMI again (a `try` turns it into a wrong value). Named check: the slot -# test's Part D row for `<`. -run_plant arm-refusal src/vm.c \ - " if (slot_type(_as) == VAL_INT) \\ - eigs_int_unwired(\"compare '\" OPNAME \"'\", _as.u); \\ - if (slot_type(_bs) == VAL_INT) \\ - eigs_int_unwired(\"compare '\" OPNAME \"'\", _bs.u); \\ -" \ - "" \ +# R1.3 N3/(A): overflow must raise, never return the wrapped int64 result. +# The builtin computes the wrapped bits through __builtin_*_overflow; dropping +# the checked raise therefore reproduces the exact fault the row promises. +# Named check: the slot test's Part D overflow_add row, with a float control. +run_plant overflow-wrap src/vm.c \ + ' if (overflow) {' \ + ' if (overflow && 0) { /* PLANT: return the wrapped int64 result */' \ tests/phase2/slot_layer.c \ - ' if (strcmp(got, want) != 0) { FAILF("arm %s with an int: got %s, want %s", g_arm->name, got, want); bad++; }' \ - ' if (0) { FAILF("arm %s with an int: got %s, want %s", g_arm->name, got, want); bad++; }' \ - "^slot-layer-test: FAIL arm lt with an int: got " \ + ' if (strcmp(got, "ran") != 0 || strcmp(pre, want) != 0) {' \ + ' if (0) {' \ + "^slot-layer-test: FAIL arm overflow_add with an int: got " \ bash tests/phase2/slot_layer.sh release # The critic's class: a population scan whose diagnostics reach the parser. diff --git a/tools/selftests.txt b/tools/selftests.txt index d4a8f583f..34e26eea1 100644 --- a/tools/selftests.txt +++ b/tools/selftests.txt @@ -57,5 +57,5 @@ tools/observer_oracle/* | timeout 600 python3 tools/observer_oracle/plants.py -- # #1758 Phase 2: the row checker's calibration (5 release builds: v0.46.0 and four planted binaries; 662 s on # the 4 GB dev box) and the slot test's planted faults (two -O0 slot-test builds per plant; 446 s there). # Keyed on the checkers, never on src/ (#1352). -tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* tests/phase2/corpus_nonzero.txt tests/suite_program_env.sh tests/suite_program_env.txt | timeout 3600 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=51 as-expected=51 unexpected=0$","count":1}] +tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* tests/phase2/corpus_nonzero.txt tests/suite_program_env.sh tests/suite_program_env.txt | timeout 3600 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=49 as-expected=49 unexpected=0$","count":1}] tools/phase2_plants.sh tests/phase2/slot_layer.sh tests/phase2/slot_layer.c tools/phase2_inventory.py | timeout 1500 bash tools/phase2_plants.sh --selftest | [{"pattern":"^plants=5 killed=5 survived=0 broken=0 transverse=5$","count":1}] From f2053fba287fca96f5317dbc841f82860a09662a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:53:53 -0500 Subject: [PATCH 061/188] phase2 R1.3e: the R1.3 MAP rows, controls and tier witnesses (#1758) The 51 R1.3 rows land with their fixtures under tests/phase2/rows and the controls under tests/phase2/controls. Beside the rows already planned: - N1.leaf-float-kind / N1.fn-float-kind: OP_NUM_ZERO/ONE/CONST keep the float kind in the leaf evaluator and the JIT emitter; - N2.sort-by-exact: sort_by's exact numeric keys around 2^53, stable on ties (N2.sort-exact is checked here, design 6); - N14.json-build-int-exact and N14.json-encode-int-exact: the exact JSON text writers go live; N14.json-path-int-exact is written and scheduled at R1.6, because json_path only parses JSON text and the decoder produces floats until R1.6 (#1827); - gate.N5.iterator-metadata: the slot test's Part E pins the four iterator sites R1.2's cost fix moved; - seven ctl.N8.refuse-* controls: float operands through a hot function, with a fn-stop witness that the JIT scanner refuses BAND/BOR/BXOR/SHL/SHR/BNOT/MOD; - N4b.abs-min-raises moves to R1.3 (abs's int arm lands here); - T1.float-kind-token (a v6-format float writer turns it red) and a redefined T1.int-replay-kind: random_int keeps the float bridge until R1.6, so the int rides the v7 assignment record and replays byte-identical. N1.fn-int-literal and A.fn-add-overflow warm with `0.5` so the callee is hot before its int opcode. tools/phase2_check.py now also proves a shaped CONTROL's tier: a control with a JIT/leaf witness prints CONTROL-WITNESS or CONTROL-VACUOUS, and a vacuous control fails the run (`controls_witnessed=C controls_vacuous=0`). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 9 +-- tests/phase2/MAP.md | 59 +++++++++++++++++-- tests/phase2/controls/ctl.B.type-of.eigs | 7 +++ tests/phase2/controls/ctl.B.type-of.out | 1 + tests/phase2/controls/ctl.N1.fn-int-not.eigs | 15 +++++ tests/phase2/controls/ctl.N1.fn-int-not.out | 1 + .../controls/ctl.N1.fn-int-truthiness.eigs | 16 +++++ .../controls/ctl.N1.fn-int-truthiness.out | 1 + tests/phase2/controls/ctl.N2.float-eq.eigs | 7 +++ tests/phase2/controls/ctl.N2.float-eq.out | 1 + .../controls/ctl.N2.fn-float-compare.eigs | 15 +++++ .../controls/ctl.N2.fn-float-compare.out | 1 + tests/phase2/controls/ctl.N3.leaf-float.eigs | 9 +++ tests/phase2/controls/ctl.N3.leaf-float.out | 1 + tests/phase2/controls/ctl.N3.osr-float.eigs | 15 +++++ tests/phase2/controls/ctl.N3.osr-float.out | 1 + tests/phase2/controls/ctl.N3.small-ints.eigs | 7 +++ tests/phase2/controls/ctl.N3.small-ints.out | 1 + .../controls/ctl.N4.int-mod-zero-raises.eigs | 10 ++++ .../controls/ctl.N4.int-mod-zero-raises.out | 1 + .../controls/ctl.N5.leaf-float-index.eigs | 9 +++ .../controls/ctl.N5.leaf-float-index.out | 1 + tests/phase2/controls/ctl.N6.small-ints.eigs | 7 +++ tests/phase2/controls/ctl.N6.small-ints.out | 1 + tests/phase2/controls/ctl.N8.refuse-band.eigs | 16 +++++ tests/phase2/controls/ctl.N8.refuse-band.out | 1 + tests/phase2/controls/ctl.N8.refuse-bnot.eigs | 16 +++++ tests/phase2/controls/ctl.N8.refuse-bnot.out | 1 + tests/phase2/controls/ctl.N8.refuse-bor.eigs | 16 +++++ tests/phase2/controls/ctl.N8.refuse-bor.out | 1 + tests/phase2/controls/ctl.N8.refuse-bxor.eigs | 16 +++++ tests/phase2/controls/ctl.N8.refuse-bxor.out | 1 + tests/phase2/controls/ctl.N8.refuse-mod.eigs | 16 +++++ tests/phase2/controls/ctl.N8.refuse-mod.out | 1 + tests/phase2/controls/ctl.N8.refuse-shl.eigs | 16 +++++ tests/phase2/controls/ctl.N8.refuse-shl.out | 1 + tests/phase2/controls/ctl.N8.refuse-shr.eigs | 16 +++++ tests/phase2/controls/ctl.N8.refuse-shr.out | 1 + tests/phase2/rows/A.add-overflow-raises.eigs | 10 ++++ tests/phase2/rows/A.add-overflow-raises.out | 1 + tests/phase2/rows/A.fn-add-overflow.eigs | 19 ++++++ tests/phase2/rows/A.fn-add-overflow.out | 1 + tests/phase2/rows/A.leaf-mul-overflow.eigs | 12 ++++ tests/phase2/rows/A.leaf-mul-overflow.out | 1 + tests/phase2/rows/A.mul-overflow-raises.eigs | 10 ++++ tests/phase2/rows/A.mul-overflow-raises.out | 1 + tests/phase2/rows/A.osr-double-overflow.eigs | 18 ++++++ tests/phase2/rows/A.osr-double-overflow.out | 1 + tests/phase2/rows/A.sub-overflow-raises.eigs | 10 ++++ tests/phase2/rows/A.sub-overflow-raises.out | 1 + tests/phase2/rows/B.type-of-both-num.eigs | 7 +++ tests/phase2/rows/B.type-of-both-num.out | 1 + tests/phase2/rows/N1.canon-eq.eigs | 9 +++ tests/phase2/rows/N1.canon-eq.out | 1 + .../rows/N1.decimal-past-int64-is-float.eigs | 8 +++ .../rows/N1.decimal-past-int64-is-float.out | 1 + tests/phase2/rows/N1.exact-past-2p53.eigs | 7 +++ tests/phase2/rows/N1.exact-past-2p53.out | 1 + tests/phase2/rows/N1.fn-dot-fields.eigs | 15 +++++ tests/phase2/rows/N1.fn-dot-fields.out | 1 + tests/phase2/rows/N1.fn-float-kind.eigs | 16 +++++ tests/phase2/rows/N1.fn-float-kind.out | 1 + tests/phase2/rows/N1.fn-int-literal.eigs | 16 +++++ tests/phase2/rows/N1.fn-int-literal.out | 1 + tests/phase2/rows/N1.fn-int-local.eigs | 15 +++++ tests/phase2/rows/N1.fn-int-local.out | 1 + tests/phase2/rows/N1.hex-wraps.eigs | 7 +++ tests/phase2/rows/N1.hex-wraps.out | 1 + tests/phase2/rows/N1.leaf-dot-get.eigs | 10 ++++ tests/phase2/rows/N1.leaf-dot-get.out | 1 + tests/phase2/rows/N1.leaf-float-kind.eigs | 13 ++++ tests/phase2/rows/N1.leaf-float-kind.out | 1 + tests/phase2/rows/N1.leaf-int-literal.eigs | 11 ++++ tests/phase2/rows/N1.leaf-int-literal.out | 1 + tests/phase2/rows/N1.literal-kind.eigs | 7 +++ tests/phase2/rows/N1.literal-kind.out | 1 + .../phase2/rows/N1.osr-global-int-store.eigs | 15 +++++ tests/phase2/rows/N1.osr-global-int-store.out | 1 + tests/phase2/rows/N1.osr-int-counter.eigs | 15 +++++ tests/phase2/rows/N1.osr-int-counter.out | 1 + .../phase2/rows/N14.json-build-int-exact.eigs | 7 +++ .../phase2/rows/N14.json-build-int-exact.out | 1 + .../rows/N14.json-encode-int-exact.eigs | 7 +++ .../phase2/rows/N14.json-encode-int-exact.out | 1 + .../phase2/rows/N14.json-path-int-exact.eigs | 7 +++ tests/phase2/rows/N14.json-path-int-exact.out | 1 + tests/phase2/rows/N2.exact-eq-past-2p53.eigs | 7 +++ tests/phase2/rows/N2.exact-eq-past-2p53.out | 1 + tests/phase2/rows/N2.exact-order.eigs | 7 +++ tests/phase2/rows/N2.exact-order.out | 1 + tests/phase2/rows/N2.fn-compare-all.eigs | 19 ++++++ tests/phase2/rows/N2.fn-compare-all.out | 1 + tests/phase2/rows/N2.fn-exact-compare.eigs | 15 +++++ tests/phase2/rows/N2.fn-exact-compare.out | 1 + tests/phase2/rows/N2.int-eq-float-kinds.eigs | 7 +++ tests/phase2/rows/N2.int-eq-float-kinds.out | 1 + tests/phase2/rows/N2.membership-exact.eigs | 7 +++ tests/phase2/rows/N2.membership-exact.out | 1 + tests/phase2/rows/N2.sort-by-exact.eigs | 11 ++++ tests/phase2/rows/N2.sort-by-exact.out | 1 + tests/phase2/rows/N2.sort-exact.eigs | 7 +++ tests/phase2/rows/N2.sort-exact.out | 1 + tests/phase2/rows/N3.exact-product.eigs | 7 +++ tests/phase2/rows/N3.exact-product.out | 1 + tests/phase2/rows/N3.fn-arith-exact.eigs | 16 +++++ tests/phase2/rows/N3.fn-arith-exact.out | 1 + tests/phase2/rows/N3.int-ops-kind.eigs | 7 +++ tests/phase2/rows/N3.int-ops-kind.out | 1 + tests/phase2/rows/N3.leaf-add-exact.eigs | 9 +++ tests/phase2/rows/N3.leaf-add-exact.out | 1 + tests/phase2/rows/N3.leaf-mul-exact.eigs | 9 +++ tests/phase2/rows/N3.leaf-mul-exact.out | 1 + tests/phase2/rows/N3.osr-module-sum.eigs | 15 +++++ tests/phase2/rows/N3.osr-module-sum.out | 1 + tests/phase2/rows/N3.osr-sum-exact.eigs | 15 +++++ tests/phase2/rows/N3.osr-sum-exact.out | 1 + tests/phase2/rows/N4b.abs-min-raises.eigs | 11 ++++ tests/phase2/rows/N4b.abs-min-raises.out | 1 + tests/phase2/rows/N4b.fn-neg-min.eigs | 19 ++++++ tests/phase2/rows/N4b.fn-neg-min.out | 1 + tests/phase2/rows/N4b.neg-min-raises.eigs | 11 ++++ tests/phase2/rows/N4b.neg-min-raises.out | 1 + tests/phase2/rows/N5.osr-index-set.eigs | 15 +++++ tests/phase2/rows/N5.osr-index-set.out | 1 + tests/phase2/rows/N7.num-type-float.eigs | 7 +++ tests/phase2/rows/N7.num-type-float.out | 1 + tests/phase2/rows/N7.num-type-int.eigs | 7 +++ tests/phase2/rows/N7.num-type-int.out | 1 + tests/phase2/rows/N7.num-type-non-number.eigs | 7 +++ tests/phase2/rows/N7.num-type-non-number.out | 1 + .../phase2/rows/O1.int-observed-numeric.eigs | 18 ++++++ tests/phase2/rows/O1.int-observed-numeric.out | 1 + tests/phase2/rows/T1.float-kind-token.out | 2 + tests/phase2/rows/T1.float-kind-token.sh | 21 +++++++ tests/phase2/rows/T1.int-replay-kind.out | 2 + tests/phase2/rows/T1.int-replay-kind.sh | 24 ++++++++ tests/phase2/rows/T1.twice-int.out | 4 ++ tests/phase2/rows/T1.twice-int.sh | 27 +++++++++ tests/phase2/rows/T1.v6-refused.out | 1 + tests/phase2/rows/T1.v6-refused.sh | 21 +++++++ tests/phase2/rows/T1.v7-header.out | 1 + tests/phase2/rows/T1.v7-header.sh | 12 ++++ tools/phase2_check.py | 15 ++++- 143 files changed, 1004 insertions(+), 12 deletions(-) create mode 100644 tests/phase2/controls/ctl.B.type-of.eigs create mode 100644 tests/phase2/controls/ctl.B.type-of.out create mode 100644 tests/phase2/controls/ctl.N1.fn-int-not.eigs create mode 100644 tests/phase2/controls/ctl.N1.fn-int-not.out create mode 100644 tests/phase2/controls/ctl.N1.fn-int-truthiness.eigs create mode 100644 tests/phase2/controls/ctl.N1.fn-int-truthiness.out create mode 100644 tests/phase2/controls/ctl.N2.float-eq.eigs create mode 100644 tests/phase2/controls/ctl.N2.float-eq.out create mode 100644 tests/phase2/controls/ctl.N2.fn-float-compare.eigs create mode 100644 tests/phase2/controls/ctl.N2.fn-float-compare.out create mode 100644 tests/phase2/controls/ctl.N3.leaf-float.eigs create mode 100644 tests/phase2/controls/ctl.N3.leaf-float.out create mode 100644 tests/phase2/controls/ctl.N3.osr-float.eigs create mode 100644 tests/phase2/controls/ctl.N3.osr-float.out create mode 100644 tests/phase2/controls/ctl.N3.small-ints.eigs create mode 100644 tests/phase2/controls/ctl.N3.small-ints.out create mode 100644 tests/phase2/controls/ctl.N4.int-mod-zero-raises.eigs create mode 100644 tests/phase2/controls/ctl.N4.int-mod-zero-raises.out create mode 100644 tests/phase2/controls/ctl.N5.leaf-float-index.eigs create mode 100644 tests/phase2/controls/ctl.N5.leaf-float-index.out create mode 100644 tests/phase2/controls/ctl.N6.small-ints.eigs create mode 100644 tests/phase2/controls/ctl.N6.small-ints.out create mode 100644 tests/phase2/controls/ctl.N8.refuse-band.eigs create mode 100644 tests/phase2/controls/ctl.N8.refuse-band.out create mode 100644 tests/phase2/controls/ctl.N8.refuse-bnot.eigs create mode 100644 tests/phase2/controls/ctl.N8.refuse-bnot.out create mode 100644 tests/phase2/controls/ctl.N8.refuse-bor.eigs create mode 100644 tests/phase2/controls/ctl.N8.refuse-bor.out create mode 100644 tests/phase2/controls/ctl.N8.refuse-bxor.eigs create mode 100644 tests/phase2/controls/ctl.N8.refuse-bxor.out create mode 100644 tests/phase2/controls/ctl.N8.refuse-mod.eigs create mode 100644 tests/phase2/controls/ctl.N8.refuse-mod.out create mode 100644 tests/phase2/controls/ctl.N8.refuse-shl.eigs create mode 100644 tests/phase2/controls/ctl.N8.refuse-shl.out create mode 100644 tests/phase2/controls/ctl.N8.refuse-shr.eigs create mode 100644 tests/phase2/controls/ctl.N8.refuse-shr.out create mode 100644 tests/phase2/rows/A.add-overflow-raises.eigs create mode 100644 tests/phase2/rows/A.add-overflow-raises.out create mode 100644 tests/phase2/rows/A.fn-add-overflow.eigs create mode 100644 tests/phase2/rows/A.fn-add-overflow.out create mode 100644 tests/phase2/rows/A.leaf-mul-overflow.eigs create mode 100644 tests/phase2/rows/A.leaf-mul-overflow.out create mode 100644 tests/phase2/rows/A.mul-overflow-raises.eigs create mode 100644 tests/phase2/rows/A.mul-overflow-raises.out create mode 100644 tests/phase2/rows/A.osr-double-overflow.eigs create mode 100644 tests/phase2/rows/A.osr-double-overflow.out create mode 100644 tests/phase2/rows/A.sub-overflow-raises.eigs create mode 100644 tests/phase2/rows/A.sub-overflow-raises.out create mode 100644 tests/phase2/rows/B.type-of-both-num.eigs create mode 100644 tests/phase2/rows/B.type-of-both-num.out create mode 100644 tests/phase2/rows/N1.canon-eq.eigs create mode 100644 tests/phase2/rows/N1.canon-eq.out create mode 100644 tests/phase2/rows/N1.decimal-past-int64-is-float.eigs create mode 100644 tests/phase2/rows/N1.decimal-past-int64-is-float.out create mode 100644 tests/phase2/rows/N1.exact-past-2p53.eigs create mode 100644 tests/phase2/rows/N1.exact-past-2p53.out create mode 100644 tests/phase2/rows/N1.fn-dot-fields.eigs create mode 100644 tests/phase2/rows/N1.fn-dot-fields.out create mode 100644 tests/phase2/rows/N1.fn-float-kind.eigs create mode 100644 tests/phase2/rows/N1.fn-float-kind.out create mode 100644 tests/phase2/rows/N1.fn-int-literal.eigs create mode 100644 tests/phase2/rows/N1.fn-int-literal.out create mode 100644 tests/phase2/rows/N1.fn-int-local.eigs create mode 100644 tests/phase2/rows/N1.fn-int-local.out create mode 100644 tests/phase2/rows/N1.hex-wraps.eigs create mode 100644 tests/phase2/rows/N1.hex-wraps.out create mode 100644 tests/phase2/rows/N1.leaf-dot-get.eigs create mode 100644 tests/phase2/rows/N1.leaf-dot-get.out create mode 100644 tests/phase2/rows/N1.leaf-float-kind.eigs create mode 100644 tests/phase2/rows/N1.leaf-float-kind.out create mode 100644 tests/phase2/rows/N1.leaf-int-literal.eigs create mode 100644 tests/phase2/rows/N1.leaf-int-literal.out create mode 100644 tests/phase2/rows/N1.literal-kind.eigs create mode 100644 tests/phase2/rows/N1.literal-kind.out create mode 100644 tests/phase2/rows/N1.osr-global-int-store.eigs create mode 100644 tests/phase2/rows/N1.osr-global-int-store.out create mode 100644 tests/phase2/rows/N1.osr-int-counter.eigs create mode 100644 tests/phase2/rows/N1.osr-int-counter.out create mode 100644 tests/phase2/rows/N14.json-build-int-exact.eigs create mode 100644 tests/phase2/rows/N14.json-build-int-exact.out create mode 100644 tests/phase2/rows/N14.json-encode-int-exact.eigs create mode 100644 tests/phase2/rows/N14.json-encode-int-exact.out create mode 100644 tests/phase2/rows/N14.json-path-int-exact.eigs create mode 100644 tests/phase2/rows/N14.json-path-int-exact.out create mode 100644 tests/phase2/rows/N2.exact-eq-past-2p53.eigs create mode 100644 tests/phase2/rows/N2.exact-eq-past-2p53.out create mode 100644 tests/phase2/rows/N2.exact-order.eigs create mode 100644 tests/phase2/rows/N2.exact-order.out create mode 100644 tests/phase2/rows/N2.fn-compare-all.eigs create mode 100644 tests/phase2/rows/N2.fn-compare-all.out create mode 100644 tests/phase2/rows/N2.fn-exact-compare.eigs create mode 100644 tests/phase2/rows/N2.fn-exact-compare.out create mode 100644 tests/phase2/rows/N2.int-eq-float-kinds.eigs create mode 100644 tests/phase2/rows/N2.int-eq-float-kinds.out create mode 100644 tests/phase2/rows/N2.membership-exact.eigs create mode 100644 tests/phase2/rows/N2.membership-exact.out create mode 100644 tests/phase2/rows/N2.sort-by-exact.eigs create mode 100644 tests/phase2/rows/N2.sort-by-exact.out create mode 100644 tests/phase2/rows/N2.sort-exact.eigs create mode 100644 tests/phase2/rows/N2.sort-exact.out create mode 100644 tests/phase2/rows/N3.exact-product.eigs create mode 100644 tests/phase2/rows/N3.exact-product.out create mode 100644 tests/phase2/rows/N3.fn-arith-exact.eigs create mode 100644 tests/phase2/rows/N3.fn-arith-exact.out create mode 100644 tests/phase2/rows/N3.int-ops-kind.eigs create mode 100644 tests/phase2/rows/N3.int-ops-kind.out create mode 100644 tests/phase2/rows/N3.leaf-add-exact.eigs create mode 100644 tests/phase2/rows/N3.leaf-add-exact.out create mode 100644 tests/phase2/rows/N3.leaf-mul-exact.eigs create mode 100644 tests/phase2/rows/N3.leaf-mul-exact.out create mode 100644 tests/phase2/rows/N3.osr-module-sum.eigs create mode 100644 tests/phase2/rows/N3.osr-module-sum.out create mode 100644 tests/phase2/rows/N3.osr-sum-exact.eigs create mode 100644 tests/phase2/rows/N3.osr-sum-exact.out create mode 100644 tests/phase2/rows/N4b.abs-min-raises.eigs create mode 100644 tests/phase2/rows/N4b.abs-min-raises.out create mode 100644 tests/phase2/rows/N4b.fn-neg-min.eigs create mode 100644 tests/phase2/rows/N4b.fn-neg-min.out create mode 100644 tests/phase2/rows/N4b.neg-min-raises.eigs create mode 100644 tests/phase2/rows/N4b.neg-min-raises.out create mode 100644 tests/phase2/rows/N5.osr-index-set.eigs create mode 100644 tests/phase2/rows/N5.osr-index-set.out create mode 100644 tests/phase2/rows/N7.num-type-float.eigs create mode 100644 tests/phase2/rows/N7.num-type-float.out create mode 100644 tests/phase2/rows/N7.num-type-int.eigs create mode 100644 tests/phase2/rows/N7.num-type-int.out create mode 100644 tests/phase2/rows/N7.num-type-non-number.eigs create mode 100644 tests/phase2/rows/N7.num-type-non-number.out create mode 100644 tests/phase2/rows/O1.int-observed-numeric.eigs create mode 100644 tests/phase2/rows/O1.int-observed-numeric.out create mode 100644 tests/phase2/rows/T1.float-kind-token.out create mode 100644 tests/phase2/rows/T1.float-kind-token.sh create mode 100644 tests/phase2/rows/T1.int-replay-kind.out create mode 100644 tests/phase2/rows/T1.int-replay-kind.sh create mode 100644 tests/phase2/rows/T1.twice-int.out create mode 100644 tests/phase2/rows/T1.twice-int.sh create mode 100644 tests/phase2/rows/T1.v6-refused.out create mode 100644 tests/phase2/rows/T1.v6-refused.sh create mode 100644 tests/phase2/rows/T1.v7-header.out create mode 100644 tests/phase2/rows/T1.v7-header.sh diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index f1463d144..264bd6bb2 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2105,7 +2105,7 @@ now has one of four shapes: last entry ends at the return sentinel is to run the whole body natively first. -The `L`, `F` and `O` rows (35 in the MAP) cover every JIT-emitter and leaf +The `L`, `F` and `O` rows (44 in the MAP) cover every JIT-emitter and leaf arm that holds a numeric site (the inventory's `## Numeric arms`, 20 today; §9.2 checks the coverage): the literals (`NUM_ZERO`, `NUM_ONE`, `CONST` and the new `INT_*`), the arithmetic, `DIV`/`MOD`, `NEG`/`NOT`/`BNOT`, the @@ -2189,7 +2189,7 @@ failing on zero rows: |---|---:|---| | R1.1 | 0 | mechanical: the compile errors (223 sites), the C slot test (§2.5; `examined` equals the derived classifier count), plant 1, the int-source check, and the differential over the suite's `.eigs` corpus | | R1.2 | 0 | mechanical: the compile errors (464 sites), the int-source check, and the differential over the suite's `.eigs` corpus (behaviour-preserving) | -| R1.3 | 44 | | +| R1.3 | 51 | `gate.N5.iterator-metadata` | | R1.4 | 6 | | | R1.5 | 7 | | | R1.6 | 17 | `gate.N5.q7-readers`, and the per-builtin behaviour table (§9.4) | @@ -2250,8 +2250,9 @@ fails if a round named here has neither rows nor its mechanical gates.) also shown in their own counters. - **Output, one line per tier:** `tier= examined=N rows tag_fail=N branch_pass=N vacuous=0 tag_timeout=K tag_signal=K`, then `controls=M - both_pass=M`, `witnessed=W` (the rows whose witness held), and an - environment banner (both binaries' `--version` and sha256). + both_pass=M`, `witnessed=W` (the rows whose witness held), + `controls_witnessed=C controls_vacuous=0` (shaped controls must prove their + tier on the branch too), and an environment banner (both binaries' `--version` and sha256). - **Exit 0** iff in every tier examined == tag_fail == branch_pass > 0 (or, for a mechanical round under `--through`, its named gates pass), vacuous == 0, the controls all pass on both, and the population checks diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 6693c107d..66ea93cf4 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -97,6 +97,14 @@ gates (design §9.2). --- ### N1 +- `N1.leaf-float-kind` [R1.3] leaf helpers return 1.0, 0.0 and 0.5; `num_type` checks their kinds before N6 changes their display + -> `["float", "float", "float"]` + tag: `num_type` undefined. + shape: L witness: leaf onef zerof halff ops: NUM_ONE NUM_ZERO CONST +- `N1.fn-float-kind` [R1.3] a hot function computes `a * 1.0 + 0.0`, then checks the result's kind + -> `["float", true]` + tag: `num_type` undefined. + shape: F witness: fn f ops: NUM_ONE NUM_ZERO MUL ADD - `N1.literal-kind` [R1.3] `print of [num_type of 3, num_type of 3.0, num_type of 1e3, num_type of 0x10]` -> `["int", "float", "float", "int"]` tag: `num_type` is undefined, an error (read) @@ -128,7 +136,7 @@ gates (design §9.2). -> `2.0` (the JIT's `NUM_ONE`/`NUM_ZERO` emitters keep their float meaning) tag: `2` (probed main) shape: F witness: fn f (witness probed main: `f 60 yes ... RET`) ops: NUM_ONE NUM_ZERO MUL ADD -- `N1.fn-int-literal` [R1.3] `define g(a) as: t is a + 1 / return t * 2`, called 60 times with `9007199254740992`; print the last result +- `N1.fn-int-literal` [R1.3] `define g(a) as: warm is 0.5 / t is a + 1 / return t * 2`, called 60 times with `9007199254740992`; print the last result -> `18014398509481986` tag: `18014398509481984` (probed main) shape: F witness: fn-stop g INT_ONE (the JIT scanner refuses the new opcode) ops: INT_ONE @@ -156,6 +164,9 @@ gates (design §9.2). shape: O witness: osr-stop count INT_ONE (the OSR scanner stops at the literal `1`, the body's first int op) ops: INT_ONE ### N2 +- `N2.sort-by-exact` [R1.3] numeric key callbacks return both int and float keys around 2^53, with a stable equal-key pair + -> `["low", "tie-a", "tie-b", "high"]` + tag: the high int rounds to the low float, so the input order survives. - `N2.int-eq-float-kinds` [R1.3] `print of [1 == 1.0, 1 != 1.0, num_type of 1, num_type of 1.0]` -> `[true, false, "int", "float"]` tag: `num_type` undefined (read) @@ -242,7 +253,7 @@ gates (design §9.2). -> `value` (the leaf bails; the generic path raises with the caller's line) tag: `9.22337203700025e+18`, no raise (probed main) shape: L witness: leaf-gen sq ops: MUL -- `A.fn-add-overflow` [R1.3] `define inc(a) as: t is a + 1 / return t`, called 60 times with small ints, then `{try print of (inc of 9223372036854775807) catch}`, printing `e.kind` +- `A.fn-add-overflow` [R1.3] `define inc(a) as: warm is 0.5 / t is a + 1 / return t`, called 60 times with small ints, then `{try print of (inc of 9223372036854775807) catch}`, printing `e.kind` -> `value` tag: `9.223372036854776e+18`, no raise (probed main) shape: F witness: fn-stop inc INT_ONE ops: INT_ONE @@ -295,7 +306,7 @@ gates (design §9.2). - `N4b.neg-min-raises` [R1.3] `m is -9223372036854775807 - 1 / {try print of (-m) catch}` -> `["value", true]`, the message naming the unary minus tag: a double, no raise. **Plant 5's named check.** -- `N4b.abs-min-raises` [R1.6] `m is -9223372036854775807 - 1 / {try print of (abs of m) catch}` +- `N4b.abs-min-raises` [R1.3] `m is -9223372036854775807 - 1 / {try print of (abs of m) catch}` -> `["value", true]` tag: `9.223372036854776e+18`, no raise - `N4b.floordiv-min-by-neg1-raises` [R1.4] `m is ... / {try print of (m // -1) catch}` @@ -310,6 +321,9 @@ gates (design §9.2). shape: F witness: fn-stop n NEG ops: NEG ### N5 +- `gate.N5.iterator-metadata` [R1.3] `tests/phase2/slot_layer.sh` Part E builds raw iterator states and runs the interpreter and `jit_helper_iter_next` + -> float controls and both SMI/boxed index/snapshot metadata yield 42; range and malformed states preserve the pinned exhaustion/ignore rules. + tag: n/a (a C fixture of the four R1.2 refusal sites); final R1.3 arms accept exact C-int indices and clamp snapshots without narrowing. - `N5.substr-fraction-raises` [R1.6] `{try print of (substr of ["hello", 1.5, 2]) catch}`, printing `e.kind` -> `value` tag: `el` (probed main: truncation) @@ -372,7 +386,7 @@ gates (design §9.2). - `N7.num-type-int` [R1.3] `print of [num_type of 0, num_type of -1, num_type of 9223372036854775807, num_type of (2 * 3)]` -> `["int", "int", "int", "int"]` tag: undefined -- `N7.num-type-non-number` [R1.3] `print of [num_type of "3", num_type of null, num_type of true, num_type of [1]]` +- `N7.num-type-non-number` [R1.3] `print of [num_type of "3", num_type of null, num_type of true, num_type of ([1])]` -> `[null, null, null, null]` (Lua `math.type` returns fail) tag: undefined - `gate.N7.embed-int` [R1.8] `make embed-smoke` with new rows: `eigs_value_new_int` round-trips 9007199254740993 exactly; `eigs_value_as_int` succeeds on an int and on an integral float, and fails with its flag on 1.5; `eigs_value_is_int` tells the kinds apart; `eigs_value_as_num` converts an int (Q3); `EIGS_TYPE_NUM` answers for both @@ -380,6 +394,27 @@ gates (design §9.2). tag: n/a (a C test of new embed functions), so it is a gate ### N8 +- `ctl.N8.refuse-band` (control) a hot function applies `a & b` to float operands 6.0 and 3.0 + -> `2` on both; the JIT scanner refuses this opcode at R1.3. + shape: F witness: fn-stop f BAND ops: BAND +- `ctl.N8.refuse-bor` (control) a hot function applies `a | b` to float operands 6.0 and 3.0 + -> `7` on both; the JIT scanner refuses this opcode at R1.3. + shape: F witness: fn-stop f BOR ops: BOR +- `ctl.N8.refuse-bxor` (control) a hot function applies `a ^ b` to float operands 6.0 and 3.0 + -> `5` on both; the JIT scanner refuses this opcode at R1.3. + shape: F witness: fn-stop f BXOR ops: BXOR +- `ctl.N8.refuse-shl` (control) a hot function applies `a << b` to float operands 6.0 and 3.0 + -> `48` on both; the JIT scanner refuses this opcode at R1.3. + shape: F witness: fn-stop f SHL ops: SHL +- `ctl.N8.refuse-shr` (control) a hot function applies `a >> b` to float operands 6.0 and 3.0 + -> `0` on both; the JIT scanner refuses this opcode at R1.3. + shape: F witness: fn-stop f SHR ops: SHR +- `ctl.N8.refuse-bnot` (control) a hot function applies `~a` to float operands 6.0 and 3.0 + -> `-7` on both; the JIT scanner refuses this opcode at R1.3. + shape: F witness: fn-stop f BNOT ops: BNOT +- `ctl.N8.refuse-mod` (control) a hot function applies `a % b` to float operands 6.0 and 3.0 + -> `0` on both; the JIT scanner refuses this opcode at R1.3. + shape: F witness: fn-stop f MOD ops: MOD - `N8.bitwise-results-int` [R1.5] `print of [6 & 3, 6 | 3, 6 ^ 3, ~0, num_type of (6 & 3)]` -> `[2, 7, 5, -1, "int"]` tag: `num_type` undefined @@ -491,6 +526,15 @@ The builtin names are decided in round 1 (`` etc. below are placehold tag: no raise, bytes `0, 0` (probed main) ### N14 +- `N14.json-build-int-exact` [R1.3] `json_build` emits an SMI and both int64 endpoints as exact JSON digits + -> `{"small": 3, "big": 9223372036854775807, "min": -9223372036854775808}` + tag: big literals round through double. +- `N14.json-encode-int-exact` [R1.3] `json_encode` walks int list and dict slots, including int64 endpoints + -> `[3,9223372036854775807,{"min":-9223372036854775808}]` + tag: big literals round through double. +- `N14.json-path-int-exact` [R1.6] `print of (json_path of ["{\"n\":9223372036854775807}", "n"])` + -> `9223372036854775807` + tag: the decoder rounds before the exact text arm (written in R1.2) can read it. - `N14.encode-kinds` [R1.7] `print of (json_encode of [3, 3.0, 0.1, -0.0])` -> `[3,3.0,0.1,-0.0]` tag: `[3,3,0.1,0]` (probed main for the first three) @@ -508,6 +552,9 @@ The builtin names are decided in round 1 (`` etc. below are placehold tag: n/a (a C test, not a program); today's `"%g"` binds `1.23457e+06` (#1762). It needs no PostgreSQL server, so it runs in CI as a gate. ### T1 +- `T1.float-kind-token` [R1.3] (sh row) record `x is 3.0 / z is -0.0`, assert the v7 assignment tokens mark both as floats, replay and compare stdout + -> `float tokens marked`, `float replay identical` + tag: v6 emits `x=3` and `z=-0`, losing kind. A planted v6-format float writer makes this row fail. - `T1.v7-header` [R1.3] (sh row) `EIGS_TRACE=t.tape eigenscript p.eigs; head -1 t.tape | cut -d' ' -f1-2` -> `V 7` tag: `V 6` @@ -517,8 +564,8 @@ The builtin names are decided in round 1 (`` etc. below are placehold - `T1.twice-float` [R1.7] (sh row) the same procedure for `x is 3.0 / y is 0.1 + 0.2 / z is -0.0 / print of [x, y, z]` -> `tapes identical`, `replay identical`, `A 0 x=3.0`, `A 0 y=0.30000000000000004`, `A 0 z=-0.0` (the kind on the tape; the exact text is N6's, R1.7) tag: `A 0 x=3` and `A 0 z=-0` (read: `%.17g`) -- `T1.int-replay-kind` [R1.3] (sh row) record `r is random_int of [1, 6] / print of [r, num_type of r]`, then replay - -> the same line twice, kind `"int"` on replay +- `T1.int-replay-kind` [R1.3] (sh row) record a replayed `random_int` draw selecting an int literal; print its exact value and `num_type`, then replay and compare bytes + -> `int replay identical`, `int assignment exact` (the int is carried by the v7 assignment record; `random_int` retains the float bridge until R1.6) tag: `num_type` undefined - `T1.v6-refused` [R1.3] (sh row) `EIGS_REPLAY=tests/phase2/fixtures/v6.tape eigenscript p.eigs`; print the rc and whether stderr names version 6 -> `rc!=0 names-6` diff --git a/tests/phase2/controls/ctl.B.type-of.eigs b/tests/phase2/controls/ctl.B.type-of.eigs new file mode 100644 index 000000000..b510344d2 --- /dev/null +++ b/tests/phase2/controls/ctl.B.type-of.eigs @@ -0,0 +1,7 @@ +# ROW: ctl.B.type-of +# ITEMS: B +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [type of 3, type of 3.0, type of -2] diff --git a/tests/phase2/controls/ctl.B.type-of.out b/tests/phase2/controls/ctl.B.type-of.out new file mode 100644 index 000000000..4a404923f --- /dev/null +++ b/tests/phase2/controls/ctl.B.type-of.out @@ -0,0 +1 @@ +["num", "num", "num"] diff --git a/tests/phase2/controls/ctl.N1.fn-int-not.eigs b/tests/phase2/controls/ctl.N1.fn-int-not.eigs new file mode 100644 index 000000000..2fad284c1 --- /dev/null +++ b/tests/phase2/controls/ctl.N1.fn-int-not.eigs @@ -0,0 +1,15 @@ +# ROW: ctl.N1.fn-int-not +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop neg NOT +# OPS: NOT +define neg(a) as: + r is not a + return r +r is null +i is 0.0 +loop while i < 60.0: + r is neg of 0 + i is i + 1.0 +print of [neg of 0.0, neg of 5, neg of 0] diff --git a/tests/phase2/controls/ctl.N1.fn-int-not.out b/tests/phase2/controls/ctl.N1.fn-int-not.out new file mode 100644 index 000000000..c8069fd98 --- /dev/null +++ b/tests/phase2/controls/ctl.N1.fn-int-not.out @@ -0,0 +1 @@ +[true, false, true] diff --git a/tests/phase2/controls/ctl.N1.fn-int-truthiness.eigs b/tests/phase2/controls/ctl.N1.fn-int-truthiness.eigs new file mode 100644 index 000000000..80092fdf1 --- /dev/null +++ b/tests/phase2/controls/ctl.N1.fn-int-truthiness.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N1.fn-int-truthiness +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop truth JUMP_IF_FALSE +# OPS: JUMP_IF_FALSE +define truth(a) as: + if a: + return 1 + return 2 +r is null +i is 0.0 +loop while i < 60.0: + r is truth of 0 + i is i + 1.0 +print of [truth of 0.0, truth of 5, truth of 0] diff --git a/tests/phase2/controls/ctl.N1.fn-int-truthiness.out b/tests/phase2/controls/ctl.N1.fn-int-truthiness.out new file mode 100644 index 000000000..13e72c4e7 --- /dev/null +++ b/tests/phase2/controls/ctl.N1.fn-int-truthiness.out @@ -0,0 +1 @@ +[2, 1, 2] diff --git a/tests/phase2/controls/ctl.N2.float-eq.eigs b/tests/phase2/controls/ctl.N2.float-eq.eigs new file mode 100644 index 000000000..2818a515e --- /dev/null +++ b/tests/phase2/controls/ctl.N2.float-eq.eigs @@ -0,0 +1,7 @@ +# ROW: ctl.N2.float-eq +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [0.5 + 0.25 == 0.75, 1 == 1.0, 3 < 3.5] diff --git a/tests/phase2/controls/ctl.N2.float-eq.out b/tests/phase2/controls/ctl.N2.float-eq.out new file mode 100644 index 000000000..601ef4cf6 --- /dev/null +++ b/tests/phase2/controls/ctl.N2.float-eq.out @@ -0,0 +1 @@ +[true, true, true] diff --git a/tests/phase2/controls/ctl.N2.fn-float-compare.eigs b/tests/phase2/controls/ctl.N2.fn-float-compare.eigs new file mode 100644 index 000000000..dcf677fa1 --- /dev/null +++ b/tests/phase2/controls/ctl.N2.fn-float-compare.eigs @@ -0,0 +1,15 @@ +# ROW: ctl.N2.fn-float-compare +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn ltf +# OPS: LT +define ltf(a, b) as: + t is a < b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is ltf of [0.5, 0.75] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N2.fn-float-compare.out b/tests/phase2/controls/ctl.N2.fn-float-compare.out new file mode 100644 index 000000000..27ba77dda --- /dev/null +++ b/tests/phase2/controls/ctl.N2.fn-float-compare.out @@ -0,0 +1 @@ +true diff --git a/tests/phase2/controls/ctl.N3.leaf-float.eigs b/tests/phase2/controls/ctl.N3.leaf-float.eigs new file mode 100644 index 000000000..49c426800 --- /dev/null +++ b/tests/phase2/controls/ctl.N3.leaf-float.eigs @@ -0,0 +1,9 @@ +# ROW: ctl.N3.leaf-float +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf sqf +# OPS: MUL +define sqf(x) as: + return x * x +print of (sqf of 1.5) diff --git a/tests/phase2/controls/ctl.N3.leaf-float.out b/tests/phase2/controls/ctl.N3.leaf-float.out new file mode 100644 index 000000000..8bd2249ac --- /dev/null +++ b/tests/phase2/controls/ctl.N3.leaf-float.out @@ -0,0 +1 @@ +2.25 diff --git a/tests/phase2/controls/ctl.N3.osr-float.eigs b/tests/phase2/controls/ctl.N3.osr-float.eigs new file mode 100644 index 000000000..717569485 --- /dev/null +++ b/tests/phase2/controls/ctl.N3.osr-float.eigs @@ -0,0 +1,15 @@ +# ROW: ctl.N3.osr-float +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr totalf +# OPS: ADD CONST NUM_ONE GE JUMP_IF_FALSE SET_LOCAL POP +define totalf(n) as: + acc is 0.5 + i is 0.0 + loop while true: + acc is acc + 1.5 + i is i + 1.0 + if i >= n: + return acc +print of (totalf of 100.0) diff --git a/tests/phase2/controls/ctl.N3.osr-float.out b/tests/phase2/controls/ctl.N3.osr-float.out new file mode 100644 index 000000000..1450a7edc --- /dev/null +++ b/tests/phase2/controls/ctl.N3.osr-float.out @@ -0,0 +1 @@ +150.5 diff --git a/tests/phase2/controls/ctl.N3.small-ints.eigs b/tests/phase2/controls/ctl.N3.small-ints.eigs new file mode 100644 index 000000000..8c8baf766 --- /dev/null +++ b/tests/phase2/controls/ctl.N3.small-ints.eigs @@ -0,0 +1,7 @@ +# ROW: ctl.N3.small-ints +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [1 + 2, 10 - 3, 6 * 7, -4] diff --git a/tests/phase2/controls/ctl.N3.small-ints.out b/tests/phase2/controls/ctl.N3.small-ints.out new file mode 100644 index 000000000..4ab2659de --- /dev/null +++ b/tests/phase2/controls/ctl.N3.small-ints.out @@ -0,0 +1 @@ +[3, 7, 42, -4] diff --git a/tests/phase2/controls/ctl.N4.int-mod-zero-raises.eigs b/tests/phase2/controls/ctl.N4.int-mod-zero-raises.eigs new file mode 100644 index 000000000..087071ec1 --- /dev/null +++ b/tests/phase2/controls/ctl.N4.int-mod-zero-raises.eigs @@ -0,0 +1,10 @@ +# ROW: ctl.N4.int-mod-zero-raises +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +try: + x is 7 % 0 +catch e: + print of e.kind diff --git a/tests/phase2/controls/ctl.N4.int-mod-zero-raises.out b/tests/phase2/controls/ctl.N4.int-mod-zero-raises.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/controls/ctl.N4.int-mod-zero-raises.out @@ -0,0 +1 @@ +value diff --git a/tests/phase2/controls/ctl.N5.leaf-float-index.eigs b/tests/phase2/controls/ctl.N5.leaf-float-index.eigs new file mode 100644 index 000000000..97f1d83d8 --- /dev/null +++ b/tests/phase2/controls/ctl.N5.leaf-float-index.eigs @@ -0,0 +1,9 @@ +# ROW: ctl.N5.leaf-float-index +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf nth +# OPS: INDEX_GET +define nth(xs, i) as: + return xs[i] +print of (nth of [[10, 20, 30], 1.0]) diff --git a/tests/phase2/controls/ctl.N5.leaf-float-index.out b/tests/phase2/controls/ctl.N5.leaf-float-index.out new file mode 100644 index 000000000..209e3ef4b --- /dev/null +++ b/tests/phase2/controls/ctl.N5.leaf-float-index.out @@ -0,0 +1 @@ +20 diff --git a/tests/phase2/controls/ctl.N6.small-ints.eigs b/tests/phase2/controls/ctl.N6.small-ints.eigs new file mode 100644 index 000000000..16504832e --- /dev/null +++ b/tests/phase2/controls/ctl.N6.small-ints.eigs @@ -0,0 +1,7 @@ +# ROW: ctl.N6.small-ints +# ITEMS: N6 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [1, 2, 3, -4, 100000] diff --git a/tests/phase2/controls/ctl.N6.small-ints.out b/tests/phase2/controls/ctl.N6.small-ints.out new file mode 100644 index 000000000..347be4583 --- /dev/null +++ b/tests/phase2/controls/ctl.N6.small-ints.out @@ -0,0 +1 @@ +[1, 2, 3, -4, 100000] diff --git a/tests/phase2/controls/ctl.N8.refuse-band.eigs b/tests/phase2/controls/ctl.N8.refuse-band.eigs new file mode 100644 index 000000000..8cc796963 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-band.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N8.refuse-band +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f BAND +# OPS: BAND +define f(a, b) as: + warm is 0.5 + t is a & b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is f of [6.0, 3.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N8.refuse-band.out b/tests/phase2/controls/ctl.N8.refuse-band.out new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-band.out @@ -0,0 +1 @@ +2 diff --git a/tests/phase2/controls/ctl.N8.refuse-bnot.eigs b/tests/phase2/controls/ctl.N8.refuse-bnot.eigs new file mode 100644 index 000000000..801812693 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-bnot.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N8.refuse-bnot +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f BNOT +# OPS: BNOT +define f(a, b) as: + warm is 0.5 + t is ~a + return t +r is null +i is 0.0 +loop while i < 60.0: + r is f of [6.0, 3.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N8.refuse-bnot.out b/tests/phase2/controls/ctl.N8.refuse-bnot.out new file mode 100644 index 000000000..17bdab103 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-bnot.out @@ -0,0 +1 @@ +-7 diff --git a/tests/phase2/controls/ctl.N8.refuse-bor.eigs b/tests/phase2/controls/ctl.N8.refuse-bor.eigs new file mode 100644 index 000000000..a2ca16187 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-bor.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N8.refuse-bor +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f BOR +# OPS: BOR +define f(a, b) as: + warm is 0.5 + t is a | b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is f of [6.0, 3.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N8.refuse-bor.out b/tests/phase2/controls/ctl.N8.refuse-bor.out new file mode 100644 index 000000000..7f8f011eb --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-bor.out @@ -0,0 +1 @@ +7 diff --git a/tests/phase2/controls/ctl.N8.refuse-bxor.eigs b/tests/phase2/controls/ctl.N8.refuse-bxor.eigs new file mode 100644 index 000000000..8a970ca5c --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-bxor.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N8.refuse-bxor +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f BXOR +# OPS: BXOR +define f(a, b) as: + warm is 0.5 + t is a ^ b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is f of [6.0, 3.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N8.refuse-bxor.out b/tests/phase2/controls/ctl.N8.refuse-bxor.out new file mode 100644 index 000000000..7ed6ff82d --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-bxor.out @@ -0,0 +1 @@ +5 diff --git a/tests/phase2/controls/ctl.N8.refuse-mod.eigs b/tests/phase2/controls/ctl.N8.refuse-mod.eigs new file mode 100644 index 000000000..154c25f62 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-mod.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N8.refuse-mod +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f MOD +# OPS: MOD +define f(a, b) as: + warm is 0.5 + t is a % b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is f of [6.0, 3.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N8.refuse-mod.out b/tests/phase2/controls/ctl.N8.refuse-mod.out new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-mod.out @@ -0,0 +1 @@ +0 diff --git a/tests/phase2/controls/ctl.N8.refuse-shl.eigs b/tests/phase2/controls/ctl.N8.refuse-shl.eigs new file mode 100644 index 000000000..32586e9fe --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-shl.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N8.refuse-shl +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f SHL +# OPS: SHL +define f(a, b) as: + warm is 0.5 + t is a << b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is f of [6.0, 3.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N8.refuse-shl.out b/tests/phase2/controls/ctl.N8.refuse-shl.out new file mode 100644 index 000000000..21e72e8ac --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-shl.out @@ -0,0 +1 @@ +48 diff --git a/tests/phase2/controls/ctl.N8.refuse-shr.eigs b/tests/phase2/controls/ctl.N8.refuse-shr.eigs new file mode 100644 index 000000000..e404f0f0b --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-shr.eigs @@ -0,0 +1,16 @@ +# ROW: ctl.N8.refuse-shr +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f SHR +# OPS: SHR +define f(a, b) as: + warm is 0.5 + t is a >> b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is f of [6.0, 3.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/controls/ctl.N8.refuse-shr.out b/tests/phase2/controls/ctl.N8.refuse-shr.out new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/phase2/controls/ctl.N8.refuse-shr.out @@ -0,0 +1 @@ +0 diff --git a/tests/phase2/rows/A.add-overflow-raises.eigs b/tests/phase2/rows/A.add-overflow-raises.eigs new file mode 100644 index 000000000..c4d7e56c5 --- /dev/null +++ b/tests/phase2/rows/A.add-overflow-raises.eigs @@ -0,0 +1,10 @@ +# ROW: A.add-overflow-raises +# ITEMS: A +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +try: + print of (9223372036854775807 + 1) +catch e: + print of [e.kind, (index_of of [e.message, "+"]) >= 0] diff --git a/tests/phase2/rows/A.add-overflow-raises.out b/tests/phase2/rows/A.add-overflow-raises.out new file mode 100644 index 000000000..56efea05e --- /dev/null +++ b/tests/phase2/rows/A.add-overflow-raises.out @@ -0,0 +1 @@ +["value", true] diff --git a/tests/phase2/rows/A.fn-add-overflow.eigs b/tests/phase2/rows/A.fn-add-overflow.eigs new file mode 100644 index 000000000..ee028484c --- /dev/null +++ b/tests/phase2/rows/A.fn-add-overflow.eigs @@ -0,0 +1,19 @@ +# ROW: A.fn-add-overflow +# ITEMS: A +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop inc INT_ONE +# OPS: INT_ONE +define inc(a) as: + warm is 0.5 + t is a + 1 + return t +r is null +i is 0.0 +loop while i < 60.0: + r is inc of 2 + i is i + 1.0 +try: + print of (inc of 9223372036854775807) +catch e: + print of e.kind diff --git a/tests/phase2/rows/A.fn-add-overflow.out b/tests/phase2/rows/A.fn-add-overflow.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/rows/A.fn-add-overflow.out @@ -0,0 +1 @@ +value diff --git a/tests/phase2/rows/A.leaf-mul-overflow.eigs b/tests/phase2/rows/A.leaf-mul-overflow.eigs new file mode 100644 index 000000000..fded1f911 --- /dev/null +++ b/tests/phase2/rows/A.leaf-mul-overflow.eigs @@ -0,0 +1,12 @@ +# ROW: A.leaf-mul-overflow +# ITEMS: A +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf-gen sq +# OPS: MUL +define sq(x) as: + return x * x +try: + print of (sq of 3037000500) +catch e: + print of e.kind diff --git a/tests/phase2/rows/A.leaf-mul-overflow.out b/tests/phase2/rows/A.leaf-mul-overflow.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/rows/A.leaf-mul-overflow.out @@ -0,0 +1 @@ +value diff --git a/tests/phase2/rows/A.mul-overflow-raises.eigs b/tests/phase2/rows/A.mul-overflow-raises.eigs new file mode 100644 index 000000000..318ac2f3d --- /dev/null +++ b/tests/phase2/rows/A.mul-overflow-raises.eigs @@ -0,0 +1,10 @@ +# ROW: A.mul-overflow-raises +# ITEMS: A +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +try: + print of (4611686018427387904 * 2) +catch e: + print of [e.kind, (index_of of [e.message, "*"]) >= 0] diff --git a/tests/phase2/rows/A.mul-overflow-raises.out b/tests/phase2/rows/A.mul-overflow-raises.out new file mode 100644 index 000000000..56efea05e --- /dev/null +++ b/tests/phase2/rows/A.mul-overflow-raises.out @@ -0,0 +1 @@ +["value", true] diff --git a/tests/phase2/rows/A.osr-double-overflow.eigs b/tests/phase2/rows/A.osr-double-overflow.eigs new file mode 100644 index 000000000..f527f752f --- /dev/null +++ b/tests/phase2/rows/A.osr-double-overflow.eigs @@ -0,0 +1,18 @@ +# ROW: A.osr-double-overflow +# ITEMS: A +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr-stop dbl MUL +# OPS: MUL +define dbl(n, two) as: + x is two + i is 1.0 + loop while true: + x is x * two + i is i + 1.0 + if i >= n: + return x +try: + print of (dbl of [63.0, 2]) +catch e: + print of e.kind diff --git a/tests/phase2/rows/A.osr-double-overflow.out b/tests/phase2/rows/A.osr-double-overflow.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/rows/A.osr-double-overflow.out @@ -0,0 +1 @@ +value diff --git a/tests/phase2/rows/A.sub-overflow-raises.eigs b/tests/phase2/rows/A.sub-overflow-raises.eigs new file mode 100644 index 000000000..fba24880f --- /dev/null +++ b/tests/phase2/rows/A.sub-overflow-raises.eigs @@ -0,0 +1,10 @@ +# ROW: A.sub-overflow-raises +# ITEMS: A +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +try: + print of (-9223372036854775807 - 2) +catch e: + print of [e.kind, (index_of of [e.message, "-"]) >= 0] diff --git a/tests/phase2/rows/A.sub-overflow-raises.out b/tests/phase2/rows/A.sub-overflow-raises.out new file mode 100644 index 000000000..56efea05e --- /dev/null +++ b/tests/phase2/rows/A.sub-overflow-raises.out @@ -0,0 +1 @@ +["value", true] diff --git a/tests/phase2/rows/B.type-of-both-num.eigs b/tests/phase2/rows/B.type-of-both-num.eigs new file mode 100644 index 000000000..1b8a03a1e --- /dev/null +++ b/tests/phase2/rows/B.type-of-both-num.eigs @@ -0,0 +1,7 @@ +# ROW: B.type-of-both-num +# ITEMS: B +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [type of 3, type of 3.0, (type of 3) == (type of 3.0), num_type of 3] diff --git a/tests/phase2/rows/B.type-of-both-num.out b/tests/phase2/rows/B.type-of-both-num.out new file mode 100644 index 000000000..d87d0837b --- /dev/null +++ b/tests/phase2/rows/B.type-of-both-num.out @@ -0,0 +1 @@ +["num", "num", true, "int"] diff --git a/tests/phase2/rows/N1.canon-eq.eigs b/tests/phase2/rows/N1.canon-eq.eigs new file mode 100644 index 000000000..94e61d179 --- /dev/null +++ b/tests/phase2/rows/N1.canon-eq.eigs @@ -0,0 +1,9 @@ +# ROW: N1.canon-eq +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +a is abs of -5 +b is 0 - 5 +print of [a == 5, -b == 5, num_type of a] diff --git a/tests/phase2/rows/N1.canon-eq.out b/tests/phase2/rows/N1.canon-eq.out new file mode 100644 index 000000000..16c0e6f1b --- /dev/null +++ b/tests/phase2/rows/N1.canon-eq.out @@ -0,0 +1 @@ +[true, true, "int"] diff --git a/tests/phase2/rows/N1.decimal-past-int64-is-float.eigs b/tests/phase2/rows/N1.decimal-past-int64-is-float.eigs new file mode 100644 index 000000000..c5db139cc --- /dev/null +++ b/tests/phase2/rows/N1.decimal-past-int64-is-float.eigs @@ -0,0 +1,8 @@ +# ROW: N1.decimal-past-int64-is-float +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +x is 9223372036854775808 +print of [num_type of x, x] diff --git a/tests/phase2/rows/N1.decimal-past-int64-is-float.out b/tests/phase2/rows/N1.decimal-past-int64-is-float.out new file mode 100644 index 000000000..958576330 --- /dev/null +++ b/tests/phase2/rows/N1.decimal-past-int64-is-float.out @@ -0,0 +1 @@ +["float", 9.223372036854776e+18] diff --git a/tests/phase2/rows/N1.exact-past-2p53.eigs b/tests/phase2/rows/N1.exact-past-2p53.eigs new file mode 100644 index 000000000..9ffc01acf --- /dev/null +++ b/tests/phase2/rows/N1.exact-past-2p53.eigs @@ -0,0 +1,7 @@ +# ROW: N1.exact-past-2p53 +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [9007199254740993, 9223372036854775807] diff --git a/tests/phase2/rows/N1.exact-past-2p53.out b/tests/phase2/rows/N1.exact-past-2p53.out new file mode 100644 index 000000000..8e07d68ac --- /dev/null +++ b/tests/phase2/rows/N1.exact-past-2p53.out @@ -0,0 +1 @@ +[9007199254740993, 9223372036854775807] diff --git a/tests/phase2/rows/N1.fn-dot-fields.eigs b/tests/phase2/rows/N1.fn-dot-fields.eigs new file mode 100644 index 000000000..43ab9882e --- /dev/null +++ b/tests/phase2/rows/N1.fn-dot-fields.eigs @@ -0,0 +1,15 @@ +# ROW: N1.fn-dot-fields +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn setx +# OPS: LOCAL_DOT_SET LOCAL_DOT_GET +define setx(p, q) as: + p.x is q + return p.x +r is null +i is 0.0 +loop while i < 60.0: + r is setx of [{"x": 1}, 9007199254740993] + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N1.fn-dot-fields.out b/tests/phase2/rows/N1.fn-dot-fields.out new file mode 100644 index 000000000..ba278ab07 --- /dev/null +++ b/tests/phase2/rows/N1.fn-dot-fields.out @@ -0,0 +1 @@ +9007199254740993 diff --git a/tests/phase2/rows/N1.fn-float-kind.eigs b/tests/phase2/rows/N1.fn-float-kind.eigs new file mode 100644 index 000000000..848374fb3 --- /dev/null +++ b/tests/phase2/rows/N1.fn-float-kind.eigs @@ -0,0 +1,16 @@ +# ROW: N1.fn-float-kind +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn f +# OPS: NUM_ONE NUM_ZERO MUL ADD +define f(a) as: + t is a * 1.0 + u is t + 0.0 + return u +r is null +i is 0.0 +loop while i < 60.0: + r is f of 2.0 + i is i + 1.0 +print of [num_type of r, r == 2.0] diff --git a/tests/phase2/rows/N1.fn-float-kind.out b/tests/phase2/rows/N1.fn-float-kind.out new file mode 100644 index 000000000..62e3a0482 --- /dev/null +++ b/tests/phase2/rows/N1.fn-float-kind.out @@ -0,0 +1 @@ +["float", true] diff --git a/tests/phase2/rows/N1.fn-int-literal.eigs b/tests/phase2/rows/N1.fn-int-literal.eigs new file mode 100644 index 000000000..0649ac1de --- /dev/null +++ b/tests/phase2/rows/N1.fn-int-literal.eigs @@ -0,0 +1,16 @@ +# ROW: N1.fn-int-literal +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop g INT_ONE +# OPS: INT_ONE +define g(a) as: + warm is 0.5 + t is a + 1 + return t * 2 +r is null +i is 0.0 +loop while i < 60.0: + r is g of 9007199254740992 + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N1.fn-int-literal.out b/tests/phase2/rows/N1.fn-int-literal.out new file mode 100644 index 000000000..07fc2a0e2 --- /dev/null +++ b/tests/phase2/rows/N1.fn-int-literal.out @@ -0,0 +1 @@ +18014398509481986 diff --git a/tests/phase2/rows/N1.fn-int-local.eigs b/tests/phase2/rows/N1.fn-int-local.eigs new file mode 100644 index 000000000..64ed02d91 --- /dev/null +++ b/tests/phase2/rows/N1.fn-int-local.eigs @@ -0,0 +1,15 @@ +# ROW: N1.fn-int-local +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn keep +# OPS: SET_LOCAL POP +define keep(q) as: + t is q + return t +r is null +i is 0.0 +loop while i < 60.0: + r is keep of 9007199254740993 + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N1.fn-int-local.out b/tests/phase2/rows/N1.fn-int-local.out new file mode 100644 index 000000000..ba278ab07 --- /dev/null +++ b/tests/phase2/rows/N1.fn-int-local.out @@ -0,0 +1 @@ +9007199254740993 diff --git a/tests/phase2/rows/N1.hex-wraps.eigs b/tests/phase2/rows/N1.hex-wraps.eigs new file mode 100644 index 000000000..a6734c0fa --- /dev/null +++ b/tests/phase2/rows/N1.hex-wraps.eigs @@ -0,0 +1,7 @@ +# ROW: N1.hex-wraps +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [0x1FFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF] diff --git a/tests/phase2/rows/N1.hex-wraps.out b/tests/phase2/rows/N1.hex-wraps.out new file mode 100644 index 000000000..d8d8f6a9d --- /dev/null +++ b/tests/phase2/rows/N1.hex-wraps.out @@ -0,0 +1 @@ +[-1, -1, 9223372036854775807] diff --git a/tests/phase2/rows/N1.leaf-dot-get.eigs b/tests/phase2/rows/N1.leaf-dot-get.eigs new file mode 100644 index 000000000..b78e45a9c --- /dev/null +++ b/tests/phase2/rows/N1.leaf-dot-get.eigs @@ -0,0 +1,10 @@ +# ROW: N1.leaf-dot-get +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf px +# OPS: LOCAL_DOT_GET +define px(p) as: + return p.x +d is {"x": 9007199254740993} +print of (px of d) diff --git a/tests/phase2/rows/N1.leaf-dot-get.out b/tests/phase2/rows/N1.leaf-dot-get.out new file mode 100644 index 000000000..ba278ab07 --- /dev/null +++ b/tests/phase2/rows/N1.leaf-dot-get.out @@ -0,0 +1 @@ +9007199254740993 diff --git a/tests/phase2/rows/N1.leaf-float-kind.eigs b/tests/phase2/rows/N1.leaf-float-kind.eigs new file mode 100644 index 000000000..483389f54 --- /dev/null +++ b/tests/phase2/rows/N1.leaf-float-kind.eigs @@ -0,0 +1,13 @@ +# ROW: N1.leaf-float-kind +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf onef zerof halff +# OPS: NUM_ONE NUM_ZERO CONST +define onef(x) as: + return 1.0 +define zerof(x) as: + return 0.0 +define halff(x) as: + return 0.5 +print of [num_type of (onef of 7), num_type of (zerof of 7), num_type of (halff of 7)] diff --git a/tests/phase2/rows/N1.leaf-float-kind.out b/tests/phase2/rows/N1.leaf-float-kind.out new file mode 100644 index 000000000..bbf995e58 --- /dev/null +++ b/tests/phase2/rows/N1.leaf-float-kind.out @@ -0,0 +1 @@ +["float", "float", "float"] diff --git a/tests/phase2/rows/N1.leaf-int-literal.eigs b/tests/phase2/rows/N1.leaf-int-literal.eigs new file mode 100644 index 000000000..c200ef9c8 --- /dev/null +++ b/tests/phase2/rows/N1.leaf-int-literal.eigs @@ -0,0 +1,11 @@ +# ROW: N1.leaf-int-literal +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf-gen big one +# OPS: INT_CONST INT_ONE +define big(x) as: + return 9007199254740993 +define one(x) as: + return 1 +print of [big of 0, one of 0] diff --git a/tests/phase2/rows/N1.leaf-int-literal.out b/tests/phase2/rows/N1.leaf-int-literal.out new file mode 100644 index 000000000..70aa4847c --- /dev/null +++ b/tests/phase2/rows/N1.leaf-int-literal.out @@ -0,0 +1 @@ +[9007199254740993, 1] diff --git a/tests/phase2/rows/N1.literal-kind.eigs b/tests/phase2/rows/N1.literal-kind.eigs new file mode 100644 index 000000000..7f709a76d --- /dev/null +++ b/tests/phase2/rows/N1.literal-kind.eigs @@ -0,0 +1,7 @@ +# ROW: N1.literal-kind +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [num_type of 3, num_type of 3.0, num_type of 1e3, num_type of 0x10] diff --git a/tests/phase2/rows/N1.literal-kind.out b/tests/phase2/rows/N1.literal-kind.out new file mode 100644 index 000000000..8b2dde2b3 --- /dev/null +++ b/tests/phase2/rows/N1.literal-kind.out @@ -0,0 +1 @@ +["int", "float", "float", "int"] diff --git a/tests/phase2/rows/N1.osr-global-int-store.eigs b/tests/phase2/rows/N1.osr-global-int-store.eigs new file mode 100644 index 000000000..de81e9986 --- /dev/null +++ b/tests/phase2/rows/N1.osr-global-int-store.eigs @@ -0,0 +1,15 @@ +# ROW: N1.osr-global-int-store +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr put +# OPS: SET_NAME NUM_ONE ADD GE JUMP_IF_FALSE +x is 0 +define put(big, n) as: + i is 0.0 + loop while true: + x is big + i is i + 1.0 + if i >= n: + return x +print of (put of [9007199254740993, 4.0]) diff --git a/tests/phase2/rows/N1.osr-global-int-store.out b/tests/phase2/rows/N1.osr-global-int-store.out new file mode 100644 index 000000000..ba278ab07 --- /dev/null +++ b/tests/phase2/rows/N1.osr-global-int-store.out @@ -0,0 +1 @@ +9007199254740993 diff --git a/tests/phase2/rows/N1.osr-int-counter.eigs b/tests/phase2/rows/N1.osr-int-counter.eigs new file mode 100644 index 000000000..50969541b --- /dev/null +++ b/tests/phase2/rows/N1.osr-int-counter.eigs @@ -0,0 +1,15 @@ +# ROW: N1.osr-int-counter +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr-stop count INT_ONE +# OPS: INT_ONE +define count(n) as: + i is 9007199254740990 + k is 0.0 + loop while true: + i is i + 1 + k is k + 1.0 + if k >= n: + return i +print of (count of 10.0) diff --git a/tests/phase2/rows/N1.osr-int-counter.out b/tests/phase2/rows/N1.osr-int-counter.out new file mode 100644 index 000000000..eebb72239 --- /dev/null +++ b/tests/phase2/rows/N1.osr-int-counter.out @@ -0,0 +1 @@ +9007199254741000 diff --git a/tests/phase2/rows/N14.json-build-int-exact.eigs b/tests/phase2/rows/N14.json-build-int-exact.eigs new file mode 100644 index 000000000..b274e4c85 --- /dev/null +++ b/tests/phase2/rows/N14.json-build-int-exact.eigs @@ -0,0 +1,7 @@ +# ROW: N14.json-build-int-exact +# ITEMS: N14 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of (json_build of ["small", 3, "big", 9223372036854775807, "min", -9223372036854775807 - 1]) diff --git a/tests/phase2/rows/N14.json-build-int-exact.out b/tests/phase2/rows/N14.json-build-int-exact.out new file mode 100644 index 000000000..3b62ebf15 --- /dev/null +++ b/tests/phase2/rows/N14.json-build-int-exact.out @@ -0,0 +1 @@ +{"small": 3, "big": 9223372036854775807, "min": -9223372036854775808} diff --git a/tests/phase2/rows/N14.json-encode-int-exact.eigs b/tests/phase2/rows/N14.json-encode-int-exact.eigs new file mode 100644 index 000000000..f8f913ff4 --- /dev/null +++ b/tests/phase2/rows/N14.json-encode-int-exact.eigs @@ -0,0 +1,7 @@ +# ROW: N14.json-encode-int-exact +# ITEMS: N14 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of (json_encode of [3, 9223372036854775807, {"min": -9223372036854775807 - 1}]) diff --git a/tests/phase2/rows/N14.json-encode-int-exact.out b/tests/phase2/rows/N14.json-encode-int-exact.out new file mode 100644 index 000000000..ca429d73b --- /dev/null +++ b/tests/phase2/rows/N14.json-encode-int-exact.out @@ -0,0 +1 @@ +[3,9223372036854775807,{"min":-9223372036854775808}] diff --git a/tests/phase2/rows/N14.json-path-int-exact.eigs b/tests/phase2/rows/N14.json-path-int-exact.eigs new file mode 100644 index 000000000..867a0d3d8 --- /dev/null +++ b/tests/phase2/rows/N14.json-path-int-exact.eigs @@ -0,0 +1,7 @@ +# ROW: N14.json-path-int-exact +# ITEMS: N14 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of (json_path of ["{\"n\":9223372036854775807}", "n"]) diff --git a/tests/phase2/rows/N14.json-path-int-exact.out b/tests/phase2/rows/N14.json-path-int-exact.out new file mode 100644 index 000000000..2045006ed --- /dev/null +++ b/tests/phase2/rows/N14.json-path-int-exact.out @@ -0,0 +1 @@ +9223372036854775807 diff --git a/tests/phase2/rows/N2.exact-eq-past-2p53.eigs b/tests/phase2/rows/N2.exact-eq-past-2p53.eigs new file mode 100644 index 000000000..19644de62 --- /dev/null +++ b/tests/phase2/rows/N2.exact-eq-past-2p53.eigs @@ -0,0 +1,7 @@ +# ROW: N2.exact-eq-past-2p53 +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [9007199254740993 == 9007199254740992.0, 9007199254740993 != 9007199254740992.0] diff --git a/tests/phase2/rows/N2.exact-eq-past-2p53.out b/tests/phase2/rows/N2.exact-eq-past-2p53.out new file mode 100644 index 000000000..cb579368c --- /dev/null +++ b/tests/phase2/rows/N2.exact-eq-past-2p53.out @@ -0,0 +1 @@ +[false, true] diff --git a/tests/phase2/rows/N2.exact-order.eigs b/tests/phase2/rows/N2.exact-order.eigs new file mode 100644 index 000000000..f646471fc --- /dev/null +++ b/tests/phase2/rows/N2.exact-order.eigs @@ -0,0 +1,7 @@ +# ROW: N2.exact-order +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [9007199254740993 > 9007199254740992.0, 9223372036854775807 < 9223372036854775808.0] diff --git a/tests/phase2/rows/N2.exact-order.out b/tests/phase2/rows/N2.exact-order.out new file mode 100644 index 000000000..ae6199aee --- /dev/null +++ b/tests/phase2/rows/N2.exact-order.out @@ -0,0 +1 @@ +[true, true] diff --git a/tests/phase2/rows/N2.fn-compare-all.eigs b/tests/phase2/rows/N2.fn-compare-all.eigs new file mode 100644 index 000000000..d7c5257fa --- /dev/null +++ b/tests/phase2/rows/N2.fn-compare-all.eigs @@ -0,0 +1,19 @@ +# ROW: N2.fn-compare-all +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop cmp EQ +# OPS: EQ +define cmp(a, b) as: + e is a == b + n is a != b + g is a > b + l is a <= b + q is a >= b + return [e, n, g, l, q] +r is null +i is 0.0 +loop while i < 60.0: + r is cmp of [9007199254740993, 9007199254740992.0] + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N2.fn-compare-all.out b/tests/phase2/rows/N2.fn-compare-all.out new file mode 100644 index 000000000..059f24083 --- /dev/null +++ b/tests/phase2/rows/N2.fn-compare-all.out @@ -0,0 +1 @@ +[false, true, true, false, true] diff --git a/tests/phase2/rows/N2.fn-exact-compare.eigs b/tests/phase2/rows/N2.fn-exact-compare.eigs new file mode 100644 index 000000000..0198b49c3 --- /dev/null +++ b/tests/phase2/rows/N2.fn-exact-compare.eigs @@ -0,0 +1,15 @@ +# ROW: N2.fn-exact-compare +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop lt LT +# OPS: LT +define lt(a, b) as: + t is a < b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is lt of [9007199254740992, 9007199254740993] + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N2.fn-exact-compare.out b/tests/phase2/rows/N2.fn-exact-compare.out new file mode 100644 index 000000000..27ba77dda --- /dev/null +++ b/tests/phase2/rows/N2.fn-exact-compare.out @@ -0,0 +1 @@ +true diff --git a/tests/phase2/rows/N2.int-eq-float-kinds.eigs b/tests/phase2/rows/N2.int-eq-float-kinds.eigs new file mode 100644 index 000000000..080fae5ee --- /dev/null +++ b/tests/phase2/rows/N2.int-eq-float-kinds.eigs @@ -0,0 +1,7 @@ +# ROW: N2.int-eq-float-kinds +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [1 == 1.0, 1 != 1.0, num_type of 1, num_type of 1.0] diff --git a/tests/phase2/rows/N2.int-eq-float-kinds.out b/tests/phase2/rows/N2.int-eq-float-kinds.out new file mode 100644 index 000000000..99105c483 --- /dev/null +++ b/tests/phase2/rows/N2.int-eq-float-kinds.out @@ -0,0 +1 @@ +[true, false, "int", "float"] diff --git a/tests/phase2/rows/N2.membership-exact.eigs b/tests/phase2/rows/N2.membership-exact.eigs new file mode 100644 index 000000000..1351c22b3 --- /dev/null +++ b/tests/phase2/rows/N2.membership-exact.eigs @@ -0,0 +1,7 @@ +# ROW: N2.membership-exact +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [list_contains of [[9007199254740993], 9007199254740992.0], list_index_of of [[1, 9007199254740993], 9007199254740992.0]] diff --git a/tests/phase2/rows/N2.membership-exact.out b/tests/phase2/rows/N2.membership-exact.out new file mode 100644 index 000000000..b24713b9a --- /dev/null +++ b/tests/phase2/rows/N2.membership-exact.out @@ -0,0 +1 @@ +[false, -1] diff --git a/tests/phase2/rows/N2.sort-by-exact.eigs b/tests/phase2/rows/N2.sort-by-exact.eigs new file mode 100644 index 000000000..a2c184d5f --- /dev/null +++ b/tests/phase2/rows/N2.sort-by-exact.eigs @@ -0,0 +1,11 @@ +# ROW: N2.sort-by-exact +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +define key(r) as: + return r.k +xs is [{"id": "high", "k": 9007199254740993}, {"id": "low", "k": 9007199254740991}, {"id": "tie-a", "k": 9007199254740992.0}, {"id": "tie-b", "k": 9007199254740992}] +ys is sort_by of [xs, key] +print of [ys[0].id, ys[1].id, ys[2].id, ys[3].id] diff --git a/tests/phase2/rows/N2.sort-by-exact.out b/tests/phase2/rows/N2.sort-by-exact.out new file mode 100644 index 000000000..02425217e --- /dev/null +++ b/tests/phase2/rows/N2.sort-by-exact.out @@ -0,0 +1 @@ +["low", "tie-a", "tie-b", "high"] diff --git a/tests/phase2/rows/N2.sort-exact.eigs b/tests/phase2/rows/N2.sort-exact.eigs new file mode 100644 index 000000000..b9ed3c83f --- /dev/null +++ b/tests/phase2/rows/N2.sort-exact.eigs @@ -0,0 +1,7 @@ +# ROW: N2.sort-exact +# ITEMS: N2 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of (sort of [9007199254740993, 9007199254740992, -1]) diff --git a/tests/phase2/rows/N2.sort-exact.out b/tests/phase2/rows/N2.sort-exact.out new file mode 100644 index 000000000..07981deda --- /dev/null +++ b/tests/phase2/rows/N2.sort-exact.out @@ -0,0 +1 @@ +[-1, 9007199254740992, 9007199254740993] diff --git a/tests/phase2/rows/N3.exact-product.eigs b/tests/phase2/rows/N3.exact-product.eigs new file mode 100644 index 000000000..da046afc7 --- /dev/null +++ b/tests/phase2/rows/N3.exact-product.eigs @@ -0,0 +1,7 @@ +# ROW: N3.exact-product +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [3037000499 * 3037000499, 4503599627370496 * 2 + 1] diff --git a/tests/phase2/rows/N3.exact-product.out b/tests/phase2/rows/N3.exact-product.out new file mode 100644 index 000000000..01df45d41 --- /dev/null +++ b/tests/phase2/rows/N3.exact-product.out @@ -0,0 +1 @@ +[9223372030926249001, 9007199254740993] diff --git a/tests/phase2/rows/N3.fn-arith-exact.eigs b/tests/phase2/rows/N3.fn-arith-exact.eigs new file mode 100644 index 000000000..51327ae4d --- /dev/null +++ b/tests/phase2/rows/N3.fn-arith-exact.eigs @@ -0,0 +1,16 @@ +# ROW: N3.fn-arith-exact +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop f MUL +# OPS: MUL +define f(a, b) as: + t is a * b + u is t + a + return u - b +r is null +i is 0.0 +loop while i < 60.0: + r is f of [94906267, 94906267] + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N3.fn-arith-exact.out b/tests/phase2/rows/N3.fn-arith-exact.out new file mode 100644 index 000000000..0be214cb1 --- /dev/null +++ b/tests/phase2/rows/N3.fn-arith-exact.out @@ -0,0 +1 @@ +9007199515875289 diff --git a/tests/phase2/rows/N3.int-ops-kind.eigs b/tests/phase2/rows/N3.int-ops-kind.eigs new file mode 100644 index 000000000..581c1aa3b --- /dev/null +++ b/tests/phase2/rows/N3.int-ops-kind.eigs @@ -0,0 +1,7 @@ +# ROW: N3.int-ops-kind +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [num_type of (2 + 3), num_type of (7 - 9), num_type of (6 * 7), num_type of (2 + 0.5)] diff --git a/tests/phase2/rows/N3.int-ops-kind.out b/tests/phase2/rows/N3.int-ops-kind.out new file mode 100644 index 000000000..156bf0616 --- /dev/null +++ b/tests/phase2/rows/N3.int-ops-kind.out @@ -0,0 +1 @@ +["int", "int", "int", "float"] diff --git a/tests/phase2/rows/N3.leaf-add-exact.eigs b/tests/phase2/rows/N3.leaf-add-exact.eigs new file mode 100644 index 000000000..7e89ac2f8 --- /dev/null +++ b/tests/phase2/rows/N3.leaf-add-exact.eigs @@ -0,0 +1,9 @@ +# ROW: N3.leaf-add-exact +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf-gen add2 +# OPS: ADD +define add2(a, b) as: + return a + b +print of (add2 of [9007199254740992, 1]) diff --git a/tests/phase2/rows/N3.leaf-add-exact.out b/tests/phase2/rows/N3.leaf-add-exact.out new file mode 100644 index 000000000..ba278ab07 --- /dev/null +++ b/tests/phase2/rows/N3.leaf-add-exact.out @@ -0,0 +1 @@ +9007199254740993 diff --git a/tests/phase2/rows/N3.leaf-mul-exact.eigs b/tests/phase2/rows/N3.leaf-mul-exact.eigs new file mode 100644 index 000000000..c712ccc00 --- /dev/null +++ b/tests/phase2/rows/N3.leaf-mul-exact.eigs @@ -0,0 +1,9 @@ +# ROW: N3.leaf-mul-exact +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf-gen sq +# OPS: MUL +define sq(x) as: + return x * x +print of (sq of 94906267) diff --git a/tests/phase2/rows/N3.leaf-mul-exact.out b/tests/phase2/rows/N3.leaf-mul-exact.out new file mode 100644 index 000000000..0be214cb1 --- /dev/null +++ b/tests/phase2/rows/N3.leaf-mul-exact.out @@ -0,0 +1 @@ +9007199515875289 diff --git a/tests/phase2/rows/N3.osr-module-sum.eigs b/tests/phase2/rows/N3.osr-module-sum.eigs new file mode 100644 index 000000000..21f98eb40 --- /dev/null +++ b/tests/phase2/rows/N3.osr-module-sum.eigs @@ -0,0 +1,15 @@ +# ROW: N3.osr-module-sum +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr-stop ADD +# OPS: ADD +acc is 9007199254740000 +step is 1 +i is 0.0 +loop while true: + acc is acc + step + i is i + 1.0 + if i >= 1000.0: + print of acc + return acc diff --git a/tests/phase2/rows/N3.osr-module-sum.out b/tests/phase2/rows/N3.osr-module-sum.out new file mode 100644 index 000000000..eebb72239 --- /dev/null +++ b/tests/phase2/rows/N3.osr-module-sum.out @@ -0,0 +1 @@ +9007199254741000 diff --git a/tests/phase2/rows/N3.osr-sum-exact.eigs b/tests/phase2/rows/N3.osr-sum-exact.eigs new file mode 100644 index 000000000..11ad8facc --- /dev/null +++ b/tests/phase2/rows/N3.osr-sum-exact.eigs @@ -0,0 +1,15 @@ +# ROW: N3.osr-sum-exact +# ITEMS: N3 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr-stop total ADD +# OPS: ADD +define total(n, step) as: + acc is 9007199254740000 + i is 0.0 + loop while true: + acc is acc + step + i is i + 1.0 + if i >= n: + return acc +print of (total of [1000.0, 1]) diff --git a/tests/phase2/rows/N3.osr-sum-exact.out b/tests/phase2/rows/N3.osr-sum-exact.out new file mode 100644 index 000000000..eebb72239 --- /dev/null +++ b/tests/phase2/rows/N3.osr-sum-exact.out @@ -0,0 +1 @@ +9007199254741000 diff --git a/tests/phase2/rows/N4b.abs-min-raises.eigs b/tests/phase2/rows/N4b.abs-min-raises.eigs new file mode 100644 index 000000000..87ee5b5ec --- /dev/null +++ b/tests/phase2/rows/N4b.abs-min-raises.eigs @@ -0,0 +1,11 @@ +# ROW: N4b.abs-min-raises +# ITEMS: N4b +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +m is -9223372036854775807 - 1 +try: + print of (abs of m) +catch e: + print of [e.kind, (index_of of [e.message, "abs"]) >= 0] diff --git a/tests/phase2/rows/N4b.abs-min-raises.out b/tests/phase2/rows/N4b.abs-min-raises.out new file mode 100644 index 000000000..56efea05e --- /dev/null +++ b/tests/phase2/rows/N4b.abs-min-raises.out @@ -0,0 +1 @@ +["value", true] diff --git a/tests/phase2/rows/N4b.fn-neg-min.eigs b/tests/phase2/rows/N4b.fn-neg-min.eigs new file mode 100644 index 000000000..78417f59e --- /dev/null +++ b/tests/phase2/rows/N4b.fn-neg-min.eigs @@ -0,0 +1,19 @@ +# ROW: N4b.fn-neg-min +# ITEMS: N4b +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop n NEG +# OPS: NEG +define n(a) as: + t is -a + return t +r is null +i is 0.0 +loop while i < 60.0: + r is n of 2 + i is i + 1.0 +m is -9223372036854775807 - 1 +try: + print of (n of m) +catch e: + print of e.kind diff --git a/tests/phase2/rows/N4b.fn-neg-min.out b/tests/phase2/rows/N4b.fn-neg-min.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/rows/N4b.fn-neg-min.out @@ -0,0 +1 @@ +value diff --git a/tests/phase2/rows/N4b.neg-min-raises.eigs b/tests/phase2/rows/N4b.neg-min-raises.eigs new file mode 100644 index 000000000..dab9a0c1b --- /dev/null +++ b/tests/phase2/rows/N4b.neg-min-raises.eigs @@ -0,0 +1,11 @@ +# ROW: N4b.neg-min-raises +# ITEMS: N4b +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +m is -9223372036854775807 - 1 +try: + print of (-m) +catch e: + print of [e.kind, (index_of of [e.message, "-"]) >= 0] diff --git a/tests/phase2/rows/N4b.neg-min-raises.out b/tests/phase2/rows/N4b.neg-min-raises.out new file mode 100644 index 000000000..56efea05e --- /dev/null +++ b/tests/phase2/rows/N4b.neg-min-raises.out @@ -0,0 +1 @@ +["value", true] diff --git a/tests/phase2/rows/N5.osr-index-set.eigs b/tests/phase2/rows/N5.osr-index-set.eigs new file mode 100644 index 000000000..110b969c0 --- /dev/null +++ b/tests/phase2/rows/N5.osr-index-set.eigs @@ -0,0 +1,15 @@ +# ROW: N5.osr-index-set +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: O +# WITNESS: osr fill +# OPS: INDEX_SET NUM_ONE ADD GE JUMP_IF_FALSE SET_LOCAL POP +define fill(big, n) as: + xs is [0, 0, 0, 0] + i is 0.0 + loop while true: + xs[i] is big + i is i + 1.0 + if i >= n: + return xs +print of (fill of [9007199254740993, 4.0]) diff --git a/tests/phase2/rows/N5.osr-index-set.out b/tests/phase2/rows/N5.osr-index-set.out new file mode 100644 index 000000000..317c794e7 --- /dev/null +++ b/tests/phase2/rows/N5.osr-index-set.out @@ -0,0 +1 @@ +[9007199254740993, 9007199254740993, 9007199254740993, 9007199254740993] diff --git a/tests/phase2/rows/N7.num-type-float.eigs b/tests/phase2/rows/N7.num-type-float.eigs new file mode 100644 index 000000000..484787f6b --- /dev/null +++ b/tests/phase2/rows/N7.num-type-float.eigs @@ -0,0 +1,7 @@ +# ROW: N7.num-type-float +# ITEMS: N7 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [num_type of 3.0, num_type of -0.0, num_type of 1e300, num_type of 2.5] diff --git a/tests/phase2/rows/N7.num-type-float.out b/tests/phase2/rows/N7.num-type-float.out new file mode 100644 index 000000000..70cb1df72 --- /dev/null +++ b/tests/phase2/rows/N7.num-type-float.out @@ -0,0 +1 @@ +["float", "float", "float", "float"] diff --git a/tests/phase2/rows/N7.num-type-int.eigs b/tests/phase2/rows/N7.num-type-int.eigs new file mode 100644 index 000000000..ae78c6d06 --- /dev/null +++ b/tests/phase2/rows/N7.num-type-int.eigs @@ -0,0 +1,7 @@ +# ROW: N7.num-type-int +# ITEMS: N7 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [num_type of 0, num_type of -1, num_type of 9223372036854775807, num_type of (2 * 3)] diff --git a/tests/phase2/rows/N7.num-type-int.out b/tests/phase2/rows/N7.num-type-int.out new file mode 100644 index 000000000..d353e7adf --- /dev/null +++ b/tests/phase2/rows/N7.num-type-int.out @@ -0,0 +1 @@ +["int", "int", "int", "int"] diff --git a/tests/phase2/rows/N7.num-type-non-number.eigs b/tests/phase2/rows/N7.num-type-non-number.eigs new file mode 100644 index 000000000..904f30e95 --- /dev/null +++ b/tests/phase2/rows/N7.num-type-non-number.eigs @@ -0,0 +1,7 @@ +# ROW: N7.num-type-non-number +# ITEMS: N7 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [num_type of "3", num_type of null, num_type of true, num_type of ([1])] diff --git a/tests/phase2/rows/N7.num-type-non-number.out b/tests/phase2/rows/N7.num-type-non-number.out new file mode 100644 index 000000000..9c12ec847 --- /dev/null +++ b/tests/phase2/rows/N7.num-type-non-number.out @@ -0,0 +1 @@ +[null, null, null, null] diff --git a/tests/phase2/rows/O1.int-observed-numeric.eigs b/tests/phase2/rows/O1.int-observed-numeric.eigs new file mode 100644 index 000000000..7855a1022 --- /dev/null +++ b/tests/phase2/rows/O1.int-observed-numeric.eigs @@ -0,0 +1,18 @@ +# ROW: O1.int-observed-numeric +# ITEMS: O1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +a is 3 +b is 140737488355328 +af is 3.0 +bf is 140737488355328.0 +i is 0.0 +loop while i < 12.0: + a is a * 2 + b is b * 2 + af is af * 2.0 + bf is bf * 2.0 + i is i + 1.0 +print of [report of a, report of af, report of b, report of bf, num_type of b] diff --git a/tests/phase2/rows/O1.int-observed-numeric.out b/tests/phase2/rows/O1.int-observed-numeric.out new file mode 100644 index 000000000..908658527 --- /dev/null +++ b/tests/phase2/rows/O1.int-observed-numeric.out @@ -0,0 +1 @@ +["diverging", "diverging", "diverging", "diverging", "int"] diff --git a/tests/phase2/rows/T1.float-kind-token.out b/tests/phase2/rows/T1.float-kind-token.out new file mode 100644 index 000000000..ca98c9bc9 --- /dev/null +++ b/tests/phase2/rows/T1.float-kind-token.out @@ -0,0 +1,2 @@ +float tokens marked +float replay identical diff --git a/tests/phase2/rows/T1.float-kind-token.sh b/tests/phase2/rows/T1.float-kind-token.sh new file mode 100644 index 000000000..766ec2f93 --- /dev/null +++ b/tests/phase2/rows/T1.float-kind-token.sh @@ -0,0 +1,21 @@ +# ROW: T1.float-kind-token +# ITEMS: T1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# TIERS: off default osr +set -eu +bin=$1 +cat > p.eigs <<'EOF' +x is 3.0 +z is -0.0 +print of [num_type of x, num_type of z] +EOF +EIGS_TRACE=t.tape "$bin" p.eigs > live.out +grep -q '^A [0-9][0-9]* x=3\.0$' t.tape +grep -q '^A [0-9][0-9]* z=-0\.0$' t.tape +printf 'float tokens marked\n' +EIGS_REPLAY=t.tape EIGS_REPLAY_STRICT=1 "$bin" p.eigs > replay.out +cmp live.out replay.out +printf 'float replay identical\n' diff --git a/tests/phase2/rows/T1.int-replay-kind.out b/tests/phase2/rows/T1.int-replay-kind.out new file mode 100644 index 000000000..6c1516f95 --- /dev/null +++ b/tests/phase2/rows/T1.int-replay-kind.out @@ -0,0 +1,2 @@ +int replay identical +int assignment exact diff --git a/tests/phase2/rows/T1.int-replay-kind.sh b/tests/phase2/rows/T1.int-replay-kind.sh new file mode 100644 index 000000000..f6b6f1d40 --- /dev/null +++ b/tests/phase2/rows/T1.int-replay-kind.sh @@ -0,0 +1,24 @@ +# ROW: T1.int-replay-kind +# ITEMS: T1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# TIERS: off default osr +set -eu +bin=$1 +cat > p.eigs <<'EOF' +r is random_int of [1, 6] +x is 9007199254740993 +if r > 3: + x is 9223372036854775807 +print of [num_type of x, x == 9007199254740993 or x == 9223372036854775807] +EOF +EIGS_TRACE=t.tape "$bin" p.eigs > live.out +EIGS_REPLAY=t.tape EIGS_REPLAY_STRICT=1 "$bin" p.eigs > replay.out +cmp live.out replay.out +printf '["int", true]\n' > expect.out +cmp expect.out live.out +printf 'int replay identical\n' +grep -q '^A [0-9][0-9]* x=9007199254740993$' t.tape +printf 'int assignment exact\n' diff --git a/tests/phase2/rows/T1.twice-int.out b/tests/phase2/rows/T1.twice-int.out new file mode 100644 index 000000000..e2820a67c --- /dev/null +++ b/tests/phase2/rows/T1.twice-int.out @@ -0,0 +1,4 @@ +tapes identical +replay identical +A 0 x=9007199254740993 +A 0 y=9007199515875289 diff --git a/tests/phase2/rows/T1.twice-int.sh b/tests/phase2/rows/T1.twice-int.sh new file mode 100644 index 000000000..c8875d031 --- /dev/null +++ b/tests/phase2/rows/T1.twice-int.sh @@ -0,0 +1,27 @@ +# ROW: T1.twice-int +# ITEMS: T1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# TIERS: off default osr +set -eu +bin=$1 +cat > p.eigs <<'EOF' +define sq(x) as: + return x * x +x is 9007199254740993 +y is sq of 94906267 +print of [x, y] +EOF +"$bin" p.eigs > live.out +EIGS_TRACE=t1.tape "$bin" p.eigs > record.out +EIGS_TRACE=t2.tape "$bin" p.eigs > record2.out +cmp t1.tape t2.tape +cmp live.out record.out +cmp live.out record2.out +printf 'tapes identical\n' +EIGS_REPLAY=t1.tape EIGS_REPLAY_STRICT=1 "$bin" p.eigs > replay.out +cmp live.out replay.out +printf 'replay identical\n' +sed -n '/^A [0-9][0-9]* x=/p; /^A [0-9][0-9]* y=/p' t1.tape diff --git a/tests/phase2/rows/T1.v6-refused.out b/tests/phase2/rows/T1.v6-refused.out new file mode 100644 index 000000000..a794dbe91 --- /dev/null +++ b/tests/phase2/rows/T1.v6-refused.out @@ -0,0 +1 @@ +rc!=0 names-6 diff --git a/tests/phase2/rows/T1.v6-refused.sh b/tests/phase2/rows/T1.v6-refused.sh new file mode 100644 index 000000000..87e633af5 --- /dev/null +++ b/tests/phase2/rows/T1.v6-refused.sh @@ -0,0 +1,21 @@ +# ROW: T1.v6-refused +# ITEMS: T1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# TIERS: off default osr +set -eu +bin=$1 +printf 'print of 3\n' > p.eigs +# Start with a tape stamped by this binary so only the format differs. +EIGS_TRACE=current.tape "$bin" p.eigs > live.out +sed '1s/^V [0-9][0-9]* /V 6 /' current.tape > v6.tape +rc=0 +EIGS_REPLAY=v6.tape EIGS_REPLAY_STRICT=1 "$bin" p.eigs > replay.out 2> replay.err || rc=$? +if [ "$rc" -eq 0 ]; then + printf 'v6 accepted\n' + exit 1 +fi +grep -q 'format v6' replay.err +printf 'rc!=0 names-6\n' diff --git a/tests/phase2/rows/T1.v7-header.out b/tests/phase2/rows/T1.v7-header.out new file mode 100644 index 000000000..5f13ad56c --- /dev/null +++ b/tests/phase2/rows/T1.v7-header.out @@ -0,0 +1 @@ +V 7 diff --git a/tests/phase2/rows/T1.v7-header.sh b/tests/phase2/rows/T1.v7-header.sh new file mode 100644 index 000000000..55db0b740 --- /dev/null +++ b/tests/phase2/rows/T1.v7-header.sh @@ -0,0 +1,12 @@ +# ROW: T1.v7-header +# ITEMS: T1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# TIERS: off default osr +set -eu +bin=$1 +printf 'x is 3\n' > p.eigs +EIGS_TRACE=t.tape "$bin" p.eigs > live.out +head -1 t.tape | cut -d' ' -f1-2 diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 5e7186f0f..3e8a6360c 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -406,7 +406,7 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): bad.append('gate %s names no file or make target' % g['id']) cnt = {t: dict(examined=0, tag_fail=0, branch_pass=0, vacuous=0, tag_timeout=0, tag_signal=0) for t in TIERS} - ctl_n = ctl_both = witnessed = 0 + ctl_n = ctl_both = witnessed = ctl_witnessed = ctl_vacuous = 0 for r, p, h in todo: want = read_text(p.rsplit('.', 1)[0] + '.out') want_rc = int(h.get('EXPECT-RC', '0')) @@ -442,6 +442,16 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): ctl_both += 1 else: out(' CONTROL-FAIL %s: %s' % (r['id'], passes)) + # A control may claim a real tier too. Its preserved stdout is + # insufficient evidence that a JIT/leaf arm actually ran. + if r['witness']['kind'] != 'none' and all(passes[t]['branch'][0] for t in tiers): + holds, ev = witness(branch, p, r['witness'], scratch) + if holds: + ctl_witnessed += 1 + out(' CONTROL-WITNESS %s %s holds [%s]' % (r['id'], r['witness']['kind'], ev)) + else: + ctl_vacuous += 1 + out(' CONTROL-VACUOUS %s %s [%s]' % (r['id'], r['witness']['kind'], ev)) continue if r['witness']['kind'] != 'none' and all(passes[t]['branch'][0] for t in tiers): holds, ev = witness(branch, p, r['witness'], scratch) @@ -461,9 +471,10 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): c['tag_signal'])) out('controls=%d both_pass=%d witnessed=%d mapped=%d gates=%d through=%s' % ( ctl_n, ctl_both, witnessed, len(landed), len(gates), through)) + out('controls_witnessed=%d controls_vacuous=%d' % (ctl_witnessed, ctl_vacuous)) rows_ok = all(c['examined'] == c['tag_fail'] == c['branch_pass'] > 0 and c['vacuous'] == 0 for c in cnt.values()) - return (not bad, rows_ok, ctl_n == ctl_both, len(landed), cnt, witnessed) + return (not bad, rows_ok, ctl_n == ctl_both and ctl_vacuous == 0, len(landed), cnt, witnessed) # ---- mechanical gates ---------------------------------------------------------- From 520540d1111107f9a3f334c2f2b8de70ad006c6f Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:54:35 -0500 Subject: [PATCH 062/188] phase2 R1.3f: the cost gate becomes a declared-expectation gate (#1758) Decided on #1758 (comment 6258431523, owner agreement 6259252684): while the int fast paths are not yet written, a CodSpeed workload may be slower than main only by a declared, bounded amount, and the merge requires none. tools/phase2_cost.sh reads tests/phase2/cost_expect.txt, one TSV row per workload and tier: workload, tier (jit|off), max_delta_pct, recover_round, reason. A declared row fails above its own maximum; an undeclared row keeps the +0.3% Ir bar. Malformed rows fail before measuring: wrong field count, an unknown workload or tier, a duplicate, a negative or non-finite maximum, a missing reason or a recover_round that is not a round name. `--final` fails while the file is non-empty; `--final BASE CAND` is the pre-merge condition (an empty file and every workload within +0.3%), recorded in the design's round plan (8, R1.3). The file is empty in this commit; the next commit declares exactly the rows measured against origin/main. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 10 ++++- tests/phase2/cost_expect.txt | 0 tools/phase2_cost.sh | 85 +++++++++++++++++++++++++++-------- 3 files changed, 75 insertions(+), 20 deletions(-) create mode 100644 tests/phase2/cost_expect.txt diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 264bd6bb2..861445df0 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1965,7 +1965,15 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: from here. - Risks: JIT int loops leave the JIT (§3: +70% Ir on a counter loop), and the leaf stops computing int helpers; declare the CodSpeed baseline - move first. Consumer hashes that relied on double rounding now raise + move first. `tools/phase2_cost.sh` reads per-workload and per-tier TSV + declarations in `tests/phase2/cost_expect.txt` (`workload`, `tier`, + `max_delta_pct`, `recover_round`, `reason`); undeclared rows retain + +0.3%. Declare only measured R1.3 costs with §3 as the reason and + `recover_round=R5`, the JIT/leaf int fast-path round. A row above its + declared maximum fails. **Pre-merge condition:** + `tools/phase2_cost.sh --final BASE CAND` must pass with the declarations file + empty; temporary costs must be recovered before integration merges. + Consumer hashes that relied on double rounding now raise ((A)); they move to the N9 wrapping builtins. 4. **R1.4, N4.** `//` (token, parser, `OP_IDIV` appended, `op_name`/`op_stack_effect`/obs marker/ABI test), `//=` beside `/=` (Q6), diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tools/phase2_cost.sh b/tools/phase2_cost.sh index e2cf50a48..0d9f0c320 100755 --- a/tools/phase2_cost.sh +++ b/tools/phase2_cost.sh @@ -1,10 +1,14 @@ #!/usr/bin/env bash # Compare release Ir on the in-repo CodSpeed workload set, in BOTH VM tiers. # The target list has one home: codspeed.yml. Consumer targets live elsewhere. -# Positive deltas above +0.3% fail; above +0.1% need attribution in the review. +# Undeclared rows allow +0.3%; declared temporary costs are bounded per row. +# TSV: workload, tier, max_delta_pct, recover_round, reason (no header). +# --final requires the declarations file to be empty before integration merges. set -eu cd "$(dirname "$0")/.." exec python3 - "$@" <<'PY' +import argparse +from decimal import Decimal, InvalidOperation import os from pathlib import Path import re @@ -14,19 +18,25 @@ import subprocess import sys import tempfile -THRESHOLD_PCT = 0.3 +THRESHOLD_PCT = Decimal('0.3') root = Path.cwd() -if len(sys.argv) != 3: - sys.exit('usage: tools/phase2_cost.sh (from repo root)') -if not shutil.which('valgrind'): - sys.exit('phase2-cost: FAIL: valgrind is required') -bins = [str(Path(p).resolve(strict=True)) for p in sys.argv[1:]] -for binary in bins: - if not os.access(binary, os.X_OK): - sys.exit('phase2-cost: FAIL: not executable: ' + binary) - symbols = subprocess.run(['nm', '-D', binary], capture_output=True, text=True, check=True).stdout - if re.search(r'__(?:asan|ubsan)', symbols): - sys.exit('phase2-cost: FAIL: sanitizer binary: ' + binary) +ap = argparse.ArgumentParser(prog='tools/phase2_cost.sh') +ap.add_argument('--final', action='store_true', + help='require an empty cost_expect.txt (the pre-merge condition)') +ap.add_argument('base', nargs='?') +ap.add_argument('cand', nargs='?') +args = ap.parse_args() +expect_path = root / 'tests/phase2/cost_expect.txt' +if not expect_path.is_file(): + sys.exit('phase2-cost: FAIL: missing tests/phase2/cost_expect.txt') +expect_text = expect_path.read_text() +if args.final and expect_text: + sys.exit('phase2-cost: FAIL: --final requires an empty tests/phase2/cost_expect.txt') +if bool(args.base) != bool(args.cand) or (not args.base and not args.final): + ap.error('supply , or --final alone') +if not args.base: + print('phase2-cost: final declarations=0 PASS') + sys.exit(0) local_workload = re.compile(r'(?:bench/[^/]+|tests/bench_[^/]+)\.eigs') workloads = set() for line in (root / 'codspeed.yml').read_text().splitlines(): @@ -47,9 +57,43 @@ expected = {p for p in tracked if local_workload.fullmatch(p)} if workloads != expected: sys.exit('phase2-cost: FAIL: CodSpeed workload coverage missing=%s stale=%s' % (sorted(expected - workloads), sorted(workloads - expected))) +expectations = {} +for n, line in enumerate(expect_text.splitlines(), 1): + if not line.strip() or line.lstrip().startswith('#'): + continue + fields = line.split('\t') + if len(fields) != 5: + sys.exit('phase2-cost: FAIL: cost_expect.txt:%d: expected five TSV fields ' + '(workload, tier, max_delta_pct, recover_round, reason)' % n) + workload, tier, maximum, recover_round, reason = (f.strip() for f in fields) + if workload not in workloads or tier not in ('jit', 'off'): + sys.exit('phase2-cost: FAIL: cost_expect.txt:%d: unknown workload/tier: %s %s' % + (n, workload, tier)) + key = (workload, tier) + if key in expectations: + sys.exit('phase2-cost: FAIL: cost_expect.txt:%d: duplicate workload/tier: %s %s' % + (n, workload, tier)) + try: + maximum = Decimal(maximum) + except InvalidOperation: + maximum = Decimal('NaN') + if not maximum.is_finite() or maximum < 0: + sys.exit('phase2-cost: FAIL: cost_expect.txt:%d: max_delta_pct must be finite and >= 0' % n) + if not re.fullmatch(r'R[1-9][0-9]*(?:\.[1-9][0-9]*)?', recover_round) or not reason: + sys.exit('phase2-cost: FAIL: cost_expect.txt:%d: recover_round and reason are required' % n) + expectations[key] = (maximum, recover_round, reason) +if not shutil.which('valgrind'): + sys.exit('phase2-cost: FAIL: valgrind is required') +bins = [str(Path(p).resolve(strict=True)) for p in (args.base, args.cand)] +for binary in bins: + if not os.access(binary, os.X_OK): + sys.exit('phase2-cost: FAIL: not executable: ' + binary) + symbols = subprocess.run(['nm', '-D', binary], capture_output=True, text=True, check=True).stdout + if re.search(r'__(?:asan|ubsan)', symbols): + sys.exit('phase2-cost: FAIL: sanitizer binary: ' + binary) logdir = Path(tempfile.mkdtemp(prefix='phase2-cost-')) -print('phase2-cost: source=codspeed.yml workloads=%d tiers=2 threshold=+%.1f%% logs=%s' % - (len(workloads), THRESHOLD_PCT, logdir), flush=True) +print('phase2-cost: source=codspeed.yml workloads=%d tiers=2 undeclared_max=+%s%% declarations=%d logs=%s' % + (len(workloads), THRESHOLD_PCT, len(expectations), logdir), flush=True) over = 0 for workload in sorted(workloads): for tier in ('jit', 'off'): @@ -81,11 +125,14 @@ for workload in sorted(workloads): if (out_a, err_a) != (out_b, err_b): sys.exit('phase2-cost: FAIL: output differs: %s %s (see %s)' % (workload, tier, logdir)) delta = 100 * (cand - base) / base - fail = (cand - base) * 100 > THRESHOLD_PCT * base + maximum, recover_round, reason = expectations.get((workload, tier), + (THRESHOLD_PCT, None, None)) + fail = Decimal((cand - base) * 100) > maximum * base over += fail - print('%-34s %-3s base=%12d cand=%12d delta=%+.4f%% %s' % - (workload, tier, base, cand, delta, 'OVER' if fail else 'ok'), flush=True) -print('phase2-cost: workloads=%d rows=%d over_0.3pct=%d %s' % + print('%-34s %-3s base=%12d cand=%12d delta=%+.4f%% max=+%s%% %s%s' % + (workload, tier, base, cand, delta, maximum, 'OVER' if fail else 'ok', + (' recover_round=%s reason=%s' % (recover_round, reason)) if recover_round else ''), flush=True) +print('phase2-cost: workloads=%d rows=%d over_declared_max=%d %s' % (len(workloads), len(workloads) * 2, over, 'FAIL' if over else 'PASS')) sys.exit(bool(over)) PY From 2b898e205fddb481ec0c4ae17cf1016ce639ad10 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 02:56:01 -0500 Subject: [PATCH 063/188] docs: the int64 kind, num_type and tape v7 (#1758 R1.3) SPEC, LANGUAGE_CONTRACT, COMPARISON, README and llms.txt describe numbers as one surface type `num` with two kinds: exact signed int64 literals (decimal within int64; hex wraps modulo 2^64) and finite binary64 floats. `type of` says "num" for both and `num_type of` says "int", "float" or null. Int `+ - *` raise `value` on overflow, unary minus and `abs` raise at INT64_MIN, mixed arithmetic converts to float, and comparison across kinds is exact. The transitional rules are stated where they hold: `/` returns a float, `%` keeps the truncating float remainder until R1.4, bitwise results and most builtin results stay floats until R1.5/R1.6, and `num of`/JSON decoders still produce floats. TRACE.md documents format v7 (exact int digits, a point or exponent on every float, v6 refused) and the changelog fragment records the change. Every executed fence passes: 194 checked, 0 failed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- README.md | 6 +++++- changes/added/1758-int64-flip.md | 5 +++++ docs/COMPARISON.md | 6 ++++-- docs/LANGUAGE_CONTRACT.md | 20 ++++++++++++------ docs/SPEC.md | 36 ++++++++++++++++++++------------ docs/TRACE.md | 16 +++++++++----- docs/llms.txt | 12 +++++++++-- 7 files changed, 72 insertions(+), 29 deletions(-) create mode 100644 changes/added/1758-int64-flip.md diff --git a/README.md b/README.md index a47b0adc2..ebbc30b35 100644 --- a/README.md +++ b/README.md @@ -323,7 +323,11 @@ and returns a buffer when every tensor operand was one. `zeros of n` returns a buffer (`zeros of [rows, cols]` still returns the nested list) — numeric work wants the flat container, and that is the name it reaches for. -EigenScript numbers are finite by construction. Operations that would overflow +EigenScript has exact signed int64 literals and finite float64 numbers. +`type of` returns `"num"` for both, and `num_type of` distinguishes `"int"` +from `"float"` (null for a non-number). Int `+ - *` raise `value` on +overflow; unary minus and `abs` raise on INT64_MIN. Comparisons between +ints and floats are exact, including beyond 2^53. Float operations that would overflow to infinity saturate at `+/-1e308`. Strict mode is the default: an out-of-domain call (`sqrt of -1`), a `NaN` result or a wrong-typed builtin argument (`abs of "x"`) raises a catchable error. Run with `EIGS_STRICT=0` to diff --git a/changes/added/1758-int64-flip.md b/changes/added/1758-int64-flip.md new file mode 100644 index 000000000..3fc75f60b --- /dev/null +++ b/changes/added/1758-int64-flip.md @@ -0,0 +1,5 @@ +- Integer literals now retain exact int64 values, with exact int/float + comparisons and checked `+`, `-`, `*`, negation and `abs` that raise `value` + on int64 overflow. `num_type` reports `"int"`, `"float"` or `null`; `type` + continues to report `"num"` for either numeric kind. Trace tape format v7 + preserves numeric kinds and refuses older tapes (#1758). diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index 6830ac39b..19f6d76d4 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -20,7 +20,7 @@ asking the running program about its own state and history. | | Python | JavaScript | Rust | Lisp | EigenScript | |---|---|---|---|---|---| | typing | dynamic | dynamic | static | dynamic | dynamic | -| numbers | int + float | float | many | many | one: 64-bit float | +| numbers | int + float | float | many | many | int64 + float64 | | assignment | `x = 1` | `let x = 1` | `let x = 1;` | `(define x 1)` | `x is 1` | | call | `f(x)` | `f(x)` | `f(x)` | `(f x)` | `f of x` | | blocks | indentation | braces | braces | parens | indentation | @@ -62,7 +62,9 @@ print(7 / 2) # 3.5 print(7 // 2) # 3 (floor division operator) ``` -EigenScript — one number type, true division; floor explicitly: +EigenScript — int64 and float64 share the `num` type; `num_type of` +distinguishes their kind. Int `+ - *` raise `value` on overflow; mixed-kind +comparison is exact. Division returns a float; floor explicitly: ```eigenscript x is 42 diff --git a/docs/LANGUAGE_CONTRACT.md b/docs/LANGUAGE_CONTRACT.md index 1938d3c0d..da0af2f38 100644 --- a/docs/LANGUAGE_CONTRACT.md +++ b/docs/LANGUAGE_CONTRACT.md @@ -137,11 +137,17 @@ examples (executed by the suite). ## Numbers **Promise:** -- One numeric type: IEEE-754 double. Integers are exact up to 2^53. +- One surface type, `num`, with exact signed int64 and finite IEEE-754 double + kinds. `num_type of` gives `"int"` or `"float"`, or null for a non-number. + Decimal integer literals within int64 and wrapping hexadecimal literals are + ints; a point or exponent produces a float, as does decimal overflow. + Int `+ - *` raise `value` on overflow; unary minus and `abs` raise at + INT64_MIN. Mixed arithmetic converts to float; cross-kind comparison is exact. + Float integer exactness ends at 2^53. - No NaN, no Infinity reaches a program. By default a NaN-producing operation, an out-of-domain argument or a wrong-typed argument raises a catchable error (strict is the default, #1361); division by zero raises - in every mode. Overflow saturates at ±1e308. Under the per-run opt-out + in every mode. Float overflow saturates at ±1e308. Under the per-run opt-out `EIGS_STRICT=0` the arithmetic is finite by construction instead: a NaN collapses to 0 and domain functions substitute a stand-in. - **Every clamp is recorded.** The finite invariant keeps a program @@ -181,13 +187,15 @@ examples (executed by the suite). are what the finite invariant requires — the `overflow` flag is how you tell. Stated here because the trade should be visible rather than discovered. -- `str of` produces the shortest representation that round-trips back to - the same double; `num of (str of x) == x`. +- Ints print exact decimal digits. For floats, `str of` produces the shortest + representation that round-trips back to the same double. During the builtin + transition, `num of` and JSON decoders still produce floats; an integer above + 2^53 must not be round-tripped through those readers yet. - **Every producer of number text obeys that same rule** — `str of`, `json_encode`, `json_build`, `json_path`, and the SIGUSR1 observer dump all share one implementation (`eigs_num_text`), so a JSON round-trip returns the same double and `json_encode of x` equals `str of x` for - every number (#875). + every float (#875). - `%` follows the dividend's sign (C semantics): `-7 % 3 == -1`. **Status:** Enforced — `tests/test_number_format.eigs`, @@ -461,7 +469,7 @@ unary and `of` are right-associative. - Out-of-range indices (including too-negative, e.g. `a[-(len+1)]`) raise a runtime error. - A non-integer index **raises** (`a[1.5]` → error). Integer-valued doubles - are accepted (`a[2.0]` works), since EigenScript has a single number type; + are accepted (`a[2.0]` works), since ints and floats share the numeric surface type; but a fractional value is never silently truncated. Because `/` always yields a double, a division-derived index must be collapsed explicitly — `a[floor of ((lo + hi) / 2)]` — which keeps the rounding decision in the diff --git a/docs/SPEC.md b/docs/SPEC.md index 021316599..587613e64 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -101,7 +101,7 @@ EigenScript is dynamically typed. The runtime types are: | type label | description | literal | |---|---|---| -| `num` | 64-bit float (the only number type) | `42`, `3.14` | +| `num` | signed int64 or 64-bit float | `42`, `3.14` | | `str` | immutable byte string | `"text"` | | `list` | mutable ordered sequence | `[1, 2, 3]` | | `dict` | mutable string-keyed map | `{"k": 1}` | @@ -184,7 +184,20 @@ print of xs ## Numbers and arithmetic -All numbers are 64-bit floats. Integer-valued numbers print without a +Numbers have two kinds: signed int64 and 64-bit float. `type of` reports +`"num"` for both; `num_type of` reports `"int"` or `"float"`, and null +for a non-number. Decimal integer literals within int64 are exact ints. +A decimal point or exponent makes a float; an out-of-range decimal integer +literal falls back to float. Hex integer literals wrap modulo 2^64. + +Int `+`, `-` and `*` preserve the int kind and raise `value` on int64 overflow. +Unary minus and `abs` also raise on INT64_MIN. Mixed int/float arithmetic +converts the int to float; comparison across kinds is exact, including +above 2^53. `/` still returns float; `%` retains truncating float remainder +until the floor-division round. Builtins retain their documented float +results during this transition, except `abs`, which preserves ints. + +Integer-valued floats print without a decimal point. Division is true division. `%` is modulo. There is no exponent operator; use `pow of [base, exp]`. @@ -235,14 +248,15 @@ still running ### The numeric model (deliberate position) -There is one number kind — the IEEE-754 f64 — and by design there is no +The float kind is IEEE-754 f64; at this stage there is no bigint or decimal type. This is a chosen position, not an oversight; the consequences are contracts you can rely on: -- **Integer exactness ends at 2^53.** Whole numbers up to `9007199254740992` +- **Float integer exactness ends at 2^53.** Whole floats up to `9007199254740992` are exact; past that the gaps between representable values exceed 1, so - `+ 1` can be invisible. Keep integer identifiers, counters, and money-in-cents - below 2^53, or use the bitwise seam below for wider exact integer work + `+ 1` can be invisible. For exact identifiers, counters, and money-in-cents, keep values in + the int kind rather than converting them to float. The transitional bitwise seam below + accepts wider exact integer operands (its operands must be exact integers below 2^63 in magnitude; past 2^53 only the representable ones qualify). - **Finite by construction — no `NaN`, no `Infinity` ever reach your program.** @@ -330,7 +344,7 @@ consequences are contracts you can rely on: `json_build`, `sort`, `random_int`, `random_hex`, `token_name`, sentinel for a valid-but-absent input — `index_of` miss `-1`, `file_exists` of a missing path `0` — is unchanged in both modes. - Overflow saturation is the same in both modes. (Division and modulo by zero + Float overflow saturation is the same in both modes; int overflow raises. (Division and modulo by zero raise in *both* modes — no defined value.) `zlib_*` forms) likewise reject a nonnumeric list element with a builtin-named `type_mismatch` error by default; `EIGS_STRICT=0` retains the @@ -358,12 +372,8 @@ false 1099511627776 ``` -Bigint / decimal value kinds would be a VM representation change rippling through -the JIT and the AOT (whose numeric speed rests on everything-being-a-double), so -they are deferred until a consumer genuinely forces them — not adopted -speculatively. Nothing above says "a number *is* an f64" any more than it must: -the contracts are exactness-below-2^53, finiteness, and the int64 bitwise seam, -which a future wider numeric kind could still honor. +Ints are exact throughout int64; floats retain the finite model above. Bigint +and decimal arithmetic remain library needs rather than additional core kinds. ## Strings diff --git a/docs/TRACE.md b/docs/TRACE.md index 876e548ef..ada5bbf23 100644 --- a/docs/TRACE.md +++ b/docs/TRACE.md @@ -27,7 +27,7 @@ The tape is plain text, one record per line: | Record | Meaning | |--------|---------| -| `V ` | Version header — always the first record (e.g. `V 6 0.44.0`). Stamped once per tape-open; a journal appended across sessions carries one per session. See [Format Versioning](#format-versioning-411). | +| `V ` | Version header — always the first record (e.g. `V 7 0.46.0`). Stamped once per tape-open; a journal appended across sessions carries one per session. See [Format Versioning](#format-versioning-411). | | `B ` | Stream association, before that stream's events. Describes state grouping and host/causal correspondence; folded as metadata by stepping, never a source-line stop. See below. | | `L ` | Source-line event (from `OP_LINE`, and when native code that ran EigenScript — a builtin's callback, an embedder's eval — gets control back: the line it entered with, so an assignment it makes next is filed under the same line on the tape as in live history, #1434; v5 carries the stream ID shown here). Duplicate lines within the same stream with no intervening `A`/`N` in that stream are deduped — the compiler emits per-statement LINEs and bare repeats are noise. | | `S ` | Scope transition (#539 v2): the `A` records that follow belong to this frame instance — `` is the chunk name (``, ``, or the function name), `` the 0-based frame depth, `` a per-thread monotonically increasing frame-instance id stamped at frame push. Emitted lazily with the same dedup discipline as `L`: only when the frame owning the next assignment differs from the last `S`, so the byte cost lands at call boundaries that actually assign. Two invocations of the same function carry different serials — their local streams never merge. Skipped on replay; folded by `--step`. | @@ -180,8 +180,12 @@ identity: `what is x at N`, `e.line` and error headers. `N` records are written with full fidelity so they can be parsed back into real values on replay: -- Numbers and `null` are written verbatim; a bool is written `true` or - `false` and read back as a bool (format v6, #1637). +- Ints are exact signed decimal digits; floats retain a decimal point or + exponent (`3.0`, `-0.0`, `1e+300`) so replay preserves the numeric kind + (format v7, #1758). An out-of-range int digit token is malformed rather + than rounded through a double. Version 6 tapes are refused by the format + check; re-record them with this binary. `null` is written verbatim; a bool + is written `true` or `false` and read back as a bool (#1637). - Strings are double-quoted; `\"`, `\\`, `\n`, `\r` are escaped, other control/non-printable bytes become `\xNN`. - Lists and dicts are emitted recursively: `[1, 2, 3]`, @@ -728,8 +732,10 @@ everywhere else in the runtime (version-and-reject, never migrate). answer (`file_exists`, `is_dir`, `mkdir`, ...) as `1`/`0`, so replaying it on a v6 binary would hand a number where the program now gets a bool; it is refused instead (covered by the existing replay kind-validation cases in - `tests/test_replay.sh`). Within a - v6 tape, replay also refuses a recorded value of a kind its builtin cannot + `tests/test_replay.sh`). **v7** (#1758) gives integer digit tokens their + exact int64 value and marks integral floats with `.0`. A v6 digit token + cannot establish its numeric kind, so v6 is refused by replay, stepping + and DAP. Within a current-format tape, replay also refuses a recorded value of a kind its builtin cannot return, with exit 3 and a message naming the record, the builtin, the kinds it returns and the tape version. Every taped builtin declares its return kinds in one table (`k_tape_kinds` in `src/trace.c`; for example diff --git a/docs/llms.txt b/docs/llms.txt index 6cacd66fc..fe49ce11c 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -210,8 +210,16 @@ sqrt(2) = 1.414213562373095 `false`, `0`, `null`, `""`, `[]`, `{}` are falsy. - `+` concatenates **strings only**. List concatenation is `append of [xs, v]` (in place) or a comprehension — `xs + ys` is a runtime error. -- Numbers are f64 and finite by construction: overflow saturates at ±1e308. - Integer bit ops are `bit_and`/`&` etc. on int64; exactness ends at 2^53. +- Numbers are signed int64 or finite f64. Decimal integer literals within + int64 are exact; a point/exponent or out-of-range decimal literal gives + float. Hex literals wrap modulo 2^64. `type of` says "num" for both; + `num_type of` says "int"/"float", or null for a non-number. Int +, -, * + raise value on overflow; unary minus and abs raise at INT64_MIN. Mixed + arithmetic converts to float, while cross-kind comparison is exact. + Division and most builtin results remain floats at this stage. + Float overflow saturates at ±1e308. + Integer bit ops accept exact int64 operands; builtin results and infix + results still convert to float until the bitwise/builtin rounds. A bit-op operand that is not an exact integer (`1.5 | 0`, `1e30 & 1`) raises a `value` error; it is never truncated. Strict mode is the DEFAULT: out-of-domain math (`sqrt of -1`), a NaN From db3fbdd31165710e23e1be1fdae38664bbd10010 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 03:51:47 -0500 Subject: [PATCH 064/188] phase2 R1.3g: declare R1.3's measured cost against origin/main (#1758) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured with tools/phase2_cost.sh on an empty declarations file, base = origin/main 540f0bcf (release, sha256 576722e5...; main's 0b25c741 changes no runtime source), candidate = this branch at 2b898e20 (release, sha256 f603b09b...): `workloads=15 rows=30 over_declared_max=30 FAIL`, every output identical between the two binaries. Every row is over +0.3%, so every row is declared: max_delta_pct is the measured delta rounded UP to the next 0.1 point (tests/bench_idxset.eigs, which prints elapsed time, varied by ~4,600 Ir over three identical runs, 0.005 points of its delta); recover_round R5; reason design §3, per tier. Measured Ir delta, jit / off tier: alloc_heavy +64.0 / +40.9 scalar_loop +210.1 / +126.8 conservative_observed +2.1 / +1.0 string_build +9.9 / +8.5 conservative_unobserved +2.7 / +1.1 unobserved_armed +66.7 / +8.8 dict_ops +0.7 / +0.7 unobserved_loop +4.0 / +1.4 observed_loop +4.0 / +1.4 bench_buf_mix +297.8 / +91.1 bench_buf_resample +191.0 / +64.4 bench_dmg_shape +172.9 / +49.0 bench_idxset +411.5 / +108.9 bench_pcm_codec +355.8 / +89.4 bench_perf +15.7 / +5.4 The JIT-tier rows exceed §3's "+70% on a counter loop" estimate because the interpreter's int paths box: mixed int/float operands (`range of N` still yields floats until R1.6, so `i * 2` is mixed), int indexes and int `/` and `%` take allocating slow paths. Per #1758's decision the branch does not merge while this file is non-empty (`--final`). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/cost_expect.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt index e69de29bb..80295b539 100644 --- a/tests/phase2/cost_expect.txt +++ b/tests/phase2/cost_expect.txt @@ -0,0 +1,30 @@ +bench/alloc_heavy.eigs jit 64.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/alloc_heavy.eigs off 41.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/conservative_observed_loop.eigs jit 2.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/conservative_observed_loop.eigs off 1.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/conservative_unobserved_loop.eigs jit 2.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/conservative_unobserved_loop.eigs off 1.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/dict_ops.eigs jit 0.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/dict_ops.eigs off 0.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/observed_loop.eigs jit 4.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/observed_loop.eigs off 1.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/scalar_loop.eigs jit 210.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/scalar_loop.eigs off 126.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/string_build.eigs jit 9.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/string_build.eigs off 8.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/unobserved_armed_loop.eigs jit 66.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/unobserved_armed_loop.eigs off 8.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/unobserved_loop.eigs jit 4.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/unobserved_loop.eigs off 1.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_buf_mix.eigs jit 297.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_buf_mix.eigs off 91.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_buf_resample.eigs jit 191.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_buf_resample.eigs off 64.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_dmg_shape.eigs jit 173.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_dmg_shape.eigs off 49.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_idxset.eigs jit 411.6 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_idxset.eigs off 109.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_pcm_codec.eigs jit 355.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_pcm_codec.eigs off 89.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_perf.eigs jit 15.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_perf.eigs off 5.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths From d33b4a9eb9b396796a9b3f518137b5bc58050f7a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 06:53:44 -0500 Subject: [PATCH 065/188] phase2 R1.3h: the vendored halting-descent corpus program writes its float literal (#1758) tests/observer_corpus/run.sh (CI's "Observer cross-repo corpus" step) went red at R1.3: 13 match, 1 diverge. The vendored iLambdaAi__test_halting_descent.eigs doubles `x` from the literal `10`, which R1.3 makes an int; under decision (A) int `*` raises on int64 overflow, so the runaway loop now stops with `integer overflow in '*'` instead of saturating at 1e308. The source relied on its int silently becoming a float; the program as written is correct to raise (Swift and Rust debug builds trap the same way). The row exists to pin the observer's reading of a doubling sequence, and overflow belongs to the N3/(A) rows. So its two `x is 10` lines become `x is 10.0`, the literal its author must write under (A), and the golden stays byte-identical: that equality is the proof that the observer's reading did not move. Checked in the interpreter, the default JIT and forced OSR. The deviation from source commit 246bd9a and its reason are recorded in tests/observer_corpus/README.md. `bash tests/observer_corpus/run.sh`: observer corpus: 14 match, 0 diverge; `git diff --stat -- tests/observer_corpus/golden/` is empty. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/observer_corpus/README.md | 15 +++++++++++++++ .../programs/iLambdaAi__test_halting_descent.eigs | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/observer_corpus/README.md b/tests/observer_corpus/README.md index b0735c98c..a0eb20319 100644 --- a/tests/observer_corpus/README.md +++ b/tests/observer_corpus/README.md @@ -59,6 +59,21 @@ so the corpus watches their convergence *counts* but not their *results*. When `dynamics` next refreshes `solve.eigs` it should print the elements (or `buf_to_list`) so the numeric signal comes back. +## Local edit note (#1758 R1.3, 2026-10-19) + +`iLambdaAi__test_halting_descent` differs from its source (iLambdaAi `246bd9a`, +`eigenscript_native/tests/test_halting_descent.eigs`) in two lines: `x is 10` +became `x is 10.0`. Since #1758 R1.3, `10` is an int literal and int `*` raises +`value` on int64 overflow (decision (A)), so the source's runaway doubling stops +with `integer overflow in '*'` after about 60 doublings instead of saturating at +`1e308`. The source relied on its int silently becoming a float; `10.0` is the +literal its author must write under (A). This row pins the observer's reading of +a doubling sequence; overflow belongs to the N3/(A) rows of +`tests/phase2/MAP.md`. **The golden is unchanged**: byte-identical with the edit +in the interpreter, the default JIT and forced OSR, which is the proof that the +observer's reading did not move. Re-vendoring from `246bd9a` would undo the edit; +take the source's own fix when it lands, or keep this one. + ## Sources (same-owner repos; vendored with provenance) - **dynamics** — `solve`/`physics`/`life`: real solvers and trajectory demos using `report`, the six predicates, `unobserved`, and `prev`. diff --git a/tests/observer_corpus/programs/iLambdaAi__test_halting_descent.eigs b/tests/observer_corpus/programs/iLambdaAi__test_halting_descent.eigs index 627e94b4c..174081f64 100644 --- a/tests/observer_corpus/programs/iLambdaAi__test_halting_descent.eigs +++ b/tests/observer_corpus/programs/iLambdaAi__test_halting_descent.eigs @@ -2,8 +2,8 @@ print of "=== HALTING: BOUNDED DESCENT TEST ===" print of "--- HD1: Entropy strictly decreases each iteration ---" counter is 0 -x is 10 -x is 10 +x is 10.0 +x is 10.0 loop while not converged: counter is counter + 1 From 198c1919b2a44756aa4426a0b9a26a29e32fa9cf Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 07:00:34 -0500 Subject: [PATCH 066/188] phase2 R1.3i: the observer oracle's known-wrong int64 verdicts are declared (#1830, #1758) At R1.3 the oracle's int64 capability rows run for the first time (main has no `num_type`, so its probe skips them), and `int64_count` reads 32 verdicts wrong: checkpoints 10 and 60, converged/stable/diverging/equilibrium, in all four arms. `make observer-oracle` and its EXPECT=int64 run, and CI's `observer oracle (floor)` lane, exited 1 on them with the floor intact (1,620 verdicts checked, 0 lost). The defect predates R1.3: the predicates' relative scale reads a unit step near 2^53 as settled, and main gives the same verdicts on an exact float counter at 2^50. Fixing it is round 3's work; int64_count becomes R3's acceptance row. Until then the verdicts are DECLARED, the instrument #1758 adopted for cost (comment 6258431523), in the same file shape: - tests/phase2/oracle_expect.txt, one TSV row per verdict: arm, row@checkpoint, predicate, recover_round (R3), reason (#1830). - score.py --declared FILE: a declared wrong verdict no longer fails; an undeclared wrong verdict still does; a STALE declaration (its verdict is right now, or was not examined) fails too, so a fix forces it out. Only capability verdicts can be declared; a row the parser cannot read is a harness error. Without --declared nothing changes, so plants.py's runs and any direct call keep the strict rule. - `make observer-oracle` and tools/observer_oracle/ci_lane.sh pass the file. - tools/phase2_cost.sh --final also requires it empty: #1776 merges only when both declaration files are empty. The design's round plan (8, R1.3) and docs/OBSERVER.md say so. At this commit: `make observer-oracle` and `make observer-oracle EXPECT=int64` both exit 0 with `32 declaration(s), 32 wrong as declared, 0 undeclared wrong, 0 stale` and `floor: 1620 verdicts checked, 0 lost`. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 9 +++-- docs/OBSERVER.md | 5 ++- docs/design/phase2-numbers.md | 15 +++++++-- tests/phase2/oracle_expect.txt | 32 ++++++++++++++++++ tools/observer_oracle/ci_lane.sh | 5 +-- tools/observer_oracle/score.py | 57 +++++++++++++++++++++++++++++--- tools/phase2_cost.sh | 14 ++++++-- 7 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 tests/phase2/oracle_expect.txt diff --git a/Makefile b/Makefile index e7a7c3305..10d4d28d3 100644 --- a/Makefile +++ b/Makefile @@ -483,13 +483,16 @@ observer-anchor: # observer-anchor builds, or reuses, in the user cache. FLOOR=, on the command # line or in the environment, names another floor; an empty FLOOR skips the floor # and the anchor. EXPECT=ieee,int64 fails when an expected capability is absent -# (#1758). CI calls score.py directly, through tools/observer_oracle/ci_lane.sh -# (the required check `observer oracle (floor)`). +# (#1758). Both pass --declared tests/phase2/oracle_expect.txt: Phase 2's known- +# wrong capability verdicts, each with its recover round (#1830); an undeclared +# wrong verdict or a stale declaration fails, and #1776 merges only when the file +# is empty (tools/phase2_cost.sh --final). CI calls score.py directly, through +# tools/observer_oracle/ci_lane.sh (the required check `observer oracle (floor)`). .PHONY: observer-oracle observer-oracle: FLOOR ?= tools/observer_oracle/floor.json observer-oracle: build $(if $(FLOOR),$(OBSERVER_ANCHOR)) - python3 tools/observer_oracle/score.py src/eigenscript $(if $(FLOOR),--floor $(FLOOR)) $(if $(EXPECT),--expect $(EXPECT)) + python3 tools/observer_oracle/score.py src/eigenscript $(if $(FLOOR),--floor $(FLOOR)) $(if $(EXPECT),--expect $(EXPECT)) --declared tests/phase2/oracle_expect.txt install-gfx: install @echo "NOTE: 'make install-gfx' is a compatibility alias for 'make install'." diff --git a/docs/OBSERVER.md b/docs/OBSERVER.md index a7794705e..f85b8bf19 100644 --- a/docs/OBSERVER.md +++ b/docs/OBSERVER.md @@ -254,7 +254,10 @@ native tiers must still witness a body. The predicate READS never run natively: A row's capability is derived from its values (IEEE inf/-inf/NaN; an int a double cannot hold exactly). Such a row runs only on a binary whose probe shows the capability (one probe checks that `1e308 * 10` overflows to inf AND that inf × 0 is NaN; a binary that does one without the other is refused), skips are printed, `EXPECT=ieee,int64` makes an absent one -fail, and every verdict on them must be right. By default the run also applies the committed floor, +fail, and every verdict on them must be right, or be declared wrong: Phase 2 passes `--declared +tests/phase2/oracle_expect.txt` (#1830), whose rows name an arm, a `row@checkpoint` and a predicate with the round +that fixes it. An undeclared wrong verdict fails, so does a declaration whose verdict is right now or was not examined, +and the integration merge (#1776) requires that file empty. By default the run also applies the committed floor, `tools/observer_oracle/floor.json` (#1764): it fails when it gets wrong any verdict the v0.46.0 tag got right. An empty `FLOOR=`, on the command line or in the environment, skips the floor. Its anchor is the binary `tools/observer_oracle/build_anchor.sh` builds from the tag into diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 861445df0..2b333f6e0 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1970,9 +1970,18 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: `max_delta_pct`, `recover_round`, `reason`); undeclared rows retain +0.3%. Declare only measured R1.3 costs with §3 as the reason and `recover_round=R5`, the JIT/leaf int fast-path round. A row above its - declared maximum fails. **Pre-merge condition:** - `tools/phase2_cost.sh --final BASE CAND` must pass with the declarations file - empty; temporary costs must be recovered before integration merges. + declared maximum fails. The observer oracle's known-wrong capability + verdicts are declared the same way (#1830): `tests/phase2/oracle_expect.txt` + (`arm`, `row@checkpoint`, `predicate`, `recover_round`, `reason`) lists the + 32 `int64_count` verdicts R1.3 first measures, `recover_round=R3`, the round + whose predicate definitions make `int64_count` its acceptance row. + `make observer-oracle` and CI's lane pass it to `score.py --declared`; an + undeclared wrong verdict fails, and so does a stale declaration (its verdict + is right now, or was not examined). **Pre-merge condition (#1776):** + `tools/phase2_cost.sh --final BASE CAND` must pass, which requires both + `tests/phase2/cost_expect.txt` and `tests/phase2/oracle_expect.txt` to be + empty; temporary costs and known-wrong verdicts must be recovered before + integration merges. Consumer hashes that relied on double rounding now raise ((A)); they move to the N9 wrapping builtins. 4. **R1.4, N4.** `//` (token, parser, `OP_IDIV` appended, diff --git a/tests/phase2/oracle_expect.txt b/tests/phase2/oracle_expect.txt new file mode 100644 index 000000000..f5c89882c --- /dev/null +++ b/tests/phase2/oracle_expect.txt @@ -0,0 +1,32 @@ +interp/straight int64_count@10 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/straight int64_count@10 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/straight int64_count@10 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/straight int64_count@10 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@10 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@10 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@10 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@10 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@10 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@10 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@10 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@10 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@10 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@10 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@10 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@10 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/straight int64_count@60 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/straight int64_count@60 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/straight int64_count@60 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/straight int64_count@60 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@60 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@60 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@60 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +interp/loop int64_count@60 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@60 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@60 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@60 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +jit/loop int64_count@60 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@60 converged R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@60 stable R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@60 diverging R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row +osr/loop int64_count@60 equilibrium R3 #1830: the predicates read a unit step near 2^53 as settled (relative scale; main reads an exact float counter at 2^50 the same way); first measured at R1.3 because the int64 capability row first runs here; int64_count is R3's acceptance row diff --git a/tools/observer_oracle/ci_lane.sh b/tools/observer_oracle/ci_lane.sh index c1580f521..a8046f4b4 100755 --- a/tools/observer_oracle/ci_lane.sh +++ b/tools/observer_oracle/ci_lane.sh @@ -54,10 +54,11 @@ make build || fail "make build failed" phase "score the candidate against the committed floor (score.py --floor)" rc=0 -python3 tools/observer_oracle/score.py src/eigenscript --floor tools/observer_oracle/floor.json | tee "$tmp/oracle.out" || rc=$? +python3 tools/observer_oracle/score.py src/eigenscript --floor tools/observer_oracle/floor.json \ + --declared tests/phase2/oracle_expect.txt | tee "$tmp/oracle.out" || rc=$? case "$rc" in 0) ;; - 1) fail "score.py exit 1: a verdict was lost or split between arms (the FLOOR VIOLATION, FINDING or CAPABILITY WRONG lines above). The gate is working: fix the change, or fix a wrong label through derive.py/certify.py and re-measure the floor" ;; + 1) fail "score.py exit 1: a verdict was lost or split between arms (the FLOOR VIOLATION, FINDING, CAPABILITY WRONG or STALE DECLARATION lines above). The gate is working: fix the change, or fix a wrong label through derive.py/certify.py and re-measure the floor" ;; *) fail "score.py exit $rc: a harness error (the OBSERVER_ORACLE_ERROR line above), not a verdict" ;; esac n=$(python3 -c 'import json; print(len(json.load(open("tools/observer_oracle/floor.json"))["verdicts"]))') \ diff --git a/tools/observer_oracle/score.py b/tools/observer_oracle/score.py index 621ed8803..9cdae5db7 100644 --- a/tools/observer_oracle/score.py +++ b/tools/observer_oracle/score.py @@ -2,7 +2,7 @@ """Score EigenScript's observer against a ground-truth corpus (#1746, #1758). usage: score.py BINARY [--corpus PATH] [--numbers ieee|clamp] [--expect CAP,...] - [--floor FILE] [--write-floor FILE [--note TEXT]] + [--floor FILE] [--declared FILE] [--write-floor FILE [--note TEXT]] labels.json must equal derive.py's derivation (the label gate). Each predicate is scored against ONE question (converged, stable, improving: @@ -52,7 +52,13 @@ Exit 1: a FINDING (any reading, REPORTED ones included, that differs between arms), a wrong verdict on a capability row, an expected capability -absent, or (--floor) a floor verdict now wrong. There are no waivers: a +absent, or (--floor) a floor verdict now wrong. --declared FILE (#1758, #1830: +Phase 2's tests/phase2/oracle_expect.txt, the shape of cost_expect.txt) lists +known-wrong CAPABILITY verdicts, one TSV row each: arm, row@checkpoint, +predicate, recover_round, reason. A declared wrong verdict does not fail; an +undeclared one does, and so does a STALE declaration, one whose verdict is +right now or was not examined, so a fix forces the declaration out. A row the +parser cannot read is a harness error. There are no waivers on the floor: a floor verdict agrees with its label, so losing it is wrong unless the label is, and a wrong label is fixed through derive/certify, which re-measures the floor. The floor's anchor is the binary build_anchor.sh builds from tag @@ -512,6 +518,33 @@ def verdicts(res, corpus, labels): return out +def load_declared(path, rows): + """--declared FILE -> {(arm, row, checkpoint, predicate): (recover_round, reason)}. + Only capability verdicts can be declared; anything unreadable is refused.""" + arms, out = {f"{t}/{f}" for t, f in ARMS}, {} + with open(path) as f: + lines = f.read().splitlines() + for n, line in enumerate(lines, 1): + if not line.strip(): + continue + fields = [x.strip() for x in line.split("\t")] + if len(fields) != 5: + raise HarnessError(f"{path}:{n}: expected five TSV fields" + " (arm, row@checkpoint, predicate, recover_round, reason)") + arm, rc, p, rnd, why = fields + rid, _, at = rc.partition("@") + row = rows.get(rid) + if (arm not in arms or not row or not row.get("capability") or not at.isdigit() + or int(at) not in row["checkpoints"] or p not in PREDS): + raise HarnessError(f"{path}:{n}: not a capability verdict: {arm} {rc} {p}") + if not re.fullmatch(r"R[1-9][0-9]*(?:\.[1-9][0-9]*)?", rnd) or not why: + raise HarnessError(f"{path}:{n}: recover_round (a round name) and reason are required") + if (arm, rid, int(at), p) in out: + raise HarnessError(f"{path}:{n}: duplicate declaration {arm} {rc} {p}") + out[(arm, rid, int(at), p)] = (rnd, why) + return out + + def findings(res): """Every (row, checkpoint, predicate) whose readings differ between arms, REPORTED readings included: a split is a fault whatever the label.""" @@ -679,7 +712,7 @@ def report(v, res, corpus, numbers, caps, probes, labels, reported, expect): def main(argv): args, opts = argv[1:], {} - for flag in ("--corpus", "--numbers", "--expect", "--floor", "--write-floor", "--note"): + for flag in ("--corpus", "--numbers", "--expect", "--floor", "--declared", "--write-floor", "--note"): if flag in args: i = args.index(flag) if i + 1 >= len(args): @@ -689,7 +722,7 @@ def main(argv): expect = set(filter(None, opts.get("--expect", "").split(","))) if len(args) != 1 or opts.get("--numbers", "clamp") not in ("ieee", "clamp") or expect - set(CAPS): raise HarnessError("usage: score.py BINARY [--corpus PATH] [--numbers ieee|clamp] [--expect ieee,int64]" - " [--floor FILE] [--write-floor FILE [--note TEXT]]") + " [--floor FILE] [--declared FILE] [--write-floor FILE [--note TEXT]]") binary = os.path.abspath(args[0]) if not (os.path.isfile(binary) and os.access(binary, os.X_OK)): raise HarnessError(f"binary not found or not executable: {binary}") @@ -704,6 +737,7 @@ def main(argv): labels = load_labels(corpus, certs, os.path.join(cdir, "labels.json")) pre = floor_preflight(opts["--floor"]) if "--floor" in opts else None rows = {r["id"]: r for r in corpus["rows"]} + declared = load_declared(opts["--declared"], rows) if "--declared" in opts else None ieee, caps, probes = capabilities(binary, opts.get("--numbers")) with anchor_lock() if stamp else contextlib.nullcontext(): res = measure(binary, corpus, caps) @@ -724,9 +758,22 @@ def main(argv): missing = sorted(c for c in expect if not caps[c]) print(f"\nCAPABILITY ROWS (every scored verdict must be right): {len(ran)} run, {len(res['skipped'])} skipped," f" {len(capwrong)} wrong verdict(s); expected and absent: {missing or 'none'}") + stale = [] + if declared is not None: + stale = sorted(k for k in declared if k not in capwrong) + print(f"DECLARED (--declared {opts['--declared']}): {len(declared)} declaration(s)," + f" {sum(1 for k in capwrong if k in declared)} wrong as declared," + f" {sum(1 for k in capwrong if k not in declared)} undeclared wrong, {len(stale)} stale") + for k in sorted(k for k in capwrong if k in declared): + print(f" DECLARED WRONG {k[0]} {k[1]}@{k[2]} {k[3]}: expected={str(v[k][1]).lower()}" + f" recover_round={declared[k][0]} reason={declared[k][1]}") + for k in stale: + print(f" STALE DECLARATION {k[0]} {k[1]}@{k[2]} {k[3]}: " + + ("the verdict is right now; remove the declaration" if k in v else "not examined")) + capwrong = [k for k in capwrong if k not in declared] for arm, rid, at, p in capwrong: print(f" CAPABILITY WRONG {arm} {rid}@{at} {p}: expected={str(v[(arm, rid, at, p)][1]).lower()}") - fail = 1 if split or capwrong or missing else 0 + fail = 1 if split or capwrong or stale or missing else 0 if pre: fail |= check_floor(pre, opts["--floor"], v, rows, corpus, labels) if stamp: diff --git a/tools/phase2_cost.sh b/tools/phase2_cost.sh index 0d9f0c320..9cef6526e 100755 --- a/tools/phase2_cost.sh +++ b/tools/phase2_cost.sh @@ -3,7 +3,9 @@ # The target list has one home: codspeed.yml. Consumer targets live elsewhere. # Undeclared rows allow +0.3%; declared temporary costs are bounded per row. # TSV: workload, tier, max_delta_pct, recover_round, reason (no header). -# --final requires the declarations file to be empty before integration merges. +# --final requires the declarations file to be empty before integration merges, +# and the observer oracle's (tests/phase2/oracle_expect.txt, score.py --declared, +# #1830) as well: #1776 merges only when neither declares anything. set -eu cd "$(dirname "$0")/.." exec python3 - "$@" <<'PY' @@ -22,7 +24,7 @@ THRESHOLD_PCT = Decimal('0.3') root = Path.cwd() ap = argparse.ArgumentParser(prog='tools/phase2_cost.sh') ap.add_argument('--final', action='store_true', - help='require an empty cost_expect.txt (the pre-merge condition)') + help='require empty cost_expect.txt and oracle_expect.txt (the pre-merge condition)') ap.add_argument('base', nargs='?') ap.add_argument('cand', nargs='?') args = ap.parse_args() @@ -32,10 +34,16 @@ if not expect_path.is_file(): expect_text = expect_path.read_text() if args.final and expect_text: sys.exit('phase2-cost: FAIL: --final requires an empty tests/phase2/cost_expect.txt') +oracle_path = root / 'tests/phase2/oracle_expect.txt' +if args.final and not oracle_path.is_file(): + sys.exit('phase2-cost: FAIL: missing tests/phase2/oracle_expect.txt') +if args.final and oracle_path.read_text(): + sys.exit('phase2-cost: FAIL: --final requires an empty tests/phase2/oracle_expect.txt' + ' (%d observer-oracle declaration(s) remain)' % len(oracle_path.read_text().splitlines())) if bool(args.base) != bool(args.cand) or (not args.base and not args.final): ap.error('supply , or --final alone') if not args.base: - print('phase2-cost: final declarations=0 PASS') + print('phase2-cost: final declarations=0 oracle_declarations=0 PASS') sys.exit(0) local_workload = re.compile(r'(?:bench/[^/]+|tests/bench_[^/]+)\.eigs') workloads = set() From 55920bebcf3c00f600e051b60c5cd796bec163c8 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 11:12:29 -0500 Subject: [PATCH 067/188] embed_smoke: tape assertions match whole v7 lines (#1758 R1.3 CI) CI's embedding smoke (asan+ubsan shards 1-3, extensions/server) failed at src/embed_smoke.c:921: the assertion expected the v6 spelling `A 0 native_after_callback=1441` for a float slot, and tape v7 marks an integral float as `1441.0` (decided, T1). The expectation moves to v7, and every tape assertion in the file now matches WHOLE lines (tape_has_lines: the needle is complete lines and starts at a line start). The old `strstr(g_tape, "N 0 host_sensor=100")` also matched `=1000` and `=100.0`, so it could not tell v6 from v7. Plant (src/trace.c tape_float_text writes v6 spelling, no `.0`): the new file reports `embed_smoke: 4 failure(s)` (lines 934, 940, 941, 942); the old file on the same planted tree reports `embed_smoke: OK`. make embed-smoke: embed_smoke: OK make embed-smoke-asan-server: embed_smoke: OK, 0 sanitizer reports Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- src/embed_smoke.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/embed_smoke.c b/src/embed_smoke.c index c218e648b..5070462cb 100644 --- a/src/embed_smoke.c +++ b/src/embed_smoke.c @@ -275,6 +275,18 @@ static void tape_sink(const char *bytes, size_t len, void *ud) { g_tape_len += len; } +/* A tape assertion matches WHOLE lines. `want` is one or more complete lines, + * each ending in '\n', and it must begin at the start of a tape line. A bare + * strstr cannot tell `=100` from `=1000` or from v7's `=100.0`, so it passes + * on a v6 tape and on a v7 one alike. */ +static int tape_has_lines(const char *tape, const char *want) { + size_t wl = strlen(want); + if (wl == 0 || want[wl - 1] != '\n') return 0; /* not whole lines: refuse */ + for (const char *p = tape; (p = strstr(p, want)) != NULL; p++) + if (p == tape || p[-1] == '\n') return 1; + return 0; +} + /* Host function: adds two numbers. Multi-arg calls receive a VAL_LIST. */ static EigsValue *host_add(EigsValue *arg) { if (eigs_value_type(arg) != EIGS_TYPE_LIST) return eigs_value_new_null(); @@ -918,15 +930,16 @@ int main(void) { SLOT_F64_RAW(s) = 1441.0; trace_assign(NM, s); g_tape[g_tape_len < sizeof g_tape ? g_tape_len : sizeof g_tape - 1] = 0; - CHECK(strstr(g_tape, "S 0 0 0\nA 0 native_after_callback=1441\n") != NULL, + /* Tape v7 marks an integral float as a float: `1441.0`, never `1441`. */ + CHECK(tape_has_lines(g_tape, "S 0 0 0\nA 0 native_after_callback=1441.0\n"), "native assignment after callback carries native scope"); } eigs_set_trace_sink(NULL, NULL); CHECK(g_tape_len > 0, "sink captured tape bytes"); g_tape[g_tape_len < sizeof g_tape ? g_tape_len : sizeof g_tape - 1] = 0; - CHECK(strstr(g_tape, "N 0 host_sensor=100") != NULL, "tape has N record 100"); - CHECK(strstr(g_tape, "N 0 host_sensor=101") != NULL, "tape has N record 101"); - CHECK(strstr(g_tape, "A 0 s1=100") != NULL, "tape has assignment record"); + CHECK(tape_has_lines(g_tape, "N 0 host_sensor=100.0\n"), "tape has N record 100.0"); + CHECK(tape_has_lines(g_tape, "N 0 host_sensor=101.0\n"), "tape has N record 101.0"); + CHECK(tape_has_lines(g_tape, "A 0 s1=100.0\n"), "tape has assignment record"); /* recording stopped: another live read advances but adds no bytes */ size_t tape_frozen = g_tape_len; From f5b74424f039020f96be7885a874b009ae63abf1 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 12:26:10 -0500 Subject: [PATCH 068/188] stdlib: real-valued formulas stay in floats under int literals; the lib differential (#1848) A real-valued stdlib formula could compute in int64 through an int literal of its own and an int argument, and raise where main answered: rest_energy of 103 main 9.25717834098922e+18, branch raised poisson_pmf of [21, 5.0] main 6.288597083156293e-08, branch raised fmt_num of [18, 18] main "18.000000000000000000", branch raised Fixes: SPEED_OF_LIGHT is a float literal; poisson_pmf divides by a FLOAT k! (_factorial_real, same domain sentinel as factorial); fmt_num's scale factor is a float. factorial of 21 still raises: decided (A), declared. tools/phase2_lib_diff.sh
is #1848's differential: every exported function of every tracked lib module (the import namespace, checked against the column-0 defines both ways; ui's fragments through ui), called with int arguments n in [-3, 110] on both binaries over the SAME copied lib source. A call main completes and the branch raises is listed; a listed function must be declared integer-domain in tests/phase2/lib_int_domain.txt, and a declaration no call needs is stale. Before the fixes: 6 functions listed, all undeclared (FAIL). After: 889 functions, 281331 calls, examined=281331, listed=1 (probability.factorial, declared), PASS. Plants: SPEED_OF_LIGHT back to the int literal -> UNDECLARED physics.rest_energy, FAIL; a declaration for permutations -> STALE, FAIL. poisson_pmf: byte-identical to main on 888 points (k 0..110, 8 lambdas) and within 1.327e-13 of SciPy 1.18.1's poisson.pmf. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- .../1848-stdlib-real-valued-literals.md | 2 + docs/design/phase2-numbers.md | 37 +++- lib/format.eigs | 4 +- lib/physics.eigs | 2 +- lib/probability.eigs | 16 +- tests/phase2/lib_int_domain.txt | 5 + tools/phase2_lib_diff.sh | 203 ++++++++++++++++++ 7 files changed, 265 insertions(+), 4 deletions(-) create mode 100644 changes/internal/1848-stdlib-real-valued-literals.md create mode 100644 tests/phase2/lib_int_domain.txt create mode 100755 tools/phase2_lib_diff.sh diff --git a/changes/internal/1848-stdlib-real-valued-literals.md b/changes/internal/1848-stdlib-real-valued-literals.md new file mode 100644 index 000000000..7c5242f96 --- /dev/null +++ b/changes/internal/1848-stdlib-real-valued-literals.md @@ -0,0 +1,2 @@ +- No entry: `rest_energy`, `poisson_pmf`/`poisson_cdf` and `fmt_num`/`fmt_percent` keep computing in floats + under #1758's unreleased int literals, so they answer as the last release does (#1848). diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 2b333f6e0..650797596 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1983,7 +1983,10 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: empty; temporary costs and known-wrong verdicts must be recovered before integration merges. Consumer hashes that relied on double rounding now raise - ((A)); they move to the N9 wrapping builtins. + ((A)); they move to the N9 wrapping builtins. The stdlib's own + real-valued formulas must not: `tools/phase2_lib_diff.sh` (§9.5, #1848) + runs every exported lib function with int arguments on main and the + branch, from R1.3 in every round. 4. **R1.4, N4.** `//` (token, parser, `OP_IDIV` appended, `op_name`/`op_stack_effect`/obs marker/ABI test), `//=` beside `/=` (Q6), `%` floor modulo for ints and floats, int division by zero raises, @@ -2524,6 +2527,38 @@ The int-fuzz sweep, if kept, shrinks to what the table does not do: a crash-only sweep (every builtin fed ints in every numeric slot must raise or return, never crash), in the shape of `tests/test_bool_fuzz.sh`. +### 9.5 `tools/phase2_lib_diff.sh ` (#1848, from R1.3) + +A real-valued stdlib formula can compute in int64 through an int literal of +its own and an int argument: `rest_energy of 103` (an int speed of light) +and `poisson_pmf of [21, 5.0]` (an int `k!` denominator) raised where main +answered. A grep cannot find the second kind, so this is a differential. +- **Population:** every tracked `lib/*.eigs` module's import namespace (its + `fn` keys), checked against the modules' column-0 `define` lines in both + directions. A function is called once, through its own module, or through + a module that re-exports it when its own cannot be imported alone (`ui`'s + `ui_w_*` fragments). `lib/pkg.eigs` is the one declared non-library module + (importing it runs the `--pkg` CLI); any other unexamined module fails. +- **Same input:** both binaries run a copy of the branch's `lib/` under a + scratch project root, so only the runtime differs. +- **Calls, the stated range:** every int n in [-3, 110]; arity 1 calls f(n), + arity k >= 2 the diagonal and, per position, n there with 1 elsewhere. +- **Verdict:** a call is listed when main completes it and the branch raises + or never reaches it. A listed function must be integer-domain and declared + in `tests/phase2/lib_int_domain.txt` with its reason (decision (A)); a + declaration no call needs is stale. Both fail. +- At R1.3: 889 functions, 281,331 calls; `probability.factorial` is the one + declaration. `rest_energy`, `poisson_pmf`/`poisson_cdf` and + `fmt_num`/`fmt_percent` were fixed (a float constant, a float `k!` + denominator, a float scale factor). The fixed `poisson_pmf` is + byte-identical to main on 888 points and within 1.3e-13 of SciPy's + `poisson.pmf` (the oracle). Calibration: the int `SPEED_OF_LIGHT` planted + back lists `rest_energy` UNDECLARED; a declaration for `permutations` is + STALE. +- **Range boundary:** ints at most 110 keep a polynomial of degree 9 in the + caller's own ints inside int64, so a listed call points at the library. + A literal that overflows only for larger arguments is not seen. + --- ## 10. The Lua differential tool (`tools/phase2_lua_diff.py`, round 1) diff --git a/lib/format.eigs b/lib/format.eigs index 5f388bb02..ffe59f1fe 100644 --- a/lib/format.eigs +++ b/lib/format.eigs @@ -18,7 +18,9 @@ define fmt_num(value, decimals) as: return "-" + (fmt_num of [0 - value, decimals]) if decimals == 0: return str of (round of value) - factor is 1 + # A float scale: value * 10^decimals is real-valued, and an int factor + # overflows int64 at 19 decimals (#1848). + factor is 1.0 for i in range of decimals: factor is factor * 10 rounded is round of (value * factor) diff --git a/lib/physics.eigs b/lib/physics.eigs index ac91dcca7..021b55b82 100644 --- a/lib/physics.eigs +++ b/lib/physics.eigs @@ -16,7 +16,7 @@ # Fundamental Constants # ============================================================ -SPEED_OF_LIGHT is 299792458 # m/s (exact) +SPEED_OF_LIGHT is 299792458.0 # m/s (exact; a float, so m·c² with an int m stays real, #1848) PLANCK is 6.62607015e-34 # J·s (exact) HBAR is 1.054571817e-34 # J·s (reduced Planck, h/2π) BOLTZMANN is 1.380649e-23 # J/K (exact) diff --git a/lib/probability.eigs b/lib/probability.eigs index 9330c0fdb..fd65024be 100644 --- a/lib/probability.eigs +++ b/lib/probability.eigs @@ -71,9 +71,23 @@ define binomial_cdf(n, k, p) as: s is s + binomial_pmf of [n, i, p] return s +# _factorial_real: n! as a FLOAT, for real-valued formulas (#1848). Same domain +# sentinel as factorial (0 for a negative n); its product is a float, so an int +# n past 20 does not raise as `factorial of 21` does (decision (A), #1758). +define _factorial_real(n) as: + if n < 0: + return 0.0 + result is 1.0 + i is 2 + loop while i <= n: + result is result * i + i is i + 1 + return result + # poisson_pmf: P(X=k) = lambda^k * e^(-lambda) / k! +# A probability is real-valued: k! is a float denominator (#1848). define poisson_pmf(k, lam) as: - return (pow of [lam, k]) * (exp of (0 - lam)) / (factorial of k) + return (pow of [lam, k]) * (exp of (0 - lam)) / (_factorial_real of k) # poisson_cdf: P(X <= k) = sum_{i=0}^{k} poisson_pmf(i, lambda) define poisson_cdf(k, lam) as: diff --git a/tests/phase2/lib_int_domain.txt b/tests/phase2/lib_int_domain.txt new file mode 100644 index 000000000..c3ff7e417 --- /dev/null +++ b/tests/phase2/lib_int_domain.txt @@ -0,0 +1,5 @@ +# Integer-domain stdlib functions (#1848): tools/phase2_lib_diff.sh lists every +# call that main completes and the branch raises; a listed function must be +# declared here, and a declaration no call needs is stale. Decision (A), #1758: +# int overflow raises, as Julia's factorial(21) does. TSV: module.function, reason. +probability.factorial n! is an integer count: past 20! it leaves int64 and raises, decided (A) in #1758 (comment 6266498388; Julia's factorial(21) raises) diff --git a/tools/phase2_lib_diff.sh b/tools/phase2_lib_diff.sh new file mode 100755 index 000000000..6899b24c6 --- /dev/null +++ b/tools/phase2_lib_diff.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash +# The stdlib's int differential (#1848, #1758 Phase 2): every exported function +# of every tracked lib/*.eigs module, called with INT arguments on origin/main +# and on the branch. Both binaries run the SAME lib source (a copy of this +# tree's lib/ under a scratch project root), so only the runtime differs. +# bash tools/phase2_lib_diff.sh +# The stated range: every int n in [-3, 110]; arity 1 calls f(n), arity k >= 2 +# calls the diagonal f(n, ..., n) and, per position, n there with 1 elsewhere. +# A `define f as:` takes the implicit parameter n (arity 1); arity 0 is not +# called. The population is the module's import namespace (its `fn` keys), +# checked against the module's column-0 `define` lines in both directions. +# A call LISTED is one main completes and the branch raises or never reaches. +# Each listed function must be an integer-domain function declared in +# tests/phase2/lib_int_domain.txt (decision (A): int overflow raises), and each +# declaration must be listed (a stale one fails). Every other listing fails. +set -eu +cd "$(dirname "$0")/.." +exec python3 - "$@" <<'PY' +import argparse +import os +from pathlib import Path +import re +import shutil +import signal +import subprocess +import sys +import tempfile + +RANGE = list(range(-3, 111)) +TIMEOUT = 120 +root = Path.cwd() +ap = argparse.ArgumentParser(prog='tools/phase2_lib_diff.sh') +ap.add_argument('main') +ap.add_argument('branch') +args = ap.parse_args() + + +def fail(msg): + print('phase2-lib-diff: FAIL: ' + msg, flush=True) + sys.exit(1) + + +bins = {} +for arm in ('main', 'branch'): + p = Path(getattr(args, arm)) + if not p.is_file() or not os.access(p, os.X_OK): + fail('not an executable: %s' % p) + bins[arm] = str(p.resolve()) +declared = {} +for n, line in enumerate((root / 'tests/phase2/lib_int_domain.txt').read_text().splitlines(), 1): + if not line.strip() or line.startswith('#'): + continue + f = line.split('\t') + if len(f) != 2 or not re.fullmatch(r'\w+\.\w+', f[0]) or not f[1].strip() or f[0] in declared: + fail('lib_int_domain.txt:%d: want one "module.functionreason" row per function' % n) + declared[f[0]] = f[1].strip() +mods = sorted(m for m in subprocess.check_output(['git', 'ls-files', '-z', 'lib/*.eigs'], + cwd=root).decode().split('\0') + if re.fullmatch(r'lib/[a-z_0-9]+\.eigs', m)) +if not mods: + fail('no tracked lib/*.eigs modules') +work = Path(tempfile.mkdtemp(prefix='phase2-libdiff-')) +(work / 'lib').mkdir() +for m in mods: + shutil.copy(root / m, work / m) +(work / 'eigs.json').write_text('{}\n') +env = {k: v for k, v in os.environ.items() + if not k.startswith('EIGS_') and k not in ('DISPLAY', 'XAUTHORITY', 'WAYLAND_DISPLAY')} +env.update(SDL_VIDEODRIVER='dummy', SDL_AUDIODRIVER='dummy') + + +def run(arm, name, text): + """Run one probe in its own session and cwd; a timeout kills the group.""" + prog = work / (name + '.eigs') + prog.write_text(text) + cwd = work / ('cwd-' + arm) + cwd.mkdir(exist_ok=True) + proc = subprocess.Popen([bins[arm], str(prog)], cwd=cwd, env=dict(env, HOME=str(cwd)), + stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, start_new_session=True) + try: + out, _ = proc.communicate(timeout=TIMEOUT) + rc = proc.returncode + except subprocess.TimeoutExpired: + os.killpg(proc.pid, signal.SIGKILL) + out, _ = proc.communicate() + rc = 124 + return rc, out.decode(errors='replace').splitlines() + + +def tuples(arity): + rows = [(n,) * arity for n in RANGE] + if arity >= 2: + rows += [tuple(n if i == j else 1 for i in range(arity)) for j in range(arity) for n in RANGE] + return sorted(dict.fromkeys(rows), key=lambda t: (max(abs(x) for x in t), t)) + + +def call_text(mod, fn, t): + a = str(t[0]) if len(t) == 1 else '[%s]' % ', '.join(map(str, t)) + return 'r is %s.%s of %s' % (mod, fn, a) + + +define_re = re.compile(r'^define ([A-Za-z_]\w*)(?:\(([^)]*)\))? as:', re.M) +own = {m: {name: 1 if params is None else len([p for p in params.split(',') if p.strip()]) + for name, params in define_re.findall((root / m).read_text()) if not name.startswith('_')} + for m in mods} +defined_anywhere = set().union(*own.values()) +# The one module that is not a library: importing it runs a command line. +NOT_LIBRARY = {'lib/pkg.eigs': 'the `eigenscript --pkg` command; importing it runs the CLI'} +# Pass 1: each module's import namespace (its `fn` keys), on both binaries. +ns, unimportable = {}, {} +for m in mods: + mod = Path(m).stem + keys, rcs = {}, {} + for arm in bins: + rcs[arm], out = run(arm, 'keys_' + mod, 'import %s\nfor k in keys of %s:\n if (type of %s[k]) == "fn":\n' + ' print of f"K {k}"\nprint of "KEYS-DONE"\n' % (mod, mod, mod)) + keys[arm] = {line[2:] for line in out if line.startswith('K ')} if 'KEYS-DONE' in out else None + if keys['main'] is None and keys['branch'] is None: + unimportable[m] = rcs + continue + if keys['main'] != keys['branch'] or not set(own[m]) <= keys['branch'] \ + or not keys['branch'] <= defined_anywhere: + fail('%s: namespaces disagree (rc main=%d branch=%d): main-only=%s branch-only=%s undefined=%s ' + 'not-exported=%s' % (m, rcs['main'], rcs['branch'], sorted((keys['main'] or set()) - (keys['branch'] or set())), + sorted((keys['branch'] or set()) - (keys['main'] or set())), + sorted((keys['branch'] or set()) - defined_anywhere), + sorted(set(own[m]) - (keys['branch'] or set())))) + ns[m] = keys['branch'] +# Pass 2: each defined function is examined once, through its own module or, +# when that cannot be imported alone (ui.eigs loads its ui_w_* fragments), +# through a module whose namespace re-exports it. +plan, skipped = [], {} +for m in mods: + for fn, arity in sorted(own[m].items()): + via = m if m in ns else next((x for x in mods if x in ns and fn in ns[x] and fn not in own[x]), None) + if via is None: + skipped.setdefault(m, []).append(fn) + else: + plan.append((via, fn, arity)) +if set(skipped) != set(NOT_LIBRARY) or not set(NOT_LIBRARY) <= set(unimportable): + fail('unexamined modules %s != the declared non-library modules %s' % (sorted(skipped), sorted(NOT_LIBRARY))) +counts = dict(modules=len(mods), importable=len(ns), functions=len(plan), + via_reexport=sum(via not in own or fn not in own[via] for via, fn, _ in plan), + no_params=0, calls=0, examined=0, unexamined=0, both_ok=0, both_raise=0, improved=0) +listed, unexamined = {}, {} +for via, fn, arity in plan: + mod = Path(via).stem + if arity == 0: + counts['no_params'] += 1 + continue + calls = tuples(arity) + text = 'import %s\n' % mod + ''.join( + 'try:\n %s\n print of f"R %d OK {type of r}"\ncatch e:\n print of f"R %d RAISE {e}"\n' + % (call_text(mod, fn, t), i, i) for i, t in enumerate(calls)) + res = {} + for arm in bins: + rc, out = run(arm, 'call_%s_%s' % (mod, fn), text) + got = {} + for line in out: + r = re.match(r'R (\d+) (OK|RAISE) ?(.*)$', line) + if r and int(r[1]) < len(calls) and int(r[1]) not in got: + got[int(r[1])] = (r[2], r[3]) + res[arm] = (rc, got) + counts['calls'] += len(calls) + for i, t in enumerate(calls): + a, b = res['main'][1].get(i), res['branch'][1].get(i) + if a is None or (a[0] == 'RAISE' and b is None): + counts['unexamined'] += 1 + unexamined.setdefault('%s.%s' % (mod, fn), [0, res['main'][0], res['branch'][0]])[0] += 1 + continue + counts['examined'] += 1 + if a[0] == 'OK' and (b is None or b[0] == 'RAISE'): + why = b[1] if b else 'not reached (branch rc=%d)' % res['branch'][0] + listed.setdefault('%s.%s' % (mod, fn), []).append('%s -> %s' % (call_text(mod, fn, t)[5:], why)) + elif a[0] == b[0] == 'OK': + counts['both_ok'] += 1 + elif a[0] == b[0]: + counts['both_raise'] += 1 + else: + counts['improved'] += 1 +print('phase2-lib-diff: range=[%d, %d] %s' % (RANGE[0], RANGE[-1], ' '.join('%s=%d' % kv for kv in counts.items()))) +for m in sorted(NOT_LIBRARY): + print(' NOT-LIBRARY %s: %d function(s) not called (%s)' % (m, len(skipped[m]), NOT_LIBRARY[m])) +for fn, (n, rca, rcb) in sorted(unexamined.items()): + print(' UNEXAMINED %s: %d call(s) main never completed (rc main=%d branch=%d)' % (fn, n, rca, rcb)) +bad = 0 +for fn in sorted(listed): + tag = 'INT-DOMAIN' if fn in declared else 'UNDECLARED' + bad += fn not in declared + print(' %s %s: %d call(s) raise on the branch only; first: %s%s' % ( + tag, fn, len(listed[fn]), listed[fn][0], ' (%s)' % declared[fn] if fn in declared else '')) +for fn in sorted(set(declared) - set(listed)): + bad += 1 + print(' STALE %s: declared integer-domain, but no call raises on the branch only' % fn) +if counts['examined'] == 0 or counts['examined'] + counts['unexamined'] != counts['calls']: + fail('examined=%d unexamined=%d calls=%d' % (counts['examined'], counts['unexamined'], counts['calls'])) +print('phase2-lib-diff: listed_functions=%d undeclared=%d stale=%d %s' % ( + len(listed), sum(f not in declared for f in listed), len(set(declared) - set(listed)), + 'FAIL' if bad else 'PASS')) +shutil.rmtree(work) +sys.exit(1 if bad else 0) +PY From d68c8c6501c35ae98cf06ed09e0dc6a65078cd11 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 12:26:21 -0500 Subject: [PATCH 069/188] tests: the TSan emitted-JIT fixture writes floats; its int twin is an R5 obligation (#1758 R1.3 CI) CI's tsan job failed `FAIL: tsan_spawn_emitted_jit did not compile emitted JIT code`: the fixture's `hot` multiplied int literals, and the JIT refuses int code until R5 (design section 3), so the row's emitted-code witness could no longer fire. Decided fix: every literal and argument is a float, so the fixture keeps testing what it exists for, a spawn racing EMITTED JIT code. With floats: `[jit] scanned=1 compiled=1` and `hot 80 yes 98.8% RET`; the TSan row `PASS: tsan_spawn_emitted_jit TSan-clean and exited 0` (it FAILed at 198c1919 on this box too). The design's round plan records the int twin as an R5 obligation: it returns beside the float one when the JIT compiles ints. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 14 ++++++++++++++ tests/tsan_spawn_emitted_jit.eigs | 19 +++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 650797596..9d26f8680 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2053,6 +2053,20 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: - `buf_to_pcm16le` with a NaN sample; - the `numerical_grad` waiver. +### Round 5 obligations (recorded by earlier rounds) + +Round 5 gives the JIT and the leaf evaluator their int fast paths (§4.4). +Until then a check that needs EMITTED code for an int program cannot fire, +so its fixture runs a float program instead. Each such fixture gets its int +twin back when R5 compiles ints: +- `tests/tsan_spawn_emitted_jit.eigs` (TSan shape fixture, R1.3 CI fix). + It races a spawn against emitted JIT code, and its row requires + `[jit] compiled>=1` and `hot`'s native RET after 80 warm calls. The R1.2 + version multiplied ints and stopped compiling at R1.3. It now writes float + literals and float arguments. At R5 the int version returns beside it as + its own `SHAPE_FIXTURES` row with the same witness, and `SHAPE_DECLARED` + grows by one. + ### Risks across both rounds - The AOT is a round of its own (ouroboros, pinned to the integration SHA). diff --git a/tests/tsan_spawn_emitted_jit.eigs b/tests/tsan_spawn_emitted_jit.eigs index 42ebdf2d3..d13c9b52f 100644 --- a/tests/tsan_spawn_emitted_jit.eigs +++ b/tests/tsan_spawn_emitted_jit.eigs @@ -3,16 +3,19 @@ # native RET diagnostic after 80 warm calls. Spawn occurs at module level, # followed by hot calls while MT mode is on; this does not cover spawn from # inside an active native caller. +# Every literal and argument is a FLOAT: the JIT refuses int code until R5 +# (design phase2-numbers.md section 3), and this fixture exists to race a +# spawn against EMITTED code. Its int twin returns at R5 (round plan, R5). define hot(v) as: - local doubled is v * 2 - return doubled + 1 -i is 0 -loop while i < 80: + local doubled is v * 2.0 + return doubled + 1.0 +i is 0.0 +loop while i < 80.0: hot of i - i is i + 1 + i is i + 1.0 define worker() as: - return hot of 20 + return hot of 20.0 h is spawn of worker -main_value is hot of 10 -if (thread_join of h) != 41 or main_value != 21: +main_value is hot of 10.0 +if (thread_join of h) != 41.0 or main_value != 21.0: throw of "emitted JIT call returned wrong value" From d261a795f5c7e2899a874d2b1fda4741a6f47aed Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 13:56:00 -0500 Subject: [PATCH 070/188] phase2 cost gate: STALE declarations fail; the declarations track the measurements (#1758 R1.3 CI) A declaration could stay loose after a round recovered part of its cost, and then hide a NEW regression underneath it. tools/phase2_cost.sh now fails a declared row measured more than STALE_TOLERANCE points BELOW its max (STALE), as the oracle declarations already do. The tolerance comes from measurement, not a guess: - run to run, a workload that prints elapsed time moved by up to 0.026 points (C17-cost-run-compare); - with the SAME binaries, a different workload path moved bench/alloc_heavy by 0.160 points: the heap layout moves a short string across a strlen-sse2 alignment boundary, 8 Ir on each of 1M make_str calls (callgrind: __strlen_sse2 34.0M vs 42.0M). NOISE = 0.2 points (the largest, rounded up). A declaration is ceil_0.1(measured + NOISE), and STALE_TOLERANCE = 2*NOISE + 0.1 = 0.5, so a fresh declaration fires neither way unless a re-run moves by more than NOISE. All 30 maxima are re-derived that way from the 198c1919 measurement (the same binaries: main's Ir reproduces C17's to the instruction). The R1.6 component is named in each row it affects, by measurement: the range-int control (only `range of N` yields ints, the critic's one-line patch) run through this gate against these declarations gives phase2-cost: workloads=15 rows=30 over_declared_max=15 stale_declarations=2 FAIL - scalar_loop jit/off STALE: R1.6 removes 57.8% / 66.0% of the excess; - 15 rows OVER: R1.6's int range alone raises conservative_observed_loop, conservative_unobserved_loop, dict_ops, observed_loop, string_build, unobserved_loop and bench_perf (both tiers, +13 to +44 points) and alloc_heavy jit (+0.29). That run is also the stale plant: a loose declaration fails as STALE. --declared TIER prints the validated rows of one tier for bench/check_regression.sh (the next commit), so the file has one parser. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 14 +++++++- tests/phase2/cost_expect.txt | 60 +++++++++++++++++------------------ tools/phase2_cost.sh | 47 +++++++++++++++++++++------ 3 files changed, 80 insertions(+), 41 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 9d26f8680..672fa4876 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1970,7 +1970,19 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: `max_delta_pct`, `recover_round`, `reason`); undeclared rows retain +0.3%. Declare only measured R1.3 costs with §3 as the reason and `recover_round=R5`, the JIT/leaf int fast-path round. A row above its - declared maximum fails. The observer oracle's known-wrong capability + declared maximum fails, and so does a row more than 0.5 points below it + (STALE, the R1.3 CI fix): a round that recovers cost must bring the + declaration down, or a new regression hides under it. A declaration is + the measured delta plus 0.2 points (the largest measured shift: a + different workload path moves `alloc_heavy` by 0.16 points), rounded up + to 0.1. A row whose cost another round moves names that component with + its measurement: R1.6's int `range` alone removes 58% (jit) and 66% + (off) of `scalar_loop`'s excess, and raises 14 other rows by up to 44 + points (the range-int control, measured at R1.3). + `bench/check_regression.sh --vs` (CI's bench job, the default tier) + reads the same `jit` rows through `phase2_cost.sh --declared jit`: a + declared workload is bounded by its max and prints `DECLARED` with its + round; an undeclared one keeps the 5% bound. The observer oracle's known-wrong capability verdicts are declared the same way (#1830): `tests/phase2/oracle_expect.txt` (`arm`, `row@checkpoint`, `predicate`, `recover_round`, `reason`) lists the 32 `int64_count` verdicts R1.3 first measures, `recover_round=R3`, the round diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt index 80295b539..0e3bff990 100644 --- a/tests/phase2/cost_expect.txt +++ b/tests/phase2/cost_expect.txt @@ -1,30 +1,30 @@ -bench/alloc_heavy.eigs jit 64.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/alloc_heavy.eigs off 41.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/conservative_observed_loop.eigs jit 2.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/conservative_observed_loop.eigs off 1.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/conservative_unobserved_loop.eigs jit 2.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/conservative_unobserved_loop.eigs off 1.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/dict_ops.eigs jit 0.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/dict_ops.eigs off 0.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/observed_loop.eigs jit 4.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/observed_loop.eigs off 1.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/scalar_loop.eigs jit 210.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/scalar_loop.eigs off 126.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/string_build.eigs jit 9.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/string_build.eigs off 8.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/unobserved_armed_loop.eigs jit 66.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/unobserved_armed_loop.eigs off 8.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -bench/unobserved_loop.eigs jit 4.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/unobserved_loop.eigs off 1.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_buf_mix.eigs jit 297.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_buf_mix.eigs off 91.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_buf_resample.eigs jit 191.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_buf_resample.eigs off 64.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_dmg_shape.eigs jit 173.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_dmg_shape.eigs off 49.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_idxset.eigs jit 411.6 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_idxset.eigs off 109.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_pcm_codec.eigs jit 355.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_pcm_codec.eigs off 89.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_perf.eigs jit 15.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_perf.eigs off 5.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/alloc_heavy.eigs jit 64.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +64.3% (range-int control, measured at R1.3, against +64.0%) until R5 +bench/alloc_heavy.eigs off 41.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/conservative_observed_loop.eigs jit 2.4 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5 +bench/conservative_observed_loop.eigs off 1.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.7% (range-int control, measured at R1.3, against +1.0%) until R5 +bench/conservative_unobserved_loop.eigs jit 2.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.6% (range-int control, measured at R1.3, against +2.7%) until R5 +bench/conservative_unobserved_loop.eigs off 1.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +26.1% (range-int control, measured at R1.3, against +1.1%) until R5 +bench/dict_ops.eigs jit 1.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +22.1% (range-int control, measured at R1.3, against +0.7%) until R5 +bench/dict_ops.eigs off 1.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.4% (range-int control, measured at R1.3, against +0.7%) until R5 +bench/observed_loop.eigs jit 4.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5 +bench/observed_loop.eigs off 1.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5 +bench/scalar_loop.eigs jit 210.4 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone removes 57.8% of this excess (range-int control, measured at R1.3: +88.6% against +210.1%), R5 the rest +bench/scalar_loop.eigs off 127.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone removes 66.0% of this excess (range-int control, measured at R1.3: +43.1% against +126.8%), R5 the rest +bench/string_build.eigs jit 10.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.2% (range-int control, measured at R1.3, against +9.9%) until R5 +bench/string_build.eigs off 8.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +23.5% (range-int control, measured at R1.3, against +8.5%) until R5 +bench/unobserved_armed_loop.eigs jit 66.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +bench/unobserved_armed_loop.eigs off 9.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/unobserved_loop.eigs jit 4.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5 +bench/unobserved_loop.eigs off 1.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5 +tests/bench_buf_mix.eigs jit 298.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_buf_mix.eigs off 91.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_buf_resample.eigs jit 191.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_buf_resample.eigs off 64.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_dmg_shape.eigs jit 173.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_dmg_shape.eigs off 49.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_idxset.eigs jit 411.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_idxset.eigs off 109.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_pcm_codec.eigs jit 356.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths +tests/bench_pcm_codec.eigs off 89.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +tests/bench_perf.eigs jit 15.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.4% (range-int control, measured at R1.3, against +15.7%) until R5 +tests/bench_perf.eigs off 5.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +18.7% (range-int control, measured at R1.3, against +5.4%) until R5 diff --git a/tools/phase2_cost.sh b/tools/phase2_cost.sh index 9cef6526e..01b6bfe46 100755 --- a/tools/phase2_cost.sh +++ b/tools/phase2_cost.sh @@ -3,6 +3,19 @@ # The target list has one home: codspeed.yml. Consumer targets live elsewhere. # Undeclared rows allow +0.3%; declared temporary costs are bounded per row. # TSV: workload, tier, max_delta_pct, recover_round, reason (no header). +# A declared row is bounded on BOTH sides. Above its max it fails (OVER). +# More than STALE_TOLERANCE points below its max it also fails (STALE): a +# round recovered cost and the declaration must come down, or a NEW +# regression could hide under the loose bound. A declaration is written as +# ceil to 0.1 of (measured delta + NOISE), so a fresh one fires neither way +# unless a re-run moves by more than NOISE (STALE_TOLERANCE = 2*NOISE + 0.1). +# NOISE = 0.2 points, the largest measured shift rounded up (R1.3 CI fix): +# run to run, a workload that prints elapsed time moved by 0.026 points; with +# the same binaries a different workload path moved bench/alloc_heavy by +# 0.160 points (the heap layout shifts a short string across a strlen +# alignment boundary, a million times). +# --declared TIER prints the validated rows of one tier (workload, max, +# recover_round): bench/check_regression.sh reads the declarations this way. # --final requires the declarations file to be empty before integration merges, # and the observer oracle's (tests/phase2/oracle_expect.txt, score.py --declared, # #1830) as well: #1776 merges only when neither declares anything. @@ -21,10 +34,14 @@ import sys import tempfile THRESHOLD_PCT = Decimal('0.3') +NOISE = Decimal('0.2') +STALE_TOLERANCE = 2 * NOISE + Decimal('0.1') root = Path.cwd() ap = argparse.ArgumentParser(prog='tools/phase2_cost.sh') ap.add_argument('--final', action='store_true', help='require empty cost_expect.txt and oracle_expect.txt (the pre-merge condition)') +ap.add_argument('--declared', choices=('jit', 'off'), + help='print the validated declarations of one tier (workload, max, recover_round) and exit') ap.add_argument('base', nargs='?') ap.add_argument('cand', nargs='?') args = ap.parse_args() @@ -40,9 +57,10 @@ if args.final and not oracle_path.is_file(): if args.final and oracle_path.read_text(): sys.exit('phase2-cost: FAIL: --final requires an empty tests/phase2/oracle_expect.txt' ' (%d observer-oracle declaration(s) remain)' % len(oracle_path.read_text().splitlines())) -if bool(args.base) != bool(args.cand) or (not args.base and not args.final): - ap.error('supply , or --final alone') -if not args.base: +if bool(args.base) != bool(args.cand) or (not args.base and not args.final and not args.declared) \ + or (args.declared and (args.base or args.final)): + ap.error('supply , or --final alone, or --declared TIER alone') +if not args.base and not args.declared: print('phase2-cost: final declarations=0 oracle_declarations=0 PASS') sys.exit(0) local_workload = re.compile(r'(?:bench/[^/]+|tests/bench_[^/]+)\.eigs') @@ -90,6 +108,11 @@ for n, line in enumerate(expect_text.splitlines(), 1): if not re.fullmatch(r'R[1-9][0-9]*(?:\.[1-9][0-9]*)?', recover_round) or not reason: sys.exit('phase2-cost: FAIL: cost_expect.txt:%d: recover_round and reason are required' % n) expectations[key] = (maximum, recover_round, reason) +if args.declared: + for (workload, tier), (maximum, recover_round, _) in sorted(expectations.items()): + if tier == args.declared: + print('%s\t%s\t%s' % (workload, maximum, recover_round)) + sys.exit(0) if not shutil.which('valgrind'): sys.exit('phase2-cost: FAIL: valgrind is required') bins = [str(Path(p).resolve(strict=True)) for p in (args.base, args.cand)] @@ -100,9 +123,10 @@ for binary in bins: if re.search(r'__(?:asan|ubsan)', symbols): sys.exit('phase2-cost: FAIL: sanitizer binary: ' + binary) logdir = Path(tempfile.mkdtemp(prefix='phase2-cost-')) -print('phase2-cost: source=codspeed.yml workloads=%d tiers=2 undeclared_max=+%s%% declarations=%d logs=%s' % - (len(workloads), THRESHOLD_PCT, len(expectations), logdir), flush=True) -over = 0 +print('phase2-cost: source=codspeed.yml workloads=%d tiers=2 undeclared_max=+%s%% declarations=%d ' + 'stale_below_max=%s logs=%s' % + (len(workloads), THRESHOLD_PCT, len(expectations), STALE_TOLERANCE, logdir), flush=True) +over = stale = 0 for workload in sorted(workloads): for tier in ('jit', 'off'): results = [] @@ -136,11 +160,14 @@ for workload in sorted(workloads): maximum, recover_round, reason = expectations.get((workload, tier), (THRESHOLD_PCT, None, None)) fail = Decimal((cand - base) * 100) > maximum * base + # STALE: clearly below a declared max (never for an undeclared row). + low = bool(recover_round) and Decimal((cand - base) * 100) < (maximum - STALE_TOLERANCE) * base over += fail + stale += low print('%-34s %-3s base=%12d cand=%12d delta=%+.4f%% max=+%s%% %s%s' % - (workload, tier, base, cand, delta, maximum, 'OVER' if fail else 'ok', + (workload, tier, base, cand, delta, maximum, 'OVER' if fail else 'STALE' if low else 'ok', (' recover_round=%s reason=%s' % (recover_round, reason)) if recover_round else ''), flush=True) -print('phase2-cost: workloads=%d rows=%d over_declared_max=%d %s' % - (len(workloads), len(workloads) * 2, over, 'FAIL' if over else 'PASS')) -sys.exit(bool(over)) +print('phase2-cost: workloads=%d rows=%d over_declared_max=%d stale_declarations=%d %s' % + (len(workloads), len(workloads) * 2, over, stale, 'FAIL' if over or stale else 'PASS')) +sys.exit(bool(over or stale)) PY From 8d08bef00b4f8b073ea10744c7de7946455d4bfe Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 13:56:00 -0500 Subject: [PATCH 071/188] bench: the regression gate honours the declared phase 2 costs (#1758 R1.3 CI) CI's bench job failed at its 5% bound on alloc_heavy (+63%), scalar_loop (+207%), string_build (+9%) and unobserved_armed_loop (+66%): exactly the costs R1.3 DECLARED in tests/phase2/cost_expect.txt (recover_round R5). The gate did not read the declarations, so the integration branch stayed red until R5 and a NEW regression would have been invisible in it. bench/check_regression.sh --vs now reads the declarations through their one parser (tools/phase2_cost.sh --declared jit): - a declared workload inside its max prints DECLARED with its round; - a declared workload over its max is a REGRESSION; - an undeclared workload keeps the 5% bound; - every declared bench row must be applied (applied == declared). The tier is fixed by the run line, not the caller: ir_of drops every EIGS_* variable (as phase2_cost.sh does), so EIGS_JIT_OFF is unset and the gate measures the default JIT tier; its rows are the `jit` rows. A missing instruction count is a FAIL (exit 2), never a 0. Reproduced first: the 198c1919 gate at the tip (build.sh binaries, as CI): the same four REGRESSION lines, rc=1. Plants (each through the real gate, declarations restored, sha checked): - scalar_loop jit max 150.0: REGRESSION ... > declared +150.0%, rc=1; - string_build and observed_loop jit rows removed: string_build REGRESSION (+9% > 5%), observed_loop ok, rc=1; - the file emptied (main after the --final rule): the same verdict lines as the 198c1919 gate. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- bench/check_regression.sh | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/bench/check_regression.sh b/bench/check_regression.sh index f41ab09a8..6f05f593e 100755 --- a/bench/check_regression.sh +++ b/bench/check_regression.sh @@ -14,8 +14,12 @@ EIGS="${EIGENSCRIPT:-$DIR/../src/eigenscript}" BASELINE="${BASELINE_OVERRIDE:-$DIR/baseline.txt}" THRESHOLD_PCT=5 +# The run line fixes the VM tier: every EIGS_* variable is dropped (as +# tools/phase2_cost.sh does), so EIGS_JIT_OFF is unset and every workload runs +# in the DEFAULT tier, the JIT. Its declared costs are therefore the `jit` rows. ir_of() { # ir_of -> instruction count - valgrind --tool=cachegrind --cachegrind-out-file=/dev/null "$1" "$2" 2>&1 \ + env $(compgen -e | grep '^EIGS_' | sed 's/^/-u /') \ + valgrind --tool=cachegrind --cachegrind-out-file=/dev/null "$1" "$2" 2>&1 \ | grep -oE "I *refs:[ ]*[0-9,]+" | grep -oE "[0-9,]+" | tr -d ',' } @@ -49,19 +53,40 @@ case "${1:-}" in # same workloads. Both built in the same environment => the Ir difference is # a pure code-change signal (this is what CI runs: PR binary vs origin/main # binary, so no cross-machine baseline drift). Fails on > THRESHOLD_PCT. - ref="$2"; fail=0 + # A workload with a DECLARED temporary cost (#1758: the `jit` rows of + # tests/phase2/cost_expect.txt, read through their one parser) is bounded + # by its declared max instead, and prints the round that recovers it. + ref="$2"; fail=0; used=0 + decl=$(bash "$DIR/../tools/phase2_cost.sh" --declared jit) \ + || { echo " FAIL: cannot read the declared costs (tools/phase2_cost.sh --declared jit)"; exit 2; } + ndecl=$(awk -F'\t' 'index($1, "bench/") == 1' <<< "$decl" | wc -l) + echo " tier: jit (EIGS_* unset on every run line); declared bench rows: $ndecl" for f in "$DIR"/*.eigs; do name=$(basename "$f" .eigs) a=$(ir_of "$EIGS" "$f") b=$(ir_of "$ref" "$f") + [[ "$a" =~ ^[1-9][0-9]*$ && "$b" =~ ^[1-9][0-9]*$ ]] \ + || { echo " FAIL: $name: no instruction count (cand='$a' ref='$b')"; exit 2; } inc=$(( (a - b) * 100 / b )) - if [ $(( (a - b) * 100 )) -gt $(( THRESHOLD_PCT * b )) ]; then + row=$(awk -F'\t' -v w="bench/$name.eigs" '$1 == w' <<< "$decl") + if [ -n "$row" ]; then + IFS=$'\t' read -r _ max round <<< "$row"; used=$((used + 1)) + # Exact decimal compare, the predicate tools/phase2_cost.sh uses. + if python3 -c 'import sys; from decimal import Decimal as D; a, b, m = map(D, sys.argv[1:]); sys.exit((a - b) * 100 > m * b)' "$a" "$b" "$max"; then + echo " DECLARED: $name Ir ${b} -> ${a} (+${inc}% <= declared +${max}%, recover_round=${round})" + else + echo " REGRESSION: $name Ir ${b} -> ${a} (+${inc}% > declared +${max}%, recover_round=${round})"; fail=1 + fi + elif [ $(( (a - b) * 100 )) -gt $(( THRESHOLD_PCT * b )) ]; then echo " REGRESSION: $name Ir ${b} -> ${a} (+${inc}% > ${THRESHOLD_PCT}%)"; fail=1 else echo " ok: $name Ir ${a} (${inc}% vs ref)" fi done - [ "$fail" -eq 0 ] && echo "no instruction-count regressions vs reference (threshold ${THRESHOLD_PCT}%)" + # Every declared bench row was applied (a declaration no workload used is + # a bound that guards nothing). + [ "$used" -eq "$ndecl" ] || { echo " FAIL: declared bench rows=$ndecl applied=$used"; exit 2; } + [ "$fail" -eq 0 ] && echo "no instruction-count regressions vs reference (threshold ${THRESHOLD_PCT}%; declared rows applied=$used)" exit $fail ;; esac From 30e73eed12cf4933352b69e04e7abb2bc4767398 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 15:16:46 -0500 Subject: [PATCH 072/188] jit_diff: its verdict no longer depends on the caller's display or load (#1758 R1.3 critic K03) The R1.3 critic ran `env -u XAUTHORITY DISPLAY=:99 bash tools/jit_diff.sh` and got LEDGER CHANGED with three OBS rows (invariant_noperthedron, ui_canvas_events, ui_dock); the builder's runs (SDL_AUDIODRIVER=dummy and a gfx wrapper) and CI were OK. Two causes, both the environment: 1. Window-opening examples. With a display, ui_dock and ui_canvas_events map a real window; their app loop ends on Escape. One Escape key from another client of the same display ends one arm with rc 0 while its twin runs to the 25 s timeout, and a one-sided timeout was a row with no adjudication (probe J2: rc=0 for both examples). With DISPLAY=:0 they open on the user's screen. Fix: the arms run headless whatever the caller has (DISPLAY/WAYLAND_DISPLAY/XAUTHORITY unset, SDL video and audio drivers `dummy`); a program that needs another driver names it in tests/suite_program_env.txt. Probe J5: no window on :99, rc=124 like its twin. 2. Load. noperthedron's output is random, so its OBS pair is adjudicated by tape; at R1.3 the REF record takes 23.9-25.8 s with the other core busy (main: 19.1-19.3 s) against the OBS loop's 25 s budget, and a timed-out record replayed as a divergence: a row. Fix: a one-sided timeout is re-run with 4x the budget before it counts, the tape pair gets 4x, and a tape pair that still times out stops the run as an instrument failure (never a row). At this commit, the same ledger and verdict under both environments: env A (critic's): jit_diff: OK (259 programs x {jit, osr} vs the interpreter; suite-env completed=15; OBS examined=714 denied=12; 32 arms adjudicated; 2 ledgered) env B (builder's): the same line. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tools/jit_diff.sh | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/tools/jit_diff.sh b/tools/jit_diff.sh index 3fc065cb7..e3e878606 100755 --- a/tools/jit_diff.sh +++ b/tools/jit_diff.sh @@ -17,6 +17,13 @@ # bash tools/jit_diff.sh # compare against the ledger # bash tools/jit_diff.sh --record # rewrite data rows; keep '#' lines set -u +# The arms run headless whatever the caller's display (#1758 R1.3 CI fix). With +# a display a window-opening example (examples/ui_dock.eigs) maps a real window, +# and one Escape key from any other client of that display ends one arm with +# rc 0 while its twin runs to the timeout: a row. CI has no display. A program +# that needs another driver names it in tests/suite_program_env.txt. +unset DISPLAY WAYLAND_DISPLAY XAUTHORITY +export SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT/src" export EIGS_TEST_DIR="$ROOT/tests" . "$ROOT/tests/suite_program_env.sh" || exit 1 @@ -66,12 +73,21 @@ gobs=$(env "${OBS[@]}" EIGS_OBS_GATE_STATS=1 timeout 30 "$EIG" "$T/elide.eigs" 2 [ "$gref" = "obs-gate: unobserved" ] && [ "$gobs" = "obs-gate: observed" ] || { echo "jit_diff: FAIL: OBS and REF do not differ in gate state ($gref vs $gobs)"; exit 1; } # $1 arm, $2 timeout. $T/ref and $T/arm are already filled. $row is the ledger name. +# A run near its budget times out on a loaded machine and not on an idle one, +# so a timeout is re-run with 4x the budget before it counts (#1758 R1.3: the +# tape record of examples/invariant_noperthedron.eigs takes 24-26 s against the +# OBS loop's 25 s). A timeout that survives the long budget in the tape pair is +# the instrument failing, and stops the run; it is never a row. +timed_out() { [ "$(tail -n 1 "$1")" = "rc=124" ]; } consider() { - local arm="$1" sec="$2" tag rr ar + local arm="$1" sec="$2" tag long=$(( $2 * 4 )) tag=$(printf '%s' "$arm" | tr a-z A-Z) - rr=$(tail -n 1 "$T/ref"); ar=$(tail -n 1 "$T/arm") - if { [ "$rr" = "rc=124" ] && [ "$ar" != "rc=124" ]; } || { [ "$ar" = "rc=124" ] && [ "$rr" != "rc=124" ]; }; then - echo "$row $tag" >> "$got"; return + if { timed_out "$T/ref" && ! timed_out "$T/arm"; } || { timed_out "$T/arm" && ! timed_out "$T/ref"; }; then + run "$T/ref" "$long" "${REF[@]}" + run "$T/arm" "$long" "${AE[@]}" + if { timed_out "$T/ref" && ! timed_out "$T/arm"; } || { timed_out "$T/arm" && ! timed_out "$T/ref"; }; then + echo "$row $tag" >> "$got"; return + fi fi diff -q <(norm "$T/ref") <(norm "$T/arm") >/dev/null && return adjudicated=$((adjudicated + 1)) @@ -81,8 +97,11 @@ consider() { echo "$row $tag" >> "$got"; return fi rm -f "$T/tape" - run "$T/rref" "$sec" "${REF[@]}" EIGS_TRACE="$T/tape" - run "$T/rarm" "$sec" "${AE[@]}" EIGS_REPLAY="$T/tape" + run "$T/rref" "$long" "${REF[@]}" EIGS_TRACE="$T/tape" + run "$T/rarm" "$long" "${AE[@]}" EIGS_REPLAY="$T/tape" + if timed_out "$T/rref" || timed_out "$T/rarm"; then + echo "jit_diff: FAIL: $row $tag: the tape adjudication timed out after ${long}s (an instrument failure, not a row)"; exit 1 + fi diff -q <(norm "$T/rref") <(norm "$T/rarm") >/dev/null && return echo "$row $tag" >> "$got" } From 2a20ace9d81e87ad5bd45e3030b22b3c08f3a903 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 19 Oct 2026 15:55:06 -0500 Subject: [PATCH 073/188] phase2 inventory: regenerated for embed_smoke.c's moved lines (#1804, #1758 R1.3 CI) The phase gate's inventory gate (#1804: the committed docs/design/phase2-inventory.txt must equal the generated one) failed at 30e73eed: `docs/design/phase2-inventory.txt is stale: 88 line(s) differ`. All 88 lines are src/embed_smoke.c numeric sites whose line numbers moved by 13 when 55920beb added the whole-line tape helper; no site was added, removed or reclassified (examined=2037 classified=2037 unclassified=0). Regenerated with tools/phase2_inventory.py; --check: phase2-inventory: PASS. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 88 ++++++++++++++++---------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 2e4d9b9aa..9c61c388f 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1577,52 +1577,52 @@ embed_smoke.c:190 test_worker_exit_lifecycle eigs_value_as_num READ j embed_smoke.c:198 test_worker_exit_lifecycle eigs_slot_num READ j embed_smoke.c:199 test_worker_exit_lifecycle eigs_slot_num READ j embed_smoke.c:214 test_worker_exit_lifecycle eigs_value_as_num READ j -embed_smoke.c:288 host_add eigs_value_as_num READ j -embed_smoke.c:288 host_add eigs_value_as_num READ j -embed_smoke.c:334 main SLOT_F64_RAW WRITE j -embed_smoke.c:336 main SLOT_F64_RAW WRITE j -embed_smoke.c:338 main SLOT_F64_RAW RAW j -embed_smoke.c:341 main SLOT_F64_RAW RAW j -embed_smoke.c:343 main SLOT_F64_RAW RAW j -embed_smoke.c:345 main SLOT_F64_RAW RAW j -embed_smoke.c:373 main eigs_value_as_num READ j -embed_smoke.c:381 main eigs_value_as_num READ j -embed_smoke.c:391 main eigs_value_as_num READ j -embed_smoke.c:416 main eigs_value_as_num READ j -embed_smoke.c:424 main eigs_value_as_num READ j -embed_smoke.c:449 main eigs_value_as_num READ j -embed_smoke.c:475 main eigs_value_as_num READ j -embed_smoke.c:486 main eigs_value_as_num READ j -embed_smoke.c:491 main eigs_value_as_num READ j -embed_smoke.c:496 main eigs_value_as_num READ j -embed_smoke.c:562 main eigs_value_as_num READ j -embed_smoke.c:580 main eigs_value_as_num READ j -embed_smoke.c:589 main eigs_value_as_num READ j -embed_smoke.c:608 main EIGS_NUM_MAX GUARD j -embed_smoke.c:616 main eigs_value_as_num READ j -embed_smoke.c:845 main eigs_value_as_num READ j -embed_smoke.c:898 main eigs_value_as_num READ j -embed_smoke.c:908 main eigs_value_as_num READ j -embed_smoke.c:918 main SLOT_F64_RAW WRITE j -embed_smoke.c:934 main eigs_value_as_num READ j -embed_smoke.c:944 main eigs_value_as_num READ j -embed_smoke.c:953 main eigs_value_as_num READ j -embed_smoke.c:962 main eigs_value_as_num READ j -embed_smoke.c:980 main eigs_value_as_num READ j -embed_smoke.c:988 main eigs_value_as_num READ j -embed_smoke.c:992 main eigs_value_as_num READ j -embed_smoke.c:997 main eigs_value_as_num READ j -embed_smoke.c:1008 main eigs_value_as_num READ j -embed_smoke.c:1013 main eigs_value_as_num READ j -embed_smoke.c:1022 main eigs_value_as_num READ j -embed_smoke.c:1041 main eigs_value_as_num READ j -embed_smoke.c:1045 main eigs_value_as_num READ j +embed_smoke.c:300 host_add eigs_value_as_num READ j +embed_smoke.c:300 host_add eigs_value_as_num READ j +embed_smoke.c:346 main SLOT_F64_RAW WRITE j +embed_smoke.c:348 main SLOT_F64_RAW WRITE j +embed_smoke.c:350 main SLOT_F64_RAW RAW j +embed_smoke.c:353 main SLOT_F64_RAW RAW j +embed_smoke.c:355 main SLOT_F64_RAW RAW j +embed_smoke.c:357 main SLOT_F64_RAW RAW j +embed_smoke.c:385 main eigs_value_as_num READ j +embed_smoke.c:393 main eigs_value_as_num READ j +embed_smoke.c:403 main eigs_value_as_num READ j +embed_smoke.c:428 main eigs_value_as_num READ j +embed_smoke.c:436 main eigs_value_as_num READ j +embed_smoke.c:461 main eigs_value_as_num READ j +embed_smoke.c:487 main eigs_value_as_num READ j +embed_smoke.c:498 main eigs_value_as_num READ j +embed_smoke.c:503 main eigs_value_as_num READ j +embed_smoke.c:508 main eigs_value_as_num READ j +embed_smoke.c:574 main eigs_value_as_num READ j +embed_smoke.c:592 main eigs_value_as_num READ j +embed_smoke.c:601 main eigs_value_as_num READ j +embed_smoke.c:620 main EIGS_NUM_MAX GUARD j +embed_smoke.c:628 main eigs_value_as_num READ j +embed_smoke.c:857 main eigs_value_as_num READ j +embed_smoke.c:910 main eigs_value_as_num READ j +embed_smoke.c:920 main eigs_value_as_num READ j +embed_smoke.c:930 main SLOT_F64_RAW WRITE j +embed_smoke.c:947 main eigs_value_as_num READ j +embed_smoke.c:957 main eigs_value_as_num READ j +embed_smoke.c:966 main eigs_value_as_num READ j +embed_smoke.c:975 main eigs_value_as_num READ j +embed_smoke.c:993 main eigs_value_as_num READ j +embed_smoke.c:1001 main eigs_value_as_num READ j +embed_smoke.c:1005 main eigs_value_as_num READ j +embed_smoke.c:1010 main eigs_value_as_num READ j +embed_smoke.c:1021 main eigs_value_as_num READ j +embed_smoke.c:1026 main eigs_value_as_num READ j +embed_smoke.c:1035 main eigs_value_as_num READ j embed_smoke.c:1054 main eigs_value_as_num READ j embed_smoke.c:1058 main eigs_value_as_num READ j -embed_smoke.c:1065 main eigs_value_as_num READ j -embed_smoke.c:1121 main eigs_value_as_num READ j -embed_smoke.c:1145 main eigs_value_as_num READ j -embed_smoke.c:1172 main eigs_value_as_num READ j +embed_smoke.c:1067 main eigs_value_as_num READ j +embed_smoke.c:1071 main eigs_value_as_num READ j +embed_smoke.c:1078 main eigs_value_as_num READ j +embed_smoke.c:1134 main eigs_value_as_num READ j +embed_smoke.c:1158 main eigs_value_as_num READ j +embed_smoke.c:1185 main eigs_value_as_num READ j ext_db.c:57 db_build_query VAL_INT TEST h ext_db.c:58 db_build_query VAL_I64_RAW RAW h ext_db.c:60 db_build_query VAL_FLOAT TEST h From 2ca17a280ef3e98ccf3a19464d2c7265c94c1910 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 08:26:15 -0500 Subject: [PATCH 074/188] tests: five JIT-purposed fixtures compile again; their int twins are R5 obligations (#1858) R1.3 made the JIT refuse int code until R5 (design section 3), so five fixtures that exist to exercise JIT code compiled less or nothing: `EIGS_JIT_STATS` compiled counts (summed over threads) on main 94657581 were 1, 1, 1, 4 and 1; at 6ea31175 they were 0, 0, 0, 2 and 1. Decided fix (as tsan_spawn_emitted_jit got in the R1.3 CI fix): the code each fixture's JIT purpose needs writes float literals. - test_spawn_jit.eigs ([100], TSan slice): `check`, `helper`, `worker`. - test_underarity_1661_repro/_trycatch.eigs ([0fd]): `g`. - tsan_mt_clear_respawn.eigs (TSan slice): `hot` and the module's two loops (their OSR compiles after each join). - test_spawn_jit_warm.eigs ([129], TSan slice): `helper`, `warm`, `worker`, `gmul`; helper's thunk runs to RET again (it stopped at INT_ONE after 11 of 16 bytes). After: 1, 1, 1, 4 and 1, each with the same native chunks as main (the hot tables match chunk for chunk; tsan_mt_clear_respawn's native bytes are equal, 1396062 / 8678310). [0fd]'s forced-JIT tier compiles g on both. Sections 100 129 0fd alone: release 20/20, ASan (detect_leaks=1) 20/20; each file alone on release and ASan rc 0 with its marker; the three TSan slice rows race-free on the TSan build. The design's Round 5 obligations list records each int twin. #1858's second Done-when (a JIT witness inside each row) is not part of this change. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 20 ++++++++++++++++++ tests/test_spawn_jit.eigs | 26 +++++++++++++++--------- tests/test_spawn_jit_warm.eigs | 23 ++++++++++++--------- tests/test_underarity_1661_repro.eigs | 17 +++++++++------- tests/test_underarity_1661_trycatch.eigs | 15 ++++++++------ tests/tsan_mt_clear_respawn.eigs | 23 ++++++++++++--------- 6 files changed, 81 insertions(+), 43 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 672fa4876..e2cb8592c 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2078,6 +2078,26 @@ twin back when R5 compiles ints: literals and float arguments. At R5 the int version returns beside it as its own `SHAPE_FIXTURES` row with the same witness, and `SHAPE_DECLARED` grows by one. +- Five more JIT-purposed fixtures (#1858, the R1.3 hardening round). Each + compiled less, or nothing, once int literals were refused. Each now writes + floats in the code its JIT purpose needs. Each int twin returns at R5 beside + its float version, run by the same row: + - `tests/test_spawn_jit.eigs` (suite [100] and the TSan slice). The + main-thread `check`, the shared `helper` and `worker` count in floats. + - `tests/test_underarity_1661_repro.eigs` and + `tests/test_underarity_1661_trycatch.eigs` (suite [0fd], in all three tiers, + the forced-JIT tier included). `g` compares, counts and returns floats. + - `tests/tsan_mt_clear_respawn.eigs` (the TSan slice). `hot`, its argument, + and the module's two loops (OSR after each join) count in floats. + - `tests/test_spawn_jit_warm.eigs` (suite [129] and the TSan slice). `helper`, + `warm`, `worker` and `gmul` are floats, so `helper`'s thunk runs to its + return again. + + The compile counts (`EIGS_JIT_STATS`, summed over threads) were 1, 1, 1, 4 + and 1 on main 94657581. The tip before the change compiled 0, 0, 0, 2 and 1; + after it, 1, 1, 1, 4 and 1. These rows assert no JIT witness of their own + (#1858's second Done-when), so another refusal would again pass them + silently. ### Risks across both rounds diff --git a/tests/test_spawn_jit.eigs b/tests/test_spawn_jit.eigs index d9adf2c2c..25d820194 100644 --- a/tests/test_spawn_jit.eigs +++ b/tests/test_spawn_jit.eigs @@ -9,27 +9,33 @@ # Each worker calls the shared `helper` enough times to cross the JIT threshold; # many workers run sequentially so compilation lands on a worker. No closure # cycle, so this is leak-clean (distinct from the still-open MT cycle-GC gap). +# +# The JIT-purposed code (helper, worker and the main-thread `check`, which is +# the chunk that compiles here) writes FLOAT literals: the JIT refuses int code +# until R5 (docs/design/phase2-numbers.md section 3), and with ints nothing in +# this file compiled. Its int twin returns at R5 (round plan, Round 5 +# obligations). define helper(x) as: - return (x * 3) + 1 + return (x * 3.0) + 1.0 define worker(k) as: - local s is 0 - local i is 0 - loop while i < 40: + local s is 0.0 + local i is 0.0 + loop while i < 40.0: s is s + (helper of i) - i is i + 1 + i is i + 1.0 return s + k # helper of i for i in 0..39: sum (3i+1) = 3*(0+..+39) + 40 = 3*780 + 40 = 2380 -expected_base is 2380 +expected_base is 2380.0 -checks is 0 -passed is 0 +checks is 0.0 +passed is 0.0 define check(label, got, want) as: - checks is checks + 1 + checks is checks + 1.0 if got == want: - passed is passed + 1 + passed is passed + 1.0 else: print of ("MISMATCH " + label + ": got=" + str of got + " want=" + str of want) diff --git a/tests/test_spawn_jit_warm.eigs b/tests/test_spawn_jit_warm.eigs index 91d0be5df..7da657998 100644 --- a/tests/test_spawn_jit_warm.eigs +++ b/tests/test_spawn_jit_warm.eigs @@ -14,26 +14,29 @@ # GET_NAME of `gmul` is what makes the race TSan-visible: emitted code is # uninstrumented, but the IC fill in jit_helper_get_name is C. Values are # pinned here; race-freedom is gated by tests/test_tsan.sh. +# helper, warm and worker compute in FLOATS so helper's thunk runs natively to +# its return: the JIT refuses int code until R5 (docs/design/phase2-numbers.md +# section 3). Its int twin returns at R5 (round plan, Round 5 obligations). -gmul is 3 +gmul is 3.0 define helper(x) as: - return (x * gmul) + 1 + return (x * gmul) + 1.0 define warm() as: - local s is 0 - local i is 0 - loop while i < 80: + local s is 0.0 + local i is 0.0 + loop while i < 80.0: s is s + (helper of i) - i is i + 1 + i is i + 1.0 return s # sum over i in 0..79 of (3i+1) = 3*3160 + 80 = 9560 define worker(k) as: - local s is 0 - local i is 0 - loop while i < 400: + local s is 0.0 + local i is 0.0 + loop while i < 400.0: s is s + (helper of i) - i is i + 1 + i is i + 1.0 return s + k # sum over i in 0..399 of (3i+1) = 3*79800 + 400 = 239800 checks is 0 diff --git a/tests/test_underarity_1661_repro.eigs b/tests/test_underarity_1661_repro.eigs index a411c4c7c..8b8c5294a 100644 --- a/tests/test_underarity_1661_repro.eigs +++ b/tests/test_underarity_1661_repro.eigs @@ -1,17 +1,20 @@ # #1661: the issue's reproducer, verbatim. A 2-param callee called # under-arity reads its unsent param at recursion depth 3000; the JIT read a # stale freelist slot (heap-use-after-free; release aborted in malloc). -n is {"d": 0} +# g writes FLOAT literals so the JIT compiles it: the JIT refuses int code +# until R5 (docs/design/phase2-numbers.md section 3). Its int twin returns +# at R5 (round plan, Round 5 obligations). +n is {"d": 0.0} define g(A, Q) as: - if Q == 1: - return 0 - n.d is n.d + 1 - if n.d > 3000: - return 0 + if Q == 1.0: + return 0.0 + n.d is n.d + 1.0 + if n.d > 3000.0: + return 0.0 local args is [A] return g of (args) g of ([1]) -n.d is 0 +n.d is 0.0 g of ([1]) print of "ok" diff --git a/tests/test_underarity_1661_trycatch.eigs b/tests/test_underarity_1661_trycatch.eigs index 5e005b9d3..f5ee94521 100644 --- a/tests/test_underarity_1661_trycatch.eigs +++ b/tests/test_underarity_1661_trycatch.eigs @@ -1,19 +1,22 @@ # #1661: the try/catch variant — the same under-arity recursion inside a # try, then a raise and catch. The stale slot read was freed again on the # way out (release: "free(): double free detected in tcache 2"). -n is {"d": 0} +# g writes FLOAT literals so the JIT compiles it: the JIT refuses int code +# until R5 (docs/design/phase2-numbers.md section 3). Its int twin returns +# at R5 (round plan, Round 5 obligations). +n is {"d": 0.0} define g(A, Q) as: - if Q == 1: - return 0 - n.d is n.d + 1 - if n.d > 3000: + if Q == 1.0: + return 0.0 + n.d is n.d + 1.0 + if n.d > 3000.0: throw of "deep" local args is [A] return g of (args) caught is 0 for round in [1, 2, 3]: - n.d is 0 + n.d is 0.0 try: g of ([1]) catch err: diff --git a/tests/tsan_mt_clear_respawn.eigs b/tests/tsan_mt_clear_respawn.eigs index c4d17e7dd..cfe1940f3 100644 --- a/tests/tsan_mt_clear_respawn.eigs +++ b/tests/tsan_mt_clear_respawn.eigs @@ -2,6 +2,9 @@ # (collector, JIT and plain refcounts back on), then re-enters it on the next # spawn. TSan must see no race across either transition, including a worker # that spawns and joins its own worker. +# `hot` and the module loops (OSR, after each join) count in FLOATS so they +# compile: the JIT refuses int code until R5 (docs/design/phase2-numbers.md +# section 3). Its int twin returns at R5 (round plan, Round 5 obligations). define sq(n) as: return n * n define spawner(n) as: @@ -13,27 +16,27 @@ define make_counter(start) as: return count return value define hot(n) as: - acc is 0 - k is 0 + acc is 0.0 + k is 0.0 loop while k < n: acc is acc + k - k is k + 1 + k is k + 1.0 return acc total is 0 -round is 0 -loop while round < 3: +round is 0.0 +loop while round < 3.0: hs is [] for k in range of 4: append of [hs, spawn of [sq, k + round]] append of [hs, spawn of [spawner, round]] for h in hs: total is total + (thread_join of h) - j is 0 - loop while j < 5000: + j is 0.0 + loop while j < 5000.0: local c is make_counter of j - j is j + 1 - total is total + (hot of 2000) - (hot of 2000) - round is round + 1 + j is j + 1.0 + total is total + (hot of 2000.0) - (hot of 2000.0) + round is round + 1.0 if total == 103: print of "All tests passed" else: From 7f070c6b9096cd87b8295e88f913b3f6aa932c53 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 08:31:08 -0500 Subject: [PATCH 075/188] tests: section [0fp] gates boxed-int ownership strictly leak-clean (#1758 R1.3) The R1.3 memory review compiled two boxed-int ownership faults into the ASan suite's binary (P1: INT_ARITH's '+' overflow-raise path skips a decref; P2: builtin_append stores a boxed int without an incref), and the full suite stayed 4282/4282: no suite program carried a boxed int through those paths. Section [0fp] runs the review's probes p01_arith and p02_containers, trimmed: no float twins (they were the review's attribution controls) and fewer iterations (200 and 100 instead of 12000 and 4000; LeakSanitizer and ASan need one occurrence). Each check is rc 0, `lsan_classify == none` (no leak tolerance, as [87] and [0fn]) and its exact PASS line with its check count: `boxed int arith: PASS checks=41`, `boxed int containers: PASS checks=10`. At this commit, alone: release `RESULTS: 2/2 passed`, ASan with detect_leaks=1 `RESULTS: 2/2 passed` (0.22 s and 0.26 s per program). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/sections/0fp-boxed-int-ownership.sh | 31 +++ tests/test_boxed_int_arith.eigs | 247 ++++++++++++++++++++++ tests/test_boxed_int_containers.eigs | 150 +++++++++++++ 3 files changed, 428 insertions(+) create mode 100644 tests/sections/0fp-boxed-int-ownership.sh create mode 100644 tests/test_boxed_int_arith.eigs create mode 100644 tests/test_boxed_int_containers.eigs diff --git a/tests/sections/0fp-boxed-int-ownership.sh b/tests/sections/0fp-boxed-int-ownership.sh new file mode 100644 index 000000000..4ae26672d --- /dev/null +++ b/tests/sections/0fp-boxed-int-ownership.sh @@ -0,0 +1,31 @@ +# #1758 R1.3: an int outside the SMI range is a BOXED heap value with a +# refcount, so every path that used to carry only immediate numbers can now +# leak or over-release one. The R1.3 memory review planted two such faults +# (an overflow raise that skips a decref; an append that stores without an +# incref) and the whole ASan suite stayed green. Each program here pushes boxed +# ints through one family of those paths, and each check is rc 0, strictly +# leak-clean (no rc_ok tolerance, like [87] and [0fn]) and its exact PASS line +# with its check count. +# test_boxed_int_arith.eigs VM arithmetic and its raise paths +# test_boxed_int_containers.eigs container stores, copies, json, sort +echo "[0fp] Boxed-int ownership (#1758 R1.3)" +check_binary_fingerprint +for __bio in "test_boxed_int_arith.eigs:boxed int arith: PASS checks=41" \ + "test_boxed_int_containers.eigs:boxed int containers: PASS checks=10"; do + __bio_f=${__bio%%:*} + __bio_m=${__bio#*:} + TOTAL=$((TOTAL + 1)) + BIO_OUTPUT=$(suite_program_run "$__bio_f" $EIGS_TMO ./eigenscript "$TESTS_DIR/$__bio_f" &1); BIO_RC=$? + if [ "$BIO_RC" -eq 0 ] && + [ "$(lsan_classify_name "$BIO_OUTPUT")" = none ] && + grep -Fxq "$__bio_m" <<< "$BIO_OUTPUT"; then + PASS=$((PASS + 1)) + echo " PASS: $__bio_f: boxed ints keep exact reference counts (leak-clean)" + else + FAIL=$((FAIL + 1)) + echo " FAIL: $__bio_f (rc=$BIO_RC, sanitizer=$(lsan_classify_name "$BIO_OUTPUT") — must exit 0, leak-clean, with '$__bio_m')" + printf '%s\n' "$BIO_OUTPUT" | eigs_failure_output + fi +done +unset __bio __bio_f __bio_m +echo "" diff --git a/tests/test_boxed_int_arith.eigs b/tests/test_boxed_int_arith.eigs new file mode 100644 index 000000000..dbf4e5fdb --- /dev/null +++ b/tests/test_boxed_int_arith.eigs @@ -0,0 +1,247 @@ +# Boxed ints (|i| >= 2^47, heap values with a refcount since R1.3) through VM +# arithmetic: the SMI boundary, the raise paths (overflow, division by zero, +# type errors) inside try/catch, mixed int/float operands, bitwise operators +# and comparisons. Trimmed from the R1.3 memory review's probe p01_arith.eigs +# (#1758). Section [0fp] runs it strictly leak-clean under ASan, so a raise path +# that forgets to release a boxed operand leaks and fails the suite. Every +# check asserts (a failed one exits nonzero); the last line pins the count. +CK is 0 +define ck(cond, msg) as: + assert of [cond, msg] + CK is CK + 1 + +P47 is 140737488355328 +SMAX is 140737488355327 +IMAX is 9223372036854775807 +IMIN is -9223372036854775807 - 1 +F47 is 140737488355328.0 +N is 200 + +ck of [(num_type of P47) == "int", "P47 int"] +ck of [(num_type of IMIN) == "int", "IMIN int"] +ck of [(num_type of F47) == "float", "F47 float"] + +# the SMI/boxed boundary, both directions +a1 is SMAX + 1 +ck of [a1 == P47, "smi+1 boxes"] +a2 is P47 - 1 +ck of [a2 == SMAX, "boxed-1 unboxes"] +a3 is P47 * 2 +ck of [a3 == 281474976710656, "boxed*2"] +a4 is 0 - P47 +ck of [a4 == -140737488355328, "0-P47 is SMI min"] +a5 is a4 - 1 +ck of [a5 == -140737488355329, "below SMI min boxes"] +a6 is IMAX - IMAX +ck of [a6 == 0, "boxed-boxed to 0"] +ck of [(IMIN + IMAX) == -1, "IMIN+IMAX"] +ck of [(str of IMIN) == "-9223372036854775808", "IMIN text"] +ck of [(str of IMAX) == "9223372036854775807", "IMAX text"] + +# overflow raises with boxed operands, N times per shape +define ov_plain(n) as: + local caught is 0 + local k is 0 + loop while k < n: + try: + local t is (IMAX - k) + (P47 + k) + print of "NOT REACHED plain" + catch err: + if err.kind == "value": + caught is caught + 1 + k is k + 1 + return caught + +define ov_listlit(n) as: + local caught is 0 + local k is 0 + loop while k < n: + try: + local xs is [P47 + k, IMAX - k, "s", IMAX + k + 1] + print of "NOT REACHED listlit" + catch err: + caught is caught + 1 + k is k + 1 + return caught + +define id3(a, b, c) as: + return [a, b, c] + +define ov_callarg(n) as: + local caught is 0 + local k is 0 + loop while k < n: + try: + local r is id3 of [P47 + k, (IMAX - k) * 2, k] + print of "NOT REACHED callarg" + catch err: + caught is caught + 1 + k is k + 1 + return caught + +define inner_ov(x) as: + local y is x + P47 + local z is [y, x, y] + local w is {"y": y, "x": x} + return y * IMAX + +define mid_ov(x) as: + local m is x - 1 + return inner_ov of (m + IMAX - P47 - P47) + +define ov_frames(n) as: + local caught is 0 + local k is 0 + loop while k < n: + try: + local r is mid_ov of (P47 + k) + print of "NOT REACHED frames" + catch err: + caught is caught + 1 + k is k + 1 + return caught + +define ov_sub_mul(n) as: + local caught is 0 + local k is 0 + loop while k < n: + try: + local t is (IMIN + k) - (P47 + 1) + catch err: + caught is caught + 1 + try: + local u is (P47 + k) * (P47 - k) + catch err: + caught is caught + 1 + try: + local v is SMAX * SMAX + catch err: + caught is caught + 1 + k is k + 1 + return caught + +define ov_compound(n) as: + local caught is 0 + local k is 0 + local acc is P47 + loop while k < n: + try: + acc += IMAX + catch err: + caught is caught + 1 + acc is P47 + k + k is k + 1 + return caught + +define ov_neg_abs(n) as: + local caught is 0 + local k is 0 + local mn is IMIN + loop while k < n: + try: + local q is -mn + catch err: + caught is caught + 1 + try: + local q2 is abs of mn + catch err: + caught is caught + 1 + local ok1 is -(P47 + k) + local ok2 is abs of (0 - P47 - k) + if ok1 != 0 - P47 - k: + print of "BAD neg" + if ok2 != P47 + k: + print of "BAD abs" + k is k + 1 + return caught + +define ov_divmod(n) as: + local caught is 0 + local k is 0 + loop while k < n: + try: + local q is (P47 + k) / 0 + catch err: + caught is caught + 1 + try: + local q2 is (IMAX - k) % 0 + catch err: + caught is caught + 1 + try: + local q3 is 1.5 | (P47 + k) + catch err: + caught is caught + 1 + try: + local q4 is (P47 + k) + "s" + catch err: + caught is caught + 1 + try: + local q5 is (P47 + k) < "s" + catch err: + caught is caught + 1 + k is k + 1 + return caught + +c1 is ov_plain of N +ck of [c1 == N, f"ov_plain caught {c1}"] +c2 is ov_listlit of N +ck of [c2 == N, f"ov_listlit caught {c2}"] +c3 is ov_callarg of N +ck of [c3 == N, f"ov_callarg caught {c3}"] +c4 is ov_frames of N +ck of [c4 == N, f"ov_frames caught {c4}"] +c5 is ov_sub_mul of N +ck of [c5 == 3 * N, f"ov_sub_mul caught {c5}"] +c6 is ov_compound of N +ck of [c6 == N, f"ov_compound caught {c6}"] +c7 is ov_neg_abs of N +ck of [c7 == 2 * N, f"ov_neg_abs caught {c7}"] +c8 is ov_divmod of N +ck of [c8 == 5 * N, f"ov_divmod caught {c8}"] + +# module scope (the global env, not a frame) +mk is 0 +mcaught is 0 +loop while mk < N: + try: + mt is (P47 + mk) * IMAX + catch err: + mcaught is mcaught + 1 + mk is mk + 1 +ck of [mcaught == N, "module-scope overflow caught"] + +# mixed int/float, the transitional / and %, bitwise operators, comparisons +ck of [(IMAX + 0.5) > 9.2e18, "IMAX+0.5 float"] +ck of [(num_type of (P47 + 0.5)) == "float", "mixed is float"] +ck of [(P47 * 1.5) == 211106232532992.0, "P47*1.5"] +ck of [(F47 + P47) == 281474976710656.0, "F47+P47"] +ck of [(num_type of (IMAX / 2)) == "float", "div float"] +ck of [((P47 + 7) % 10) == 5, "mod"] +ck of [(P47 & 0xFF) == 0, "band"] +ck of [(IMAX & 1) == 1, "band IMAX"] +ck of [((P47 + 3) | 0) == 140737488355331, "bor"] +ck of [(P47 << 1) == 281474976710656, "shl"] +ck of [(P47 >> 47) == 1, "shr"] +ck of [(~P47) == -140737488355329, "bnot"] +ck of [P47 < IMAX, "lt"] +ck of [IMIN < SMAX, "lt2"] +ck of [P47 == F47, "eq cross kind"] +ck of [(P47 + 1) > F47, "gt cross kind"] +ck of [9007199254740993 > 9007199254740992.0, "exact N2 past 2^53"] +ck of [9007199254740993 != 9007199254740992.0, "exact ne past 2^53"] +ck of [not (IMAX == 9223372036854775808), "IMAX vs 2^63 float"] + +define cmp_churn(n) as: + local k is 0 + local hits is 0 + loop while k < n: + local x is P47 + k + local y is IMAX - k + local f is F47 + k + if x < y and x >= f and x <= f and y > x and x == f and not (x != f): + hits is hits + 1 + k is k + 1 + return hits +ck of [(cmp_churn of N) == N, "cmp churn"] + +print of f"boxed int arith: PASS checks={CK}" diff --git a/tests/test_boxed_int_containers.eigs b/tests/test_boxed_int_containers.eigs new file mode 100644 index 000000000..eeb533721 --- /dev/null +++ b/tests/test_boxed_int_containers.eigs @@ -0,0 +1,150 @@ +# Boxed ints (|i| >= 2^47, heap values with a refcount since R1.3) through +# containers: list literals, append, index and slot stores, slices, copies, +# destructuring, nested lists and dicts, dict stores and removal, membership, +# reductions, sort and sort_by (exact order), json build/encode/decode/path, +# string formatting, and the error paths (int dict keys, out-of-range index +# and slice) looped under try/catch. Trimmed from the R1.3 memory review's +# probe p02_containers.eigs (#1758). Section [0fp] runs it strictly leak-clean +# under ASan, so a store that forgets to take a boxed int's reference (or one +# that takes it twice) fails the suite. Every check asserts (a failed one +# exits nonzero); the last line pins the count. +CK is 0 +define ck(cond, msg) as: + assert of [cond, msg] + CK is CK + 1 + +P47 is 140737488355328 +SMAX is 140737488355327 +IMAX is 9223372036854775807 +IMIN is -9223372036854775807 - 1 +B53 is 9007199254740993 +F47 is 140737488355328.0 +N is 100 + +define work(base, n) as: + local k is 0 + local total is 0 + loop while k < n: + local b is base + k + # list build (literal) with boxed, SMI, float, string + local xs is [b, SMAX, IMAX, IMIN, 1, 2.5, "s"] + # append boxed and SMI + append of [xs, b + 1] + append of [xs, k] + # set: overwrite boxed with boxed, with SMI, with float, with string, and back + xs[0] is b + 2 + xs[0] is 7 + xs[0] is 7.5 + xs[0] is "str" + xs[0] is b + 3 + set_at of [xs, 1, b] + set_at of [xs, 1, IMIN] + xs[2] += 1 - 1 + xs[5] is b + # index read + local r0 is xs[0] + local r1 is xs[-2] + local r2 is get_at of [xs, 3] + # slice and copies + local sl is xs[0:4] + local sl2 is xs[2:] + local cp is concat of [xs, [b]] + local cmp2 is [v for v in xs if v != "s"] + local dst is [0, 0, 0] + copy_into of [dst, 0, [b, IMAX, IMIN]] + local nc is num_copy of b + # destructure + [da, db] is [b, IMAX] + # nested containers + local nest is [[b, [IMAX, b]], {"k": [IMIN, {"z": b}]}] + nest[0][1][0] is b + 5 + nest[1]["k"][1]["z"] is IMIN + # dict values + local d is {"a": b, "b": SMAX} + d.c is IMAX + d["e"] is IMIN + dict_set of [d, "f", b] + d.a is 3 + d.a is b + 9 + dict_remove of [d, "b"] + local ks is keys of d + local vs is values of d + # membership and reductions + local has is list_contains of [xs, IMAX] + local at is list_index_of of [xs, IMIN] + local mx is max of [b, IMAX - 1] + local sm is sum of [b, b] + # json + local js is json_encode of [nest, d, xs] + local back is json_decode of js + local jb is json_build of ["a", b, "b", IMIN] + local jp is json_path of [js, "0"] + # formatting + local s1 is f"{b}|{IMIN}|{IMAX}|{nest}" + local s2 is str of xs + total is total + len of s1 + len of s2 - len of s1 - len of s2 + if not (has and at == 1 and r2 == IMIN and nc == b and da == b and len of cp == 10): + print of ["BAD", has, at, r2, nc, da, len of cp] + assert of [false, "work invariant"] + k is k + 1 + return total + +ck of [(work of [P47, N]) == 0, "work"] + +# exact checks once +xs is [P47, SMAX, IMAX, IMIN, 1] +append of [xs, P47 + 1] +ck of [xs[5] == 140737488355329, "append boxed"] +xs[1] is IMIN +ck of [xs[1] == IMIN, "set boxed over smi"] +ck of [(str of xs[0:3]) == "[140737488355328, -9223372036854775808, 9223372036854775807]", "slice text"] +srt is sort of [B53, 9007199254740992.0, 9007199254740992, IMAX, IMIN, F47, P47, -1] +ck of [(str of srt) == "[-9223372036854775808, -1, 140737488355328, 140737488355328, 9007199254740992, 9007199254740992, 9007199254740993, 9223372036854775807]", "sort exact order"] +ck of [(num_type of srt[2]) != (num_type of srt[3]), "sort keeps both kinds at the tie"] +sb is sort_by of [[P47, 3, IMIN, IMAX], (v) => 0.0 - v] +ck of [sb[0] == IMAX and sb[3] == IMIN, "sort_by order"] +ck of [(json_encode of [3, IMAX, {"min": IMIN}]) == "[3,9223372036854775807,{\"min\":-9223372036854775808}]", "json exact"] +ck of [(f"{P47}") == "140737488355328", "fstring digits"] + +# error paths, looped: int dict keys (refused), boxed index, boxed slice +# bounds, a raise inside a sort_by key +define errs(n) as: + local caught is 0 + local k is 0 + local ys is [P47, IMAX, IMIN, "s"] + local dd is {"a": P47} + loop while k < n: + try: + dd[P47 + k] is IMAX + catch e: + caught is caught + 1 + try: + local q is {P47: IMIN} + catch e: + caught is caught + 1 + try: + local q is dd[IMAX - k] + catch e: + caught is caught + 1 + try: + local q is ys[P47 + k] + catch e: + caught is caught + 1 + try: + ys[IMIN + k] is P47 + catch e: + caught is caught + 1 + try: + local q is ys[1:IMAX - k] + catch e: + caught is caught + 1 + try: + local q is sort_by of [[P47, IMIN, k], (v) => 0 - v] + catch e: + caught is caught + 1 + k is k + 1 + return caught +ec is errs of N +ck of [ec == 7 * N, f"errs caught {ec}"] + +print of f"boxed int containers: PASS checks={CK}" From b85a07ec1508603174a786621734c21b1c45d2b5 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 08:44:43 -0500 Subject: [PATCH 076/188] docs: list_get_ref / dict_value_get_ref and the channel copy say what R1.3's code does (#1863) Four statements predated R1.3's boxed ints: - src/container.h (the getter comment, and the slot invariant at the top): "NULL when the element is numeric (#1758: an int included)" and "a TAG_HEAP pointer ... to a Value whose type is none of NUM / NULL / BOOL". The getters return NULL only for `slot_is_f64(s) || slot_is_smi(s)` (container.h:133, :137); a boxed int (|i| >= 2^47) is a heap slot that eigs_container_slot keeps, so it comes back as its non-NULL VAL_INT Value. - docs/design/phase2-numbers.md's slot table rows for the two getters said the same; they now cite those lines. - .claude/rules/c-runtime-memory.md said "NULL for a number by contract" and named VAL_NUM (renamed in R1.2). It now says double or SMI, and that `get_ref(...)->type == VAL_INT` is true for a boxed int only. - docs/CONCURRENCY.md said VAL_INT "has an explicit refusal until R1.3"; chan_clone_rec copies it (`case VAL_INT: return make_int(...)`, src/eigenscript.c:2682) and copies it at any depth (:2678). Probed: [2^47+1, {"k": 2^47+1}] through a channel arrives equal, kind "int". The comment lines move container.h's rows, so docs/design/ phase2-inventory.txt is regenerated: 98 rows moved, all container.h, the same row text at a new line (MOVED only), and phase2-inventory: PASS. The strict shape contract stays SHAPE_CONTRACT errors=0. No code changes; the fragment is internal. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- .claude/rules/c-runtime-memory.md | 14 +- .../1863-container-get-ref-comments.md | 1 + docs/CONCURRENCY.md | 7 +- docs/design/phase2-inventory.txt | 196 +++++++++--------- docs/design/phase2-numbers.md | 4 +- src/container.h | 13 +- 6 files changed, 122 insertions(+), 113 deletions(-) create mode 100644 changes/internal/1863-container-get-ref-comments.md diff --git a/.claude/rules/c-runtime-memory.md b/.claude/rules/c-runtime-memory.md index 2d88b80cf..51f27824d 100644 --- a/.claude/rules/c-runtime-memory.md +++ b/.claude/rules/c-runtime-memory.md @@ -146,11 +146,15 @@ iteration, or a collector that quietly stops working). - **Container elements are `EigsSlot` storage (#1665 arm D); read them only through `src/container.h`, and know which getter owns what.** Every rule below was bought by a real bug during the migration: - - `list_get_ref` / `dict_value_get_ref` return **NULL for a number** by - contract. Test `list_elem_type` / `slot_type` before dereferencing, and - never write `get_ref(...)->type == VAL_NUM` (always false). Ragged tensor - rows crashed `relu`/`gather` this way (B5), and the DMG in-place - register-write fast path silently never fired (B2, +38% Ir). + - `list_get_ref` / `dict_value_get_ref` return **NULL for an immediate + number**, a double or an SMI (`src/container.h`:133 and :137). A boxed + int (|i| >= 2^47, since #1758 R1.3) is a heap slot, so it comes back as a + non-NULL `VAL_INT` Value. Test `list_elem_type` / `slot_type` before + dereferencing. Never write `get_ref(...)->type == VAL_FLOAT` (always + false), and never read `get_ref(...)->type == VAL_INT` as "an int" (it is + true for a boxed int only, never for an SMI). Ragged tensor rows crashed + `relu`/`gather` this way (B5), and the DMG in-place register-write fast + path silently never fired (B2, +38% Ir). - A view (`list_get_view`, `slot_view`, `EIGS_VIEW`, `BUILTIN_*_VIEW`) is **stack storage**: never return it, store it, or incref-and-keep it, and a `BUILTIN_*_VIEW` compound literal dies at its enclosing block. A view in diff --git a/changes/internal/1863-container-get-ref-comments.md b/changes/internal/1863-container-get-ref-comments.md new file mode 100644 index 000000000..909f18dbf --- /dev/null +++ b/changes/internal/1863-container-get-ref-comments.md @@ -0,0 +1 @@ +- Comments only: `src/container.h` states that `list_get_ref` and `dict_value_get_ref` return NULL for a double or an SMI, and a boxed int's `VAL_INT` Value otherwise, and that container storage holds boxed ints outside the SMI range (#1863). No behaviour changes. diff --git a/docs/CONCURRENCY.md b/docs/CONCURRENCY.md index f30447dfb..8e3060f8f 100644 --- a/docs/CONCURRENCY.md +++ b/docs/CONCURRENCY.md @@ -167,11 +167,12 @@ depth-64 tail SHARES **The rows the table cannot construct in three lines, and why they behave the way they do.** `chan_clone_rec` (src/eigenscript.c) switches on `ValType` with no `default:`, so `-Werror=switch` forces every new type to choose a side; the -switch handles each type explicitly: `VAL_FLOAT`, `VAL_NULL`, `VAL_STR`, +switch handles each type explicitly: `VAL_FLOAT`, `VAL_INT`, `VAL_NULL`, `VAL_STR`, `VAL_LIST`, `VAL_DICT`, `VAL_BUFFER`, `VAL_BOOL`, and `VAL_TEXT_BUILDER` are rebuilt (copy), while `VAL_FN` and `VAL_BUILTIN` take a refcount -(share). `VAL_INT` has an explicit refusal until R1.3 supplies `make_int` -for a fresh exact copy; R1.2 has no program-visible int producer. +(share). An int is a fresh exact copy, `make_int` of the same value +(src/eigenscript.c:2682), and like the other scalars it is copied at any depth +(src/eigenscript.c:2678). A new `ValType` must choose a side in the switch for the compiler to accept it. The copy is recursive but not an identity-preserving graph copy: two references to one list or dict become two independent copies. At recursion depth 65 diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index a9507e0d1..1045c0101 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1292,104 +1292,104 @@ compiler.c:2962 compile_node_inner AST_NUM TEST a compiler.c:3017 compile_node_inner AST_NUM TEST a compiler.c:3061 compile_node_inner AST_NUM TEST a compiler.c:3874 obs_ast_scan_d AST_NUM CASE i -container.h:26 eigs_container_slot VAL_F64_RAW RAW b -container.h:26 eigs_container_slot VAL_FLOAT TEST a -container.h:26 eigs_container_slot num_guard GUARD c -container.h:26 eigs_container_slot slot_from_f64 PRODUCE c -container.h:29 eigs_container_slot VAL_INT TEST a -container.h:30 eigs_container_slot VAL_I64_RAW RAW b -container.h:31 eigs_container_slot slot_from_int PRODUCE c -container.h:49 eigs_slot_store_owned SLOT_F64_RAW RAW b -container.h:49 eigs_slot_store_owned num_guard GUARD c -container.h:49 eigs_slot_store_owned slot_from_f64 PRODUCE c -container.h:49 eigs_slot_store_owned slot_is_f64 TEST a -container.h:52 eigs_slot_store_owned VAL_FLOAT TEST a -container.h:52 eigs_slot_store_owned VAL_INT TEST a -container.h:58 eigs_slot_store_borrow SLOT_F64_RAW RAW b -container.h:58 eigs_slot_store_borrow num_guard GUARD c -container.h:58 eigs_slot_store_borrow slot_from_f64 PRODUCE c -container.h:58 eigs_slot_store_borrow slot_is_f64 TEST a -container.h:85 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c -container.h:87 dict_value_rewrite_num slot_from_f64 PRODUCE c -container.h:91 list_rewrite_num list_rewrite_num PRODUCE c -container.h:93 list_rewrite_num slot_from_f64 PRODUCE c -container.h:102 slot_type VAL_FLOAT YIELD a -container.h:102 slot_type slot_is_f64 TEST a -container.h:106 slot_type VAL_INT YIELD a -container.h:106 slot_type slot_is_smi TEST a -container.h:130 list_get_ref slot_is_f64 TEST a -container.h:130 list_get_ref slot_is_smi TEST a -container.h:134 dict_value_get_ref slot_is_f64 TEST a -container.h:134 dict_value_get_ref slot_is_smi TEST a -container.h:144 eigs_slot_num eigs_slot_num READ b -container.h:145 eigs_slot_num SLOT_F64_RAW RAW b -container.h:145 eigs_slot_num slot_is_f64 TEST a -container.h:146 eigs_slot_num slot_is_smi TEST a -container.h:146 eigs_slot_num slot_smi_val RAW b -container.h:147 eigs_slot_num val_is_number TEST a -container.h:148 eigs_slot_num eigs_num_arg READ b -container.h:149 eigs_slot_num eigs_num_arg_slow READ b -container.h:151 eigs_slot_elem_num eigs_slot_elem_num READ b -container.h:152 eigs_slot_elem_num SLOT_F64_RAW RAW b -container.h:152 eigs_slot_elem_num slot_is_f64 TEST a -container.h:153 eigs_slot_elem_num slot_is_smi TEST a -container.h:153 eigs_slot_elem_num slot_smi_val RAW b -container.h:155 eigs_slot_elem_num eigs_num_arg READ b -container.h:155 eigs_slot_elem_num val_is_number TEST a -container.h:156 eigs_slot_elem_num eigs_num_arg_slow READ b -container.h:159 eigs_slot_opt_num eigs_slot_opt_num READ b -container.h:161 eigs_slot_opt_num SLOT_F64_RAW RAW b -container.h:161 eigs_slot_opt_num slot_is_f64 TEST a -container.h:162 eigs_slot_opt_num slot_is_smi TEST a -container.h:162 eigs_slot_opt_num slot_smi_val RAW b -container.h:163 eigs_slot_opt_num val_is_number TEST a -container.h:164 eigs_slot_opt_num eigs_num_arg READ b -container.h:166 eigs_slot_opt_num eigs_num_arg_slow READ b -container.h:176 slot_view slot_is_f64 TEST a -container.h:177 slot_view slot_is_smi TEST a -container.h:178 slot_view VAL_INT TAGSET c -container.h:179 slot_view VAL_I64_RAW WRITE c -container.h:179 slot_view slot_smi_val RAW b -container.h:184 slot_view VAL_FLOAT TEST a -container.h:186 slot_view VAL_FLOAT TAGSET c -container.h:187 slot_view SLOT_F64_RAW RAW b -container.h:187 slot_view VAL_F64_RAW WRITE c -container.h:187 slot_view slot_is_f64 TEST a -container.h:188 slot_view eigs_num_arg READ b -container.h:201 eigs_view_check VAL_FLOAT TEST a -container.h:201 eigs_view_check VAL_INT TEST a -container.h:227 list_get_return slot_is_smi TEST a -container.h:228 list_get_return SLOT_F64_RAW RAW b -container.h:228 list_get_return make_num PRODUCE c -container.h:228 list_get_return slot_is_f64 TEST a -container.h:235 dict_value_get_return slot_is_smi TEST a -container.h:236 dict_value_get_return SLOT_F64_RAW RAW b -container.h:236 dict_value_get_return make_num PRODUCE c -container.h:236 dict_value_get_return slot_is_f64 TEST a -container.h:266 eigs_slot_box SLOT_F64_RAW RAW b -container.h:266 eigs_slot_box make_num PRODUCE c -container.h:266 eigs_slot_box num_guard GUARD c -container.h:266 eigs_slot_box slot_is_f64 TEST a -container.h:267 eigs_slot_box slot_is_smi TEST a -container.h:289 list_set_num list_set_num PRODUCE c -container.h:290 list_set_num list_rewrite_num PRODUCE c -container.h:290 list_set_num num_guard GUARD c -container.h:292 list_append_num list_append_num PRODUCE c -container.h:293 list_append_num num_guard GUARD c -container.h:295 list_append_num slot_from_f64 PRODUCE c -container.h:297 dict_value_set_num dict_value_set_num PRODUCE c -container.h:298 dict_value_set_num dict_value_rewrite_num PRODUCE c -container.h:298 dict_value_set_num num_guard GUARD c -container.h:327 list_get_num list_get_num READ b -container.h:329 list_get_num slot_is_smi TEST a -container.h:329 list_get_num slot_smi_val RAW b -container.h:330 list_get_num slot_is_f64 TEST a -container.h:331 list_get_num SLOT_F64_RAW RAW b -container.h:334 dict_value_get_num dict_value_get_num READ b -container.h:336 dict_value_get_num slot_is_smi TEST a -container.h:336 dict_value_get_num slot_smi_val RAW b -container.h:337 dict_value_get_num slot_is_f64 TEST a -container.h:338 dict_value_get_num SLOT_F64_RAW RAW b +container.h:27 eigs_container_slot VAL_F64_RAW RAW b +container.h:27 eigs_container_slot VAL_FLOAT TEST a +container.h:27 eigs_container_slot num_guard GUARD c +container.h:27 eigs_container_slot slot_from_f64 PRODUCE c +container.h:30 eigs_container_slot VAL_INT TEST a +container.h:31 eigs_container_slot VAL_I64_RAW RAW b +container.h:32 eigs_container_slot slot_from_int PRODUCE c +container.h:50 eigs_slot_store_owned SLOT_F64_RAW RAW b +container.h:50 eigs_slot_store_owned num_guard GUARD c +container.h:50 eigs_slot_store_owned slot_from_f64 PRODUCE c +container.h:50 eigs_slot_store_owned slot_is_f64 TEST a +container.h:53 eigs_slot_store_owned VAL_FLOAT TEST a +container.h:53 eigs_slot_store_owned VAL_INT TEST a +container.h:59 eigs_slot_store_borrow SLOT_F64_RAW RAW b +container.h:59 eigs_slot_store_borrow num_guard GUARD c +container.h:59 eigs_slot_store_borrow slot_from_f64 PRODUCE c +container.h:59 eigs_slot_store_borrow slot_is_f64 TEST a +container.h:86 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c +container.h:88 dict_value_rewrite_num slot_from_f64 PRODUCE c +container.h:92 list_rewrite_num list_rewrite_num PRODUCE c +container.h:94 list_rewrite_num slot_from_f64 PRODUCE c +container.h:103 slot_type VAL_FLOAT YIELD a +container.h:103 slot_type slot_is_f64 TEST a +container.h:107 slot_type VAL_INT YIELD a +container.h:107 slot_type slot_is_smi TEST a +container.h:133 list_get_ref slot_is_f64 TEST a +container.h:133 list_get_ref slot_is_smi TEST a +container.h:137 dict_value_get_ref slot_is_f64 TEST a +container.h:137 dict_value_get_ref slot_is_smi TEST a +container.h:147 eigs_slot_num eigs_slot_num READ b +container.h:148 eigs_slot_num SLOT_F64_RAW RAW b +container.h:148 eigs_slot_num slot_is_f64 TEST a +container.h:149 eigs_slot_num slot_is_smi TEST a +container.h:149 eigs_slot_num slot_smi_val RAW b +container.h:150 eigs_slot_num val_is_number TEST a +container.h:151 eigs_slot_num eigs_num_arg READ b +container.h:152 eigs_slot_num eigs_num_arg_slow READ b +container.h:154 eigs_slot_elem_num eigs_slot_elem_num READ b +container.h:155 eigs_slot_elem_num SLOT_F64_RAW RAW b +container.h:155 eigs_slot_elem_num slot_is_f64 TEST a +container.h:156 eigs_slot_elem_num slot_is_smi TEST a +container.h:156 eigs_slot_elem_num slot_smi_val RAW b +container.h:158 eigs_slot_elem_num eigs_num_arg READ b +container.h:158 eigs_slot_elem_num val_is_number TEST a +container.h:159 eigs_slot_elem_num eigs_num_arg_slow READ b +container.h:162 eigs_slot_opt_num eigs_slot_opt_num READ b +container.h:164 eigs_slot_opt_num SLOT_F64_RAW RAW b +container.h:164 eigs_slot_opt_num slot_is_f64 TEST a +container.h:165 eigs_slot_opt_num slot_is_smi TEST a +container.h:165 eigs_slot_opt_num slot_smi_val RAW b +container.h:166 eigs_slot_opt_num val_is_number TEST a +container.h:167 eigs_slot_opt_num eigs_num_arg READ b +container.h:169 eigs_slot_opt_num eigs_num_arg_slow READ b +container.h:179 slot_view slot_is_f64 TEST a +container.h:180 slot_view slot_is_smi TEST a +container.h:181 slot_view VAL_INT TAGSET c +container.h:182 slot_view VAL_I64_RAW WRITE c +container.h:182 slot_view slot_smi_val RAW b +container.h:187 slot_view VAL_FLOAT TEST a +container.h:189 slot_view VAL_FLOAT TAGSET c +container.h:190 slot_view SLOT_F64_RAW RAW b +container.h:190 slot_view VAL_F64_RAW WRITE c +container.h:190 slot_view slot_is_f64 TEST a +container.h:191 slot_view eigs_num_arg READ b +container.h:204 eigs_view_check VAL_FLOAT TEST a +container.h:204 eigs_view_check VAL_INT TEST a +container.h:230 list_get_return slot_is_smi TEST a +container.h:231 list_get_return SLOT_F64_RAW RAW b +container.h:231 list_get_return make_num PRODUCE c +container.h:231 list_get_return slot_is_f64 TEST a +container.h:238 dict_value_get_return slot_is_smi TEST a +container.h:239 dict_value_get_return SLOT_F64_RAW RAW b +container.h:239 dict_value_get_return make_num PRODUCE c +container.h:239 dict_value_get_return slot_is_f64 TEST a +container.h:269 eigs_slot_box SLOT_F64_RAW RAW b +container.h:269 eigs_slot_box make_num PRODUCE c +container.h:269 eigs_slot_box num_guard GUARD c +container.h:269 eigs_slot_box slot_is_f64 TEST a +container.h:270 eigs_slot_box slot_is_smi TEST a +container.h:292 list_set_num list_set_num PRODUCE c +container.h:293 list_set_num list_rewrite_num PRODUCE c +container.h:293 list_set_num num_guard GUARD c +container.h:295 list_append_num list_append_num PRODUCE c +container.h:296 list_append_num num_guard GUARD c +container.h:298 list_append_num slot_from_f64 PRODUCE c +container.h:300 dict_value_set_num dict_value_set_num PRODUCE c +container.h:301 dict_value_set_num dict_value_rewrite_num PRODUCE c +container.h:301 dict_value_set_num num_guard GUARD c +container.h:330 list_get_num list_get_num READ b +container.h:332 list_get_num slot_is_smi TEST a +container.h:332 list_get_num slot_smi_val RAW b +container.h:333 list_get_num slot_is_f64 TEST a +container.h:334 list_get_num SLOT_F64_RAW RAW b +container.h:337 dict_value_get_num dict_value_get_num READ b +container.h:339 dict_value_get_num slot_is_smi TEST a +container.h:339 dict_value_get_num slot_smi_val RAW b +container.h:340 dict_value_get_num slot_is_f64 TEST a +container.h:341 dict_value_get_num SLOT_F64_RAW RAW b eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a eigenscript.c:309 val_type_name VAL_FLOAT CASE a diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index e2cb8592c..71e28e073 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -678,7 +678,7 @@ result).** | `builtins.c:sort_cmp_str` | guarded | reached only after `builtin_sort` proved every element a string (its homogeneity test names `VAL_NUM`, compile-forced) (D2) | | `builtins_host.c:ls_entry_cmp` | guarded | sorts the string entries `ls` built itself (D2) | | `container.h:dict_value_get_num` | smi-arm | bridge reader (2.7): an int element converts to its double, exactly (|SMI| < 2^47), until R1.6 deletes the bridge (D1) | -| `container.h:dict_value_get_ref` | smi-arm | NULL for a number by contract, an int included; the caller then types the element (D1) | +| `container.h:dict_value_get_ref` | smi-arm | NULL for an SMI or a double (container.h:137); since R1.3 a boxed int (\|i\| >= 2^47) is a heap slot and comes back as its non-NULL `VAL_INT` Value, so the caller types the element before reading it (D1) | | `container.h:dict_value_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value`, the one SMI boxer (unwired until R1.3) (D1) | | `container.h:eigs_container_slot` | not-a-classifier | the canonicalizing Value-to-slot writer (R1.2): it reads a Value, not a slot, and writes the bits; a `VAL_INT` box becomes an SMI inside [-2^47, 2^47) and stays a heap slot outside it (2.1) (D3) | | `container.h:eigs_slot_adopt` | guarded | decides ownership from what `eigs_container_slot` returned (compile-forced); a small int comes back as an SMI and its box is released (D3) | @@ -690,7 +690,7 @@ result).** | `container.h:eigs_slot_store_borrow` | guarded | an SMI is canonical storage and comes back as it is, with no reference to take (D1) | | `container.h:eigs_slot_store_owned` | guarded | an SMI is canonical storage and comes back as it is, with no reference to release (D1) | | `container.h:list_get_num` | smi-arm | bridge reader: an int element converts to its double (D1) | -| `container.h:list_get_ref` | smi-arm | NULL for a number by contract, an int included (D1) | +| `container.h:list_get_ref` | smi-arm | NULL for an SMI or a double (container.h:133); since R1.3 a boxed int (\|i\| >= 2^47) is a heap slot and comes back as its non-NULL `VAL_INT` Value (D1) | | `container.h:list_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value` (unwired until R1.3) (D1) | | `container.h:slot_type` | smi-arm | an SMI's type is `VAL_INT` (R1.2); any other unknown tag refuses instead of being read as a pointer (D1) | | `container.h:slot_view` | smi-arm | an SMI's facade is an exact `VAL_INT` view (R1.2) (D1) | diff --git a/src/container.h b/src/container.h index 9880553a6..c9c8fa9ba 100644 --- a/src/container.h +++ b/src/container.h @@ -3,13 +3,14 @@ /* Container slot boundary (#1665 arm D). List items and dict values are * EigsSlot storage (B10, the flip). Every stored slot is one of: - * - an immediate number, always num_guard'ed (the default x86 NaN - * 0xFFF8... is SLOT_NULL_BITS, so an unguarded double could read back - * as null); + * - an immediate number: a double, always num_guard'ed (the default x86 + * NaN 0xFFF8... is SLOT_NULL_BITS, so an unguarded double could read + * back as null), or an SMI, an int in [-2^47, 2^47) (#1758 design 2.1); * - SLOT_NULL_BITS or a bool encoding (the immortal singletons are never * stored as heap pointers); * - a TAG_HEAP pointer owning one counted reference to a Value whose type - * is none of NUM / NULL / BOOL. + * is none of FLOAT / NULL / BOOL. A VAL_INT there is an int outside the + * SMI range, a box (eigs_container_slot below keeps it, since R1.3). * All-zero bits are the number 0.0, not a vacancy: calloc'd storage reads as * zeros, so only slots below `count` are meaningful. Nothing outside this * header touches the storage arrays except the bulk alloc/grow/free code that @@ -124,7 +125,9 @@ static inline ValType dict_value_type(const Value *dict, int i) { } /* Return the real heap pointer (including the immortal null/bool singleton), - * or NULL when the element is numeric (#1758: an int included). */ + * or NULL when the element is an immediate number: a double or an SMI. A + * boxed int (|i| >= 2^47, #1758 R1.3) is a heap slot, so it comes back as its + * non-NULL VAL_INT Value; type the element (list_elem_type) before reading. */ static inline Value *list_get_ref(const Value *list, int i) { EigsSlot s = list_slot(list, i); return (slot_is_f64(s) || slot_is_smi(s)) ? NULL : eigs_slot_ref(s); From 432872d11d39a7250e134bc26e1fa673677517dd Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 08:44:43 -0500 Subject: [PATCH 077/188] tests: poisson_pmf pins its float Stirling branch at an int k (k = 1490, 3000) With an int k past 170, poisson_pmf takes Stirling's series. Main's int literals there (`k2 is k * k`, `12 * k`, ..., `1260 * k * k2 * k2`) leave int64 from k = 1490 and raise; the merge kept float factors. Nothing in the repo pinned it: phase2_lib_diff's range is [-3, 110] by design, and the merge round's boundary table was evidence only. Four rows: poisson_pmf of [1490, 1000.0] and of [3000, 3000.0] are floats and equal main 94657581's values at the same arguments within 1e-12 relative (main prints 5.902674575941492e-48 and 0.007283453882998077; this build gives the same bits on this box), the tolerance of the other log-domain rows. Proved once in a git-archive scratch copy: with the int-literal plant in lib/probability.eigs the file dies (`Error line 105: integer overflow in '*'`, rc 1, no "All tests passed."); the same plant against the file without these rows passes 42/42. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/test_probability.eigs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_probability.eigs b/tests/test_probability.eigs index 2a862905f..dd017b98a 100644 --- a/tests/test_probability.eigs +++ b/tests/test_probability.eigs @@ -63,6 +63,13 @@ assert_near of [probability.poisson_cdf of [200, 190.0], 0.7784236536636114, 7.7 # A large lambda underflows e^-lambda to 0 even when the probability is a # normal double, so the direct formula would return exactly 0. assert_near of [probability.poisson_pmf of [100, 800.0], 8.005888215986707e-216, 8.005888215986707e-228, "poisson_pmf(100, 800) e^-lambda underflow"] +# An INT k past 170 takes Stirling's series, whose products must be floats: +# with int literals, 1260 * k * k2 * k2 leaves int64 from k = 1490 and raises +# (#1758). The expected values are main 94657581's at the same arguments. +assert_eq of [num_type of (probability.poisson_pmf of [1490, 1000.0]), "float", "poisson_pmf(int 1490, 1000) is a float"] +assert_near of [probability.poisson_pmf of [1490, 1000.0], 5.902674575941492e-48, 5.902674575941492e-60, "poisson_pmf(int 1490, 1000) Stirling"] +assert_eq of [num_type of (probability.poisson_pmf of [3000, 3000.0]), "float", "poisson_pmf(int 3000, 3000) is a float"] +assert_near of [probability.poisson_pmf of [3000, 3000.0], 0.007283453882998077, 7.283453882998077e-15, "poisson_pmf(int 3000, 3000) Stirling"] # ---- Normal Distribution ---- print of "--- Normal ---" From d48ad181d5b4d6ff4ed67e5d9fa073e36effebd0 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 09:01:12 -0500 Subject: [PATCH 078/188] ci: a phase2 workflow runs the MAP rows and the lib differential on phase2-numbers (#1758 R1.3) No workflow called tools/phase2_check.sh or tools/phase2_lib_diff.sh, so Phase 2's behavioural contract (the MAP rows) and the stdlib int differential had only ever run on a builder's or a critic's machine (mechanical-gates section 151). .github/workflows/phase2.yml runs on every push to phase2-numbers and on workflow_dispatch. Its one step builds the v0.46.0 anchor (make observer-anchor, the observer oracle's recipe, in a scratch cache), origin/main (a git archive, plain make) and this commit (make build under the compiler guard), then runs tools/phase2_ci.sh on the three binaries. tools/phase2_ci.sh derives --through: a round has landed when every one of its MAP rows has its file in tests/phase2/rows (read with phase2_check.py's own MAP parser), and --through is the last round, in plan order, before the first round with rows that has not. A file alone is not a landing: the R1.6 row N14.json-path-int-exact has had its file since R1.3 and fails on this branch (it prints 9.223372036854776e+18). "The latest round with a row file" would select R1.6; measured, `--through R1.6` at this commit fails with 29 rows without files (6 R1.4, 7 R1.5, 16 R1.6) and that row's BRANCH-FAIL in every tier. The partly landed round is printed. Each tool must exit 0 and print its own PASS line, whole. The --smi-trap binary is not built: phase2_check.py reads --smi-trap and --baseline only for a mechanical --through (R1.1, R1.2, R2.1), which this derivation never selects (those rounds have no rows). Local run of the workflow's own run block (extracted with PyYAML, GitHub's bash -eo pipefail, RUNNER_TEMP scratch): `phase2-ci: PASS (through=R1.3)`, `phase2-check: PASS`, `phase2-lib-diff: listed_functions=1 undeclared=0 stale=0 PASS`, cc-guard examined=29, 9 minutes. GitHub dispatches a workflow only when it is on the default branch or has run once; this file reaches its first run by a push to phase2-numbers. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- .github/workflows/phase2.yml | 53 ++++++++++++++++++++++++++ docs/CI.md | 1 + tools/phase2_ci.sh | 73 ++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 .github/workflows/phase2.yml create mode 100755 tools/phase2_ci.sh diff --git a/.github/workflows/phase2.yml b/.github/workflows/phase2.yml new file mode 100644 index 000000000..a112753a0 --- /dev/null +++ b/.github/workflows/phase2.yml @@ -0,0 +1,53 @@ +name: phase2 + +# #1758 Phase 2's own gates on its integration branch: the MAP rows that have +# landed, on the v0.46.0 anchor and this commit (tools/phase2_check.sh, design +# 9.2), and the stdlib's int differential against origin/main +# (tools/phase2_lib_diff.sh, design 9.5). Before this lane both had only run on +# a builder's or a critic's machine (mechanical-gates section 151). +# tools/phase2_ci.sh derives the round to check from the MAP and the row files. +# +# `gh workflow run phase2.yml --ref ` dispatches it. GitHub accepts a +# dispatch only for a workflow on the default branch, or one that has run at +# least once; this file lives on phase2-numbers, so its first run is a push +# there. + +on: + push: + branches: [phase2-numbers] + workflow_dispatch: + +permissions: + contents: read + +jobs: + phase2: + name: phase2 (MAP rows + lib differential) + runs-on: ubuntu-latest + # Measured locally (4 GB dev box): about 12 minutes, most of it the three + # builds; this bounds a hang. + timeout-minutes: 45 + steps: + # fetch-depth 0 brings every branch and tag: origin/main and v0.46.0. + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + - name: Build the v0.46.0 anchor, origin/main and this commit; run tools/phase2_ci.sh + run: | + set -euo pipefail + # The anchor: the observer oracle's recipe (make observer-anchor, a + # git archive of the tag built under env -i) in a scratch cache. + export XDG_CACHE_HOME="$RUNNER_TEMP/cache" + make --no-print-directory observer-anchor + anchor="$XDG_CACHE_HOME/eigs-oracle-anchor/$(sha256sum tools/observer_oracle/build_anchor.sh | cut -d' ' -f1)/src/eigenscript" + # The baseline: origin/main's own tree, plain make. + mkdir -p "$RUNNER_TEMP/main" + git archive origin/main | tar -x -C "$RUNNER_TEMP/main" + make -C "$RUNNER_TEMP/main" > "$RUNNER_TEMP/main-build.log" 2>&1 \ + || { tail -n 50 "$RUNNER_TEMP/main-build.log"; echo "::error::the origin/main build failed"; exit 1; } + # This commit, under the compiler guard (docs/CI.md, [99i]). + export CC_GUARD_LOG="$RUNNER_TEMP/cc-guard.log" + : > "$CC_GUARD_LOG" + PATH="$PWD/tools/cc-guard-bin:$PATH" make build + bash tools/cc_guard.sh --report + bash tools/phase2_ci.sh "$anchor" "$RUNNER_TEMP/main/src/eigenscript" src/eigenscript diff --git a/docs/CI.md b/docs/CI.md index 397e59fec..2802c2817 100644 --- a/docs/CI.md +++ b/docs/CI.md @@ -723,6 +723,7 @@ file: | `Scorecard analysis` (`scorecard.yml`) | advisory | runs on push, schedule and `branch_protection_rule`, never on a PR; a posture score | | `Analyze (python)`, `Analyze (javascript-typescript)` | advisory | CodeQL *default setup* (a GitHub app, not a workflow file) over the repo's non-C code; the C analysis that blocks is `Analyze C` | | `issue-triage / …` (`issue-triage.yml`), `release.yml` jobs | advisory | not triggered by PRs or pushes to `main` | +| `phase2 (MAP rows + lib differential)` (`phase2.yml`) | advisory | #1758's integration branch only: a push to `phase2-numbers` or `workflow_dispatch`, never a PR or the queue; `tools/phase2_ci.sh` checks the MAP rows of every landed round and the stdlib int differential | ## Coverage on pull requests diff --git a/tools/phase2_ci.sh b/tools/phase2_ci.sh new file mode 100755 index 000000000..66b84bfb5 --- /dev/null +++ b/tools/phase2_ci.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# tools/phase2_ci.sh +# #1758 Phase 2's CI lane (.github/workflows/phase2.yml): the MAP rows that have +# landed (tools/phase2_check.sh, design 9.2) and the stdlib int differential +# (tools/phase2_lib_diff.sh, design 9.5). The workflow builds the three +# binaries: the v0.46.0 anchor (make observer-anchor), origin/main and this +# commit. +# +# --through is DERIVED, so no round constant needs bumping. A round has landed +# when every one of its MAP rows has its file in tests/phase2/rows (read with +# phase2_check.py's own MAP parser), and --through is the last round, in plan +# order, before the first round with rows that has not. A file may land ahead +# of its round (a target row: N14.json-path-int-exact's R1.6 file came with +# R1.3), so a file alone is not a landing; a partly landed round is printed +# and checked once it is complete. A round with no rows of its own (R1.8, +# R2.1) never selects itself: its gates are its own builder's to run. +# +# Each tool must exit 0 AND print its own PASS line, whole: a tool that died +# after its last successful command never prints it. +set -u +[ $# -eq 3 ] || { echo "usage: tools/phase2_ci.sh "; exit 2; } +bins=() +for b in "$@"; do case "$b" in /*) bins+=("$b") ;; *) bins+=("$PWD/$b") ;; esac; done +cd "$(dirname "$0")/.." || exit 2 +tmp=$(mktemp "${TMPDIR:-/tmp}/phase2-ci.XXXXXX") || exit 2 +trap 'rm -f "$tmp"' EXIT +python3 -W error - > "$tmp" <<'EOF' || { cat "$tmp"; echo "phase2-ci: FAIL: could not derive --through"; exit 1; } +import os, sys +sys.path.insert(0, 'tools') +import phase2_check as p +rows, bad = p.parse_map(os.path.join(p.ROOT, 'tests/phase2/MAP.md')) +if bad: + print('phase2-ci: the MAP does not parse: ' + '; '.join(bad)) + sys.exit(1) +have = {} +for r in rows: + if r['kind'] == 'row' and r['round']: + landed = bool(p.row_file(os.path.join(p.ROOT, 'tests/phase2/rows'), r['id'])) + have.setdefault(r['round'], []).append((r['id'], landed)) +through, done = None, True +for rd in p.ROUNDS: + if not have.get(rd): + continue + got = [i for i, ok in have[rd] if ok] + if done and len(got) == len(have[rd]): + through = rd + continue + done = False + if got: + print('phase2-ci: %s has %d of %d row files (%s): not checked until all land' + % (rd, len(got), len(have[rd]), ' '.join(got))) +if through is None: + print('phase2-ci: no round has all of its row files') + sys.exit(1) +print('THROUGH ' + through) +EOF +grep -v '^THROUGH ' "$tmp" +through=$(sed -n 's/^THROUGH //p' "$tmp") +echo "phase2-ci: through=$through (the last round whose MAP rows all have files)" +fails="" +verdict() { # verdict NAME RC OUTPUT VERDICT-ERE: the tool's output; rc 0 and its verdict line, once + printf '%s\n' "$3" + [ "$2" -eq 0 ] && [ "$(grep -cE "$4" <<< "$3")" -eq 1 ] || fails="$fails $1(rc=$2)" +} +out=$(bash tools/phase2_check.sh --through "$through" "${bins[0]}" "${bins[2]}" 2>&1); rc=$? +verdict phase2-check "$rc" "$out" '^phase2-check: PASS$' +out=$(bash tools/phase2_lib_diff.sh "${bins[1]}" "${bins[2]}" 2>&1); rc=$? +verdict phase2-lib-diff "$rc" "$out" '^phase2-lib-diff: listed_functions=[0-9]+ undeclared=0 stale=0 PASS$' +if [ -n "$fails" ]; then + echo "phase2-ci: FAIL:$fails" + exit 1 +fi +echo "phase2-ci: PASS (through=$through)" From dabe7ce83f66d7765496ab951f39a44dff445379 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 09:04:02 -0500 Subject: [PATCH 079/188] gates: the enrolment check covers tools/ entry points (mechanical-gates section 151) A gate tool no workflow calls has bitten twice: a CHANGELOG-cited scaling gate (#1183) and Phase 2's phase2_check.sh and phase2_lib_diff.sh. The check that already enrols tests/*.sh and tests/*.py now enrols tools/ with the same invocation scan and the same exemptions file. - Population, by the directory listing: every top-level tools/*.sh and tools/*.py, and each tools// that holds a script (a package, reached when CI runs any of its scripts). No hand-kept list of gates. - Reached: from a .github/workflows/*.yml step through invocations, as the scan already read them (the suite, top-level tests/ and tools/ shell scripts). Three rules are new: a tools/ target may be .py or in a subdirectory; a tools/ script's "$(dirname "$0")/x" call reaches its sibling; `python3 -W error x.py` skips -W's word. - Otherwise the script needs a row in tests/enrolment_exemptions.txt with its reason; a row for an invoked or missing file is stale, as before. 18 rows: self-test-only scripts, hooks, generators, manual tools, and tools that run in CI through make, an import or a Python call, which the scan does not read. Each reason was checked by reading its caller. At this commit: `PASS: test-enrolment: examined=119 enrolled=118 exempt=1; tools examined=70 enrolled=52 exempt=18`. Proved through the real gate on a copy of the tree: an unreferenced tools/zz_unreferenced_gate.sh, one only named in a workflow comment and one only echoed by a step are each red by name; one a planted step runs is green (enrolled 53). Each new rule removed in turn turns the unmodified tree red (phase2_check.py, tools/observer_oracle/, the _-prefixed .py helpers). A fourth candidate rule (scanning tools/*/*.sh) changed nothing when removed, so it is not in. The self-test gains three cases (a .sh, a .py and a package plant): `checks=7`, pinned in tools/selftests.txt. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/CI.md | 6 +++-- tests/enrolment_exemptions.txt | 23 ++++++++++++++++-- tools/enrolment_check.sh | 43 ++++++++++++++++++++++++++++++---- tools/selftests.txt | 2 +- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/docs/CI.md b/docs/CI.md index 2802c2817..34ab67304 100644 --- a/docs/CI.md +++ b/docs/CI.md @@ -751,7 +751,9 @@ need no suite run — plus changed-gate self-tests, exit 1 on any failure; the d joins when a binary exists. Its gate list is the only copy: the `gate-selftests` CI job runs the same script. Among them, `tools/enrolment_check.sh` (also suite `[99ab]`) fails when a `tests/*.sh` or -`tests/*.py` is invoked by no suite section, workflow step or enrolled script; -exceptions live in `tests/enrolment_exemptions.txt` with a reason each. +`tests/*.py` is invoked by no suite section, workflow step or enrolled script, +and when a `tools/` entry point (a top-level `tools/*.sh` or `tools/*.py`, or a +`tools//` package) is reached from no workflow step that way; exceptions +live in `tests/enrolment_exemptions.txt` with a reason each. Counts that grow with the suite (child-script sites, doc-claim populations) are floors: adding a test needs no count edit, a drop is red. diff --git a/tests/enrolment_exemptions.txt b/tests/enrolment_exemptions.txt index c21886d7c..01cbe539b 100644 --- a/tests/enrolment_exemptions.txt +++ b/tests/enrolment_exemptions.txt @@ -1,3 +1,22 @@ -# Test scripts nothing in CI runs, on purpose (tools/enrolment_check.sh, #1264). -# `path | reason`. A row for a missing or invoked file fails; prefer a section. +# Test scripts and tools/ entry points that no workflow invokes, as tools/enrolment_check.sh +# reads "invoked" (#1264; tools/ since #1758 R1.3). `path | reason`: the reason says how the +# script does run. A row for a missing or invoked file fails; prefer a section or a workflow step. tests/test_gc_runner_controls.py | manual deferred control for the GC traversal runner (tests/GC_TRAVERSAL.md); forks child sessions and must run with the heavy slot released, so it is run by hand +tools/asan_receipts_check.sh | self-test only (--selftest is its one mode) of ci.yml's ASan receipt step; its tools/selftests.txt row runs when ci.yml changes, and nightly +tools/builtin_usage.sh | a report over local consumer checkouts (counts builtin references), not a gate; run by hand +tools/core_ext_boundary_selftest.sh | self-test only (--selftest is its one mode) of tools/core_ext_boundary_check.sh, which CI runs; its tools/selftests.txt row runs when either changes, and nightly +tools/doc_coupling_hook.sh | a Claude Code hook (.claude/settings.json) for agent sessions, not a CI gate +tools/freestanding_check.sh | runs in CI through make: ci.yml's `make freestanding-check` recipe calls it; this scan does not follow make +tools/gen_lsp_builtin_index.sh | a generator, not a gate: make regenerates src/lsp_builtin_index.h when its sources change +tools/gen_lsp_stdlib_index.sh | a generator, not a gate: make writes src/lsp_stdlib_index.h for `make lsp`, which CI runs +tools/mutants.sh | the manual mutation trains (its header); its --selftest is a tools/selftests.txt row +tools/phase2_corpus_diff.sh | the corpus differential of Phase 2's mechanical rounds (R1.1, R1.2, R2.1): tools/phase2_check.py runs it under such a --through and in its --selftest, and no landed round selects one +tools/phase2_cost.sh | each Phase 2 round's builder runs its BASE CAND gate (design section 8); CI's bench job reads its declarations through bench/check_regression.sh (--declared jit), which this scan does not read +tools/phase2_plants.sh | self-test only, Phase 2's planted faults: its tools/selftests.txt row runs when the checks it names change, and nightly +tools/release_skill_check.sh | checks the release runbook (.claude/skills/release/SKILL.md) by hand; only its --selftest runs, as a tools/selftests.txt row +tools/section_fragments_check.sh | self-test only (--selftest is its one mode); its tools/selftests.txt row runs when the runner-text gates change, and nightly +tools/selftests_selection_selftest.sh | self-test only (--selftest is its one mode) of tools/selftests.sh's row selection; its tools/selftests.txt row runs when the driver changes, and nightly +tools/stop_gate.sh | a Claude Code Stop hook (.claude/settings.json), not a CI gate; its --selftest is a tools/selftests.txt row +tools/ai_benchmark.py | a module tests/test_ai_benchmark.py imports (suite [99acb]); this scan sees no imports +tools/bounded_process.py | a module tests/test_gc_runner_controls.py imports (the manual GC runner control, exempt above) +tools/phase2_inventory.py | runs through tools/phase2_check.py (its inventory gate, every mode, now in CI) and tests/phase2/slot_layer.sh (suite [0fk]): a Python call and a nested tests/ script this scan does not read diff --git a/tools/enrolment_check.sh b/tools/enrolment_check.sh index 7cd34da43..d56b846ea 100644 --- a/tools/enrolment_check.sh +++ b/tools/enrolment_check.sh @@ -15,6 +15,17 @@ # imports, globbed directories, mutant harnesses and python drivers, so # "invoked" has no single syntactic meaning for them. # +# The same scan enrols tools/ (mechanical-gates section 151, #1758 R1.3: Phase +# 2's two gate tools had run only on builders' machines). Every top-level +# tools/*.sh and tools/*.py is an entry point, and so is each tools// +# package holding a script, by the directory listing, never a hand-kept list. +# Each must be reached from a .github/workflows/*.yml step through invocations +# (the suite, a top-level tests/ or tools/ shell script, a script beside it +# called as "$(dirname "$0")/x"), or be listed in the same exemptions file as +# local-only with its reason. Not seen: a tool run only through make, a Python +# subprocess or an import; a package counts as reached when CI runs any of its +# scripts. +# # Usage: tools/enrolment_check.sh [--selftest] exit 0 pass, 1 fail, 2 no instrument # ENROL_ROOT overrides the repository root (the selftest points it at a copy). set -u @@ -27,7 +38,8 @@ if [ "${1:-}" = "--selftest" ]; then trap 'rm -rf "$ST"' EXIT mkdir -p "$ST/tests/sections" "$ST/tools" "$ST/.github" cp tests/*.sh tests/*.py "$EXEMPT" "$ST/tests/" && cp tests/sections/*.sh "$ST/tests/sections/" \ - && cp tools/*.sh tools/selftests.txt "$ST/tools/" && cp -R .github/workflows "$ST/.github/" + && cp tools/*.sh tools/*.py tools/selftests.txt "$ST/tools/" && cp -R .github/workflows "$ST/.github/" \ + && for d in tools/*/; do cp -R "$d" "$ST/tools/"; done n=0; bad=0 case_() { # case_ local out rc; n=$((n + 1)) @@ -46,6 +58,13 @@ if [ "${1:-}" = "--selftest" ]; then rm "$ST/tests/test_clean.sh" echo 'tests/test_cli.sh | planted: test_cli.sh IS invoked' >> "$ST/$EXEMPT" case_ "an exemption for an invoked script is stale: red" 1 "exempts tests/test_cli.sh, which IS invoked" + sed -i.bak '$d' "$ST/$EXEMPT" && rm -f "$ST/$EXEMPT.bak" + printf '#!/bin/bash\nexit 1\n' > "$ST/tools/zz_plant_gate.sh" + case_ "an uninvoked tools/zz_plant_gate.sh is red and named" 1 "tools/zz_plant_gate.sh is invoked by no workflow" + mv "$ST/tools/zz_plant_gate.sh" "$ST/tools/zz_plant_gate.py" + case_ "an uninvoked tools/zz_plant_gate.py is red and named" 1 "tools/zz_plant_gate.py is invoked by no workflow" + rm "$ST/tools/zz_plant_gate.py"; mkdir "$ST/tools/zz_pkg"; printf 'raise SystemExit(1)\n' > "$ST/tools/zz_pkg/gate.py" + case_ "an uninvoked package tools/zz_pkg/ is red and named" 1 "tools/zz_pkg/ is invoked by no workflow" echo " checks=$n" exit "$bad" fi @@ -82,7 +101,9 @@ function strip(s, c) { w = s; sub(/[[:space:]].*/, "", w); gsub(/["\047]/, "", w) if (w ~ /^(bash|sh|dash|python3?|source|\.)$/) { s = substr(s, length(w) + 1); sub(/^[[:space:]]+/, "", s) - while (s ~ /^-[A-Za-z]+[[:space:]]/) sub(/^-[A-Za-z]+[[:space:]]+/, "", s) + while (s ~ /^-[A-Za-z]+[[:space:]]/) # python3 -W error x.py: -W and -X take a word + if (w ~ /^python/ && s ~ /^-[WX][[:space:]]/) sub(/^-[WX][[:space:]]+[^[:space:]]+[[:space:]]*/, "", s) + else sub(/^-[A-Za-z]+[[:space:]]+/, "", s) w = s; sub(/[[:space:]].*/, "", w); gsub(/["\047]/, "", w) } else if (closed && s !~ /[[:space:]]/) continue # `x.sh)` is a case pattern b = w; sub(/.*\//, "", b); d = w; sub(/\/?[^\/]*$/, "", d) @@ -90,7 +111,8 @@ function strip(s, c) { # the dir of a tests/ script, or a bare name after `cd tests` — never $WORK/x (#1264 r2). intests = (d ~ /(^|\/)tests$|TESTS_DIR\}?$/) || (d == "$DIR" && FILENAME ~ /^tests\//) || (d == "" && FILENAME !~ /^tools\//) if (w !~ /tools\// && w ~ /\.(sh|py)$/ && intests && index(known, " " b " ")) print FILENAME "\ttests/" b - else if (w ~ /tools\/[^\/]*\.sh$/) print FILENAME "\ttools/" b + else if (w ~ /tools\/([^\/]+\/)?[^\/]+\.(sh|py)$/) { t = w; sub(/^.*tools\//, "tools/", t); print FILENAME "\t" t } + else if (d == "$DIR" && FILENAME ~ /^tools\// && w ~ /\.(sh|py)$/) { t = FILENAME; sub(/[^\/]*$/, b, t); print FILENAME "\t" t } } }' tests/run_all_tests.sh tests/sections/*.sh .github/workflows/*.yml tests/*.sh tools/*.sh | sort -u > "$EDGES" # Commands in the self-test table are reachable through its driver. @@ -122,5 +144,18 @@ for f in tests/*.sh tests/*.py; do else echo " FAIL: $f is invoked by nothing -- add a suite section in tests/sections/ (or a workflow step), or list it in $EXEMPT with a reason"; rc=1; fi done [ "$total" -gt 0 ] || { echo "test-enrolment: ABORTED: tests/*.sh + tests/*.py is empty"; exit 2; } -[ "$rc" -eq 0 ] && echo "PASS: test-enrolment: examined=$total enrolled=$ok exempt=$ex" +tt=0; tok=0; tex=0 +for f in tools/*.sh tools/*.py tools/*/; do + case "$f" in + */) pkg=0; for g in "$f"*.sh "$f"*.py; do [ -f "$g" ] && pkg=1; done; [ "$pkg" = 1 ] || continue + grep -q "^$f" <<< "$REACHED" && hit=1 || hit=0 ;; + *) [ -f "$f" ] || continue; grep -qxF "$f" <<< "$REACHED" && hit=1 || hit=0 ;; + esac + tt=$((tt + 1)) + if [ "$hit" = 1 ]; then tok=$((tok + 1)) + elif grep -q "^[[:space:]]*$f[[:space:]]*|" <<< "$EXEMPTED"; then tex=$((tex + 1)) + else echo " FAIL: $f is invoked by no workflow -- run it from a .github/workflows/ step (or a script one runs), or list it in $EXEMPT as local-only with a reason"; rc=1; fi +done +[ "$tt" -gt 0 ] || { echo "tool-enrolment: ABORTED: tools/*.sh + tools/*.py is empty"; exit 2; } +[ "$rc" -eq 0 ] && echo "PASS: test-enrolment: examined=$total enrolled=$ok exempt=$ex; tools examined=$tt enrolled=$tok exempt=$tex" exit "$rc" diff --git a/tools/selftests.txt b/tools/selftests.txt index 34e26eea1..b077f9354 100644 --- a/tools/selftests.txt +++ b/tools/selftests.txt @@ -30,7 +30,7 @@ tools/codspeed_targets_check.sh codspeed.yml | timeout 30 bash tools/codspeed_ta tools/consumer_acceptance.sh tools/_derive_variants.py tools/_extract_runcmd.py reports/consumer_acceptance/* | timeout 25 bash tools/consumer_acceptance.sh --self-test tools/core_ext_boundary_check.sh tools/core_ext_boundary_selftest.sh | timeout 120 bash tools/core_ext_boundary_selftest.sh --selftest | [{"pattern":"^PASS: core-ext boundary:","count":1}] tools/docs_claims_check.sh | timeout 30 bash tools/docs_claims_check.sh --selftest | [{"pattern":"^SELFTEST: 17 case\\(s\\) run, 17 passed, 0 failed$","count":1}] -tools/enrolment_check.sh tests/enrolment_exemptions.txt tools/selftests.txt | timeout 30 bash tools/enrolment_check.sh --selftest | [{"pattern":"^ checks=4$","count":1}] +tools/enrolment_check.sh tests/enrolment_exemptions.txt tools/selftests.txt | timeout 30 bash tools/enrolment_check.sh --selftest | [{"pattern":"^ checks=7$","count":1}] tools/obs_marker_check.sh | timeout 30 bash tools/obs_marker_check.sh --selftest tools/obs_reader_sync_check.sh tools/obs_marker_check.sh | timeout 30 bash tools/obs_reader_sync_check.sh --selftest | [{"pattern":"^SELFTEST: ([0-9]+) passed.*$","count":11,"floor":true,"value":true}] tools/performance_observer_docs.py docs/PERFORMANCE.md bench/observer_callgrind.txt bench/baseline.txt bench/observed_loop.eigs bench/unobserved_loop.eigs bench/conservative_observed_loop.eigs bench/conservative_unobserved_loop.eigs | timeout 30 python3 tools/performance_observer_docs.py --selftest From 6382b6a5b4d7115cd4ad772f824d57de0850d15f Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 09:19:49 -0500 Subject: [PATCH 080/188] gates: the enrolment self-test copies a tools/ package with BSD cp too `cp -R tools/observer_oracle/ DEST` copies the directory's CONTENTS on BSD cp (macOS) and the directory on GNU cp, so on a Mac the self-test's copy would have flattened the package into tools/ and its control case would have gone red. The copy now drops the trailing slash. The self-test is `checks=7` under bash 5 and under bash 3.2; the live check passes under both. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tools/enrolment_check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/enrolment_check.sh b/tools/enrolment_check.sh index d56b846ea..83217e881 100644 --- a/tools/enrolment_check.sh +++ b/tools/enrolment_check.sh @@ -39,7 +39,7 @@ if [ "${1:-}" = "--selftest" ]; then mkdir -p "$ST/tests/sections" "$ST/tools" "$ST/.github" cp tests/*.sh tests/*.py "$EXEMPT" "$ST/tests/" && cp tests/sections/*.sh "$ST/tests/sections/" \ && cp tools/*.sh tools/*.py tools/selftests.txt "$ST/tools/" && cp -R .github/workflows "$ST/.github/" \ - && for d in tools/*/; do cp -R "$d" "$ST/tools/"; done + && for d in tools/*/; do cp -R "${d%/}" "$ST/tools/"; done n=0; bad=0 case_() { # case_ local out rc; n=$((n + 1)) From e6be83cb83656ea5aa4749d4a76eb51428a5adfb Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 11:01:56 -0500 Subject: [PATCH 081/188] Add floor division and floor modulo for phase 2 N4 -7 // 2 now returns exact int -4; -7 % 3 returns int 2 and -7.5 % 2 returns float 0.5. Append OP_IDIV and both slash tokens, retain the descriptor ABI, and wire compound names/fields/indices. Raise value on zero divisors and INT64_MIN // -1; compute INT64_MIN % -1 as zero without issuing the faulting division. Record #1758 comment 6294926822: float/mixed // by zero raises DIV's current error through R1.4 and joins DIV/MOD at N11. The JIT/leaf remain conservative. Update the four executed front doors, grammar, token diagnostics, inventory, and changelog together. Validation: -O2 release build, 0 warnings. Focused arithmetic suite 2480/2480. MAP through R1.4: mapped=60, controls=18, witnessed=23, controls_witnessed=13, vacuous=0; phase2-check PASS. Formatter 38/38; lint 274/274; canonical doc examples 198/198, populations 12/12. Observer markers:101 opcodes; suite labels:304, both PASS. Independent arithmetic critic:2578/2578. Constant probe disassembles IDIV and MOD. Full release/ASan, differential, cost and fault-plant acceptance follow before bundle delivery. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- README.md | 17 + changes/changed/1758-r1-4-floor-division.md | 1 + docs/COMPARISON.md | 21 +- docs/GRAMMAR.md | 10 +- docs/SPEC.md | 27 +- docs/design/phase2-inventory.txt | 995 +++++++++--------- docs/design/phase2-numbers.md | 10 +- docs/llms.txt | 19 +- src/chunk.c | 6 +- src/compiler.c | 3 +- src/eigenscript.c | 2 + src/eigenscript.h | 3 +- src/lexer.c | 6 +- src/parser.c | 7 +- src/vm.c | 85 +- src/vm.h | 1 + tests/phase2/MAP.md | 13 +- tests/phase2/rows/N4.compound-floordiv.eigs | 14 + tests/phase2/rows/N4.compound-floordiv.out | 1 + .../rows/N4.float-floordiv-zero-raises.eigs | 11 + .../rows/N4.float-floordiv-zero-raises.out | 4 + tests/phase2/rows/N4.floor-mod.eigs | 7 + tests/phase2/rows/N4.floor-mod.out | 1 + tests/phase2/rows/N4.floordiv.eigs | 7 + tests/phase2/rows/N4.floordiv.out | 1 + tests/phase2/rows/N4.fn-floor-mod.eigs | 16 + tests/phase2/rows/N4.fn-floor-mod.out | 1 + tests/phase2/rows/N4.fn-floordiv.eigs | 16 + tests/phase2/rows/N4.fn-floordiv.out | 1 + .../rows/N4.int-floordiv-zero-raises.eigs | 10 + .../rows/N4.int-floordiv-zero-raises.out | 1 + .../rows/N4b.floordiv-min-by-neg1-raises.eigs | 11 + .../rows/N4b.floordiv-min-by-neg1-raises.out | 1 + tests/phase2/rows/N4b.min-mod-neg1-zero.eigs | 8 + tests/phase2/rows/N4b.min-mod-neg1-zero.out | 1 + tests/sections/0fq-floor-division-1758.sh | 13 + tests/test_doc_examples.py | 8 +- tests/test_floor_division.eigs | 123 +++ tests/test_fmt.sh | 4 + tests/test_lint.sh | 11 + tests/test_lsp.py | 4 + tests/test_opcode_abi.c | 2 + 42 files changed, 974 insertions(+), 529 deletions(-) create mode 100644 changes/changed/1758-r1-4-floor-division.md create mode 100644 tests/phase2/rows/N4.compound-floordiv.eigs create mode 100644 tests/phase2/rows/N4.compound-floordiv.out create mode 100644 tests/phase2/rows/N4.float-floordiv-zero-raises.eigs create mode 100644 tests/phase2/rows/N4.float-floordiv-zero-raises.out create mode 100644 tests/phase2/rows/N4.floor-mod.eigs create mode 100644 tests/phase2/rows/N4.floor-mod.out create mode 100644 tests/phase2/rows/N4.floordiv.eigs create mode 100644 tests/phase2/rows/N4.floordiv.out create mode 100644 tests/phase2/rows/N4.fn-floor-mod.eigs create mode 100644 tests/phase2/rows/N4.fn-floor-mod.out create mode 100644 tests/phase2/rows/N4.fn-floordiv.eigs create mode 100644 tests/phase2/rows/N4.fn-floordiv.out create mode 100644 tests/phase2/rows/N4.int-floordiv-zero-raises.eigs create mode 100644 tests/phase2/rows/N4.int-floordiv-zero-raises.out create mode 100644 tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.eigs create mode 100644 tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.out create mode 100644 tests/phase2/rows/N4b.min-mod-neg1-zero.eigs create mode 100644 tests/phase2/rows/N4b.min-mod-neg1-zero.out create mode 100644 tests/sections/0fq-floor-division-1758.sh create mode 100644 tests/test_floor_division.eigs diff --git a/README.md b/README.md index 69795c86f..be8163391 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,23 @@ Comparisons, `not` and predicates return `true`/`false`, a `bool`. A bool is not a number: `true + 1` and `(x > 0) == 1` raise, so test a bool directly (`if x > 0:`). See [docs/SPEC.md](docs/SPEC.md#booleans-comparison-and-logic). + +`//` floors the quotient; `%` has the divisor's sign. `//=` applies the same +operation to its assignment target, like `/=`. Zero divisors raise `value` +for all numeric operand kinds in this round. Two ints produce an int for +`//` and `%`; a float operand produces a float. `/` always produces a float. + +```eigenscript +x is -7 +x //= 2 +print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] +print of [num_type of (7 // 2), num_type of (7.0 // 2)] +``` +```output +[-4, -4, 2, -2, 0.5] +["int", "float"] +``` + ### Ask Your Code Every value quietly remembers how it has been changing — and you don't pay diff --git a/changes/changed/1758-r1-4-floor-division.md b/changes/changed/1758-r1-4-floor-division.md new file mode 100644 index 000000000..04193efa2 --- /dev/null +++ b/changes/changed/1758-r1-4-floor-division.md @@ -0,0 +1 @@ +- Add floor division `//` and `//=`, returning an exact int for two ints and a float otherwise. `%` now uses floor modulo with the divisor's sign. Integer floor-division overflow raises; `INT64_MIN % -1` is 0. Zero divisors still raise for every numeric kind until N11 (#1758). diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index 4be44c9fe..87c9d8364 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -15,6 +15,23 @@ fundamental way: **every assignment is observed**, and the language has first-class constructs (`converged`, `what is x`, `prev of x`) for asking the running program about its own state and history. + +`//` floors the quotient; `%` has the divisor's sign. `//=` applies the same +operation to its assignment target, like `/=`. Zero divisors raise `value` +for all numeric operand kinds in this round. Two ints produce an int for +`//` and `%`; a float operand produces a float. `/` always produces a float. + +```eigenscript +x is -7 +x //= 2 +print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] +print of [num_type of (7 // 2), num_type of (7.0 // 2)] +``` +```output +[-4, -4, 2, -2, 0.5] +["int", "float"] +``` + ## At a glance | | Python | JavaScript | Rust | Lisp | EigenScript | @@ -68,14 +85,14 @@ print(7 // 2) # 3 (floor division operator) EigenScript — int64 and float64 share the `num` type; `num_type of` distinguishes their kind. Int `+ - *` raise `value` on overflow; mixed-kind -comparison is exact. Division returns a float; floor explicitly: +comparison is exact. `/` returns a float; `//` floors the quotient: ```eigenscript x is 42 x += 1 print of x print of (7 / 2) -print of (floor of (7 / 2)) +print of (7 // 2) ``` ```output 43 diff --git a/docs/GRAMMAR.md b/docs/GRAMMAR.md index 9c9604d77..eef374cf5 100644 --- a/docs/GRAMMAR.md +++ b/docs/GRAMMAR.md @@ -99,10 +99,10 @@ converged stable improving oscillating diverging equilibrium ### Operators and Punctuation ``` -+ - * / % ++ - * / // % & | ^ << >> ~ < > <= >= == != -+= -= *= /= %= &= |= ^= <<= >>= ++= -= *= /= //= %= &= |= ^= <<= >>= ( ) [ ] { } , : . |> pipe (left-associative, desugars a |> b to b of a) @@ -194,7 +194,7 @@ destructure_stmt = '[' IDENT { ',' IDENT } ']' 'is' expression local_assign_stmt = 'local' IDENT 'is' expression assign_stmt = IDENT assign_op expression -assign_op = 'is' | '+=' | '-=' | '*=' | '/=' | '%=' +assign_op = 'is' | '+=' | '-=' | '*=' | '/=' | '//=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' ; compound forms desugar: x += e == x is x + e @@ -228,7 +228,7 @@ shift_expr = addition { ( '<<' | '>>' ) addition } addition = multiply { ( '+' | '-' ) multiply } -multiply = unary { ( '*' | '/' | '%' ) unary } +multiply = unary { ( '*' | '/' | '//' | '%' ) unary } unary = '-' unary | 'not' unary @@ -322,7 +322,7 @@ From lowest to highest precedence: | 7 | `&` | Left | Bitwise AND | | 8 | `<<` `>>` | Left | Shifts | | 9 | `+` `-` | Left | Addition, subtraction | -| 10 | `*` `/` `%` | Left | Multiplication, division, modulo | +| 10 | `*` `/` `//` `%` | Left | Multiplication, true/floor division, floor modulo | | 11 | `-` (unary) `not` `~` | Right | Negation, logical NOT, bitwise NOT | | 12 | `of` | Right | Function call / observation (`f of g of x` = `f of (g of x)`) | | 13 | `[i]` `[a:b]` `.key` | Left | Index, slice, dot access | diff --git a/docs/SPEC.md b/docs/SPEC.md index 5ab50caf0..bb4663f23 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -159,7 +159,7 @@ inner outer ``` -Compound assignment operators update in place: `+= -= *= /= %= &= |= ^= +Compound assignment operators update in place: `+= -= *= /= //= %= &= |= ^= <<= >>=`. They work on plain names, dict fields, and indexed elements. ```eigenscript @@ -193,14 +193,35 @@ literal falls back to float. Hex integer literals wrap modulo 2^64. Int `+`, `-` and `*` preserve the int kind and raise `value` on int64 overflow. Unary minus and `abs` also raise on INT64_MIN. Mixed int/float arithmetic converts the int to float; comparison across kinds is exact, including -above 2^53. `/` still returns float; `%` retains truncating float remainder -until the floor-division round. Builtins retain their documented float +above 2^53. `/` returns float; `//` floors (an int for two ints, a float otherwise). +`%` is floor modulo for both kinds, with the sign of the divisor. Both int +operators are exact, and `INT64_MIN // -1` raises `value` while +`INT64_MIN % -1` is the int 0. Division, floor division and modulo by zero +raise `value`, including float and mixed operands (IEEE zero division waits +for N11). Builtins retain their documented float results during this transition, except `abs`, which preserves ints. Integer-valued floats print without a decimal point. Division is true division. `%` is modulo. There is no exponent operator; use `pow of [base, exp]`. + +`//` floors the quotient; `%` has the divisor's sign. `//=` applies the same +operation to its assignment target, like `/=`. Zero divisors raise `value` +for all numeric operand kinds in this round. Two ints produce an int for +`//` and `%`; a float operand produces a float. `/` always produces a float. + +```eigenscript +x is -7 +x //= 2 +print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] +print of [num_type of (7 // 2), num_type of (7.0 // 2)] +``` +```output +[-4, -4, 2, -2, 0.5] +["int", "float"] +``` + Numeric literals accept the usual decimal forms plus a leading or trailing dot and scientific notation: `.5`, `1.`, `1e5`, `1E5` are all single numbers. Hexadecimal *integer* literals are lexed explicitly: diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 1045c0101..0bee303f9 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,12 +1,12 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2037 classified=2037 unclassified=0 +examined=2046 classified=2046 unclassified=0 files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 502 CASE=60 DATA=4 TEST=435 YIELD=3 -(b) payload reads 572 RAW=130 READ=442 -(c) producers 475 GUARD=73 PARSE=3 PRODUCE=374 TAGSET=5 WRITE=20 +(a) type tests 504 CASE=60 DATA=4 TEST=437 YIELD=3 +(b) payload reads 577 RAW=134 READ=443 +(c) producers 477 GUARD=74 PARSE=3 PRODUCE=377 TAGSET=5 WRITE=18 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 20 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=7 (f) equality, ordering and hashing 53 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=23 @@ -16,20 +16,20 @@ files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token -make_num 365 +make_num 368 val_is_number 185 -eigs_num_arg 172 +eigs_num_arg 173 VAL_FLOAT 150 -VAL_INT 146 +VAL_INT 150 eigs_list_num 130 SLOT_F64_RAW 83 -num_guard 62 -VAL_F64_RAW 56 +num_guard 63 +VAL_F64_RAW 54 AST_NUM 52 +VAL_I64_RAW 50 slot_is_f64 50 eigs_value_as_num 48 eigs_slot_num 47 -VAL_I64_RAW 46 buffer_read_num 37 slot_from_f64 37 slot_is_smi 33 @@ -39,8 +39,8 @@ list_set_num 22 slot_smi_val 20 slot_f64_value 19 strtod 16 -NUM_REUSE 12 eigs_slot_opt_num 12 +NUM_REUSE 10 eigs_num_arg_slow 9 slot_int_value 9 EIGS_NUM_MAX 8 @@ -69,7 +69,7 @@ data.number (AST) 3 ## Per file (category counts) builtins.c 350 a=84 b=104 c=111 e=6 f=13 h=21 i=11 -vm.c 299 a=70 b=96 c=69 e=2 f=10 i=52 +vm.c 308 a=72 b=101 c=71 e=2 f=10 i=52 ext_gfx.c 298 a=104 b=124 c=70 builtins_tensor.c 200 a=55 b=59 c=86 eigenscript.c 123 a=22 b=18 c=15 e=7 f=18 i=43 @@ -1271,27 +1271,27 @@ chunk.c:1107 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a compiler.c:583 add_num_constant make_num PRODUCE c compiler.c:599 literal_index_u16 data.number RAW b compiler.c:599 literal_index_u16 number RAW b -compiler.c:814 collect_referenced_names_skip AST_NUM CASE a -compiler.c:958 collect_referenced_names AST_NUM CASE a -compiler.c:1097 scan_for_captures AST_NUM CASE a -compiler.c:1204 ast_has_closure AST_NUM CASE a -compiler.c:1282 subtree_overwrite_safe AST_NUM CASE a -compiler.c:1492 scan_for_interrogated AST_NUM CASE a -compiler.c:1614 scan_for_env_bound AST_NUM CASE a -compiler.c:1681 collect_module_names_walk AST_NUM CASE a -compiler.c:1819 scan_dispatch_rebind AST_NUM CASE a -compiler.c:2006 cond_is_observer_based AST_NUM CASE i -compiler.c:2094 compile_node_inner AST_NUM CASE a -compiler.c:2095 compile_node_inner data.number RAW b -compiler.c:2095 compile_node_inner number RAW b -compiler.c:2095 compile_node_inner number RAW b +compiler.c:815 collect_referenced_names_skip AST_NUM CASE a +compiler.c:959 collect_referenced_names AST_NUM CASE a +compiler.c:1098 scan_for_captures AST_NUM CASE a +compiler.c:1205 ast_has_closure AST_NUM CASE a +compiler.c:1283 subtree_overwrite_safe AST_NUM CASE a +compiler.c:1493 scan_for_interrogated AST_NUM CASE a +compiler.c:1615 scan_for_env_bound AST_NUM CASE a +compiler.c:1682 collect_module_names_walk AST_NUM CASE a +compiler.c:1820 scan_dispatch_rebind AST_NUM CASE a +compiler.c:2007 cond_is_observer_based AST_NUM CASE i +compiler.c:2095 compile_node_inner AST_NUM CASE a +compiler.c:2096 compile_node_inner data.number RAW b +compiler.c:2096 compile_node_inner number RAW b compiler.c:2096 compile_node_inner number RAW b compiler.c:2097 compile_node_inner number RAW b -compiler.c:2103 compile_node_inner number RAW b -compiler.c:2962 compile_node_inner AST_NUM TEST a -compiler.c:3017 compile_node_inner AST_NUM TEST a -compiler.c:3061 compile_node_inner AST_NUM TEST a -compiler.c:3874 obs_ast_scan_d AST_NUM CASE i +compiler.c:2098 compile_node_inner number RAW b +compiler.c:2104 compile_node_inner number RAW b +compiler.c:2963 compile_node_inner AST_NUM TEST a +compiler.c:3018 compile_node_inner AST_NUM TEST a +compiler.c:3062 compile_node_inner AST_NUM TEST a +compiler.c:3875 obs_ast_scan_d AST_NUM CASE i container.h:27 eigs_container_slot VAL_F64_RAW RAW b container.h:27 eigs_container_slot VAL_FLOAT TEST a container.h:27 eigs_container_slot num_guard GUARD c @@ -1392,169 +1392,169 @@ container.h:340 dict_value_get_num slot_is_f64 TEST a container.h:341 dict_value_get_num SLOT_F64_RAW RAW b eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a -eigenscript.c:309 val_type_name VAL_FLOAT CASE a -eigenscript.c:310 val_type_name VAL_INT CASE a -eigenscript.c:427 ent_child_slot SLOT_F64_RAW RAW i -eigenscript.c:427 ent_child_slot slot_is_f64 TEST i -eigenscript.c:429 ent_child_slot slot_is_smi TEST i -eigenscript.c:429 ent_child_slot slot_smi_val RAW i -eigenscript.c:437 compute_entropy_impl VAL_F64_RAW RAW i -eigenscript.c:437 compute_entropy_impl VAL_FLOAT CASE i -eigenscript.c:440 compute_entropy_impl VAL_I64_RAW RAW i -eigenscript.c:440 compute_entropy_impl VAL_INT CASE i -eigenscript.c:790 observer_slot_update val_is_number TEST i -eigenscript.c:792 observer_slot_update VAL_I64_RAW RAW i -eigenscript.c:792 observer_slot_update VAL_INT TEST i -eigenscript.c:793 observer_slot_update VAL_F64_RAW RAW i -eigenscript.c:855 observer_slot_sample_gated val_is_number TEST i -eigenscript.c:856 observer_slot_sample_gated VAL_I64_RAW RAW i -eigenscript.c:856 observer_slot_sample_gated VAL_INT TEST i -eigenscript.c:857 observer_slot_sample_gated VAL_F64_RAW RAW i -eigenscript.c:940 observer_slot_saturated EIGS_NUM_MAX GUARD i -eigenscript.c:1389 observer_entropy_now slot_is_f64 TEST i -eigenscript.c:1391 observer_entropy_now SLOT_F64_RAW RAW i -eigenscript.c:1392 observer_entropy_now slot_is_smi TEST i -eigenscript.c:1394 observer_entropy_now slot_smi_val RAW i -eigenscript.c:1439 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1440 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1443 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1447 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1448 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:311 val_type_name VAL_FLOAT CASE a +eigenscript.c:312 val_type_name VAL_INT CASE a +eigenscript.c:429 ent_child_slot SLOT_F64_RAW RAW i +eigenscript.c:429 ent_child_slot slot_is_f64 TEST i +eigenscript.c:431 ent_child_slot slot_is_smi TEST i +eigenscript.c:431 ent_child_slot slot_smi_val RAW i +eigenscript.c:439 compute_entropy_impl VAL_F64_RAW RAW i +eigenscript.c:439 compute_entropy_impl VAL_FLOAT CASE i +eigenscript.c:442 compute_entropy_impl VAL_I64_RAW RAW i +eigenscript.c:442 compute_entropy_impl VAL_INT CASE i +eigenscript.c:792 observer_slot_update val_is_number TEST i +eigenscript.c:794 observer_slot_update VAL_I64_RAW RAW i +eigenscript.c:794 observer_slot_update VAL_INT TEST i +eigenscript.c:795 observer_slot_update VAL_F64_RAW RAW i +eigenscript.c:857 observer_slot_sample_gated val_is_number TEST i +eigenscript.c:858 observer_slot_sample_gated VAL_I64_RAW RAW i +eigenscript.c:858 observer_slot_sample_gated VAL_INT TEST i +eigenscript.c:859 observer_slot_sample_gated VAL_F64_RAW RAW i +eigenscript.c:942 observer_slot_saturated EIGS_NUM_MAX GUARD i +eigenscript.c:1391 observer_entropy_now slot_is_f64 TEST i +eigenscript.c:1393 observer_entropy_now SLOT_F64_RAW RAW i +eigenscript.c:1394 observer_entropy_now slot_is_smi TEST i +eigenscript.c:1396 observer_entropy_now slot_smi_val RAW i +eigenscript.c:1441 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1442 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1445 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1449 observer_slot_trajectory make_num PRODUCE i eigenscript.c:1450 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1456 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1489 observer_slot_from_trajectory eigs_num_arg READ i -eigenscript.c:1489 observer_slot_from_trajectory val_is_number TEST i -eigenscript.c:1490 observer_slot_from_trajectory val_is_number TEST i -eigenscript.c:1508 observer_slot_from_trajectory VAL_FLOAT TEST i -eigenscript.c:1508 observer_slot_from_trajectory VAL_FLOAT TEST i -eigenscript.c:1508 observer_slot_from_trajectory VAL_INT TEST i -eigenscript.c:1508 observer_slot_from_trajectory VAL_INT TEST i -eigenscript.c:1513 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1514 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1524 observer_slot_from_trajectory VAL_FLOAT TEST i -eigenscript.c:1524 observer_slot_from_trajectory VAL_INT TEST i -eigenscript.c:1529 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1542 observer_slot_from_trajectory val_is_number TEST i -eigenscript.c:1547 observer_slot_from_trajectory eigs_num_arg READ i -eigenscript.c:1650 free_value VAL_FLOAT TEST a -eigenscript.c:1731 free_value VAL_FLOAT CASE a -eigenscript.c:1732 free_value VAL_INT CASE a -eigenscript.c:1741 make_num make_num PRODUCE c -eigenscript.c:1742 make_num num_guard GUARD c -eigenscript.c:1758 make_num VAL_FLOAT TAGSET c -eigenscript.c:1759 make_num VAL_F64_RAW WRITE c -eigenscript.c:1768 make_int VAL_INT TAGSET c -eigenscript.c:1769 make_int VAL_I64_RAW WRITE c -eigenscript.c:1775 recycle_intermediate VAL_FLOAT TEST a -eigenscript.c:1797 make_num_permanent make_num_permanent PRODUCE c -eigenscript.c:1798 make_num_permanent num_guard GUARD c -eigenscript.c:1800 make_num_permanent VAL_FLOAT TAGSET c -eigenscript.c:1801 make_num_permanent VAL_F64_RAW WRITE c -eigenscript.c:1830 eigs_num_arg_slow eigs_num_arg_slow READ b -eigenscript.c:1831 eigs_num_arg_slow VAL_F64_RAW RAW b -eigenscript.c:1831 eigs_num_arg_slow VAL_FLOAT TEST a -eigenscript.c:1835 eigs_num_arg_slow VAL_I64_RAW RAW b -eigenscript.c:1835 eigs_num_arg_slow VAL_INT TEST a -eigenscript.c:1842 eigs_list_num eigs_list_num READ b -eigenscript.c:1849 eigs_list_num eigs_slot_num READ b -eigenscript.c:1852 eigs_elem_num eigs_elem_num READ b -eigenscript.c:1853 eigs_elem_num eigs_slot_elem_num READ b -eigenscript.c:1856 eigs_opt_num eigs_opt_num READ b -eigenscript.c:1857 eigs_opt_num eigs_slot_opt_num READ b -eigenscript.c:1893 slot_from_value VAL_FLOAT TEST a -eigenscript.c:1897 slot_from_value VAL_F64_RAW RAW b -eigenscript.c:1899 slot_from_value slot_from_f64 PRODUCE c -eigenscript.c:1903 slot_from_value VAL_INT TEST a -eigenscript.c:1904 slot_from_value VAL_I64_RAW RAW b -eigenscript.c:1907 slot_from_value slot_from_int PRODUCE c -eigenscript.c:1927 slot_to_value SLOT_F64_RAW RAW b -eigenscript.c:1927 slot_to_value make_num PRODUCE c -eigenscript.c:1927 slot_to_value slot_is_f64 TEST a -eigenscript.c:1935 slot_to_value slot_is_smi TEST a -eigenscript.c:1935 slot_to_value slot_smi_val RAW b -eigenscript.c:2428 module_ns_project slot_is_f64 TEST a -eigenscript.c:2428 module_ns_project slot_is_f64 TEST a -eigenscript.c:2433 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2433 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:2678 chan_clone_rec VAL_FLOAT TEST a -eigenscript.c:2678 chan_clone_rec VAL_INT TEST a -eigenscript.c:2681 chan_clone_rec VAL_F64_RAW RAW b -eigenscript.c:2681 chan_clone_rec VAL_FLOAT CASE a -eigenscript.c:2681 chan_clone_rec make_num PRODUCE c -eigenscript.c:2682 chan_clone_rec VAL_I64_RAW RAW b -eigenscript.c:2682 chan_clone_rec VAL_INT CASE a -eigenscript.c:2869 is_truthy VAL_F64_RAW RAW b -eigenscript.c:2869 is_truthy VAL_FLOAT CASE a -eigenscript.c:2870 is_truthy VAL_I64_RAW RAW b -eigenscript.c:2870 is_truthy VAL_INT CASE a -eigenscript.c:2909 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:2909 values_equal_impl VAL_INT TEST f -eigenscript.c:2910 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2910 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:1451 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1452 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1458 observer_slot_trajectory make_num PRODUCE i +eigenscript.c:1491 observer_slot_from_trajectory eigs_num_arg READ i +eigenscript.c:1491 observer_slot_from_trajectory val_is_number TEST i +eigenscript.c:1492 observer_slot_from_trajectory val_is_number TEST i +eigenscript.c:1510 observer_slot_from_trajectory VAL_FLOAT TEST i +eigenscript.c:1510 observer_slot_from_trajectory VAL_FLOAT TEST i +eigenscript.c:1510 observer_slot_from_trajectory VAL_INT TEST i +eigenscript.c:1510 observer_slot_from_trajectory VAL_INT TEST i +eigenscript.c:1515 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1516 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1526 observer_slot_from_trajectory VAL_FLOAT TEST i +eigenscript.c:1526 observer_slot_from_trajectory VAL_INT TEST i +eigenscript.c:1531 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1544 observer_slot_from_trajectory val_is_number TEST i +eigenscript.c:1549 observer_slot_from_trajectory eigs_num_arg READ i +eigenscript.c:1652 free_value VAL_FLOAT TEST a +eigenscript.c:1733 free_value VAL_FLOAT CASE a +eigenscript.c:1734 free_value VAL_INT CASE a +eigenscript.c:1743 make_num make_num PRODUCE c +eigenscript.c:1744 make_num num_guard GUARD c +eigenscript.c:1760 make_num VAL_FLOAT TAGSET c +eigenscript.c:1761 make_num VAL_F64_RAW WRITE c +eigenscript.c:1770 make_int VAL_INT TAGSET c +eigenscript.c:1771 make_int VAL_I64_RAW WRITE c +eigenscript.c:1777 recycle_intermediate VAL_FLOAT TEST a +eigenscript.c:1799 make_num_permanent make_num_permanent PRODUCE c +eigenscript.c:1800 make_num_permanent num_guard GUARD c +eigenscript.c:1802 make_num_permanent VAL_FLOAT TAGSET c +eigenscript.c:1803 make_num_permanent VAL_F64_RAW WRITE c +eigenscript.c:1832 eigs_num_arg_slow eigs_num_arg_slow READ b +eigenscript.c:1833 eigs_num_arg_slow VAL_F64_RAW RAW b +eigenscript.c:1833 eigs_num_arg_slow VAL_FLOAT TEST a +eigenscript.c:1837 eigs_num_arg_slow VAL_I64_RAW RAW b +eigenscript.c:1837 eigs_num_arg_slow VAL_INT TEST a +eigenscript.c:1844 eigs_list_num eigs_list_num READ b +eigenscript.c:1851 eigs_list_num eigs_slot_num READ b +eigenscript.c:1854 eigs_elem_num eigs_elem_num READ b +eigenscript.c:1855 eigs_elem_num eigs_slot_elem_num READ b +eigenscript.c:1858 eigs_opt_num eigs_opt_num READ b +eigenscript.c:1859 eigs_opt_num eigs_slot_opt_num READ b +eigenscript.c:1895 slot_from_value VAL_FLOAT TEST a +eigenscript.c:1899 slot_from_value VAL_F64_RAW RAW b +eigenscript.c:1901 slot_from_value slot_from_f64 PRODUCE c +eigenscript.c:1905 slot_from_value VAL_INT TEST a +eigenscript.c:1906 slot_from_value VAL_I64_RAW RAW b +eigenscript.c:1909 slot_from_value slot_from_int PRODUCE c +eigenscript.c:1929 slot_to_value SLOT_F64_RAW RAW b +eigenscript.c:1929 slot_to_value make_num PRODUCE c +eigenscript.c:1929 slot_to_value slot_is_f64 TEST a +eigenscript.c:1937 slot_to_value slot_is_smi TEST a +eigenscript.c:1937 slot_to_value slot_smi_val RAW b +eigenscript.c:2430 module_ns_project slot_is_f64 TEST a +eigenscript.c:2430 module_ns_project slot_is_f64 TEST a +eigenscript.c:2435 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2435 module_ns_project dict_value_rewrite_num PRODUCE c +eigenscript.c:2680 chan_clone_rec VAL_FLOAT TEST a +eigenscript.c:2680 chan_clone_rec VAL_INT TEST a +eigenscript.c:2683 chan_clone_rec VAL_F64_RAW RAW b +eigenscript.c:2683 chan_clone_rec VAL_FLOAT CASE a +eigenscript.c:2683 chan_clone_rec make_num PRODUCE c +eigenscript.c:2684 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:2684 chan_clone_rec VAL_INT CASE a +eigenscript.c:2871 is_truthy VAL_F64_RAW RAW b +eigenscript.c:2871 is_truthy VAL_FLOAT CASE a +eigenscript.c:2872 is_truthy VAL_I64_RAW RAW b +eigenscript.c:2872 is_truthy VAL_INT CASE a eigenscript.c:2911 values_equal_impl VAL_FLOAT TEST f eigenscript.c:2911 values_equal_impl VAL_INT TEST f eigenscript.c:2912 values_equal_impl VAL_F64_RAW RAW f eigenscript.c:2912 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2913 values_equal_impl val_is_number TEST f -eigenscript.c:2914 values_equal_impl val_is_number TEST f -eigenscript.c:2928 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2928 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:2928 values_equal_impl VAL_FLOAT CASE f -eigenscript.c:2929 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2929 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:2929 values_equal_impl VAL_INT CASE f -eigenscript.c:2959 values_equal_impl buffer_read_num READ f +eigenscript.c:2913 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:2913 values_equal_impl VAL_INT TEST f +eigenscript.c:2914 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2914 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2915 values_equal_impl val_is_number TEST f +eigenscript.c:2916 values_equal_impl val_is_number TEST f +eigenscript.c:2930 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2930 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:2930 values_equal_impl VAL_FLOAT CASE f +eigenscript.c:2931 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2931 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:2931 values_equal_impl VAL_INT CASE f eigenscript.c:2961 values_equal_impl buffer_read_num READ f -eigenscript.c:3001 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3016 eigs_num_text strtod PARSE e -eigenscript.c:3026 value_to_string VAL_FLOAT CASE e -eigenscript.c:3027 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3027 value_to_string eigs_num_text FORMAT e -eigenscript.c:3030 value_to_string VAL_INT CASE e -eigenscript.c:3031 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4332 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4333 gc_value_is_node VAL_INT CASE a -eigenscript.h:195 number RAW b -eigenscript.h:213 AST_NUM DATA a -eigenscript.h:239 number RAW b -eigenscript.h:280 VAL_FLOAT DATA a -eigenscript.h:289 VAL_INT DATA a -eigenscript.h:297 #define val_is_number VAL_FLOAT TEST a -eigenscript.h:297 #define val_is_number VAL_INT TEST a -eigenscript.h:297 #define val_is_number val_is_number TEST a -eigenscript.h:318 #define VAL_F64_RAW VAL_F64_RAW RAW b -eigenscript.h:318 #define VAL_F64_RAW f64_ RAW b -eigenscript.h:319 #define VAL_I64_RAW VAL_I64_RAW RAW b -eigenscript.h:319 #define VAL_I64_RAW i64_ RAW b -eigenscript.h:320 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b -eigenscript.h:320 #define VAL_F64_OFFSET f64_ RAW b -eigenscript.h:1394 eigs_num_arg_slow READ b -eigenscript.h:1395 eigs_num_arg eigs_num_arg READ b -eigenscript.h:1396 eigs_num_arg VAL_F64_RAW RAW b -eigenscript.h:1396 eigs_num_arg VAL_FLOAT TEST a -eigenscript.h:1397 eigs_num_arg eigs_num_arg_slow READ b -eigenscript.h:1399 eigs_list_num READ b -eigenscript.h:1404 eigs_elem_num READ b -eigenscript.h:1405 eigs_opt_num READ b -eigenscript.h:1776 make_num PRODUCE c -eigenscript.h:1787 make_num_permanent PRODUCE c -eigenscript.h:1839 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1881 num_guard num_guard GUARD c -eigenscript.h:1889 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1889 num_guard EIGS_NUM_MAX GUARD c +eigenscript.c:2963 values_equal_impl buffer_read_num READ f +eigenscript.c:3003 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:3018 eigs_num_text strtod PARSE e +eigenscript.c:3028 value_to_string VAL_FLOAT CASE e +eigenscript.c:3029 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3029 value_to_string eigs_num_text FORMAT e +eigenscript.c:3032 value_to_string VAL_INT CASE e +eigenscript.c:3033 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4334 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4335 gc_value_is_node VAL_INT CASE a +eigenscript.h:196 number RAW b +eigenscript.h:214 AST_NUM DATA a +eigenscript.h:240 number RAW b +eigenscript.h:281 VAL_FLOAT DATA a +eigenscript.h:290 VAL_INT DATA a +eigenscript.h:298 #define val_is_number VAL_FLOAT TEST a +eigenscript.h:298 #define val_is_number VAL_INT TEST a +eigenscript.h:298 #define val_is_number val_is_number TEST a +eigenscript.h:319 #define VAL_F64_RAW VAL_F64_RAW RAW b +eigenscript.h:319 #define VAL_F64_RAW f64_ RAW b +eigenscript.h:320 #define VAL_I64_RAW VAL_I64_RAW RAW b +eigenscript.h:320 #define VAL_I64_RAW i64_ RAW b +eigenscript.h:321 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b +eigenscript.h:321 #define VAL_F64_OFFSET f64_ RAW b +eigenscript.h:1395 eigs_num_arg_slow READ b +eigenscript.h:1396 eigs_num_arg eigs_num_arg READ b +eigenscript.h:1397 eigs_num_arg VAL_F64_RAW RAW b +eigenscript.h:1397 eigs_num_arg VAL_FLOAT TEST a +eigenscript.h:1398 eigs_num_arg eigs_num_arg_slow READ b +eigenscript.h:1400 eigs_list_num READ b +eigenscript.h:1405 eigs_elem_num READ b +eigenscript.h:1406 eigs_opt_num READ b +eigenscript.h:1777 make_num PRODUCE c +eigenscript.h:1788 make_num_permanent PRODUCE c +eigenscript.h:1840 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1882 num_guard num_guard GUARD c eigenscript.h:1890 num_guard EIGS_NUM_MAX GUARD c eigenscript.h:1890 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1899 buffer_read_num buffer_read_num READ b -eigenscript.h:1900 buffer_read_num num_guard GUARD c -eigenscript.h:1906 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1915 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1924 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1925 buffer_read_byte buffer_read_num READ b -eigenscript.h:1927 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1938 num_guard_named num_guard_named GUARD c -eigenscript.h:1944 num_guard_named num_guard GUARD c -eigenscript.h:2250 eigs_num_text FORMAT e +eigenscript.h:1891 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1891 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1900 buffer_read_num buffer_read_num READ b +eigenscript.h:1901 buffer_read_num num_guard GUARD c +eigenscript.h:1907 finite_num_to_byte finite_num_to_byte READ b +eigenscript.h:1916 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1925 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1926 buffer_read_byte buffer_read_num READ b +eigenscript.h:1928 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1939 num_guard_named num_guard_named GUARD c +eigenscript.h:1945 num_guard_named num_guard GUARD c +eigenscript.h:2251 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j @@ -2144,14 +2144,14 @@ jit_smoke.c:642 run_exit_cases SLOT_F64_RAW RAW d lexer.c:35 tok_add number RAW b lexer.c:42 tok_add number RAW b lexer.c:42 tok_add number RAW b -lexer.c:647 tokenize_at_line number RAW b -lexer.c:734 tokenize_at_line number RAW b -lexer.c:735 tokenize_at_line number RAW b -lexer.c:748 tokenize_at_line strtod PARSE c -lexer.c:749 tokenize_at_line number RAW b -lexer.c:765 tokenize_at_line number RAW b -lexer.c:766 tokenize_at_line number RAW b +lexer.c:651 tokenize_at_line number RAW b +lexer.c:738 tokenize_at_line number RAW b +lexer.c:739 tokenize_at_line number RAW b +lexer.c:752 tokenize_at_line strtod PARSE c +lexer.c:753 tokenize_at_line number RAW b +lexer.c:769 tokenize_at_line number RAW b lexer.c:770 tokenize_at_line number RAW b +lexer.c:774 tokenize_at_line number RAW b lint.c:247 collect_refs AST_NUM CASE a lint.c:311 collect_assigns AST_NUM CASE a lint.c:369 cond_has_bare_predicate AST_NUM CASE a @@ -2211,10 +2211,10 @@ model_train.c:1459 builtin_native_train_step strtod PARSE c model_train.c:1474 builtin_native_train_step eigs_slot_num READ b model_train.c:1477 builtin_native_train_step eigs_slot_num READ b parser.c:524 free_ast AST_NUM CASE a -parser.c:806 parse_primary AST_NUM DATA a -parser.c:807 parse_primary data.number WRITE c -parser.c:807 parse_primary number RAW b -parser.c:807 parse_primary number RAW b +parser.c:807 parse_primary AST_NUM DATA a +parser.c:808 parse_primary data.number WRITE c +parser.c:808 parse_primary number RAW b +parser.c:808 parse_primary number RAW b tape_read.c:368 tape_parse strtod PARSE g tape_read.c:387 tape_parse strtod PARSE g tape_read.c:388 tape_parse strtod PARSE g @@ -2272,302 +2272,311 @@ value_slot.h:229 slot_int_value slot_is_smi TEST a value_slot.h:229 slot_int_value slot_smi_val RAW b value_slot.h:232 slot_int_value VAL_I64_RAW RAW b value_slot.h:232 slot_int_value VAL_INT TEST a -vm.c:107 obs_dump_num eigs_num_text FORMAT i -vm.c:118 obs_dump_value SLOT_F64_RAW RAW i -vm.c:118 obs_dump_value slot_is_f64 TEST i -vm.c:119 obs_dump_value slot_is_smi TEST i -vm.c:119 obs_dump_value slot_smi_val RAW i -vm.c:125 obs_dump_value VAL_F64_RAW RAW i -vm.c:125 obs_dump_value VAL_FLOAT CASE i -vm.c:126 obs_dump_value VAL_I64_RAW RAW i -vm.c:126 obs_dump_value VAL_INT CASE i -vm.c:214 obs_dump_scope slot_is_f64 TEST i -vm.c:215 obs_dump_scope SLOT_F64_RAW RAW i -vm.c:216 obs_dump_scope slot_is_smi TEST i -vm.c:217 obs_dump_scope slot_smi_val RAW i -vm.c:706 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c -vm.c:786 slot_bridge_unwrap slot_is_f64 TEST a -vm.c:788 slot_bridge_unwrap SLOT_F64_RAW RAW b -vm.c:788 slot_bridge_unwrap make_num PRODUCE c -vm.c:797 slot_bridge_unwrap slot_is_smi TEST a -vm.c:833 vm_slot_lift SLOT_F64_RAW RAW b -vm.c:833 vm_slot_lift make_num PRODUCE c -vm.c:833 vm_slot_lift slot_is_f64 TEST a -vm.c:838 vm_slot_lift slot_is_smi TEST a -vm.c:870 slot_truthy SLOT_F64_RAW RAW b -vm.c:870 slot_truthy slot_is_f64 TEST a -vm.c:874 slot_truthy slot_is_smi TEST a -vm.c:874 slot_truthy slot_smi_val RAW b -vm.c:890 vm_int_arith slot_from_int PRODUCE c -vm.c:898 vm_bit_operand slot_int_value READ b -vm.c:899 vm_bit_operand num_to_i64_exact READ b -vm.c:899 vm_bit_operand slot_f64_value READ b -vm.c:907 vm_number_compare slot_int_value READ b -vm.c:907 vm_number_compare slot_int_value READ b -vm.c:909 vm_number_compare slot_f64_value READ b -vm.c:910 vm_number_compare slot_f64_value READ b -vm.c:922 vm_iter_index slot_f64_value READ b -vm.c:928 vm_iter_index slot_int_value READ b -vm.c:936 vm_iter_limit slot_int_value READ b -vm.c:984 make_iter_state make_num PRODUCE c -vm.c:997 make_iter_state make_num PRODUCE c -vm.c:1219 vm_store_local_slot slot_is_f64 TEST a -vm.c:1223 vm_store_local_slot VAL_FLOAT TEST a -vm.c:1225 vm_store_local_slot SLOT_F64_RAW RAW b -vm.c:1225 vm_store_local_slot VAL_F64_RAW WRITE c -vm.c:1408 jit_helper_local_idx_get buffer_read_num READ b -vm.c:1408 jit_helper_local_idx_get slot_from_f64 PRODUCE c -vm.c:1569 jit_helper_dot_set slot_is_f64 TEST a -vm.c:1572 jit_helper_dot_set SLOT_F64_RAW RAW b -vm.c:1639 jit_helper_local_dot_set slot_is_f64 TEST a -vm.c:1640 jit_helper_local_dot_set SLOT_F64_RAW RAW b -vm.c:1690 obs_slot_observable slot_is_f64 TEST i -vm.c:1697 obs_slot_num SLOT_F64_RAW RAW i -vm.c:1697 obs_slot_num slot_is_f64 TEST i -vm.c:1698 obs_slot_num slot_is_smi TEST i -vm.c:1698 obs_slot_num slot_smi_val RAW i -vm.c:1699 obs_slot_num VAL_INT TEST i -vm.c:1700 obs_slot_num VAL_I64_RAW RAW i -vm.c:1863 jit_helper_iter_next buffer_read_num READ b -vm.c:1863 jit_helper_iter_next num_guard GUARD c -vm.c:1863 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1869 jit_helper_iter_next list_set_num PRODUCE c -vm.c:1939 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b -vm.c:1939 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c -vm.c:1943 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c -vm.c:1946 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c -vm.c:1985 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:1999 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:1999 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:2010 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:2011 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:2029 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:2029 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2112 loop_iter_store make_num PRODUCE c -vm.c:2119 loop_iter_store slot_is_f64 TEST a -vm.c:2120 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2125 loop_iter_store make_num PRODUCE c -vm.c:2240 vm_value_index_is_int VAL_INT TEST a -vm.c:2241 vm_value_index_is_int VAL_I64_RAW RAW b -vm.c:2246 vm_value_index_is_int VAL_F64_RAW RAW b -vm.c:2259 jit_helper_index_set slot_is_f64 TEST a -vm.c:2264 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2265 jit_helper_index_set slot_is_f64 TEST a -vm.c:2267 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2269 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2279 jit_helper_index_set slot_is_f64 TEST a -vm.c:2281 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2282 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2284 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2296 jit_helper_index_set val_is_number TEST a -vm.c:2299 jit_helper_index_set eigs_num_arg READ b +vm.c:117 obs_dump_num eigs_num_text FORMAT i +vm.c:128 obs_dump_value SLOT_F64_RAW RAW i +vm.c:128 obs_dump_value slot_is_f64 TEST i +vm.c:129 obs_dump_value slot_is_smi TEST i +vm.c:129 obs_dump_value slot_smi_val RAW i +vm.c:135 obs_dump_value VAL_F64_RAW RAW i +vm.c:135 obs_dump_value VAL_FLOAT CASE i +vm.c:136 obs_dump_value VAL_I64_RAW RAW i +vm.c:136 obs_dump_value VAL_INT CASE i +vm.c:224 obs_dump_scope slot_is_f64 TEST i +vm.c:225 obs_dump_scope SLOT_F64_RAW RAW i +vm.c:226 obs_dump_scope slot_is_smi TEST i +vm.c:227 obs_dump_scope slot_smi_val RAW i +vm.c:716 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c +vm.c:796 slot_bridge_unwrap slot_is_f64 TEST a +vm.c:798 slot_bridge_unwrap SLOT_F64_RAW RAW b +vm.c:798 slot_bridge_unwrap make_num PRODUCE c +vm.c:807 slot_bridge_unwrap slot_is_smi TEST a +vm.c:843 vm_slot_lift SLOT_F64_RAW RAW b +vm.c:843 vm_slot_lift make_num PRODUCE c +vm.c:843 vm_slot_lift slot_is_f64 TEST a +vm.c:848 vm_slot_lift slot_is_smi TEST a +vm.c:880 slot_truthy SLOT_F64_RAW RAW b +vm.c:880 slot_truthy slot_is_f64 TEST a +vm.c:884 slot_truthy slot_is_smi TEST a +vm.c:884 slot_truthy slot_smi_val RAW b +vm.c:900 vm_int_arith slot_from_int PRODUCE c +vm.c:908 vm_bit_operand slot_int_value READ b +vm.c:909 vm_bit_operand num_to_i64_exact READ b +vm.c:909 vm_bit_operand slot_f64_value READ b +vm.c:917 vm_number_compare slot_int_value READ b +vm.c:917 vm_number_compare slot_int_value READ b +vm.c:919 vm_number_compare slot_f64_value READ b +vm.c:920 vm_number_compare slot_f64_value READ b +vm.c:932 vm_iter_index slot_f64_value READ b +vm.c:938 vm_iter_index slot_int_value READ b +vm.c:946 vm_iter_limit slot_int_value READ b +vm.c:994 make_iter_state make_num PRODUCE c +vm.c:1007 make_iter_state make_num PRODUCE c +vm.c:1229 vm_store_local_slot slot_is_f64 TEST a +vm.c:1233 vm_store_local_slot VAL_FLOAT TEST a +vm.c:1235 vm_store_local_slot SLOT_F64_RAW RAW b +vm.c:1235 vm_store_local_slot VAL_F64_RAW WRITE c +vm.c:1418 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1418 jit_helper_local_idx_get slot_from_f64 PRODUCE c +vm.c:1579 jit_helper_dot_set slot_is_f64 TEST a +vm.c:1582 jit_helper_dot_set SLOT_F64_RAW RAW b +vm.c:1649 jit_helper_local_dot_set slot_is_f64 TEST a +vm.c:1650 jit_helper_local_dot_set SLOT_F64_RAW RAW b +vm.c:1700 obs_slot_observable slot_is_f64 TEST i +vm.c:1707 obs_slot_num SLOT_F64_RAW RAW i +vm.c:1707 obs_slot_num slot_is_f64 TEST i +vm.c:1708 obs_slot_num slot_is_smi TEST i +vm.c:1708 obs_slot_num slot_smi_val RAW i +vm.c:1709 obs_slot_num VAL_INT TEST i +vm.c:1710 obs_slot_num VAL_I64_RAW RAW i +vm.c:1873 jit_helper_iter_next buffer_read_num READ b +vm.c:1873 jit_helper_iter_next num_guard GUARD c +vm.c:1873 jit_helper_iter_next slot_from_f64 PRODUCE c +vm.c:1879 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1949 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b +vm.c:1949 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c +vm.c:1953 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c +vm.c:1956 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c +vm.c:1995 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b +vm.c:2009 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b +vm.c:2009 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c +vm.c:2020 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2021 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2039 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:2039 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2122 loop_iter_store make_num PRODUCE c +vm.c:2129 loop_iter_store slot_is_f64 TEST a +vm.c:2130 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2135 loop_iter_store make_num PRODUCE c +vm.c:2250 vm_value_index_is_int VAL_INT TEST a +vm.c:2251 vm_value_index_is_int VAL_I64_RAW RAW b +vm.c:2256 vm_value_index_is_int VAL_F64_RAW RAW b +vm.c:2269 jit_helper_index_set slot_is_f64 TEST a +vm.c:2274 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2275 jit_helper_index_set slot_is_f64 TEST a +vm.c:2277 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2279 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2289 jit_helper_index_set slot_is_f64 TEST a +vm.c:2291 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2292 jit_helper_index_set list_rewrite_num PRODUCE c +vm.c:2294 jit_helper_index_set SLOT_F64_RAW RAW b vm.c:2306 jit_helper_index_set val_is_number TEST a vm.c:2309 jit_helper_index_set eigs_num_arg READ b -vm.c:2312 jit_helper_index_set val_is_number TEST a -vm.c:2313 jit_helper_index_set eigs_num_arg READ b -vm.c:2332 jit_helper_index_get slot_is_f64 TEST a -vm.c:2334 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2341 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2352 jit_helper_index_get buffer_read_num READ b -vm.c:2354 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2356 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2372 jit_helper_index_get val_is_number TEST a -vm.c:2375 jit_helper_index_get eigs_num_arg READ b -vm.c:2387 jit_helper_index_get val_is_number TEST a -vm.c:2390 jit_helper_index_get eigs_num_arg READ b -vm.c:2399 jit_helper_index_get val_is_number TEST a -vm.c:2402 jit_helper_index_get eigs_num_arg READ b -vm.c:2404 jit_helper_index_get buffer_read_num READ b -vm.c:2404 jit_helper_index_get make_num PRODUCE c -vm.c:2998 vm_take_error_value make_num PRODUCE c -vm.c:3102 slot_type_name slot_is_f64 TEST e -vm.c:3103 slot_type_name slot_is_smi TEST e -vm.c:3345 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a -vm.c:3346 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b -vm.c:3346 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3355 vm_run_ex/CASE(INT_ZERO) slot_from_int PRODUCE c -vm.c:3359 vm_run_ex/CASE(INT_ONE) slot_from_int PRODUCE c -vm.c:3365 vm_run_ex/CASE(INT_CONST) VAL_I64_RAW RAW b -vm.c:3366 vm_run_ex/CASE(INT_CONST) slot_from_int PRODUCE c -vm.c:3377 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3382 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3402 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3402 #define NUM_REUSE VAL_FLOAT TEST a -vm.c:3413 #define ARITH_FAST slot_f64_value READ b -vm.c:3413 #define ARITH_FAST slot_f64_value READ b -vm.c:3414 #define ARITH_FAST num_guard GUARD c -vm.c:3419 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3420 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3428 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3429 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3437 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3449 #define INT_ARITH slot_int_value READ b -vm.c:3449 #define INT_ARITH slot_int_value READ b -vm.c:3463 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3463 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3464 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3464 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3464 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3465 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3465 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3466 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3466 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3467 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3468 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3468 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3469 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3469 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3469 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3469 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3519 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3519 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3520 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3520 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3520 #define NUM_BINOP num_guard GUARD c -vm.c:3521 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3521 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3523 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3523 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3524 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3524 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3525 #define NUM_BINOP make_num PRODUCE c -vm.c:3526 #define NUM_BINOP val_is_number TEST a -vm.c:3526 #define NUM_BINOP val_is_number TEST a -vm.c:3527 #define NUM_BINOP eigs_num_arg READ b -vm.c:3527 #define NUM_BINOP eigs_num_arg READ b -vm.c:3528 #define NUM_BINOP num_guard GUARD c -vm.c:3531 #define NUM_BINOP make_num PRODUCE c -vm.c:3535 #define NUM_BINOP make_num PRODUCE c -vm.c:3553 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3553 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3554 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3556 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3558 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3558 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3558 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3561 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3563 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3563 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3564 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3564 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3565 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3570 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3578 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3578 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3578 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3579 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3579 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3579 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3580 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3580 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3581 vm_run_ex/CASE(MOD) NUM_REUSE TEST a -vm.c:3581 vm_run_ex/CASE(MOD) VAL_F64_RAW WRITE c -vm.c:3582 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3584 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3584 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3589 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3617 #define INT_BINOP_R slot_f64_value READ b -vm.c:3621 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3648 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3651 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3651 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3654 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3658 vm_run_ex/CASE(NEG) slot_int_value READ b -vm.c:3663 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c -vm.c:3668 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3690 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3694 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3703 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3703 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3709 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3709 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3729 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3729 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3735 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3735 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3757 #define NUM_CMP slot_f64_value READ f -vm.c:3757 #define NUM_CMP slot_f64_value READ f -vm.c:4705 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4707 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4714 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4724 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4726 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4728 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4750 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4752 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4753 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4755 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4757 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4767 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4769 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4769 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4771 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4783 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4786 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4793 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4796 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4799 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4800 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4856 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4859 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4920 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4921 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:4947 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:4947 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5053 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5054 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5127 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5131 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5131 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5470 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5471 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5472 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5506 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5507 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5508 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5572 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5573 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5573 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5573 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5577 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5578 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5579 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5580 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5584 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5598 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5599 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5600 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5601 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5621 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5647 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5650 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5651 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5654 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5670 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5678 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5681 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5686 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5706 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5707 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5708 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5709 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5839 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5839 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5856 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5857 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5859 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5866 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5870 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5873 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5874 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5877 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5888 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5891 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6485 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6486 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6487 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6490 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6500 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6501 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6503 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6507 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:2316 jit_helper_index_set val_is_number TEST a +vm.c:2319 jit_helper_index_set eigs_num_arg READ b +vm.c:2322 jit_helper_index_set val_is_number TEST a +vm.c:2323 jit_helper_index_set eigs_num_arg READ b +vm.c:2342 jit_helper_index_get slot_is_f64 TEST a +vm.c:2344 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2351 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2362 jit_helper_index_get buffer_read_num READ b +vm.c:2364 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2366 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2382 jit_helper_index_get val_is_number TEST a +vm.c:2385 jit_helper_index_get eigs_num_arg READ b +vm.c:2397 jit_helper_index_get val_is_number TEST a +vm.c:2400 jit_helper_index_get eigs_num_arg READ b +vm.c:2409 jit_helper_index_get val_is_number TEST a +vm.c:2412 jit_helper_index_get eigs_num_arg READ b +vm.c:2414 jit_helper_index_get buffer_read_num READ b +vm.c:2414 jit_helper_index_get make_num PRODUCE c +vm.c:3008 vm_take_error_value make_num PRODUCE c +vm.c:3112 slot_type_name slot_is_f64 TEST e +vm.c:3113 slot_type_name slot_is_smi TEST e +vm.c:3356 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3357 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3357 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3366 vm_run_ex/CASE(INT_ZERO) slot_from_int PRODUCE c +vm.c:3370 vm_run_ex/CASE(INT_ONE) slot_from_int PRODUCE c +vm.c:3376 vm_run_ex/CASE(INT_CONST) VAL_I64_RAW RAW b +vm.c:3377 vm_run_ex/CASE(INT_CONST) slot_from_int PRODUCE c +vm.c:3388 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3393 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3413 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3413 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3424 #define ARITH_FAST slot_f64_value READ b +vm.c:3424 #define ARITH_FAST slot_f64_value READ b +vm.c:3425 #define ARITH_FAST num_guard GUARD c +vm.c:3430 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3431 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3439 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3440 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3448 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3460 #define INT_ARITH slot_int_value READ b +vm.c:3460 #define INT_ARITH slot_int_value READ b +vm.c:3474 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3474 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3475 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3475 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3475 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3476 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3476 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3477 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3477 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3478 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3479 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3479 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3480 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3480 vm_run_ex/CASE(ADD) eigs_num_arg READ b +vm.c:3480 vm_run_ex/CASE(ADD) make_num PRODUCE c +vm.c:3480 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3530 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3530 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3531 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3531 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3531 #define NUM_BINOP num_guard GUARD c +vm.c:3532 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3532 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3534 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3534 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3535 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3535 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3536 #define NUM_BINOP make_num PRODUCE c +vm.c:3537 #define NUM_BINOP val_is_number TEST a +vm.c:3537 #define NUM_BINOP val_is_number TEST a +vm.c:3538 #define NUM_BINOP eigs_num_arg READ b +vm.c:3538 #define NUM_BINOP eigs_num_arg READ b +vm.c:3539 #define NUM_BINOP num_guard GUARD c +vm.c:3542 #define NUM_BINOP make_num PRODUCE c +vm.c:3546 #define NUM_BINOP make_num PRODUCE c +vm.c:3564 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3564 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3565 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3567 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3569 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3569 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3569 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3572 vm_run_ex/CASE(DIV) eigs_num_arg READ b +vm.c:3574 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3574 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3575 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3575 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3576 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3581 vm_run_ex/CASE(DIV) make_num PRODUCE c +vm.c:3589 vm_run_ex/CASE(IDIV) val_is_number TEST a +vm.c:3589 vm_run_ex/CASE(IDIV) val_is_number TEST a +vm.c:3590 vm_run_ex/CASE(IDIV) VAL_INT TEST a +vm.c:3590 vm_run_ex/CASE(IDIV) VAL_INT TEST a +vm.c:3591 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b +vm.c:3591 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b +vm.c:3606 vm_run_ex/CASE(IDIV) eigs_num_arg READ b +vm.c:3611 vm_run_ex/CASE(IDIV) make_num PRODUCE c +vm.c:3613 vm_run_ex/CASE(IDIV) eigs_num_arg READ b +vm.c:3613 vm_run_ex/CASE(IDIV) make_num PRODUCE c +vm.c:3613 vm_run_ex/CASE(IDIV) num_guard GUARD c +vm.c:3629 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3629 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3630 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3630 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3631 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b +vm.c:3631 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b +vm.c:3643 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3646 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3648 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3648 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3648 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3654 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3682 #define INT_BINOP_R slot_f64_value READ b +vm.c:3686 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3713 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3716 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3716 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3719 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3723 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3728 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3733 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3755 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3759 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3768 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3768 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3774 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3774 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3794 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3794 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3800 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3800 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3822 #define NUM_CMP slot_f64_value READ f +vm.c:3822 #define NUM_CMP slot_f64_value READ f +vm.c:4770 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4772 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4779 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4789 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4791 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4793 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4815 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4817 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4818 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4820 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4822 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4832 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4834 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4834 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4836 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4848 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4851 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4858 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4861 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4864 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4865 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4921 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4924 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4985 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4986 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5012 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:5012 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5118 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5119 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5192 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5196 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5196 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5535 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5536 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5537 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5571 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5572 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5573 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5637 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5638 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5638 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5638 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5642 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5643 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5644 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5645 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5649 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5663 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5664 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5665 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5666 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5686 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5712 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5715 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5716 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5719 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5735 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5743 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5746 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5751 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5771 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5772 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5773 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5774 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5904 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5904 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5921 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5922 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5924 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5931 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5935 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5938 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5939 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5942 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5953 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5956 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6550 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6551 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6552 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6555 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6565 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6566 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6568 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6572 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 71e28e073..bbf687b17 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1676,7 +1676,9 @@ numbers are at `0740af03`. - parser.c (multiplicative level), fmt.c, lint, the LSP and ouroboros `frontend.eigs`; - JIT MOD (§4.2). - - Float `x % 0` (NaN) and `x / 0` (inf) wait for N11 in round 2. + - Float `x % 0` (NaN), `x / 0` (inf) and float/mixed `x // 0` + (`floor(x/0)`, ±inf or NaN) wait for N11 in round 2. All raise today; + the `//` rule is #1758 comment 6294926822. - **N4b (INT64_MIN edges):** - vm.c:3522 `CASE(NEG)` (int arm raises on INT64_MIN); - builtins.c `builtin_abs` (2056); @@ -1738,6 +1740,10 @@ numbers are at `0740af03`. - eigenscript.h:1876 `num_guard`, `num_guard_named`, `EIGS_NUM_MAX` and `STRICT_DOMAIN`: the 74 clamp sites (`num_guard` 60, `num_guard_named` 6, `EIGS_NUM_MAX` 8); + - vm.c `CASE(DIV)`, `CASE(MOD)` and the float/mixed arm of `CASE(IDIV)`: + all three zero-divisor checks raise through R1.4; N11 changes them together + to IEEE division, floor division (`floor(x/0)`, ±inf or NaN) and modulo + (NaN), per #1758 comment 6294926822. Int `// 0` and `% 0` still raise; - builtins_tensor.c `op_sqrt` (711) and `op_log_safe` (729); - builtins.c `asin`/`acos` domain; - state.c:62 `st->strict` defaults to 1 and must become opt-in; @@ -2256,7 +2262,7 @@ failing on zero rows: | R1.1 | 0 | mechanical: the compile errors (223 sites), the C slot test (§2.5; `examined` equals the derived classifier count), plant 1, the int-source check, and the differential over the suite's `.eigs` corpus | | R1.2 | 0 | mechanical: the compile errors (464 sites), the int-source check, and the differential over the suite's `.eigs` corpus (behaviour-preserving) | | R1.3 | 51 | `gate.N5.iterator-metadata` | -| R1.4 | 6 | | +| R1.4 | 9 | | | R1.5 | 7 | | | R1.6 | 17 | `gate.N5.q7-readers`, and the per-builtin behaviour table (§9.4) | | R1.7 | 12 | `gate.N14.db-param-exact` | diff --git a/docs/llms.txt b/docs/llms.txt index 1787773a4..1c4c5024d 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -216,7 +216,7 @@ sqrt(2) = 1.414213562373095 `num_type of` says "int"/"float", or null for a non-number. Int +, -, * raise value on overflow; unary minus and abs raise at INT64_MIN. Mixed arithmetic converts to float, while cross-kind comparison is exact. - Division and most builtin results remain floats at this stage. + True division `/` and most builtin results remain floats at this stage. Float overflow saturates at ±1e308. Integer bit ops accept exact int64 operands; builtin results and infix results still convert to float until the bitwise/builtin rounds. @@ -236,6 +236,23 @@ sqrt(2) = 1.414213562373095 `type_mismatch` error by default; `EIGS_STRICT=0` retains numeric-zero substitution. `str_from_bytes` stops at numeric NUL without inspecting later elements; byte codecs consume the complete list. + +`//` floors the quotient; `%` has the divisor's sign. `//=` applies the same +operation to its assignment target, like `/=`. Zero divisors raise `value` +for all numeric operand kinds in this round. Two ints produce an int for +`//` and `%`; a float operand produces a float. `/` always produces a float. + +```eigenscript +x is -7 +x //= 2 +print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] +print of [num_type of (7 // 2), num_type of (7.0 // 2)] +``` +```output +[-4, -4, 2, -2, 0.5] +["int", "float"] +``` + - Hex integer literals: `0xFF`, `0X10` (digits only). Hex-float forms (`0x1p4`) are parse errors. No `mod` keyword — the operator is `%`. - f-strings interpolate: `f"step {i}: {report of x}"`. Escapes: `\n \t \r \\ \" \{ \}`. Each `{…}` converts with the builtin `str`, even if you rebind `str`. diff --git a/src/chunk.c b/src/chunk.c index 50e4c63b3..54480f412 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -347,7 +347,7 @@ const char *op_name(uint8_t op) { #define N(o) case o: return #o + 3; N(OP_CONST) N(OP_NULL) N(OP_NUM_ZERO) N(OP_NUM_ONE) N(OP_TRUE) N(OP_FALSE) N(OP_INT_ZERO) N(OP_INT_ONE) N(OP_INT_CONST) - N(OP_ADD) N(OP_SUB) N(OP_MUL) N(OP_DIV) N(OP_MOD) + N(OP_ADD) N(OP_SUB) N(OP_MUL) N(OP_DIV) N(OP_MOD) N(OP_IDIV) N(OP_BAND) N(OP_BOR) N(OP_BXOR) N(OP_SHL) N(OP_SHR) N(OP_NEG) N(OP_NOT) N(OP_BNOT) N(OP_EQ) N(OP_NE) N(OP_LT) N(OP_GT) N(OP_LE) N(OP_GE) @@ -521,7 +521,7 @@ static int op_verify_operands(uint8_t op8, VerifyRole roles[3]) { * silently walk wrong. */ case OP_NULL: case OP_NUM_ZERO: case OP_NUM_ONE: case OP_TRUE: case OP_FALSE: case OP_INT_ZERO: case OP_INT_ONE: - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_IDIV: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: case OP_NEG: case OP_NOT: case OP_BNOT: case OP_EQ: case OP_NE: case OP_LT: case OP_GT: case OP_LE: case OP_GE: @@ -665,7 +665,7 @@ static StackEffect op_verify_stack_effect(uint8_t op8, int operand0) { * DOT_GET, ITER_SETUP and the interrogatives. They still require their * operands: see the frame-base note above — vm_pop()'s guard is the bottom * of the whole VM stack, not the bottom of this frame's window. */ - case OP_DIV: case OP_MOD: + case OP_DIV: case OP_MOD: case OP_IDIV: return EFF(2, 2, 1); case OP_DOT_GET: case OP_ITER_SETUP: case OP_INTERROGATE: case OP_INTERROGATE_NAMED: diff --git a/src/compiler.c b/src/compiler.c index bc2d5ca89..d82685b73 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -322,7 +322,7 @@ static int op_stack_effect(uint8_t op8) { case OP_POP: return -1; /* Pop 2, push 1 = net -1 */ - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_IDIV: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: case OP_EQ: case OP_NE: case OP_LT: case OP_GT: case OP_LE: case OP_GE: case OP_INDEX_GET: @@ -663,6 +663,7 @@ static uint8_t binop_to_opcode(const char *op) { if (op[0] == '-' && op[1] == 0) return OP_SUB; if (op[0] == '*' && op[1] == 0) return OP_MUL; if (op[0] == '/' && op[1] == 0) return OP_DIV; + if (op[0] == '/' && op[1] == '/') return OP_IDIV; if (op[0] == '%' && op[1] == 0) return OP_MOD; if (op[0] == '&' && op[1] == 0) return OP_BAND; if (op[0] == '|' && op[1] == 0) return OP_BOR; diff --git a/src/eigenscript.c b/src/eigenscript.c index 6fe333039..caa94e34d 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -246,6 +246,8 @@ const char* tok_type_name(TokType t) { case TOK_MINUS: return "'-'"; case TOK_STAR: return "'*'"; case TOK_SLASH: return "'/'"; + case TOK_SLASH_SLASH: return "'//'"; + case TOK_SLASH_SLASH_EQ: return "'//='"; case TOK_PERCENT: return "'%'"; case TOK_LT: return "'<'"; case TOK_GT: return "'>'"; diff --git a/src/eigenscript.h b/src/eigenscript.h index f12db821e..e81467801 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -187,7 +187,8 @@ typedef enum { TOK_PLUS_EQ, TOK_MINUS_EQ, TOK_STAR_EQ, TOK_SLASH_EQ, TOK_PERCENT_EQ, TOK_AMP_EQ, TOK_BITOR_EQ, TOK_CARET_EQ, TOK_SHL_EQ, TOK_SHR_EQ, TOK_NEWLINE, TOK_INDENT, TOK_DEDENT, - TOK_EOF + TOK_EOF, + TOK_SLASH_SLASH, TOK_SLASH_SLASH_EQ /* #1758 N4/Q6: append; existing token IDs stay fixed */ } TokType; typedef struct { diff --git a/src/lexer.c b/src/lexer.c index 7f9233b61..566dd74df 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -221,7 +221,7 @@ static TokType keyword_type(const char *word) { } int tok_base_string_id_count(void) { - return (int)TOK_EOF + 1; + return (int)TOK_SLASH_SLASH_EQ + 1; } /* Recognised multi-char operators. Each operator is spelled once, as @@ -229,6 +229,7 @@ int tok_base_string_id_count(void) { #define LEX_MULTI_OP_MAP(X2, X3) \ X3(TOK_SHL_EQ, '<', '<', '=') \ X3(TOK_SHR_EQ, '>', '>', '=') \ + X3(TOK_SLASH_SLASH_EQ, '/', '/', '=') \ X2(TOK_EQ, '=', '=') \ X2(TOK_NE, '!', '=') \ X2(TOK_LE, '<', '=') \ @@ -239,6 +240,7 @@ int tok_base_string_id_count(void) { X2(TOK_MINUS_EQ, '-', '=') \ X2(TOK_STAR_EQ, '*', '=') \ X2(TOK_SLASH_EQ, '/', '=') \ + X2(TOK_SLASH_SLASH, '/', '/') \ X2(TOK_PERCENT_EQ, '%', '=') \ X2(TOK_AMP_EQ, '&', '=') \ X2(TOK_BITOR_EQ, '|', '=') \ @@ -355,6 +357,8 @@ const char* tok_base_string(TokType t) { case TOK_MINUS: return "- "; case TOK_STAR: return "* "; case TOK_SLASH: return "/ "; + case TOK_SLASH_SLASH: return "// "; + case TOK_SLASH_SLASH_EQ: return "//= "; case TOK_PERCENT: return "% "; case TOK_LT: return "< "; case TOK_GT: return "> "; diff --git a/src/parser.c b/src/parser.c index 1cb5a83f3..a203bf25d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -533,7 +533,7 @@ void free_ast(ASTNode *node) { } static int is_compound_assign(TokType t) { - return t >= TOK_PLUS_EQ && t <= TOK_SHR_EQ; + return (t >= TOK_PLUS_EQ && t <= TOK_SHR_EQ) || t == TOK_SLASH_SLASH_EQ; } static void compound_to_op(TokType t, char op[4]) { @@ -543,6 +543,7 @@ static void compound_to_op(TokType t, char op[4]) { case TOK_MINUS_EQ: op[0] = '-'; break; case TOK_STAR_EQ: op[0] = '*'; break; case TOK_SLASH_EQ: op[0] = '/'; break; + case TOK_SLASH_SLASH_EQ: op[0] = '/'; op[1] = '/'; break; case TOK_PERCENT_EQ: op[0] = '%'; break; case TOK_AMP_EQ: op[0] = '&'; break; case TOK_BITOR_EQ: op[0] = '|'; break; @@ -1177,11 +1178,13 @@ static ASTNode* parse_unary_body(Parser *p) { static ASTNode* parse_multiply(Parser *p) { ASTNode *left = parse_unary(p); - while (p_cur(p)->type == TOK_STAR || p_cur(p)->type == TOK_SLASH || p_cur(p)->type == TOK_PERCENT) { + while (p_cur(p)->type == TOK_STAR || p_cur(p)->type == TOK_SLASH || + p_cur(p)->type == TOK_SLASH_SLASH || p_cur(p)->type == TOK_PERCENT) { if (chain_too_deep(p)) break; char op[4] = {0}; if (p_cur(p)->type == TOK_STAR) op[0] = '*'; else if (p_cur(p)->type == TOK_SLASH) op[0] = '/'; + else if (p_cur(p)->type == TOK_SLASH_SLASH) { op[0] = '/'; op[1] = '/'; } else op[0] = '%'; Token *op_tok = p_advance(p); ASTNode *right = parse_unary(p); diff --git a/src/vm.c b/src/vm.c index bb2c6292a..bed02080f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -64,6 +64,16 @@ int vm_sandbox_work_charge(uint64_t amount) { return 1; } +/* #1758 N4: floor modulo. Avoid a - floor(a/b)*b: a/b can overflow or + * round across an integer boundary. As in Lua's luai_nummod, correct fmod's + * truncating remainder to have the divisor's sign. The executor uses only + * this floor result, never the truncating remainder. */ +static double vm_floor_mod(double a, double b) { + double rem = fmod(a, b); + if (rem != 0.0 && ((rem < 0.0) != (b < 0.0))) rem += b; + return rem; +} + /* #262 Phase-3 D: read the last-observed trajectory (dH, entropy) for the * observer loop-stall check. Prefers the slot model (the default); falls back * to the global last-observer Value when the slot isn't populated (e.g. a @@ -3196,6 +3206,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, [OP_TRUE] = &&lbl_TRUE, [OP_FALSE] = &&lbl_FALSE, [OP_ADD] = &&lbl_ADD, [OP_SUB] = &&lbl_SUB, [OP_MUL] = &&lbl_MUL, [OP_DIV] = &&lbl_DIV, [OP_MOD] = &&lbl_MOD, + [OP_IDIV] = &&lbl_IDIV, [OP_BAND] = &&lbl_BAND, [OP_BOR] = &&lbl_BOR, [OP_BXOR] = &&lbl_BXOR, [OP_SHL] = &&lbl_SHL, [OP_SHR] = &&lbl_SHR, [OP_NEG] = &&lbl_NEG, [OP_NOT] = &&lbl_NOT, [OP_BNOT] = &&lbl_BNOT, @@ -3573,19 +3584,73 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, DISPATCH(); } + CASE(IDIV): { + Value *b = vm_pop(); Value *a = vm_pop(); + if (val_is_number(a) && val_is_number(b)) { + if (a->type == VAL_INT && b->type == VAL_INT) { + int64_t ai = VAL_I64_RAW(a), bi = VAL_I64_RAW(b); + if (bi == 0) { + rt_error(EK_VALUE, current_line, "division by zero"); + vm_push(make_int(0)); + } else if (ai == INT64_MIN && bi == -1) { + rt_error(EK_VALUE, current_line, "integer overflow in '//'"); + vm_push(make_int(0)); + } else { + int64_t q = ai / bi, rem = ai % bi; + /* C truncates. A nonzero remainder with the opposite sign + * to the divisor moves the quotient down by one (N4). */ + if (rem != 0 && ((rem < 0) != (bi < 0))) q--; + vm_push(make_int(q)); + } + } else { + double divisor = eigs_num_arg(b, "floor division"); + /* #1758 comment 6294926822: exactly DIV's error through R1.4. + * N11 changes this float arm with DIV/MOD to IEEE floor(x/0). */ + if (divisor == 0.0) { + rt_error(EK_VALUE, current_line, "division by zero"); + vm_push(make_num(0)); + } else { + vm_push(make_num(num_guard(floor(eigs_num_arg(a, "floor division") / divisor)))); + } + } + } else { + rt_error(EK_TYPE, current_line, "cannot apply '//' to %s and %s", + val_type_name(a->type), val_type_name(b->type)); + vm_push(make_int(0)); + } + /* vm_pop owns both boxes, including INT64_MIN and a boxed divisor; + * every result and raise path releases both references. */ + val_decref(a); val_decref(b); + DISPATCH(); + } + CASE(MOD): { Value *b = vm_pop(); Value *a = vm_pop(); - if (val_is_number(a) && val_is_number(b) && eigs_num_arg(b, "modulo") != 0.0) { - double r = num_guard(fmod(eigs_num_arg(a, "modulo"), eigs_num_arg(b, "modulo"))); - if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } - if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } - vm_push(make_num(r)); + if (val_is_number(a) && val_is_number(b)) { + if (a->type == VAL_INT && b->type == VAL_INT) { + int64_t ai = VAL_I64_RAW(a), bi = VAL_I64_RAW(b); + if (bi == 0) { + rt_error(EK_VALUE, current_line, "modulo by zero"); + vm_push(make_int(0)); + } else { + /* N4b: x86 idiv faults for INT64_MIN / -1 even when only + * the remainder is needed. Handle it before C's %. */ + int64_t rem = bi == -1 ? 0 : ai % bi; + if (rem != 0 && ((rem < 0) != (bi < 0))) rem += bi; + vm_push(make_int(rem)); + } + } else { + double divisor = eigs_num_arg(b, "modulo"); + if (divisor == 0.0) { + rt_error(EK_VALUE, current_line, "modulo by zero"); + vm_push(make_num(0)); + } else { + vm_push(make_num(num_guard(vm_floor_mod(eigs_num_arg(a, "modulo"), divisor)))); + } + } } else { - if (!(val_is_number(a) && val_is_number(b))) - rt_error(EK_TYPE, current_line, "cannot apply '%%' to %s and %s", - val_type_name(a->type), val_type_name(b->type)); - else - rt_error(EK_VALUE, current_line, "modulo by zero"); + rt_error(EK_TYPE, current_line, "cannot apply '%%' to %s and %s", + val_type_name(a->type), val_type_name(b->type)); vm_push(make_num(0)); } val_decref(a); val_decref(b); diff --git a/src/vm.h b/src/vm.h index 5a8c7adc2..152768fe9 100644 --- a/src/vm.h +++ b/src/vm.h @@ -227,6 +227,7 @@ typedef enum { OP_INT_ZERO, /*obs:NONE*/ /* push int 0 */ OP_INT_ONE, /*obs:NONE*/ /* push int 1 */ OP_INT_CONST, /*obs:NONE*/ /* [idx:16] push int constant pool entry */ + OP_IDIV, /*obs:NONE*/ /* #1758 N4: floor division, appended */ OP_COUNT /* sentinel — number of opcodes */ } OpCode; diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 66ea93cf4..5f3d30d0e 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -274,7 +274,7 @@ gates (design §9.2). -> `[3.5, 3.0, "float"]` tag: `[3.5, 3, ...]` then `num_type` undefined (probed main for `[3.5, 3]`) - `N4.floordiv` [R1.4] `print of [7 // 2, -7 // 2, 7.5 // 2, num_type of (7 // 2), num_type of (7.5 // 2)]` - -> `[3, -4, 3.0, "int", "float"]` + -> `[3, -4, 3, "int", "float"]` (R1.4 text; N6 adds `.0` to the float at R1.7) tag: parse error, `unexpected '/'` (probed main) - `N4.floor-mod` [R1.4] `print of [-7 % 3, 7 % -3, -7.5 % 2, 7 % 3]` -> `[2, -2, 0.5, 1]` @@ -302,6 +302,17 @@ gates (design §9.2). tag: `3` (probed main) shape: F witness: fn-stop d DIV (SMI operands fail DIV's operand guard) ops: DIV +- `N4.fn-floordiv` [R1.4] a multi-statement `d(a, b)` returns `a // b`, called 60 times with `[-7.5, 2]`; print the value and kind + -> `[-4, "float"]` (R1.4 float text) + tag: parse error + shape: F witness: fn-stop d IDIV (the scanner's default refuses IDIV) ops: IDIV +- `N4.compound-floordiv` [R1.4] apply `//=` to a name, a dict field and list indices, with int and float operands of both signs + -> `[-4, -4, [-4, -4], "int", "float"]` + tag: parse error +- `N4.float-floordiv-zero-raises` [R1.4] float/mixed `// 0`, including `0.0 // 0.0` and negative zero + -> `["value", "division by zero"]` four times (same as `/`, until N11; #1758 comment 6294926822) + tag: parse error + ### N4b - `N4b.neg-min-raises` [R1.3] `m is -9223372036854775807 - 1 / {try print of (-m) catch}` -> `["value", true]`, the message naming the unary minus diff --git a/tests/phase2/rows/N4.compound-floordiv.eigs b/tests/phase2/rows/N4.compound-floordiv.eigs new file mode 100644 index 000000000..d3bbda151 --- /dev/null +++ b/tests/phase2/rows/N4.compound-floordiv.eigs @@ -0,0 +1,14 @@ +# ROW: N4.compound-floordiv +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +x is -7 +x //= 2 +d is {"x": 7.5} +d.x //= -2 +xs is [7, -7.5] +xs[0] //= -2 +xs[1] //= 2 +print of [x, d.x, xs, num_type of x, num_type of d.x] diff --git a/tests/phase2/rows/N4.compound-floordiv.out b/tests/phase2/rows/N4.compound-floordiv.out new file mode 100644 index 000000000..5e7764260 --- /dev/null +++ b/tests/phase2/rows/N4.compound-floordiv.out @@ -0,0 +1 @@ +[-4, -4, [-4, -4], "int", "float"] diff --git a/tests/phase2/rows/N4.float-floordiv-zero-raises.eigs b/tests/phase2/rows/N4.float-floordiv-zero-raises.eigs new file mode 100644 index 000000000..21371e513 --- /dev/null +++ b/tests/phase2/rows/N4.float-floordiv-zero-raises.eigs @@ -0,0 +1,11 @@ +# ROW: N4.float-floordiv-zero-raises +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +for pair in [[1.0, 0], [0.0, 0.0], [7, 0.0], [1.0, -0.0]]: + try: + print of (pair[0] // pair[1]) + catch e: + print of [e.kind, e.message] diff --git a/tests/phase2/rows/N4.float-floordiv-zero-raises.out b/tests/phase2/rows/N4.float-floordiv-zero-raises.out new file mode 100644 index 000000000..73f961180 --- /dev/null +++ b/tests/phase2/rows/N4.float-floordiv-zero-raises.out @@ -0,0 +1,4 @@ +["value", "division by zero"] +["value", "division by zero"] +["value", "division by zero"] +["value", "division by zero"] diff --git a/tests/phase2/rows/N4.floor-mod.eigs b/tests/phase2/rows/N4.floor-mod.eigs new file mode 100644 index 000000000..c03b313fa --- /dev/null +++ b/tests/phase2/rows/N4.floor-mod.eigs @@ -0,0 +1,7 @@ +# ROW: N4.floor-mod +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [-7 % 3, 7 % -3, -7.5 % 2, 7 % 3] diff --git a/tests/phase2/rows/N4.floor-mod.out b/tests/phase2/rows/N4.floor-mod.out new file mode 100644 index 000000000..c67209e7a --- /dev/null +++ b/tests/phase2/rows/N4.floor-mod.out @@ -0,0 +1 @@ +[2, -2, 0.5, 1] diff --git a/tests/phase2/rows/N4.floordiv.eigs b/tests/phase2/rows/N4.floordiv.eigs new file mode 100644 index 000000000..35dcf9fb9 --- /dev/null +++ b/tests/phase2/rows/N4.floordiv.eigs @@ -0,0 +1,7 @@ +# ROW: N4.floordiv +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [7 // 2, -7 // 2, 7.5 // 2, num_type of (7 // 2), num_type of (7.5 // 2)] diff --git a/tests/phase2/rows/N4.floordiv.out b/tests/phase2/rows/N4.floordiv.out new file mode 100644 index 000000000..f13b0757d --- /dev/null +++ b/tests/phase2/rows/N4.floordiv.out @@ -0,0 +1 @@ +[3, -4, 3, "int", "float"] diff --git a/tests/phase2/rows/N4.fn-floor-mod.eigs b/tests/phase2/rows/N4.fn-floor-mod.eigs new file mode 100644 index 000000000..af80c94ff --- /dev/null +++ b/tests/phase2/rows/N4.fn-floor-mod.eigs @@ -0,0 +1,16 @@ +# ROW: N4.fn-floor-mod +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop m MOD +# OPS: MOD +define m(a, b) as: + warm is 0.5 + t is a % b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is m of [-7, 3] + i is i + 1.0 +print of [r, m of [-7.5, 2]] diff --git a/tests/phase2/rows/N4.fn-floor-mod.out b/tests/phase2/rows/N4.fn-floor-mod.out new file mode 100644 index 000000000..ede3ad8ce --- /dev/null +++ b/tests/phase2/rows/N4.fn-floor-mod.out @@ -0,0 +1 @@ +[2, 0.5] diff --git a/tests/phase2/rows/N4.fn-floordiv.eigs b/tests/phase2/rows/N4.fn-floordiv.eigs new file mode 100644 index 000000000..f516e14d7 --- /dev/null +++ b/tests/phase2/rows/N4.fn-floordiv.eigs @@ -0,0 +1,16 @@ +# ROW: N4.fn-floordiv +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop d IDIV +# OPS: IDIV +define d(a, b) as: + warm is 0.5 + t is a // b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is d of [-7.5, 2] + i is i + 1.0 +print of [r, num_type of r] diff --git a/tests/phase2/rows/N4.fn-floordiv.out b/tests/phase2/rows/N4.fn-floordiv.out new file mode 100644 index 000000000..e25c371f9 --- /dev/null +++ b/tests/phase2/rows/N4.fn-floordiv.out @@ -0,0 +1 @@ +[-4, "float"] diff --git a/tests/phase2/rows/N4.int-floordiv-zero-raises.eigs b/tests/phase2/rows/N4.int-floordiv-zero-raises.eigs new file mode 100644 index 000000000..128a6923b --- /dev/null +++ b/tests/phase2/rows/N4.int-floordiv-zero-raises.eigs @@ -0,0 +1,10 @@ +# ROW: N4.int-floordiv-zero-raises +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +try: + print of (7 // 0) +catch e: + print of e.kind diff --git a/tests/phase2/rows/N4.int-floordiv-zero-raises.out b/tests/phase2/rows/N4.int-floordiv-zero-raises.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/rows/N4.int-floordiv-zero-raises.out @@ -0,0 +1 @@ +value diff --git a/tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.eigs b/tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.eigs new file mode 100644 index 000000000..5d5c402b1 --- /dev/null +++ b/tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.eigs @@ -0,0 +1,11 @@ +# ROW: N4b.floordiv-min-by-neg1-raises +# ITEMS: N4b +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +m is -9223372036854775807 - 1 +try: + print of (m // -1) +catch e: + print of [e.kind, (index_of of [e.message, "//"]) >= 0] diff --git a/tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.out b/tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.out new file mode 100644 index 000000000..56efea05e --- /dev/null +++ b/tests/phase2/rows/N4b.floordiv-min-by-neg1-raises.out @@ -0,0 +1 @@ +["value", true] diff --git a/tests/phase2/rows/N4b.min-mod-neg1-zero.eigs b/tests/phase2/rows/N4b.min-mod-neg1-zero.eigs new file mode 100644 index 000000000..3c9ea8013 --- /dev/null +++ b/tests/phase2/rows/N4b.min-mod-neg1-zero.eigs @@ -0,0 +1,8 @@ +# ROW: N4b.min-mod-neg1-zero +# ITEMS: N4b +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +m is -9223372036854775807 - 1 +print of [m % -1, num_type of (m % -1)] diff --git a/tests/phase2/rows/N4b.min-mod-neg1-zero.out b/tests/phase2/rows/N4b.min-mod-neg1-zero.out new file mode 100644 index 000000000..d44312f4b --- /dev/null +++ b/tests/phase2/rows/N4b.min-mod-neg1-zero.out @@ -0,0 +1 @@ +[0, "int"] diff --git a/tests/sections/0fq-floor-division-1758.sh b/tests/sections/0fq-floor-division-1758.sh new file mode 100644 index 000000000..612836880 --- /dev/null +++ b/tests/sections/0fq-floor-division-1758.sh @@ -0,0 +1,13 @@ +# #1758 N4: integer/float floor division, floor modulo, compound targets, +# boxed-int success and raise ownership. Strictly leak-clean, as [87]. +echo "[0fq] Floor division and modulo (#1758 N4)" +check_binary_fingerprint +TOTAL=$((TOTAL + 1)) +FLOOR_OUT=$(suite_program_run test_floor_division.eigs $EIGS_TMO ./eigenscript "$TESTS_DIR/test_floor_division.eigs" &1); FLOOR_RC=$? +if [ "$FLOOR_RC" -eq 0 ] && [ "$(lsan_classify_name "$FLOOR_OUT")" = none ] && grep -q '^All tests passed' <<< "$FLOOR_OUT"; then + PASS=$((PASS + 1)); echo " PASS: floor arithmetic and boxed ownership (leak-clean)" +else + FAIL=$((FAIL + 1)); echo " FAIL: floor arithmetic rc=$FLOOR_RC" + printf '%s\n' "$FLOOR_OUT" | eigs_failure_output +fi +echo "" diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py index e766a4605..4ca4edb39 100644 --- a/tests/test_doc_examples.py +++ b/tests/test_doc_examples.py @@ -324,10 +324,10 @@ def is_asan_build(): # --------------------------------------------------------------------------- POPULATION = { # file fences paired fragment nocheck value-comments - "README.md": ( 7, 3, 4, 0, 0), - "docs/llms.txt": ( 9, 6, 2, 1, 0), - "docs/SPEC.md": ( 85, 81, 1, 3, 0), # #1740: +1 paired (bitwise exact-int raises) - "docs/COMPARISON.md": ( 19, 18, 1, 0, 0), + "README.md": ( 8, 4, 4, 0, 0), + "docs/llms.txt": ( 10, 7, 2, 1, 0), + "docs/SPEC.md": ( 86, 82, 1, 3, 0), # #1740: +1 paired (bitwise exact-int raises) + "docs/COMPARISON.md": ( 20, 19, 1, 0, 0), "docs/CONCURRENCY.md": ( 8, 8, 0, 0, 0), # #1736: +1 paired (detached task catches its own error) "docs/STDLIB.md": ( 15, 7, 8, 0, 0), "docs/SYNTAX.md": ( 35, 15, 20, 0, 1), diff --git a/tests/test_floor_division.eigs b/tests/test_floor_division.eigs new file mode 100644 index 000000000..02e7dd941 --- /dev/null +++ b/tests/test_floor_division.eigs @@ -0,0 +1,123 @@ +# #1758 N4/N4b/Q6: exact floor arithmetic and owned boxed operands. +load_file of "lib/test.eigs" + +assert_eq of [7 // 2, 3, "int floor division"] +assert_eq of [-7 // 2, -4, "negative dividend floors"] +assert_eq of [7 // -2, -4, "negative divisor floors"] +assert_eq of [-7 // -2, 3, "two negatives"] +assert_eq of [7 + 9 // 2 * 3, 19, "multiplicative precedence"] +assert_eq of [24 / 3 // 2, 4, "multiplicative left associativity"] +assert_eq of [num_type of (7 // 2), "int", "int quotient kind"] +assert_eq of [num_type of (7.0 // 2), "float", "mixed quotient kind"] +assert_eq of [num_type of (7 // 2.0), "float", "reverse mixed quotient kind"] +assert_eq of [-7.5 // 2, -4, "float quotient floors"] +assert_eq of [-7 % 3, 2, "N4 positive divisor remainder"] +assert_eq of [7 % -3, -2, "N4 negative divisor remainder"] +assert_eq of [-7.5 % 2, 0.5, "N4 float remainder"] +assert_eq of [7.5 % -2, -0.5, "N4 negative float divisor"] +assert_eq of [num_type of (7 % 3), "int", "int remainder kind"] +assert_eq of [num_type of (7.0 % 3), "float", "mixed remainder kind"] +assert_eq of [1e300 % 3.0, 0, "remainder without overflowing the quotient product"] + +# Independent small-number quotient oracle; identity and sign cover every +# sign combination and exact multiples without permitting C truncation. +for a in range of [-30, 31]: + for b in range of [-7, 8]: + if b != 0: + q is a // b + rem is a % b + assert_eq of [q, floor of (a / b), "small quotient oracle"] + assert_eq of [q * b + rem, a, "division/modulo identity"] + assert of [rem == 0 or ((rem > 0) == (b > 0)), "divisor sign"] + +# Exact boxed int cases: generated from Python integer // and %, so no +# float round-trip can agree accidentally above 2^53. +assert_eq of [9007199254740993 // 3, 3002399751580331, "boxed quotient"] +assert_eq of [9007199254740993 % 3, 0, "boxed remainder"] +assert_eq of [-9007199254740993 // 3, -3002399751580331, "boxed quotient"] +assert_eq of [-9007199254740993 % 3, 0, "boxed remainder"] +assert_eq of [9223372036854775807 // -3, -3074457345618258603, "boxed quotient"] +assert_eq of [9223372036854775807 % -3, -2, "boxed remainder"] +assert_eq of [(-9223372036854775807 - 1) // 3, -3074457345618258603, "boxed quotient"] +assert_eq of [(-9223372036854775807 - 1) % 3, 1, "boxed remainder"] +assert_eq of [(-9223372036854775807 - 1) % -1, 0, "boxed remainder"] +assert_eq of [1 // (-9223372036854775807 - 1), -1, "boxed quotient"] +assert_eq of [1 % (-9223372036854775807 - 1), -9223372036854775807, "boxed remainder"] +assert_eq of [-1 // 9223372036854775807, -1, "boxed quotient"] +assert_eq of [-1 % 9223372036854775807, 9223372036854775806, "boxed remainder"] +assert_eq of [(-9223372036854775807 - 1) // 9223372036854775807, -2, "boxed quotient"] +assert_eq of [(-9223372036854775807 - 1) % 9223372036854775807, 9223372036854775806, "boxed remainder"] + +# Q6: the existing compound-assignment target machinery must carry //. +x is -7 +x //= 2 +assert_eq of [x, -4, "name //="] +d is {"x": 7.5} +d.x //= -2 +assert_eq of [d.x, -4, "field //="] +xs is [7, -7.5] +xs[0] //= -2 +xs[1] //= 2 +assert_eq of [xs, [-4, -4], "index //="] +assert_eq of [num_type of xs[1], "float", "compound float kind"] + +# Fresh boxed operands in success and catch paths. Repeated calls make a +# missing decref measurable under LSan rather than hidden by live globals. +define boxed(n) as: + return 9223372036854775807 - n +for k in range of [0, 80]: + large is boxed of k + assert_eq of [large % -1, 0, "boxed modulo special divisor"] + assert_eq of [large // 1, large, "boxed quotient retained"] + for op in ["//", "%"]: + caught is false + try: + if op == "//": + unused is (boxed of k) // 0 + else: + unused is (boxed of k) % 0 + catch e: + caught is e.kind == "value" + assert_eq of [caught, true, "boxed zero divisor raises"] + caught is false + try: + unused is (-9223372036854775807 - 1) // -1 + catch e: + caught is e.kind == "value" and (index_of of [e.message, "//"]) >= 0 + assert_eq of [caught, true, "N4b quotient overflow names operator"] + for operands in [[boxed of k, "bad"], ["bad", boxed of k]]: + caught is false + try: + unused is operands[0] // operands[1] + catch e: + caught is e.kind == "type_mismatch" + assert_eq of [caught, true, "boxed // type error owns both operands"] + caught is false + try: + unused is operands[0] % operands[1] + catch e: + caught is e.kind == "type_mismatch" + assert_eq of [caught, true, "boxed % type error owns both operands"] + +# #1758 comment 6294926822: all zero divisors raise in R1.4, including +# float/mixed // and //=; / and % retain their existing errors until N11. +for pair in [[1.0, 0], [0.0, 0.0], [7, 0.0], [1.0, -0.0]]: + for op in ["//", "/", "%", "//="]: + caught is false + try: + if op == "//": + unused is pair[0] // pair[1] + elif op == "/": + unused is pair[0] / pair[1] + elif op == "%": + unused is pair[0] % pair[1] + else: + local zz is pair[0] + zz //= pair[1] + catch e: + caught is e.kind == "value" and e.message == "division by zero" + if op == "%": + caught is e.kind == "value" and e.message == "modulo by zero" + assert_eq of [caught, true, "zero-divisor error compatibility"] + +test_summary of null diff --git a/tests/test_fmt.sh b/tests/test_fmt.sh index d57f6e198..8df2846ef 100644 --- a/tests/test_fmt.sh +++ b/tests/test_fmt.sh @@ -131,6 +131,10 @@ EXPECTED=$(printf 'x is 1 + 2\n') check "--write mode" "$ACTUAL" "$EXPECTED" rm -f "$TMPFILE" +# #1758 N4/Q6: formatter inherits the lexer's single operator table. +ACTUAL=$(fmt_str "$(printf 'x is -7//2\nx//=2\n')") +check "// and //= spaced whole" "$ACTUAL" "$(printf 'x is -7 // 2\nx //= 2\n')" + # --- Multi-char operators must not be split (#729) --- # The third pass of fix_spacing is character-level; any operator missing from # its multi-char table gets split by the single-char branches, which silently diff --git a/tests/test_lint.sh b/tests/test_lint.sh index df144cd20..ed9fdffe5 100644 --- a/tests/test_lint.sh +++ b/tests/test_lint.sh @@ -2648,6 +2648,17 @@ check_contains "#1251 W019 names the interrogative's own line" "$OUTPUT" ":6: wa check_contains "#1251 W019 names 'prev of's own line" "$OUTPUT" ":8: warning\[W019\]: interrogative 'prev of" rm -f "$TMPFILE" +# #1758 N4/Q6: lint uses the same parser; retain diagnostics for the new tokens. +TMPFILE=$(mktemp /tmp/eigs_floor_lint_XXXXXX.eigs) +printf 'x is -7 // 2\nx //= 2\nprint of x\n' > "$TMPFILE" +FLOOR_LINT_RC=0 +OUTPUT=$("$EIGS" --lint "$TMPFILE" 2>&1) || FLOOR_LINT_RC=$? +check_status "// and //= lint clean" "$FLOOR_LINT_RC" 0 +printf 'x is // 2\n' > "$TMPFILE" +OUTPUT=$("$EIGS" --lint "$TMPFILE" 2>&1) || true +check_contains "unexpected // diagnostic names the token" "$OUTPUT" "unexpected '//'" +rm -f "$TMPFILE" + # --- #1121 ledger: no child of this file may have tripped a sanitizer --- # One check, covering every linter invocation above rather than a sample. In a # release build no file is ever written and this passes trivially, which is diff --git a/tests/test_lsp.py b/tests/test_lsp.py index 69b31ef94..6fbd6a022 100755 --- a/tests/test_lsp.py +++ b/tests/test_lsp.py @@ -244,6 +244,10 @@ def main(): r = converse([INIT, did_open("x is 5\nprint of x\n"), SHUTDOWN, EXIT]) check("clean document → empty diagnostics", diagnostics(r) == []) + # #1758 N4/Q6: shared tokenizer/parser/compiler accept both new spellings. + r = converse([INIT, did_open("x is -7 // 2\nx //= 2\nprint of x\n"), SHUTDOWN, EXIT]) + check("floor division and compound assignment have clean diagnostics", diagnostics(r) == []) + # #1366: these are capacity/stack invariants rather than observable LSP # semantics at today's 16-parameter parser cap. Pin the shared bound and # heap allocation so neither can silently regress while behavior stays green. diff --git a/tests/test_opcode_abi.c b/tests/test_opcode_abi.c index 77ca2af75..0ff015f9f 100644 --- a/tests/test_opcode_abi.c +++ b/tests/test_opcode_abi.c @@ -39,6 +39,8 @@ ABI_ASSERT(OP_FALSE, 96); ABI_ASSERT(OP_INT_ZERO, 97); ABI_ASSERT(OP_INT_ONE, 98); ABI_ASSERT(OP_INT_CONST, 99); +/* #1758 N4: append-only floor division; no descriptor ABI bump. */ +ABI_ASSERT(OP_IDIV, 100); /* #704: the revision the ABI-stamped descriptors in the .eigs fixtures under * tests/ declare. Those From 3bd8c8d1225d7d3f1be4b229f7ee0ba87a13b70e Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 11:04:31 -0500 Subject: [PATCH 082/188] Witness and declare N4 changes in successful stdlib values The existing int-domain differential compared only OK/RAISE and types, so it could pass over every changed negative remainder. Derive modulo users and named callers from module source and compare their successful JSON values, preserving the original all-export overflow check. Add negative boundary and typed entry probes, including supervision's observer feed. Declare eleven changed public functions as N4 with their domains and reasons; missing and unused declarations fail separately. Document the source-closure/range boundary rather than claiming general semantic reachability. Validation: phase2-lib-diff modules=78 functions=889 calls=281423, examined=281423 unexamined=0. N4 source_functions=28 exported_functions=19, calls=4631 both_ok=2500 changed_functions=11. listed_functions=12 undeclared=0 stale=0 PASS; factorial is the retained (A) declaration. Syntax and whitespace checks green. Mutation calibration follows as part of the round acceptance before bundle delivery. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 15 +++ tests/phase2/lib_floor_mod.txt | 14 +++ tools/phase2_lib_diff.sh | 195 +++++++++++++++++++++++++++++---- 3 files changed, 205 insertions(+), 19 deletions(-) create mode 100644 tests/phase2/lib_floor_mod.txt diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index bbf687b17..5fd57fb52 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2607,6 +2607,21 @@ answered. A grep cannot find the second kind, so this is a differential. `poisson.pmf` (the oracle). Calibration: the int `SPEED_OF_LIGHT` planted back lists `rest_energy` UNDECLARED; a declaration for `permutations` is STALE. +- **R1.4, N4 successful value changes.** The original OK/RAISE differential + cannot see a changed successful remainder. The same tool now derives a + conservative modulo-user/named-caller closure from the tracked module + source (including private helpers), and compares JSON result values for + its exported functions, ignoring only numeric-kind differences. Every + changed function needs an `N4:` reason in + `tests/phase2/lib_floor_mod.txt`; an unused declaration is STALE. The + integer-domain raise declarations remain independent and unchanged. + Negative boundary probes (-7 and -719469) reach weekday and civil-era + boundaries missed by [-3, 110]. Typed probes cover the meta-interpreter's + source/AST entry points, accepted negative numeric checksum buffers, and + supervision's negative heartbeat observer feed as well as its return. + The closure is conservative by name, not a full resolver; the release + census reviews dynamic dispatch and caller domains separately. Successful + values outside that closure remain outside this extra N4 comparison. - **Range boundary:** ints at most 110 keep a polynomial of degree 9 in the caller's own ints inside int64, so a listed call points at the library. A literal that overflows only for larger arguments is not seen. diff --git a/tests/phase2/lib_floor_mod.txt b/tests/phase2/lib_floor_mod.txt new file mode 100644 index 000000000..d7d4051cc --- /dev/null +++ b/tests/phase2/lib_floor_mod.txt @@ -0,0 +1,14 @@ +# N4 successful stdlib value changes (#1758). TSV: module.function, N4: reason. +# phase2_lib_diff.sh derives modulo users and named callers from source; each +# declaration must be exercised by a changed successful result or is stale. +datetime.days_from_civil N4: _fdiv and month normalization now floor negative years/months in the civil-date formula. +datetime.civil_from_days N4: _fdiv now floors negative era offsets for dates before the civil epoch. +datetime.weekday_from_days N4: days before -4 now map to the non-negative weekday index (days + 4) % 7. +datetime.epoch_from_civil N4: inherits days_from_civil's floor corrections for negative years/months. +datetime.civil_from_epoch N4: _fdiv floors negative epoch seconds to the previous day with a non-negative remainder. +eigen.eigen_eval N4: the meta-interpreter's % binop inherits host floor modulo for opposite-sign operands. +eigen.eigen_run N4: running source through eigen_eval inherits host floor modulo for opposite-sign operands. +checksum.adler32 N4: accepted numeric buffers can contain negative non-byte samples; their modulo residues now floor (documented byte inputs are unchanged). +checksum.sum8 N4: accepted numeric buffers can contain negative non-byte samples; their modulo residues now floor (documented byte inputs are unchanged). +supervise.supervise_step N4: a negative heartbeat's bounded observer signature now uses the non-negative progress % 8 residue. +supervise.supervise_run N4: inherits supervise_step's changed observer feed for negative heartbeat progress. diff --git a/tools/phase2_lib_diff.sh b/tools/phase2_lib_diff.sh index 6899b24c6..619fa454a 100755 --- a/tools/phase2_lib_diff.sh +++ b/tools/phase2_lib_diff.sh @@ -13,10 +13,16 @@ # Each listed function must be an integer-domain function declared in # tests/phase2/lib_int_domain.txt (decision (A): int overflow raises), and each # declaration must be listed (a stale one fails). Every other listing fails. +# N4 also compares successful JSON values (numeric kinds compare equal) for +# the source-derived closure of modulo users. Negative-boundary and evaluator +# probes reach paths the uniform int sweep cannot. Changes require an N4 reason +# in lib_floor_mod.txt; unused declarations fail. The final summary keeps the +# original contract consumed by phase2_ci.sh and includes both kinds of change. set -eu cd "$(dirname "$0")/.." exec python3 - "$@" <<'PY' import argparse +import json import os from pathlib import Path import re @@ -46,14 +52,22 @@ for arm in ('main', 'branch'): if not p.is_file() or not os.access(p, os.X_OK): fail('not an executable: %s' % p) bins[arm] = str(p.resolve()) -declared = {} -for n, line in enumerate((root / 'tests/phase2/lib_int_domain.txt').read_text().splitlines(), 1): - if not line.strip() or line.startswith('#'): - continue - f = line.split('\t') - if len(f) != 2 or not re.fullmatch(r'\w+\.\w+', f[0]) or not f[1].strip() or f[0] in declared: - fail('lib_int_domain.txt:%d: want one "module.functionreason" row per function' % n) - declared[f[0]] = f[1].strip() +def declarations(name, rule=None): + rows = {} + for n, line in enumerate((root / 'tests/phase2' / name).read_text().splitlines(), 1): + if not line.strip() or line.startswith('#'): + continue + f = line.split('\t') + if len(f) != 2 or not re.fullmatch(r'\w+\.\w+', f[0]) or not f[1].strip() or f[0] in rows: + fail('%s:%d: want one "module.functionreason" row per function' % (name, n)) + if rule and not f[1].startswith(rule + ': '): + fail('%s:%d: reason must name %s' % (name, n, rule)) + rows[f[0]] = f[1].strip() + return rows + + +declared = declarations('lib_int_domain.txt') +floor_declared = declarations('lib_floor_mod.txt', 'N4') mods = sorted(m for m in subprocess.check_output(['git', 'ls-files', '-z', 'lib/*.eigs'], cwd=root).decode().split('\0') if re.fullmatch(r'lib/[a-z_0-9]+\.eigs', m)) @@ -95,8 +109,24 @@ def tuples(arity): return sorted(dict.fromkeys(rows), key=lambda t: (max(abs(x) for x in t), t)) +def same_value(a, b): + # Ignore only the intended numeric-kind distinction, recursively. Python's + # plain equality would also treat true as 1 and hide a semantic change. + if type(a) in (int, float) and type(b) in (int, float): + return a == b + if type(a) is not type(b): + return False + if isinstance(a, list): + return len(a) == len(b) and all(same_value(x, y) for x, y in zip(a, b)) + if isinstance(a, dict): + return a.keys() == b.keys() and all(same_value(a[k], b[k]) for k in a) + return a == b + + def call_text(mod, fn, t): - a = str(t[0]) if len(t) == 1 else '[%s]' % ', '.join(map(str, t)) + if isinstance(t, dict): + return 'r is ' + t['call'] + a = t if isinstance(t, str) else (str(t[0]) if len(t) == 1 else '[%s]' % ', '.join(map(str, t))) return 'r is %s.%s of %s' % (mod, fn, a) @@ -104,6 +134,79 @@ define_re = re.compile(r'^define ([A-Za-z_]\w*)(?:\(([^)]*)\))? as:', re.M) own = {m: {name: 1 if params is None else len([p for p in params.split(',') if p.strip()]) for name, params in define_re.findall((root / m).read_text()) if not name.startswith('_')} for m in mods} +# A conservative named-reference closure: include private helpers and callbacks, +# not only `f of` calls. Ordinary strings and comments cannot seed a modulo user; +# f-string contents remain visible so an interpolated `%` cannot be missed. +# Over-approximation can add comparisons but never waive a changed result. +def code_only(source): + pattern = r'#[^\n]*|(?:f)?"(?:\\.|[^"\\])*"|(?:f)?\'(?:\\.|[^\'\\])*\'' + def mask(match): + text = match[0] + return text if text.startswith(('f"', "f'")) else re.sub(r'[^\n]', ' ', text) + return re.sub(pattern, mask, source) + + +bodies = {} +for m in mods: + source = code_only((root / m).read_text()) + definitions = list(define_re.finditer(source)) + for match in definitions: + end = match.end() + # A function ends at the next nonblank, nonindented source line. + for line in source[end:].splitlines(keepends=True): + if line.strip() and not line[0].isspace(): + break + end += len(line) + bodies[(m, match[1])] = source[match.start():end] +by_name = {} +for key in bodies: + by_name.setdefault(key[1], set()).add(key) +refs = {key: set().union(*(by_name.get(name, set()) for name in re.findall(r'\b[A-Za-z_]\w*\b', body))) - {key} + for key, body in bodies.items()} +floor_scope = {key for key, body in bodies.items() if '%' in body} +while True: + widened = floor_scope | {key for key in bodies if refs[key] & floor_scope} + if widened == floor_scope: + break + floor_scope = widened +if not floor_scope: + fail('no modulo function found in tracked stdlib sources') +# These are public API input shapes, not exemptions. They exercise the two +# meta-interpreter entries whose numeric int arguments cannot reach a binop. +floor_inputs = { + ('lib/checksum.eigs', 'adler32'): ['buf_from_list of ([-7.0, 2.0])'], + ('lib/checksum.eigs', 'sum8'): ['buf_from_list of ([-7.0, 2.0])'], + ('lib/supervise.eigs', 'supervise_step'): [{'call': '_phase2_negative_step of []'}], + ('lib/supervise.eigs', 'supervise_run'): [{'call': '_phase2_negative_run of []'}], + ('lib/eigen.eigs', 'eigen_eval'): ['[["binop", "%", ["num", -7], ["num", 3]], {}]', + '[["binop", "%", ["num", 7], ["num", -3]], {}]', + '[["binop", "%", ["num", -7.5], ["num", 2]], {}]', + '[["binop", "%", ["num", 7.5], ["num", -2]], {}]'], + ('lib/eigen.eigs', 'eigen_run'): ['"return -7 % 3"', '"return 7 % -3"', + '"return -7.5 % 2"', '"return 7.5 % -2"'], +} +# A negative heartbeat changes an observer feed even when this tick's returned +# restart count is still zero. Observe the feed and the public result together; +# one cooperative task is alive for the tick and explicitly killed afterwards. +floor_prelude = {} +for fn, call in (('supervise_step', 'supervise_step of sup'), + ('supervise_run', 'supervise_run of [sup, 1]')): + suffix = 'step' if fn == 'supervise_step' else 'run' + floor_prelude[('lib/supervise.eigs', fn)] = ( + 'load_file of "lib/supervise.eigs"\n' + 'define _phase2_worker(slot) as:\n' + ' task_yield of null\n' + ' return null\n' + 'define _phase2_negative_%s() as:\n' + ' local sup is supervisor_new of 0\n' + ' local child is supervise of [sup, _phase2_worker, 0]\n' + ' heartbeat of [0, -7]\n' + ' local result is %s\n' + ' task_kill of child.id\n' + ' return [result, _sup_o0]\n' % (suffix, call)) +for key in floor_inputs: + if key not in floor_scope or key[1] not in own.get(key[0], {}): + fail('N4 API probe no longer belongs to an exported modulo user: %s.%s' % key) defined_anywhere = set().union(*own.values()) # The one module that is not a library: importing it runs a command line. NOT_LIBRARY = {'lib/pkg.eigs': 'the `eigenscript --pkg` command; importing it runs the CLI'} @@ -137,32 +240,62 @@ for m in mods: if via is None: skipped.setdefault(m, []).append(fn) else: - plan.append((via, fn, arity)) + plan.append((m, via, fn, arity)) if set(skipped) != set(NOT_LIBRARY) or not set(NOT_LIBRARY) <= set(unimportable): fail('unexamined modules %s != the declared non-library modules %s' % (sorted(skipped), sorted(NOT_LIBRARY))) counts = dict(modules=len(mods), importable=len(ns), functions=len(plan), - via_reexport=sum(via not in own or fn not in own[via] for via, fn, _ in plan), + via_reexport=sum(via not in own or fn not in own[via] for _, via, fn, _ in plan), no_params=0, calls=0, examined=0, unexamined=0, both_ok=0, both_raise=0, improved=0) -listed, unexamined = {}, {} -for via, fn, arity in plan: +listed, unexamined, floor_changed = {}, {}, {} +floor_functions, floor_calls, floor_both_ok = 0, 0, 0 +for source, via, fn, arity in plan: mod = Path(via).stem if arity == 0: counts['no_params'] += 1 continue calls = tuples(arity) - text = 'import %s\n' % mod + ''.join( - 'try:\n %s\n print of f"R %d OK {type of r}"\ncatch e:\n print of f"R %d RAISE {e}"\n' - % (call_text(mod, fn, t), i, i) for i, t in enumerate(calls)) + compare_value = (source, fn) in floor_scope + if compare_value: + floor_functions += 1 + # -7 reaches weekday_from_days; -719469 crosses civil_from_days' + # epoch offset and exposes its private _fdiv's negative dividend. + for n in (-7, -719469): + calls += [(n,) * arity] + calls += [tuple(n if i == j else 1 for i in range(arity)) for j in range(arity)] + calls = list(dict.fromkeys(calls)) + floor_inputs.get((source, fn), []) + value_line = ' print of f"V %d {json_encode of r}"\n' if compare_value else '' + # load_file exposes private observer state in the targeted supervision + # probe and also defines a function named supervise. Preserve the import + # namespace before that definition so the original int sweep is unchanged. + prelude = floor_prelude.get((source, fn), '') + call_mod = '_phase2_libdiff_module' if prelude else mod + header = 'import %s\n' % mod + if prelude: + header += '_phase2_libdiff_module is %s\n' % mod + text = header + prelude + ''.join( + ('try:\n %s\n print of f"R %d OK {type of r}"\n' % (call_text(call_mod, fn, t), i)) + + (value_line % i if compare_value else '') + + ('catch e:\n print of f"R %d RAISE {e}"\n' % i) for i, t in enumerate(calls)) res = {} for arm in bins: rc, out = run(arm, 'call_%s_%s' % (mod, fn), text) - got = {} + got, values = {}, {} for line in out: r = re.match(r'R (\d+) (OK|RAISE) ?(.*)$', line) if r and int(r[1]) < len(calls) and int(r[1]) not in got: got[int(r[1])] = (r[2], r[3]) - res[arm] = (rc, got) + v = re.match(r'V (\d+) (.*)$', line) + if v and int(v[1]) < len(calls): + if int(v[1]) in values: + fail('duplicate N4 value from %s %s.%s call %s' % (arm, mod, fn, v[1])) + try: + values[int(v[1])] = json.loads(v[2]) + except ValueError: + fail('non-JSON N4 value from %s %s.%s: %s' % (arm, mod, fn, line)) + res[arm] = (rc, got, values) counts['calls'] += len(calls) + if compare_value: + floor_calls += len(calls) for i, t in enumerate(calls): a, b = res['main'][1].get(i), res['branch'][1].get(i) if a is None or (a[0] == 'RAISE' and b is None): @@ -175,6 +308,15 @@ for via, fn, arity in plan: listed.setdefault('%s.%s' % (mod, fn), []).append('%s -> %s' % (call_text(mod, fn, t)[5:], why)) elif a[0] == b[0] == 'OK': counts['both_ok'] += 1 + if compare_value: + floor_both_ok += 1 + if i not in res['main'][2] or i not in res['branch'][2]: + fail('missing successful N4 value for %s.%s call %d' % (mod, fn, i)) + av, bv = res['main'][2][i], res['branch'][2][i] + if not same_value(av, bv): + floor_changed.setdefault('%s.%s' % (mod, fn), []).append( + '%s -> %s (main) / %s (branch)' % (call_text(mod, fn, t)[5:], + json.dumps(av), json.dumps(bv))) elif a[0] == b[0]: counts['both_raise'] += 1 else: @@ -193,10 +335,25 @@ for fn in sorted(listed): for fn in sorted(set(declared) - set(listed)): bad += 1 print(' STALE %s: declared integer-domain, but no call raises on the branch only' % fn) +print('phase2-lib-diff: N4 source_functions=%d exported_functions=%d calls=%d both_ok=%d changed_functions=%d' % ( + len(floor_scope), floor_functions, floor_calls, floor_both_ok, len(floor_changed))) +for fn in sorted(floor_changed): + tag = 'N4' if fn in floor_declared else 'UNDECLARED-N4' + bad += fn not in floor_declared + print(' %s %s: %d successful value change(s); first: %s%s' % ( + tag, fn, len(floor_changed[fn]), floor_changed[fn][0], + ' (%s)' % floor_declared[fn] if fn in floor_declared else '')) +for fn in sorted(set(floor_declared) - set(floor_changed)): + bad += 1 + print(' STALE-N4 %s: declared floor-modulo change, but no successful value changes' % fn) +if floor_functions == 0 or floor_both_ok == 0: + fail('N4 comparison examined no successful exported modulo calls') if counts['examined'] == 0 or counts['examined'] + counts['unexamined'] != counts['calls']: fail('examined=%d unexamined=%d calls=%d' % (counts['examined'], counts['unexamined'], counts['calls'])) print('phase2-lib-diff: listed_functions=%d undeclared=%d stale=%d %s' % ( - len(listed), sum(f not in declared for f in listed), len(set(declared) - set(listed)), + len(set(listed) | set(floor_changed)), + sum(f not in declared for f in listed) + sum(f not in floor_declared for f in floor_changed), + len(set(declared) - set(listed)) + len(set(floor_declared) - set(floor_changed)), 'FAIL' if bad else 'PASS')) shutil.rmtree(work) sys.exit(1 if bad else 0) From 0d6242f54afd43c1bd928573450f2cd0d8c54a46 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 11:25:27 -0500 Subject: [PATCH 083/188] Pin the heap-int domain in floor arithmetic ownership fixtures range still produces floats through the builtin bridge. The first N4 ownership fixture used its counter in INT64_MAX - k, which therefore produced a float instead of a heap-backed int. A live num_type probe returned ["float", "float"], exposing the vacuous ownership traffic. Use VM int counters for the quotient/remainder grid and fresh boxed success/error paths. Assert each large operand is an int beyond the SMI range, so an immediate cannot conceal a missing decref. Runtime unchanged. Validation: focused release floor arithmetic 2560/2560, 0 failures; the kind/domain assertions now witness fresh heap operands. Full final release and ASan acceptance follow before delivery. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/test_floor_division.eigs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/test_floor_division.eigs b/tests/test_floor_division.eigs index 02e7dd941..d3d699779 100644 --- a/tests/test_floor_division.eigs +++ b/tests/test_floor_division.eigs @@ -21,14 +21,18 @@ assert_eq of [1e300 % 3.0, 0, "remainder without overflowing the quotient produc # Independent small-number quotient oracle; identity and sign cover every # sign combination and exact multiples without permitting C truncation. -for a in range of [-30, 31]: - for b in range of [-7, 8]: +a is -30 +loop while a <= 30: + b is -7 + loop while b <= 7: if b != 0: q is a // b rem is a % b assert_eq of [q, floor of (a / b), "small quotient oracle"] assert_eq of [q * b + rem, a, "division/modulo identity"] assert of [rem == 0 or ((rem > 0) == (b > 0)), "divisor sign"] + b is b + 1 + a is a + 1 # Exact boxed int cases: generated from Python integer // and %, so no # float round-trip can agree accidentally above 2^53. @@ -65,8 +69,13 @@ assert_eq of [num_type of xs[1], "float", "compound float kind"] # missing decref measurable under LSan rather than hidden by live globals. define boxed(n) as: return 9223372036854775807 - n -for k in range of [0, 80]: +# range still yields floats through R1.5. Use a VM int counter and pin +# the fresh operand kind so an immediate float cannot hide a missing decref. +k is 0 +loop while k < 80: large is boxed of k + assert_eq of [num_type of large, "int", "ownership fixture is boxed int"] + assert of [large > 140737488355327, "ownership fixture exceeds the SMI range"] assert_eq of [large % -1, 0, "boxed modulo special divisor"] assert_eq of [large // 1, large, "boxed quotient retained"] for op in ["//", "%"]: @@ -98,6 +107,7 @@ for k in range of [0, 80]: catch e: caught is e.kind == "type_mismatch" assert_eq of [caught, true, "boxed % type error owns both operands"] + k is k + 1 # #1758 comment 6294926822: all zero divisors raise in R1.4, including # float/mixed // and //=; / and % retain their existing errors until N11. From 0ebf3314d97e08c44734bcc22c379ddd622366f2 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 11:47:52 -0500 Subject: [PATCH 084/188] Review floor arithmetic payload reads and bool operand coverage The first full release run exposed num-read's stale35 allowance: 4307/4309 passed, 2 failed (the raw-read check and its child ledger). Review the exact delta: IDIV adds two guarded int reads; MOD replaces two old float reuse writes with two guarded int reads. Allow37 and name the int guards in the reason. Runtime code and binary unchanged. Enroll both bool operand positions of // in the existing generator and record the append-only token text/vocabulary/compound checklist sites. Validation: num-read examined191 functions81 allowlisted81 violations0 stale0 PASS; a temporary source tree with one extra read reports38 vs37 and FAIL. Bool sweep calls3022 probes5268 raised4542 violations0 broken0 PASS. Replacing the new left-bool probes with successful integer divisions makes all four rows fail, then restoring them returns green. Whitespace check clean; full release and ASan acceptance rerun before delivery. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 6 +++++- tests/bool_fuzz_gen.eigs | 2 ++ tools/num_read_allowlist.txt | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 5fd57fb52..7478ab0c9 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1672,7 +1672,11 @@ numbers are at `0740af03`. needs no `EIGS_BYTECODE_ABI` bump. - Lexer: `//` lexes as two `TOK_SLASH` today, so a new `TOK_SLASH_SLASH` is appended to the token enum, the X2 table (lexer.c:241) and the token - text (lexer.c:357). + text (lexer.c:357). `//=` is appended too and uses the X3 table. Keep + both text homes (`tok_base_string` and `tok_type_name`) in lockstep; + `tok_base_string_id_count` follows the last appended token, since + `TOK_EOF` keeps its existing ID. Append-only compound tokens also need + the parser's compound predicate and conversion outside the old range. - parser.c (multiplicative level), fmt.c, lint, the LSP and ouroboros `frontend.eigs`; - JIT MOD (§4.2). diff --git a/tests/bool_fuzz_gen.eigs b/tests/bool_fuzz_gen.eigs index a19ec4346..9cfa2ac71 100644 --- a/tests/bool_fuzz_gen.eigs +++ b/tests/bool_fuzz_gen.eigs @@ -267,6 +267,8 @@ for v in ["true", "false"]: append of [vm_calls, ["1 - " + v, "arith-sub", v]] append of [vm_calls, [v + " * 2", "arith-mul", v]] append of [vm_calls, ["2 / " + v, "arith-div", v]] + append of [vm_calls, [v + " // 2", "arith-idiv-left", v]] + append of [vm_calls, ["2 // " + v, "arith-idiv-right", v]] append of [vm_calls, [v + " % 2", "arith-mod", v]] append of [vm_calls, ["0 - " + v, "arith-neg", v]] append of [vm_calls, [v + " < 1", "order", v]] diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 9a2216195..55fb3efe9 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -77,7 +77,7 @@ vm.c|obs_slot_num|2|observer numeric channel (#1758): reads an immediate after s vm.c|slot_bridge_unwrap|1|NaN-boxing boundary after slot_is_f64 vm.c|slot_truthy|1|truthiness after slot_is_f64 vm.c|vm_leaf_accessor_exec|1|leaf-accessor fast path: constants the scanner admitted only as VAL_FLOAT (chunk_scan_leaf_accessor) and values behind VAL_FLOAT tests -vm.c|vm_run_ex|35|the interpreter loop: every opcode reads numbers behind slot_is_f64 / type == VAL_FLOAT dispatch; NUM_REUSE in-place writes; the iterator state list is VM-built +vm.c|vm_run_ex|37|typed interpreter payload accesses: float slots/boxes behind slot_is_f64, VAL_FLOAT or NUM_REUSE; INT_CONST is verifier-typed, other int reads behind VAL_INT guards including both IDIV/MOD operands (#1758 N4) and temporal/slice/dispatch diagnostics; iterator state is VM-built vm.c|vm_slot_lift|1|NaN-boxing boundary after slot_is_f64 vm.c|vm_store_local_slot|2|in-place local number store after slot_is_f64 builtins.c|builtin_json_build|1|VAL_INT text is exact digits; float text retains the bridge (#1758 R1.2d) From d52aa6c69a1a855e1230b902cd614bebe8c27f0b Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 13:32:30 -0500 Subject: [PATCH 085/188] Declare measured R1.4 MOD costs and narrow stale bounds Reprice only the 17 red rows of the canonical make-built 30-row cost matrix against origin/main. Use the design's exact ceiling of measured percent delta + 0.2 to 0.1; retain the R5 recovery requirement and all 13 unaffected bounds. No cost-check logic or tolerance changes. Name the N4 components: non-pooled integer MOD result allocation and retained integer state reaching generic index/Value paths, plus float MOD losing NUM_REUSE. The string-build off-tier reason explicitly requires restoring generic float reuse as well as future native MOD coverage. Fresh 6382b6a5 controls completed for 15 of 17 affected rows. Both PCM controls were interrupted by the harness limit; the declarations label that attribution as source-traced and do not claim a fresh PCM control. The full origin/main/candidate measurements cover both PCM tiers. Validation (tools/phase2_cost.sh, make release binaries): first: workloads=15 rows=30 over_declared_max=14 stale_declarations=3 FAIL final: workloads=15 rows=30 over_declared_max=0 stale_declarations=0 PASS All benchmark outputs agree; bounds are generated from raw Ir counts. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/cost_expect.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt index 3aa9e53d0..f796c3dd8 100644 --- a/tests/phase2/cost_expect.txt +++ b/tests/phase2/cost_expect.txt @@ -1,5 +1,5 @@ -bench/alloc_heavy.eigs jit 64.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +64.3% (range-int control, measured at R1.3, against +64.0%) until R5 -bench/alloc_heavy.eigs off 41.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths +bench/alloc_heavy.eigs jit 68.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +64.3% (range-int control, measured at R1.3, against +64.0%) until R5; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8199903452, R1.4 Ir=8415252793, measured main delta=+68.4121%, bound=ceil(delta+0.2,0.1) +bench/alloc_heavy.eigs off 44.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8229622729, R1.4 Ir=8442823382, measured main delta=+44.6791%, bound=ceil(delta+0.2,0.1) bench/conservative_observed_loop.eigs jit 2.4 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5 bench/conservative_observed_loop.eigs off 1.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.7% (range-int control, measured at R1.3, against +1.0%) until R5 bench/conservative_unobserved_loop.eigs jit 2.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.6% (range-int control, measured at R1.3, against +2.7%) until R5 @@ -8,23 +8,23 @@ bench/dict_ops.eigs jit 1.0 R5 design §3: INT_* literal opcodes stop the JIT sc bench/dict_ops.eigs off 1.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.4% (range-int control, measured at R1.3, against +0.7%) until R5 bench/observed_loop.eigs jit 4.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5 bench/observed_loop.eigs off 1.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5 -bench/scalar_loop.eigs jit 211.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone removes 57.8% of this excess (range-int control, measured at R1.3: +88.6% against +210.1%), R5 the rest; merge of 94657581 component (#1171): env_store_slot bumps the assign-count inside its hold, so the branch's interpreted int stores pay +424,992 Ir there against -225,073 in vm_run_ex (CAND +200,055 Ir, +0.20%) while main's JIT-compiled loop moves BASE -9,041; measured +210.10% at R1.3, +210.81% after the merge -bench/scalar_loop.eigs off 127.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone removes 66.0% of this excess (range-int control, measured at R1.3: +43.1% against +126.8%), R5 the rest; merge of 94657581 component (#1171): env_store_slot +599,992 Ir (the assign-count bump moved inside its hold) against vm_run_ex -400,073 on the branch (CAND +200,037, +0.19%), while on main the same move saves (vm_run_ex -480,053, env_store_slot +399,995: BASE -78,939, -0.17%); measured +126.81% at R1.3, +127.64% after the merge -bench/string_build.eigs jit 10.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.2% (range-int control, measured at R1.3, against +9.9%) until R5 -bench/string_build.eigs off 8.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +23.5% (range-int control, measured at R1.3, against +8.5%) until R5 +bench/scalar_loop.eigs jit 210.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone removes 57.8% of this excess (range-int control, measured at R1.3: +88.6% against +210.1%), R5 the rest; merge of 94657581 component (#1171): env_store_slot bumps the assign-count inside its hold, so the branch's interpreted int stores pay +424,992 Ir there against -225,073 in vm_run_ex (CAND +200,055 Ir, +0.20%) while main's JIT-compiled loop moves BASE -9,041; measured +210.10% at R1.3, +210.81% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=99738384, R1.4 Ir=99697847, measured main delta=+210.5725%, bound=ceil(delta+0.2,0.1) +bench/scalar_loop.eigs off 127.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone removes 66.0% of this excess (range-int control, measured at R1.3: +43.1% against +126.8%), R5 the rest; merge of 94657581 component (#1171): env_store_slot +599,992 Ir (the assign-count bump moved inside its hold) against vm_run_ex -400,073 on the branch (CAND +200,037, +0.19%), while on main the same move saves (vm_run_ex -480,053, env_store_slot +399,995: BASE -78,939, -0.17%); measured +126.81% at R1.3, +127.64% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=104109956, R1.4 Ir=104069767, measured main delta=+127.3221%, bound=ceil(delta+0.2,0.1) +bench/string_build.eigs jit 11.6 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.2% (range-int control, measured at R1.3, against +9.9%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=82669260, R1.4 Ir=83813773, measured main delta=+11.3960%, bound=ceil(delta+0.2,0.1) +bench/string_build.eigs off 10.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +23.5% (range-int control, measured at R1.3, against +8.5%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=85095023, R1.4 Ir=86239916, measured main delta=+9.9831%, bound=ceil(delta+0.2,0.1) bench/unobserved_armed_loop.eigs jit 66.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/unobserved_armed_loop.eigs off 9.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +3,000,000 Ir on both trees (600,000 stores; the assign-count bump moved inside its hold), which saves 2,400,031 in the branch's vm_run_ex (CAND +600,065, +0.06%) but 4,800,031 in main's (BASE -1,798,626, -0.21%); measured +8.85% at R1.3, +9.15% after the merge +bench/unobserved_armed_loop.eigs off 9.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +3,000,000 Ir on both trees (600,000 stores; the assign-count bump moved inside its hold), which saves 2,400,031 in the branch's vm_run_ex (CAND +600,065, +0.06%) but 4,800,031 in main's (BASE -1,798,626, -0.21%); measured +8.85% at R1.3, +9.15% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=930827459, R1.4 Ir=928427649, measured main delta=+8.7891%, bound=ceil(delta+0.2,0.1) bench/unobserved_loop.eigs jit 4.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5 bench/unobserved_loop.eigs off 1.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5 -tests/bench_buf_mix.eigs jit 298.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_buf_mix.eigs off 91.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_buf_resample.eigs jit 191.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_buf_resample.eigs off 64.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_dmg_shape.eigs jit 176.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; merge of 94657581 BASE component (#1171): jit_helper_call no longer calls the out-of-line slot_decref (0c16522f), so main's slot_decref drops 14,517,154 -> 28,754 Ir (BASE -14,503,457, -1.12%), while the branch runs this int code interpreted and does not reach it (CAND -445,382, -0.01%); measured +172.92% at R1.3, +175.98% after the merge -tests/bench_dmg_shape.eigs off 49.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_idxset.eigs jit 411.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_idxset.eigs off 109.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths -tests/bench_pcm_codec.eigs jit 356.0 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -tests/bench_pcm_codec.eigs off 89.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +74,400,025 Ir against vm_run_ex -63,600,434 on the branch (CAND +10,800,129, +0.03%), while on main the same move saves (vm_run_ex -92,400,393, env_store_slot +66,000,030: BASE -26,400,939, -0.13%); measured +89.39% at R1.3, +89.70% after the merge +tests/bench_buf_mix.eigs jit 311.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=2997588303, R1.4 Ir=3102110794, measured main delta=+311.4903%, bound=ceil(delta+0.2,0.1) +tests/bench_buf_mix.eigs off 97.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=3014239251, R1.4 Ir=3118762031, measured main delta=+96.9936%, bound=ceil(delta+0.2,0.1) +tests/bench_buf_resample.eigs jit 196.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14070973095, R1.4 Ir=14341781156, measured main delta=+196.6971%, bound=ceil(delta+0.2,0.1) +tests/bench_buf_resample.eigs off 67.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14114616143, R1.4 Ir=14385424763, measured main delta=+67.2701%, bound=ceil(delta+0.2,0.1) +tests/bench_dmg_shape.eigs jit 208.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; merge of 94657581 BASE component (#1171): jit_helper_call no longer calls the out-of-line slot_decref (0c16522f), so main's slot_decref drops 14,517,154 -> 28,754 Ir (BASE -14,503,457, -1.12%), while the branch runs this int code interpreted and does not reach it (CAND -445,382, -0.01%); measured +172.92% at R1.3, +175.98% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3527659645, R1.4 Ir=3944225152, measured main delta=+208.5522%, bound=ceil(delta+0.2,0.1) +tests/bench_dmg_shape.eigs off 66.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3546396130, R1.4 Ir=3963267113, measured main delta=+66.2412%, bound=ceil(delta+0.2,0.1) +tests/bench_idxset.eigs jit 455.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489963988, R1.4 Ir=531588673, measured main delta=+454.8994%, bound=ceil(delta+0.2,0.1) +tests/bench_idxset.eigs off 126.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489962938, R1.4 Ir=531587958, measured main delta=+126.6422%, bound=ceil(delta+0.2,0.1) +tests/bench_pcm_codec.eigs jit 376.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39010338030, measured main delta=+376.5029%, bound=ceil(delta+0.2,0.1) +tests/bench_pcm_codec.eigs off 97.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +74,400,025 Ir against vm_run_ex -63,600,434 on the branch (CAND +10,800,129, +0.03%), while on main the same move saves (vm_run_ex -92,400,393, env_store_slot +66,000,030: BASE -26,400,939, -0.13%); measured +89.39% at R1.3, +89.70% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39192628174, measured main delta=+97.5413%, bound=ceil(delta+0.2,0.1) tests/bench_perf.eigs jit 15.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.4% (range-int control, measured at R1.3, against +15.7%) until R5 tests/bench_perf.eigs off 5.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +18.7% (range-int control, measured at R1.3, against +5.4%) until R5 From 2987cc3b70701158b1988ef133a08fa057d18018 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 13:50:06 -0500 Subject: [PATCH 086/188] Declare the deliberate worker-task exit in the corpus ledger The R1.4 original-population differential exercised all 532 R1.3 files and caught one missing standalone-error declaration from #1810. Section 104c independently requires task_exit_worker_unjoined_task.eigs to exit 1: an uncaught inner task error on a worker must fail the whole process. Record that existing contract; no runtime, gate logic or expected value changes. Full corpus: examined=532 same=524 same_nonzero=43 same_under_replay=4 nondet=1 diff=2 timeout_both=1 undeclared=1 stale=0 (restricted rc3). The two diffs are N4's required metadata changes: appending OP_IDIV adds one accepted cell to the bytecode sweep (145/2159 -> 146/2158); appending // and //= grows the self-describing base vocabulary 89 -> 91. Direct nine-cell and vocabulary probes prove those exact changes, stable old base-token prefix/structural IDs, and no other fixture stdout/stderr diff. Restored ledger through the real corpus tool: examined=1 same=1 same_nonzero=1 diff=0 undeclared=0 stale=0 (restricted rc3 by design). make: exit 0; release binary identity unchanged. Full release/ASan and JIT/replay/strict differentials remain CI-deferred by the orchestrator. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/corpus_nonzero.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phase2/corpus_nonzero.txt b/tests/phase2/corpus_nonzero.txt index bd91709b6..7c5e4a318 100644 --- a/tests/phase2/corpus_nonzero.txt +++ b/tests/phase2/corpus_nonzero.txt @@ -48,3 +48,4 @@ tests/task_exit_detached_tape.eigs 1 deliberate uncaught worker/task error: the tests/task_exit_detached_try.eigs 1 deliberate uncaught worker/task error: the suite expects exit 1 (#1736) tests/thread_exit_join_uncaught.eigs 1 deliberate uncaught worker/task error: the suite expects exit 1 (#1745) tests/thread_exit_unjoined_death.eigs 1 deliberate uncaught worker/task error: the suite expects exit 1 (#1745) +tests/task_exit_worker_unjoined_task.eigs 1 deliberate unjoined worker-task error: tests/sections/104c-worker-task-exit-1810.sh requires process exit 1 (#1810) From 596bfd975247f4cf66b77aa96df90b376d453405 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 14:25:19 -0500 Subject: [PATCH 087/188] Match Python's float-divmod quotient for floor division 1.0 // 0.1 returned float 10 instead of 9, and 1e-300 // -1e300 returned negative zero instead of -1. The #1882 decision requires CPython's quotient correction for float/mixed //: derive from fmod, adjust an opposite-sign remainder, then floor and snap the quotient; zero takes the sign of a/b. //= shares the fixed opcode. Keep int arithmetic, owned-operand release and zero-divisor errors intact. The JIT scanner and leaf whitelist still refuse IDIV; no other tier computes a float floor quotient. Add both requested MAP rows, their F witnesses and compound boundary coverage. Pin decimal, sign, quotient-snapping and underflow cases in the focused suite and execute examples in all four front-door docs. Update the design, generated inventory and #1882 changelog fragment together. Validation: - copied critic oracle: 5202 cases; before FAIL=32, after FAIL=0; agree=4958, deferred_nonfinite=40, deferred_signed_zero=204 (N11). Both minimal values/kinds/bytes and //= match Python. - focused floor suite: 2570/2570, zero failures. - phase2-check through R1.4: mapped=65 controls=18 witnessed=25, controls_witnessed=13 vacuous=0 PASS; all five added rows present. - planted floor(a/b): all five new rows fail in off/default/osr/trace, then restoring source and make returns the real MAP gate to PASS. - docs: 198/198, populations=12/12; make: zero warnings. - num-read: examined=191 allowlisted=81 violations=0 stale=0 PASS; obs markers:101 opcodes classified,7 checks PASS. - libdiff: calls=281423 examined=281423 unexamined=0; N4 changed=11; listed_functions=12 undeclared=0 stale=0 PASS. Cost follows after the verified bundle checkpoint. Long local lanes are explicitly deferred to the orchestrator's full CI lane. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- README.md | 6 + changes/fixed/1882-float-floor-division.md | 1 + docs/COMPARISON.md | 6 + docs/SPEC.md | 6 + docs/design/phase2-inventory.txt | 240 +++++++++--------- docs/design/phase2-numbers.md | 6 + docs/llms.txt | 6 + src/vm.c | 17 +- tests/phase2/MAP.md | 18 ++ ...N4.compound-float-floordiv-boundaries.eigs | 14 + .../N4.compound-float-floordiv-boundaries.out | 1 + .../rows/N4.float-floordiv-rounding.eigs | 7 + .../rows/N4.float-floordiv-rounding.out | 1 + .../rows/N4.float-floordiv-underflow.eigs | 7 + .../rows/N4.float-floordiv-underflow.out | 1 + .../rows/N4.fn-float-floordiv-rounding.eigs | 16 ++ .../rows/N4.fn-float-floordiv-rounding.out | 1 + .../rows/N4.fn-float-floordiv-underflow.eigs | 16 ++ .../rows/N4.fn-float-floordiv-underflow.out | 1 + tests/test_floor_division.eigs | 16 ++ 20 files changed, 266 insertions(+), 121 deletions(-) create mode 100644 changes/fixed/1882-float-floor-division.md create mode 100644 tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs create mode 100644 tests/phase2/rows/N4.compound-float-floordiv-boundaries.out create mode 100644 tests/phase2/rows/N4.float-floordiv-rounding.eigs create mode 100644 tests/phase2/rows/N4.float-floordiv-rounding.out create mode 100644 tests/phase2/rows/N4.float-floordiv-underflow.eigs create mode 100644 tests/phase2/rows/N4.float-floordiv-underflow.out create mode 100644 tests/phase2/rows/N4.fn-float-floordiv-rounding.eigs create mode 100644 tests/phase2/rows/N4.fn-float-floordiv-rounding.out create mode 100644 tests/phase2/rows/N4.fn-float-floordiv-underflow.eigs create mode 100644 tests/phase2/rows/N4.fn-float-floordiv-underflow.out diff --git a/README.md b/README.md index be8163391..430b08a27 100644 --- a/README.md +++ b/README.md @@ -165,16 +165,22 @@ not a number: `true + 1` and `(x > 0) == 1` raise, so test a bool directly operation to its assignment target, like `/=`. Zero divisors raise `value` for all numeric operand kinds in this round. Two ints produce an int for `//` and `%`; a float operand produces a float. `/` always produces a float. +Float and mixed `//` use Python’s `divmod` quotient correction: `1.0 // 0.1` +is `9.0`, and `1e-300 // -1e300` is `-1.0`. `//=` uses the same rule. ```eigenscript x is -7 x //= 2 print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] print of [num_type of (7 // 2), num_type of (7.0 // 2)] +y is 1.0 +y //= 0.1 +print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ``` ```output [-4, -4, 2, -2, 0.5] ["int", "float"] +[9, 9, -1, 9, "float"] ``` ### Ask Your Code diff --git a/changes/fixed/1882-float-floor-division.md b/changes/fixed/1882-float-floor-division.md new file mode 100644 index 000000000..42ae0e338 --- /dev/null +++ b/changes/fixed/1882-float-floor-division.md @@ -0,0 +1 @@ +Float and mixed `//` and `//=` now use Python’s `divmod` quotient correction. Decimal boundaries such as `1.0 // 0.1` return `9.0`, and an underflowed negative ratio such as `1e-300 // -1e300` returns `-1.0`. Integer arithmetic and the current zero-divisor errors are unchanged. (#1882) diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index 87c9d8364..75b896ca3 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -20,16 +20,22 @@ asking the running program about its own state and history. operation to its assignment target, like `/=`. Zero divisors raise `value` for all numeric operand kinds in this round. Two ints produce an int for `//` and `%`; a float operand produces a float. `/` always produces a float. +Float and mixed `//` use Python’s `divmod` quotient correction: `1.0 // 0.1` +is `9.0`, and `1e-300 // -1e300` is `-1.0`. `//=` uses the same rule. ```eigenscript x is -7 x //= 2 print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] print of [num_type of (7 // 2), num_type of (7.0 // 2)] +y is 1.0 +y //= 0.1 +print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ``` ```output [-4, -4, 2, -2, 0.5] ["int", "float"] +[9, 9, -1, 9, "float"] ``` ## At a glance diff --git a/docs/SPEC.md b/docs/SPEC.md index bb4663f23..b9b4e1a99 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -210,16 +210,22 @@ exponent operator; use `pow of [base, exp]`. operation to its assignment target, like `/=`. Zero divisors raise `value` for all numeric operand kinds in this round. Two ints produce an int for `//` and `%`; a float operand produces a float. `/` always produces a float. +Float and mixed `//` use Python’s `divmod` quotient correction: `1.0 // 0.1` +is `9.0`, and `1e-300 // -1e300` is `-1.0`. `//=` uses the same rule. ```eigenscript x is -7 x //= 2 print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] print of [num_type of (7 // 2), num_type of (7.0 // 2)] +y is 1.0 +y //= 0.1 +print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ``` ```output [-4, -4, 2, -2, 0.5] ["int", "float"] +[9, 9, -1, 9, "float"] ``` Numeric literals accept the usual decimal forms plus a leading or diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 0bee303f9..a52ef0376 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -2460,123 +2460,123 @@ vm.c:3591 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b vm.c:3591 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b vm.c:3606 vm_run_ex/CASE(IDIV) eigs_num_arg READ b vm.c:3611 vm_run_ex/CASE(IDIV) make_num PRODUCE c -vm.c:3613 vm_run_ex/CASE(IDIV) eigs_num_arg READ b -vm.c:3613 vm_run_ex/CASE(IDIV) make_num PRODUCE c -vm.c:3613 vm_run_ex/CASE(IDIV) num_guard GUARD c -vm.c:3629 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3629 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3630 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3630 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3631 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b -vm.c:3631 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b -vm.c:3643 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3646 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3648 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3648 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3648 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3654 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3682 #define INT_BINOP_R slot_f64_value READ b -vm.c:3686 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3713 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3716 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3716 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3719 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3723 vm_run_ex/CASE(NEG) slot_int_value READ b -vm.c:3728 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c -vm.c:3733 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3755 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3759 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3768 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3768 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3774 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3774 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3794 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3794 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3800 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3800 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3822 #define NUM_CMP slot_f64_value READ f -vm.c:3822 #define NUM_CMP slot_f64_value READ f -vm.c:4770 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4772 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4779 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4789 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4791 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4793 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4815 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4817 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4818 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4820 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4822 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4832 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4834 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4834 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4836 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4848 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4851 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4858 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4861 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4864 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4865 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4921 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4924 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4985 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4986 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5012 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:5012 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5118 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5119 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5192 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5196 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5196 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5535 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5536 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5537 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5571 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5572 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5573 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5637 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5638 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5638 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5638 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5642 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5643 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5644 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5645 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5649 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5663 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5664 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5665 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5666 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5686 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5712 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5715 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5716 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5719 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5735 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5743 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5746 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5751 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5771 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5772 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5773 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5774 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5904 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5904 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5921 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5922 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5924 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5931 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5935 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5938 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5939 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5942 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5953 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5956 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6550 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6551 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6552 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6555 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6565 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6566 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6568 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6572 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:3616 vm_run_ex/CASE(IDIV) eigs_num_arg READ b +vm.c:3628 vm_run_ex/CASE(IDIV) make_num PRODUCE c +vm.c:3628 vm_run_ex/CASE(IDIV) num_guard GUARD c +vm.c:3644 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3644 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3645 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3645 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3646 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b +vm.c:3646 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b +vm.c:3658 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3661 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3663 vm_run_ex/CASE(MOD) eigs_num_arg READ b +vm.c:3663 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3663 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3669 vm_run_ex/CASE(MOD) make_num PRODUCE c +vm.c:3697 #define INT_BINOP_R slot_f64_value READ b +vm.c:3701 #define INT_BINOP_R slot_from_f64 PRODUCE c +vm.c:3728 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3731 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3731 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3734 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3738 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3743 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3748 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3770 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3774 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c +vm.c:3783 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3783 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3789 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3789 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3809 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3809 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3815 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3815 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3837 #define NUM_CMP slot_f64_value READ f +vm.c:3837 #define NUM_CMP slot_f64_value READ f +vm.c:4785 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4787 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4794 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4804 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4806 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4808 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4830 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4832 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4833 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4835 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4837 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4847 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4849 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4849 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4851 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4863 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4866 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4873 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4876 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4879 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4880 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4936 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4939 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:5000 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:5001 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5027 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:5027 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5133 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5134 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5207 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5211 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5211 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5550 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5551 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5552 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5586 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5587 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5588 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5652 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5653 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5653 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5653 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5657 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5658 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5659 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5660 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5664 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5678 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5679 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5680 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5681 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5701 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5727 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5730 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5731 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5734 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5750 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5758 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5761 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5766 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5786 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5787 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5788 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5789 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5919 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5919 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5936 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5937 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5939 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5946 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5950 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5953 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5954 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5957 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5968 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5971 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6565 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6566 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6567 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6570 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6580 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6581 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6583 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6587 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 7478ab0c9..16892e73f 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1680,6 +1680,12 @@ numbers are at `0740af03`. - parser.c (multiplicative level), fmt.c, lint, the LSP and ouroboros `frontend.eigs`; - JIT MOD (§4.2). + - Float and mixed `//` follow CPython's `float_divmod` quotient correction + (#1882): derive `(a - fmod(a,b)) / b`, subtract one for an opposite-sign + nonzero remainder, then floor and snap upward when the fractional part + exceeds 0.5; a zero quotient takes the sign of `a/b`. This gives + `1.0 // 0.1 == 9.0` and `1e-300 // -1e300 == -1.0`, unlike `floor(a/b)`. + The VM's `CASE(IDIV)` is the only evaluator; the JIT and leaf refuse it. - Float `x % 0` (NaN), `x / 0` (inf) and float/mixed `x // 0` (`floor(x/0)`, ±inf or NaN) wait for N11 in round 2. All raise today; the `//` rule is #1758 comment 6294926822. diff --git a/docs/llms.txt b/docs/llms.txt index 1c4c5024d..829e1710c 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -241,16 +241,22 @@ sqrt(2) = 1.414213562373095 operation to its assignment target, like `/=`. Zero divisors raise `value` for all numeric operand kinds in this round. Two ints produce an int for `//` and `%`; a float operand produces a float. `/` always produces a float. +Float and mixed `//` use Python’s `divmod` quotient correction: `1.0 // 0.1` +is `9.0`, and `1e-300 // -1e300` is `-1.0`. `//=` uses the same rule. ```eigenscript x is -7 x //= 2 print of [x, 7 // -2, -7 % 3, 7 % -3, -7.5 % 2] print of [num_type of (7 // 2), num_type of (7.0 // 2)] +y is 1.0 +y //= 0.1 +print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ``` ```output [-4, -4, 2, -2, 0.5] ["int", "float"] +[9, 9, -1, 9, "float"] ``` - Hex integer literals: `0xFF`, `0X10` (digits only). Hex-float forms diff --git a/src/vm.c b/src/vm.c index bed02080f..a155d4b5f 100644 --- a/src/vm.c +++ b/src/vm.c @@ -3610,7 +3610,22 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, rt_error(EK_VALUE, current_line, "division by zero"); vm_push(make_num(0)); } else { - vm_push(make_num(num_guard(floor(eigs_num_arg(a, "floor division") / divisor)))); + /* #1882: Python float_divmod's quotient, not floor(a/b). + * Derive it from fmod so decimal boundaries and an + * underflowed opposite-sign ratio agree with floor %. */ + double dividend = eigs_num_arg(a, "floor division"); + double rem = fmod(dividend, divisor); + double div = (dividend - rem) / divisor; + if (rem != 0.0 && ((rem < 0.0) != (divisor < 0.0))) + div -= 1.0; + double floordiv; + if (div != 0.0) { + floordiv = floor(div); + if (div - floordiv > 0.5) floordiv += 1.0; + } else { + floordiv = copysign(0.0, dividend / divisor); + } + vm_push(make_num(num_guard(floordiv))); } } } else { diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 5f3d30d0e..a3804406e 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -313,6 +313,24 @@ gates (design §9.2). -> `["value", "division by zero"]` four times (same as `/`, until N11; #1758 comment 6294926822) tag: parse error +- `N4.float-floordiv-rounding` [R1.4] Python float-divmod quotient at decimal boundaries: `1.0 // 0.1`, mixed `1 // 0.1`, negative pairs, `7.5 // 0.1`, opposite signs, `3.0 // -0.1` quotient snapping and result kind + -> `[9, 9, 9, 74, -10, -30, "float"]` + tag: parse error +- `N4.float-floordiv-underflow` [R1.4] `1e-300 // -1e300`, the sign-reversed pair, a positive underflow and result kind + -> `[-1, -1, 0, "float"]` + tag: parse error +- `N4.fn-float-floordiv-rounding` [R1.4] multi-statement `rd(a, b)` called 60 times with `[1.0, 0.1]`, then mixed/negative/7.5 and quotient-snapping boundaries + -> `[9, 9, 9, 74, -30, "float"]` + tag: parse error + shape: F witness: fn-stop rd IDIV (the scanner's default refuses IDIV) ops: IDIV +- `N4.fn-float-floordiv-underflow` [R1.4] multi-statement `ud(a, b)` called 60 times with `[1e-300, -1e300]`, then the sign-reversed pair + -> `[-1, -1, "float"]` + tag: parse error + shape: F witness: fn-stop ud IDIV (the scanner's default refuses IDIV) ops: IDIV +- `N4.compound-float-floordiv-boundaries` [R1.4] `//=` at the decimal boundary on a name and dict field, and both underflow signs on list indices + -> `[9, 9, [-1, -1], "float", "float"]` + tag: parse error + ### N4b - `N4b.neg-min-raises` [R1.3] `m is -9223372036854775807 - 1 / {try print of (-m) catch}` -> `["value", true]`, the message naming the unary minus diff --git a/tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs new file mode 100644 index 000000000..944ad835d --- /dev/null +++ b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs @@ -0,0 +1,14 @@ +# ROW: N4.compound-float-floordiv-boundaries +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +x is 1.0 +x //= 0.1 +d is {"x": 1} +d.x //= 0.1 +xs is [1e-300, -1e-300] +xs[0] //= -1e300 +xs[1] //= 1e300 +print of [x, d.x, xs, num_type of x, num_type of d.x] diff --git a/tests/phase2/rows/N4.compound-float-floordiv-boundaries.out b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.out new file mode 100644 index 000000000..ad6dccf15 --- /dev/null +++ b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.out @@ -0,0 +1 @@ +[9, 9, [-1, -1], "float", "float"] diff --git a/tests/phase2/rows/N4.float-floordiv-rounding.eigs b/tests/phase2/rows/N4.float-floordiv-rounding.eigs new file mode 100644 index 000000000..b47c3422a --- /dev/null +++ b/tests/phase2/rows/N4.float-floordiv-rounding.eigs @@ -0,0 +1,7 @@ +# ROW: N4.float-floordiv-rounding +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [1.0 // 0.1, 1 // 0.1, -1.0 // -0.1, 7.5 // 0.1, 1.0 // -0.1, 3.0 // -0.1, num_type of (1 // 0.1)] diff --git a/tests/phase2/rows/N4.float-floordiv-rounding.out b/tests/phase2/rows/N4.float-floordiv-rounding.out new file mode 100644 index 000000000..7e673045d --- /dev/null +++ b/tests/phase2/rows/N4.float-floordiv-rounding.out @@ -0,0 +1 @@ +[9, 9, 9, 74, -10, -30, "float"] diff --git a/tests/phase2/rows/N4.float-floordiv-underflow.eigs b/tests/phase2/rows/N4.float-floordiv-underflow.eigs new file mode 100644 index 000000000..3ce2c6c79 --- /dev/null +++ b/tests/phase2/rows/N4.float-floordiv-underflow.eigs @@ -0,0 +1,7 @@ +# ROW: N4.float-floordiv-underflow +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [1e-300 // -1e300, -1e-300 // 1e300, 1e-300 // 1e300, num_type of (1e-300 // -1e300)] diff --git a/tests/phase2/rows/N4.float-floordiv-underflow.out b/tests/phase2/rows/N4.float-floordiv-underflow.out new file mode 100644 index 000000000..02c90e177 --- /dev/null +++ b/tests/phase2/rows/N4.float-floordiv-underflow.out @@ -0,0 +1 @@ +[-1, -1, 0, "float"] diff --git a/tests/phase2/rows/N4.fn-float-floordiv-rounding.eigs b/tests/phase2/rows/N4.fn-float-floordiv-rounding.eigs new file mode 100644 index 000000000..7bd9e3a9c --- /dev/null +++ b/tests/phase2/rows/N4.fn-float-floordiv-rounding.eigs @@ -0,0 +1,16 @@ +# ROW: N4.fn-float-floordiv-rounding +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop rd IDIV +# OPS: IDIV +define rd(a, b) as: + warm is 0.5 + t is a // b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is rd of [1.0, 0.1] + i is i + 1.0 +print of [r, rd of [1, 0.1], rd of [-1.0, -0.1], rd of [7.5, 0.1], rd of [3.0, -0.1], num_type of r] diff --git a/tests/phase2/rows/N4.fn-float-floordiv-rounding.out b/tests/phase2/rows/N4.fn-float-floordiv-rounding.out new file mode 100644 index 000000000..f3f9746e5 --- /dev/null +++ b/tests/phase2/rows/N4.fn-float-floordiv-rounding.out @@ -0,0 +1 @@ +[9, 9, 9, 74, -30, "float"] diff --git a/tests/phase2/rows/N4.fn-float-floordiv-underflow.eigs b/tests/phase2/rows/N4.fn-float-floordiv-underflow.eigs new file mode 100644 index 000000000..4cb505b4f --- /dev/null +++ b/tests/phase2/rows/N4.fn-float-floordiv-underflow.eigs @@ -0,0 +1,16 @@ +# ROW: N4.fn-float-floordiv-underflow +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop ud IDIV +# OPS: IDIV +define ud(a, b) as: + warm is 0.5 + t is a // b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is ud of [1e-300, -1e300] + i is i + 1.0 +print of [r, ud of [-1e-300, 1e300], num_type of r] diff --git a/tests/phase2/rows/N4.fn-float-floordiv-underflow.out b/tests/phase2/rows/N4.fn-float-floordiv-underflow.out new file mode 100644 index 000000000..2157a2566 --- /dev/null +++ b/tests/phase2/rows/N4.fn-float-floordiv-underflow.out @@ -0,0 +1 @@ +[-1, -1, "float"] diff --git a/tests/test_floor_division.eigs b/tests/test_floor_division.eigs index d3d699779..f3a1311aa 100644 --- a/tests/test_floor_division.eigs +++ b/tests/test_floor_division.eigs @@ -19,6 +19,22 @@ assert_eq of [num_type of (7 % 3), "int", "int remainder kind"] assert_eq of [num_type of (7.0 % 3), "float", "mixed remainder kind"] assert_eq of [1e300 % 3.0, 0, "remainder without overflowing the quotient product"] +# #1882: Python float_divmod rounds from fmod, including mixed operands. +assert_eq of [1.0 // 0.1, 9.0, "decimal quotient boundary"] +assert_eq of [1 // 0.1, 9.0, "mixed decimal quotient boundary"] +assert_eq of [-1.0 // -0.1, 9.0, "negative decimal pair"] +assert_eq of [7.5 // 0.1, 74.0, "fractional decimal quotient boundary"] +assert_eq of [3.0 // -0.1, -30.0, "quotient snaps after floor correction"] +assert_eq of [1e-300 // -1e300, -1.0, "negative quotient underflow floors"] +assert_eq of [-1e-300 // 1e300, -1.0, "negative dividend underflow floors"] +assert_eq of [num_type of (1 // 0.1), "float", "mixed boundary result kind"] +rounding_target is 1.0 +rounding_target //= 0.1 +assert_eq of [rounding_target, 9.0, "compound decimal quotient boundary"] +underflow_target is 1e-300 +underflow_target //= -1e300 +assert_eq of [underflow_target, -1.0, "compound quotient underflow"] + # Independent small-number quotient oracle; identity and sign cover every # sign combination and exact multiples without permitting C truncation. a is -30 From fac59c5e07ca3dbae57784f3a5b08dccda195c2b Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 14:41:00 -0500 Subject: [PATCH 088/188] Keep the corrected zero-quotient sign freestanding copysign(0.0, a/b) introduces a new unresolved copysign call under the freestanding flags; the mini-libm does not provide it. Select -0.0 or 0.0 with signbit(a/b), preserving #1882's required ratio sign without a new libm dependency. Add byte-level quotient sign assertions for both signs. No allowlist or numeric-policy change. Validation on the final portable release build: - make: zero warnings; focused floor suite 2572/2572. - copied critic oracle: 5202 cases, FAIL=0, agree=4958; deferred_nonfinite=40 and deferred_signed_zero=204 remain N11. Minimal values/kinds/bytes and //= match Python. - phase2-check through R1.4: mapped=65 controls=18 witnessed=25, controls_witnessed=13 vacuous=0 PASS. - libdiff: calls=281423 examined=281423 unexamined=0; changed=11; listed_functions=12 undeclared=0 stale=0 PASS. - freestanding: stage1=75 undefined/92 allowlisted, stage2=30/32 HAL; both stages PASS, with no import-ledger changes. The earlier cost attempt was explicitly interrupted and excluded. Bundle this commit and print its verified tip before restarting canonical cost. The orchestrator runs the long CI lanes after push. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- src/vm.c | 2 +- tests/test_floor_division.eigs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index a155d4b5f..84bf253ce 100644 --- a/src/vm.c +++ b/src/vm.c @@ -3623,7 +3623,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, floordiv = floor(div); if (div - floordiv > 0.5) floordiv += 1.0; } else { - floordiv = copysign(0.0, dividend / divisor); + floordiv = signbit(dividend / divisor) ? -0.0 : 0.0; } vm_push(make_num(num_guard(floordiv))); } diff --git a/tests/test_floor_division.eigs b/tests/test_floor_division.eigs index f3a1311aa..5b3f636e0 100644 --- a/tests/test_floor_division.eigs +++ b/tests/test_floor_division.eigs @@ -25,6 +25,8 @@ assert_eq of [1 // 0.1, 9.0, "mixed decimal quotient boundary"] assert_eq of [-1.0 // -0.1, 9.0, "negative decimal pair"] assert_eq of [7.5 // 0.1, 74.0, "fractional decimal quotient boundary"] assert_eq of [3.0 // -0.1, -30.0, "quotient snaps after floor correction"] +assert_eq of [f64_to_bytes of (-0.0 // 2.0), [128, 0, 0, 0, 0, 0, 0, 0], "zero quotient takes negative ratio sign"] +assert_eq of [f64_to_bytes of (-0.0 // -2.0), [0, 0, 0, 0, 0, 0, 0, 0], "zero quotient takes positive ratio sign"] assert_eq of [1e-300 // -1e300, -1.0, "negative quotient underflow floors"] assert_eq of [-1e-300 // 1e300, -1.0, "negative dividend underflow floors"] assert_eq of [num_type of (1 // 0.1), "float", "mixed boundary result kind"] From 738f8ec1d98bc8457349570d425e0e305ccec0ea Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 15:21:32 -0500 Subject: [PATCH 089/188] Normalize empty operation headers in floor-division MAP rows Remove the trailing spaces from the three new S-row OPS headers. The checker accepts an empty value without a trailing separator; program bodies and expected results are unchanged. Validation: phase2-check --through R1.4: controls=18 both_pass=18 witnessed=25 mapped=65 gates=1; controls_witnessed=13 controls_vacuous=0; phase2-check: PASS. git diff --check against 6382b6a5 is clean. The release artifact remains byte-identical to the corrected VM. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs | 2 +- tests/phase2/rows/N4.float-floordiv-rounding.eigs | 2 +- tests/phase2/rows/N4.float-floordiv-underflow.eigs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs index 944ad835d..4785442aa 100644 --- a/tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs +++ b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.eigs @@ -3,7 +3,7 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: x is 1.0 x //= 0.1 d is {"x": 1} diff --git a/tests/phase2/rows/N4.float-floordiv-rounding.eigs b/tests/phase2/rows/N4.float-floordiv-rounding.eigs index b47c3422a..85f442101 100644 --- a/tests/phase2/rows/N4.float-floordiv-rounding.eigs +++ b/tests/phase2/rows/N4.float-floordiv-rounding.eigs @@ -3,5 +3,5 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: print of [1.0 // 0.1, 1 // 0.1, -1.0 // -0.1, 7.5 // 0.1, 1.0 // -0.1, 3.0 // -0.1, num_type of (1 // 0.1)] diff --git a/tests/phase2/rows/N4.float-floordiv-underflow.eigs b/tests/phase2/rows/N4.float-floordiv-underflow.eigs index 3ce2c6c79..1edbed832 100644 --- a/tests/phase2/rows/N4.float-floordiv-underflow.eigs +++ b/tests/phase2/rows/N4.float-floordiv-underflow.eigs @@ -3,5 +3,5 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: print of [1e-300 // -1e300, -1e-300 // 1e300, 1e-300 // 1e300, num_type of (1e-300 // -1e300)] From 2d6587ee7e8862d3d30e602198210bc637586482 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 16:24:29 -0500 Subject: [PATCH 090/188] changes: the #1882 fragment starts with '- ' as the fragment check requires CI's precheck (tools/changelog_fragments.sh) failed the full lane on 738f8ec1: the R1.4 fix round's fragment lacked its leading bullet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/fixed/1882-float-floor-division.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes/fixed/1882-float-floor-division.md b/changes/fixed/1882-float-floor-division.md index 42ae0e338..619b68a9f 100644 --- a/changes/fixed/1882-float-floor-division.md +++ b/changes/fixed/1882-float-floor-division.md @@ -1 +1 @@ -Float and mixed `//` and `//=` now use Python’s `divmod` quotient correction. Decimal boundaries such as `1.0 // 0.1` return `9.0`, and an underflowed negative ratio such as `1e-300 // -1e300` returns `-1.0`. Integer arithmetic and the current zero-divisor errors are unchanged. (#1882) +- Float and mixed `//` and `//=` now use Python’s `divmod` quotient correction. Decimal boundaries such as `1.0 // 0.1` return `9.0`, and an underflowed negative ratio such as `1e-300 // -1e300` returns `-1.0`. Integer arithmetic and the current zero-divisor errors are unchanged. (#1882) From 7b95a5a41de4e8e578532ab3ed8017f9181911e1 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 16:49:07 -0500 Subject: [PATCH 091/188] Implement Lua 5.4 integer bitwise results and shift rules (N8) Return exact int64 patterns from operators and bit_* builtins. Bound shift counts before negating them, reverse negative counts, zero wide counts, and zero-fill right shifts. Preserve #1740 exact-integer refusal and release owned boxed operands on every path. Validation: Lua 5.4.9 cases=16836 agree=16836 mismatch=0; focused release Tests=181 Pass=181 Fail=0; MAP through R1.5 mapped=72 controls=18 witnessed=27 PASS in four tiers; docs=202/202; numeric reads examined=192 violations=0. Focused ASan, warning builds, plants, libdiff and cost are follow-up validation. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- README.md | 15 + changes/breaking/1758-n8-lua-bitwise.md | 1 + docs/COMPARISON.md | 15 + docs/SPEC.md | 28 +- docs/design/phase2-inventory.txt | 936 +++++++++--------- docs/design/phase2-numbers.md | 18 +- docs/llms.txt | 20 +- src/builtins.c | 44 +- src/eigenscript.h | 10 + src/vm.c | 47 +- tests/phase2/lua_bitwise_diff.py | 102 ++ .../rows/N5.bitwise-fraction-raises.eigs | 10 + .../rows/N5.bitwise-fraction-raises.out | 1 + .../rows/N5.integral-float-converts.eigs | 7 + .../rows/N5.integral-float-converts.out | 1 + tests/phase2/rows/N8.bit-builtins-int64.eigs | 7 + tests/phase2/rows/N8.bit-builtins-int64.out | 1 + tests/phase2/rows/N8.bitwise-results-int.eigs | 7 + tests/phase2/rows/N8.bitwise-results-int.out | 1 + tests/phase2/rows/N8.fn-bitwise-all.eigs | 17 + tests/phase2/rows/N8.fn-bitwise-all.out | 1 + tests/phase2/rows/N8.fn-bitwise.eigs | 13 + tests/phase2/rows/N8.fn-bitwise.out | 1 + tests/phase2/rows/N8.lua-shifts.eigs | 7 + tests/phase2/rows/N8.lua-shifts.out | 1 + tests/test_bitwise.eigs | 56 +- tests/test_doc_examples.py | 8 +- tools/num_read_allowlist.txt | 1 + 28 files changed, 802 insertions(+), 574 deletions(-) create mode 100644 changes/breaking/1758-n8-lua-bitwise.md create mode 100644 tests/phase2/lua_bitwise_diff.py create mode 100644 tests/phase2/rows/N5.bitwise-fraction-raises.eigs create mode 100644 tests/phase2/rows/N5.bitwise-fraction-raises.out create mode 100644 tests/phase2/rows/N5.integral-float-converts.eigs create mode 100644 tests/phase2/rows/N5.integral-float-converts.out create mode 100644 tests/phase2/rows/N8.bit-builtins-int64.eigs create mode 100644 tests/phase2/rows/N8.bit-builtins-int64.out create mode 100644 tests/phase2/rows/N8.bitwise-results-int.eigs create mode 100644 tests/phase2/rows/N8.bitwise-results-int.out create mode 100644 tests/phase2/rows/N8.fn-bitwise-all.eigs create mode 100644 tests/phase2/rows/N8.fn-bitwise-all.out create mode 100644 tests/phase2/rows/N8.fn-bitwise.eigs create mode 100644 tests/phase2/rows/N8.fn-bitwise.out create mode 100644 tests/phase2/rows/N8.lua-shifts.eigs create mode 100644 tests/phase2/rows/N8.lua-shifts.out diff --git a/README.md b/README.md index 430b08a27..87d3e5c94 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,21 @@ not a number: `true + 1` and `(x > 0) == 1` raise, so test a bool directly (`if x > 0:`). See [docs/SPEC.md](docs/SPEC.md#booleans-comparison-and-logic). +Bitwise operators and `bit_*` builtins return ints, including when an +operand is an integral float. They use Lua 5.4's 64-bit shift rules: `>>` +zero-fills; a negative count shifts in the opposite direction; a count of +64 or more, or -64 or less, gives zero. Each operand must be an exact int64; +a fractional or out-of-range float raises `value`. + +```eigenscript +print of [1 << 64, 1 << -1, -1 >> 1, 8 >> -1, 1 << 63] +print of [bit_shr of [-1, 1], bit_shl of [8, -1], num_type of (3.0 & 1)] +``` +```output +[0, 0, 9223372036854775807, 16, -9223372036854775808] +[9223372036854775807, 4, "int"] +``` + `//` floors the quotient; `%` has the divisor's sign. `//=` applies the same operation to its assignment target, like `/=`. Zero divisors raise `value` for all numeric operand kinds in this round. Two ints produce an int for diff --git a/changes/breaking/1758-n8-lua-bitwise.md b/changes/breaking/1758-n8-lua-bitwise.md new file mode 100644 index 000000000..8364e6add --- /dev/null +++ b/changes/breaking/1758-n8-lua-bitwise.md @@ -0,0 +1 @@ +- Bitwise operators and `bit_*` builtins now return exact int64 values. Shifts follow Lua 5.4: right shifts zero-fill, negative counts reverse direction, and counts outside (-64, 64) give zero. Fractional or out-of-range operands still raise `value` (#1740, #1758 N8). diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index 75b896ca3..9ae430730 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -16,6 +16,21 @@ first-class constructs (`converged`, `what is x`, `prev of x`) for asking the running program about its own state and history. +Bitwise operators and `bit_*` builtins return ints, including when an +operand is an integral float. They use Lua 5.4's 64-bit shift rules: `>>` +zero-fills; a negative count shifts in the opposite direction; a count of +64 or more, or -64 or less, gives zero. Each operand must be an exact int64; +a fractional or out-of-range float raises `value`. + +```eigenscript +print of [1 << 64, 1 << -1, -1 >> 1, 8 >> -1, 1 << 63] +print of [bit_shr of [-1, 1], bit_shl of [8, -1], num_type of (3.0 & 1)] +``` +```output +[0, 0, 9223372036854775807, 16, -9223372036854775808] +[9223372036854775807, 4, "int"] +``` + `//` floors the quotient; `%` has the divisor's sign. `//=` applies the same operation to its assignment target, like `/=`. Zero divisors raise `value` for all numeric operand kinds in this round. Two ints produce an int for diff --git a/docs/SPEC.md b/docs/SPEC.md index b9b4e1a99..7dd3f8f08 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -282,10 +282,8 @@ consequences are contracts you can rely on: - **Float integer exactness ends at 2^53.** Whole floats up to `9007199254740992` are exact; past that the gaps between representable values exceed 1, so `+ 1` can be invisible. For exact identifiers, counters, and money-in-cents, keep values in - the int kind rather than converting them to float. The transitional bitwise seam below - accepts wider exact integer operands - (its operands must be exact integers below 2^63 in magnitude; past 2^53 only - the representable ones qualify). + the int kind rather than converting them to float. Bitwise operations preserve all int64 bits and return ints; integral float + operands convert only when they are exactly representable as int64. - **Finite by construction — no `NaN`, no `Infinity` ever reach your program.** Overflow saturates at `±1e308` instead of becoming `Infinity`. Every *defined* operation returns a usable finite number; an *undefined* one — @@ -667,8 +665,24 @@ print of (bit_shl of [1, 32]) Every operand, the shift count included, must be an **exact integer** in `[-2^63, 2^63)`, Lua 5.4's rule. A fractional operand or one outside int64 has no integer representation, and the operation raises a catchable -`value` error instead of truncating. A valid shift count is then masked -to `[0, 63]`: +`value` error instead of truncating. + +Bitwise operators and `bit_*` builtins return ints, including when an +operand is an integral float. They use Lua 5.4's 64-bit shift rules: `>>` +zero-fills; a negative count shifts in the opposite direction; a count of +64 or more, or -64 or less, gives zero. Each operand must be an exact int64; +a fractional or out-of-range float raises `value`. + +```eigenscript +print of [1 << 64, 1 << -1, -1 >> 1, 8 >> -1, 1 << 63] +print of [bit_shr of [-1, 1], bit_shl of [8, -1], num_type of (3.0 & 1)] +``` +```output +[0, 0, 9223372036854775807, 16, -9223372036854775808] +[9223372036854775807, 4, "int"] +``` + +The operand checks also apply to shift counts: ```eigenscript print of ((-9223372036854775808 | 0) == -9223372036854775808) @@ -688,7 +702,7 @@ catch e: ``` ```output true -1 +0 value '<<': number 0.5 has no integer representation value diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index a52ef0376..d76ee0d94 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,12 +1,12 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2046 classified=2046 unclassified=0 +examined=2040 classified=2040 unclassified=0 files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 ## Per category -(a) type tests 504 CASE=60 DATA=4 TEST=437 YIELD=3 -(b) payload reads 577 RAW=134 READ=443 -(c) producers 477 GUARD=74 PARSE=3 PRODUCE=377 TAGSET=5 WRITE=18 +(a) type tests 505 CASE=60 DATA=4 TEST=438 YIELD=3 +(b) payload reads 576 RAW=135 READ=441 +(c) producers 471 GUARD=74 PARSE=3 PRODUCE=371 TAGSET=5 WRITE=18 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 20 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=7 (f) equality, ordering and hashing 53 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=23 @@ -16,22 +16,22 @@ files=64 tokens=46 role_rules=8 derived_accessors=18 wrappers=7 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token -make_num 368 +make_num 362 val_is_number 185 -eigs_num_arg 173 +eigs_num_arg 171 +VAL_INT 151 VAL_FLOAT 150 -VAL_INT 150 eigs_list_num 130 SLOT_F64_RAW 83 num_guard 63 VAL_F64_RAW 54 AST_NUM 52 -VAL_I64_RAW 50 +VAL_I64_RAW 51 slot_is_f64 50 eigs_value_as_num 48 eigs_slot_num 47 buffer_read_num 37 -slot_from_f64 37 +slot_from_f64 35 slot_is_smi 33 number 26 buffer_read_byte 22 @@ -41,11 +41,11 @@ slot_f64_value 19 strtod 16 eigs_slot_opt_num 12 NUM_REUSE 10 +slot_from_int 10 eigs_num_arg_slow 9 slot_int_value 9 EIGS_NUM_MAX 8 finite_num_to_byte 8 -slot_from_int 8 eigs_num_text 7 eigs_opt_num 6 eigs_slot_elem_num 6 @@ -68,7 +68,7 @@ list_get_num 1 data.number (AST) 3 ## Per file (category counts) -builtins.c 350 a=84 b=104 c=111 e=6 f=13 h=21 i=11 +builtins.c 344 a=85 b=103 c=105 e=6 f=13 h=21 i=11 vm.c 308 a=72 b=101 c=71 e=2 f=10 i=52 ext_gfx.c 298 a=104 b=124 c=70 builtins_tensor.c 200 a=55 b=59 c=86 @@ -299,7 +299,7 @@ D3 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET) guarded slot_is_null=1 ## Builtins registered=312 numeric=231 classified=231 unclassified=0 stale=0 classes: float-producing=57 int-preserving=37 int-requiring=85 other=52 -LOSS (42): abs add bit_and bit_not bit_or bit_shl bit_shr bit_xor ceil db_execute db_query_json db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed +LOSS (36): abs add ceil db_execute db_query_json db_query_value floor hex json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed Q7: geometry=9 bounded=13 magnitude=13 abs builtin_abs int-preserving LOSS - VAL_I64_RAW,VAL_INT,eigs_num_arg,make_num,val_is_number acos builtin_acos float-producing - - eigs_num_arg,make_num,val_is_number @@ -330,12 +330,12 @@ audio_stream_push builtin_audio_stream_push other audio_stream_queued builtin_audio_stream_queued int-preserving - - make_num audio_sweep builtin_audio_sweep float-producing - magnitude VAL_FLOAT,VAL_INT,eigs_list_num,make_num audio_volume builtin_audio_volume int-requiring - bounded VAL_FLOAT,VAL_INT,eigs_slot_num,make_num -bit_and builtin_bit_and int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number -bit_not builtin_bit_not int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number -bit_or builtin_bit_or int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number -bit_shl builtin_bit_shift_left int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number -bit_shr builtin_bit_shift_right int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number -bit_xor builtin_bit_xor int-requiring LOSS - eigs_num_arg,make_num,num_to_i64_exact,val_is_number +bit_and builtin_bit_and int-requiring - - VAL_I64_RAW,VAL_INT,eigs_num_arg,num_to_i64_exact,val_is_number +bit_not builtin_bit_not int-requiring - - VAL_I64_RAW,VAL_INT,eigs_num_arg,num_to_i64_exact,val_is_number +bit_or builtin_bit_or int-requiring - - VAL_I64_RAW,VAL_INT,eigs_num_arg,num_to_i64_exact,val_is_number +bit_shl builtin_bit_shift_left int-requiring - - VAL_I64_RAW,VAL_INT,eigs_num_arg,num_to_i64_exact,val_is_number +bit_shr builtin_bit_shift_right int-requiring - - VAL_I64_RAW,VAL_INT,eigs_num_arg,num_to_i64_exact,val_is_number +bit_xor builtin_bit_xor int-requiring - - VAL_I64_RAW,VAL_INT,eigs_num_arg,num_to_i64_exact,val_is_number buf_copy builtin_buf_copy int-requiring - - VAL_FLOAT,VAL_INT,eigs_slot_num buf_deinterleave builtin_buf_deinterleave int-requiring - - VAL_FLOAT,VAL_INT,eigs_num_arg,eigs_slot_num,val_is_number buf_dot builtin_buf_dot float-producing - - VAL_FLOAT,VAL_INT,buffer_read_num,eigs_slot_num,make_num,num_guard @@ -536,354 +536,348 @@ zeros_like builtin_tensor_zeros_like float-producing ## Sites (file:line scope token kind category) builtins.c:164 builtin_usleep val_is_number TEST a builtins.c:165 builtin_usleep eigs_num_arg READ b -builtins.c:350 bit_int num_to_i64_exact READ b -builtins.c:361 bit_pair val_is_number TEST a -builtins.c:361 bit_pair val_is_number TEST a -builtins.c:362 bit_pair eigs_num_arg READ b -builtins.c:363 bit_pair eigs_num_arg READ b -builtins.c:372 builtin_bit_and make_num PRODUCE c -builtins.c:380 builtin_bit_or make_num PRODUCE c -builtins.c:388 builtin_bit_xor make_num PRODUCE c -builtins.c:392 builtin_bit_not val_is_number TEST a -builtins.c:394 builtin_bit_not eigs_num_arg READ b -builtins.c:395 builtin_bit_not make_num PRODUCE c -builtins.c:403 builtin_bit_shift_left make_num PRODUCE c -builtins.c:414 builtin_bit_shift_right make_num PRODUCE c -builtins.c:422 builtin_monotonic_ns make_num PRODUCE c -builtins.c:430 builtin_monotonic_ms make_num PRODUCE c -builtins.c:441 builtin_clock_unix make_num PRODUCE c -builtins.c:446 builtin_len make_num PRODUCE c -builtins.c:448 builtin_len make_num PRODUCE c -builtins.c:451 builtin_len make_num PRODUCE c -builtins.c:454 builtin_len make_num PRODUCE c -builtins.c:456 builtin_len make_num PRODUCE c -builtins.c:466 builtin_len make_num PRODUCE c -builtins.c:495 builtin_num make_num PRODUCE c -builtins.c:496 builtin_num val_is_number TEST a -builtins.c:503 builtin_num make_num PRODUCE c -builtins.c:522 builtin_num make_num PRODUCE c -builtins.c:530 builtin_num make_num PRODUCE c -builtins.c:535 builtin_num make_num PRODUCE c -builtins.c:535 builtin_num num_guard_named GUARD c -builtins.c:535 builtin_num strtod PARSE c -builtins.c:537 builtin_num make_num PRODUCE c -builtins.c:538 builtin_num make_num PRODUCE c -builtins.c:557 builtin_append VAL_FLOAT YIELD a -builtins.c:591 builtin_get_observer_thresholds make_num PRODUCE i -builtins.c:592 builtin_get_observer_thresholds make_num PRODUCE i -builtins.c:593 builtin_get_observer_thresholds make_num PRODUCE i -builtins.c:643 builtin_exit val_is_number TEST a -builtins.c:644 builtin_exit eigs_num_arg READ b -builtins.c:647 builtin_exit val_is_number TEST a -builtins.c:648 builtin_exit eigs_list_num READ b -builtins.c:783 builtin_observe make_num PRODUCE i -builtins.c:784 builtin_observe make_num PRODUCE i -builtins.c:785 builtin_observe make_num PRODUCE i -builtins.c:867 builtin_type VAL_FLOAT CASE a -builtins.c:868 builtin_type VAL_INT CASE a -builtins.c:886 builtin_num_type VAL_INT TEST a -builtins.c:887 builtin_num_type VAL_FLOAT TEST a -builtins.c:923 eigs_json_encode_value VAL_FLOAT CASE h -builtins.c:930 eigs_json_encode_value eigs_num_arg READ h -builtins.c:930 eigs_json_encode_value eigs_num_text FORMAT h -builtins.c:934 eigs_json_encode_value VAL_INT CASE h -builtins.c:936 eigs_json_encode_value VAL_I64_RAW RAW h -builtins.c:1299 eigs_json_parse_number make_num PRODUCE h -builtins.c:1306 eigs_json_parse_number make_num PRODUCE h -builtins.c:1315 eigs_json_parse_number make_num PRODUCE h -builtins.c:1320 eigs_json_parse_number strtod PARSE h -builtins.c:1330 eigs_json_parse_number strtod PARSE h -builtins.c:1334 eigs_json_parse_number make_num PRODUCE h -builtins.c:1505 builtin_json_build val_is_number TEST h -builtins.c:1507 builtin_json_build VAL_I64_RAW RAW h -builtins.c:1507 builtin_json_build VAL_INT TEST h -builtins.c:1508 builtin_json_build eigs_num_arg READ h -builtins.c:1508 builtin_json_build eigs_num_text FORMAT h -builtins.c:1692 builtin_scan_ints make_num PRODUCE c -builtins.c:1806 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1807 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1808 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1809 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1810 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1811 builtin_scan_int_tokens make_num PRODUCE c -builtins.c:1914 builtin_char_at val_is_number TEST a -builtins.c:1916 builtin_char_at eigs_num_arg READ b -builtins.c:1950 builtin_substr val_is_number TEST a -builtins.c:1951 builtin_substr val_is_number TEST a -builtins.c:1953 builtin_substr eigs_num_arg READ b -builtins.c:1954 builtin_substr eigs_num_arg READ b -builtins.c:1984 builtin_index_of make_num PRODUCE c -builtins.c:1991 builtin_index_of make_num PRODUCE c -builtins.c:1996 builtin_index_of make_num PRODUCE c -builtins.c:1997 builtin_index_of make_num PRODUCE c -builtins.c:2005 builtin_sin make_num PRODUCE c -builtins.c:2005 builtin_sin val_is_number TEST a -builtins.c:2006 builtin_sin eigs_num_arg READ b -builtins.c:2006 builtin_sin make_num PRODUCE c -builtins.c:2010 builtin_cos make_num PRODUCE c -builtins.c:2010 builtin_cos val_is_number TEST a -builtins.c:2011 builtin_cos eigs_num_arg READ b -builtins.c:2011 builtin_cos make_num PRODUCE c -builtins.c:2015 builtin_tan make_num PRODUCE c -builtins.c:2015 builtin_tan val_is_number TEST a -builtins.c:2016 builtin_tan eigs_num_arg READ b -builtins.c:2016 builtin_tan make_num PRODUCE c -builtins.c:2020 builtin_asin make_num PRODUCE c -builtins.c:2020 builtin_asin val_is_number TEST a -builtins.c:2021 builtin_asin eigs_num_arg READ b -builtins.c:2026 builtin_asin make_num PRODUCE c -builtins.c:2030 builtin_asin make_num PRODUCE c -builtins.c:2034 builtin_acos make_num PRODUCE c -builtins.c:2034 builtin_acos val_is_number TEST a -builtins.c:2035 builtin_acos eigs_num_arg READ b -builtins.c:2040 builtin_acos make_num PRODUCE c -builtins.c:2044 builtin_acos make_num PRODUCE c -builtins.c:2048 builtin_atan make_num PRODUCE c -builtins.c:2048 builtin_atan val_is_number TEST a -builtins.c:2049 builtin_atan eigs_num_arg READ b -builtins.c:2049 builtin_atan make_num PRODUCE c -builtins.c:2054 builtin_atan2 make_num PRODUCE c -builtins.c:2057 builtin_atan2 make_num PRODUCE c -builtins.c:2057 builtin_atan2 val_is_number TEST a -builtins.c:2057 builtin_atan2 val_is_number TEST a -builtins.c:2058 builtin_atan2 eigs_num_arg READ b -builtins.c:2058 builtin_atan2 eigs_num_arg READ b -builtins.c:2058 builtin_atan2 make_num PRODUCE c -builtins.c:2062 builtin_floor make_num PRODUCE c -builtins.c:2062 builtin_floor val_is_number TEST a -builtins.c:2063 builtin_floor eigs_num_arg READ b -builtins.c:2063 builtin_floor make_num PRODUCE c -builtins.c:2067 builtin_ceil make_num PRODUCE c -builtins.c:2067 builtin_ceil val_is_number TEST a -builtins.c:2068 builtin_ceil eigs_num_arg READ b -builtins.c:2068 builtin_ceil make_num PRODUCE c -builtins.c:2072 builtin_round make_num PRODUCE c -builtins.c:2072 builtin_round val_is_number TEST a -builtins.c:2073 builtin_round eigs_num_arg READ b -builtins.c:2073 builtin_round make_num PRODUCE c -builtins.c:2077 builtin_abs make_num PRODUCE c -builtins.c:2077 builtin_abs val_is_number TEST a -builtins.c:2078 builtin_abs VAL_INT TEST a -builtins.c:2079 builtin_abs VAL_I64_RAW RAW b -builtins.c:2086 builtin_abs eigs_num_arg READ b -builtins.c:2086 builtin_abs make_num PRODUCE c +builtins.c:337 bit_int VAL_I64_RAW RAW b +builtins.c:337 bit_int VAL_INT TEST a +builtins.c:338 bit_int eigs_num_arg READ b +builtins.c:339 bit_int num_to_i64_exact READ b +builtins.c:350 bit_pair val_is_number TEST a +builtins.c:350 bit_pair val_is_number TEST a +builtins.c:381 builtin_bit_not val_is_number TEST a +builtins.c:408 builtin_monotonic_ns make_num PRODUCE c +builtins.c:416 builtin_monotonic_ms make_num PRODUCE c +builtins.c:427 builtin_clock_unix make_num PRODUCE c +builtins.c:432 builtin_len make_num PRODUCE c +builtins.c:434 builtin_len make_num PRODUCE c +builtins.c:437 builtin_len make_num PRODUCE c +builtins.c:440 builtin_len make_num PRODUCE c +builtins.c:442 builtin_len make_num PRODUCE c +builtins.c:452 builtin_len make_num PRODUCE c +builtins.c:481 builtin_num make_num PRODUCE c +builtins.c:482 builtin_num val_is_number TEST a +builtins.c:489 builtin_num make_num PRODUCE c +builtins.c:508 builtin_num make_num PRODUCE c +builtins.c:516 builtin_num make_num PRODUCE c +builtins.c:521 builtin_num make_num PRODUCE c +builtins.c:521 builtin_num num_guard_named GUARD c +builtins.c:521 builtin_num strtod PARSE c +builtins.c:523 builtin_num make_num PRODUCE c +builtins.c:524 builtin_num make_num PRODUCE c +builtins.c:543 builtin_append VAL_FLOAT YIELD a +builtins.c:577 builtin_get_observer_thresholds make_num PRODUCE i +builtins.c:578 builtin_get_observer_thresholds make_num PRODUCE i +builtins.c:579 builtin_get_observer_thresholds make_num PRODUCE i +builtins.c:629 builtin_exit val_is_number TEST a +builtins.c:630 builtin_exit eigs_num_arg READ b +builtins.c:633 builtin_exit val_is_number TEST a +builtins.c:634 builtin_exit eigs_list_num READ b +builtins.c:769 builtin_observe make_num PRODUCE i +builtins.c:770 builtin_observe make_num PRODUCE i +builtins.c:771 builtin_observe make_num PRODUCE i +builtins.c:853 builtin_type VAL_FLOAT CASE a +builtins.c:854 builtin_type VAL_INT CASE a +builtins.c:872 builtin_num_type VAL_INT TEST a +builtins.c:873 builtin_num_type VAL_FLOAT TEST a +builtins.c:909 eigs_json_encode_value VAL_FLOAT CASE h +builtins.c:916 eigs_json_encode_value eigs_num_arg READ h +builtins.c:916 eigs_json_encode_value eigs_num_text FORMAT h +builtins.c:920 eigs_json_encode_value VAL_INT CASE h +builtins.c:922 eigs_json_encode_value VAL_I64_RAW RAW h +builtins.c:1285 eigs_json_parse_number make_num PRODUCE h +builtins.c:1292 eigs_json_parse_number make_num PRODUCE h +builtins.c:1301 eigs_json_parse_number make_num PRODUCE h +builtins.c:1306 eigs_json_parse_number strtod PARSE h +builtins.c:1316 eigs_json_parse_number strtod PARSE h +builtins.c:1320 eigs_json_parse_number make_num PRODUCE h +builtins.c:1491 builtin_json_build val_is_number TEST h +builtins.c:1493 builtin_json_build VAL_I64_RAW RAW h +builtins.c:1493 builtin_json_build VAL_INT TEST h +builtins.c:1494 builtin_json_build eigs_num_arg READ h +builtins.c:1494 builtin_json_build eigs_num_text FORMAT h +builtins.c:1678 builtin_scan_ints make_num PRODUCE c +builtins.c:1792 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1793 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1794 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1795 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1796 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1797 builtin_scan_int_tokens make_num PRODUCE c +builtins.c:1900 builtin_char_at val_is_number TEST a +builtins.c:1902 builtin_char_at eigs_num_arg READ b +builtins.c:1936 builtin_substr val_is_number TEST a +builtins.c:1937 builtin_substr val_is_number TEST a +builtins.c:1939 builtin_substr eigs_num_arg READ b +builtins.c:1940 builtin_substr eigs_num_arg READ b +builtins.c:1970 builtin_index_of make_num PRODUCE c +builtins.c:1977 builtin_index_of make_num PRODUCE c +builtins.c:1982 builtin_index_of make_num PRODUCE c +builtins.c:1983 builtin_index_of make_num PRODUCE c +builtins.c:1991 builtin_sin make_num PRODUCE c +builtins.c:1991 builtin_sin val_is_number TEST a +builtins.c:1992 builtin_sin eigs_num_arg READ b +builtins.c:1992 builtin_sin make_num PRODUCE c +builtins.c:1996 builtin_cos make_num PRODUCE c +builtins.c:1996 builtin_cos val_is_number TEST a +builtins.c:1997 builtin_cos eigs_num_arg READ b +builtins.c:1997 builtin_cos make_num PRODUCE c +builtins.c:2001 builtin_tan make_num PRODUCE c +builtins.c:2001 builtin_tan val_is_number TEST a +builtins.c:2002 builtin_tan eigs_num_arg READ b +builtins.c:2002 builtin_tan make_num PRODUCE c +builtins.c:2006 builtin_asin make_num PRODUCE c +builtins.c:2006 builtin_asin val_is_number TEST a +builtins.c:2007 builtin_asin eigs_num_arg READ b +builtins.c:2012 builtin_asin make_num PRODUCE c +builtins.c:2016 builtin_asin make_num PRODUCE c +builtins.c:2020 builtin_acos make_num PRODUCE c +builtins.c:2020 builtin_acos val_is_number TEST a +builtins.c:2021 builtin_acos eigs_num_arg READ b +builtins.c:2026 builtin_acos make_num PRODUCE c +builtins.c:2030 builtin_acos make_num PRODUCE c +builtins.c:2034 builtin_atan make_num PRODUCE c +builtins.c:2034 builtin_atan val_is_number TEST a +builtins.c:2035 builtin_atan eigs_num_arg READ b +builtins.c:2035 builtin_atan make_num PRODUCE c +builtins.c:2040 builtin_atan2 make_num PRODUCE c +builtins.c:2043 builtin_atan2 make_num PRODUCE c +builtins.c:2043 builtin_atan2 val_is_number TEST a +builtins.c:2043 builtin_atan2 val_is_number TEST a +builtins.c:2044 builtin_atan2 eigs_num_arg READ b +builtins.c:2044 builtin_atan2 eigs_num_arg READ b +builtins.c:2044 builtin_atan2 make_num PRODUCE c +builtins.c:2048 builtin_floor make_num PRODUCE c +builtins.c:2048 builtin_floor val_is_number TEST a +builtins.c:2049 builtin_floor eigs_num_arg READ b +builtins.c:2049 builtin_floor make_num PRODUCE c +builtins.c:2053 builtin_ceil make_num PRODUCE c +builtins.c:2053 builtin_ceil val_is_number TEST a +builtins.c:2054 builtin_ceil eigs_num_arg READ b +builtins.c:2054 builtin_ceil make_num PRODUCE c +builtins.c:2058 builtin_round make_num PRODUCE c +builtins.c:2058 builtin_round val_is_number TEST a +builtins.c:2059 builtin_round eigs_num_arg READ b +builtins.c:2059 builtin_round make_num PRODUCE c +builtins.c:2063 builtin_abs make_num PRODUCE c +builtins.c:2063 builtin_abs val_is_number TEST a +builtins.c:2064 builtin_abs VAL_INT TEST a +builtins.c:2065 builtin_abs VAL_I64_RAW RAW b +builtins.c:2072 builtin_abs eigs_num_arg READ b +builtins.c:2072 builtin_abs make_num PRODUCE c +builtins.c:2081 minmax_reduce eigs_num_arg READ b +builtins.c:2081 minmax_reduce make_num PRODUCE c +builtins.c:2081 minmax_reduce val_is_number TEST a +builtins.c:2086 minmax_reduce make_num PRODUCE c +builtins.c:2089 minmax_reduce make_num PRODUCE c +builtins.c:2093 minmax_reduce make_num PRODUCE c +builtins.c:2093 minmax_reduce val_is_number TEST a +builtins.c:2094 minmax_reduce eigs_num_arg READ b +builtins.c:2094 minmax_reduce eigs_num_arg READ b builtins.c:2095 minmax_reduce eigs_num_arg READ b -builtins.c:2095 minmax_reduce make_num PRODUCE c -builtins.c:2095 minmax_reduce val_is_number TEST a -builtins.c:2100 minmax_reduce make_num PRODUCE c -builtins.c:2103 minmax_reduce make_num PRODUCE c -builtins.c:2107 minmax_reduce make_num PRODUCE c -builtins.c:2107 minmax_reduce val_is_number TEST a -builtins.c:2108 minmax_reduce eigs_num_arg READ b -builtins.c:2108 minmax_reduce eigs_num_arg READ b -builtins.c:2109 minmax_reduce eigs_num_arg READ b -builtins.c:2111 minmax_reduce make_num PRODUCE c -builtins.c:2120 builtin_pi make_num PRODUCE c -builtins.c:2176 builtin_random make_num PRODUCE c -builtins.c:2185 builtin_random_int make_num PRODUCE c -builtins.c:2188 builtin_random_int val_is_number TEST a -builtins.c:2188 builtin_random_int val_is_number TEST a -builtins.c:2189 builtin_random_int make_num PRODUCE c -builtins.c:2193 builtin_random_int eigs_num_arg READ b -builtins.c:2194 builtin_random_int eigs_num_arg READ b -builtins.c:2204 builtin_random_int make_num PRODUCE c -builtins.c:2216 builtin_random_int make_num PRODUCE c -builtins.c:2221 builtin_seed_random val_is_number TEST a -builtins.c:2223 builtin_seed_random eigs_num_arg READ b -builtins.c:2451 builtin_json_path val_is_number TEST h -builtins.c:2453 builtin_json_path VAL_I64_RAW RAW h -builtins.c:2453 builtin_json_path VAL_INT TEST h -builtins.c:2454 builtin_json_path eigs_num_arg READ h -builtins.c:2454 builtin_json_path eigs_num_text FORMAT h -builtins.c:2558 builtin_token_name val_is_number TEST a -builtins.c:2559 builtin_token_name eigs_num_arg READ b -builtins.c:2595 builtin_state_at val_is_number TEST i -builtins.c:2596 builtin_state_at eigs_num_arg READ i -builtins.c:2642 builtin_chr val_is_number TEST a -builtins.c:2646 builtin_chr eigs_num_arg READ b -builtins.c:2670 builtin_hex val_is_number TEST e -builtins.c:2671 builtin_hex eigs_num_arg READ e -builtins.c:2673 builtin_hex val_is_number TEST e -builtins.c:2674 builtin_hex val_is_number TEST e -builtins.c:2675 builtin_hex eigs_list_num READ e -builtins.c:2676 builtin_hex eigs_list_num READ e -builtins.c:2703 builtin_ord make_num PRODUCE c -builtins.c:2706 builtin_ord make_num PRODUCE c -builtins.c:2707 builtin_ord make_num PRODUCE c -builtins.c:2824 vm_desc_abi_error val_is_number TEST a -builtins.c:2832 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2837 vm_desc_abi_error eigs_num_arg READ b -builtins.c:2933 desc_isolate_const VAL_FLOAT CASE a -builtins.c:2934 desc_isolate_const VAL_INT CASE a -builtins.c:3051 vm_build_chunk_desc_body val_is_number TEST a -builtins.c:3056 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3112 vm_build_chunk_desc_body val_is_number TEST a -builtins.c:3113 vm_build_chunk_desc_body eigs_num_arg READ b -builtins.c:3430 builtin_sandbox_run val_is_number TEST a -builtins.c:3431 builtin_sandbox_run eigs_list_num READ b -builtins.c:3437 builtin_sandbox_run val_is_number TEST a -builtins.c:3438 builtin_sandbox_run eigs_list_num READ b -builtins.c:3439 builtin_sandbox_run eigs_list_num READ b -builtins.c:3446 builtin_sandbox_run val_is_number TEST a -builtins.c:3447 builtin_sandbox_run eigs_list_num READ b -builtins.c:3489 builtin_sandbox_run make_num PRODUCE c -builtins.c:3670 builtin_sandbox_run make_num PRODUCE c +builtins.c:2097 minmax_reduce make_num PRODUCE c +builtins.c:2106 builtin_pi make_num PRODUCE c +builtins.c:2162 builtin_random make_num PRODUCE c +builtins.c:2171 builtin_random_int make_num PRODUCE c +builtins.c:2174 builtin_random_int val_is_number TEST a +builtins.c:2174 builtin_random_int val_is_number TEST a +builtins.c:2175 builtin_random_int make_num PRODUCE c +builtins.c:2179 builtin_random_int eigs_num_arg READ b +builtins.c:2180 builtin_random_int eigs_num_arg READ b +builtins.c:2190 builtin_random_int make_num PRODUCE c +builtins.c:2202 builtin_random_int make_num PRODUCE c +builtins.c:2207 builtin_seed_random val_is_number TEST a +builtins.c:2209 builtin_seed_random eigs_num_arg READ b +builtins.c:2437 builtin_json_path val_is_number TEST h +builtins.c:2439 builtin_json_path VAL_I64_RAW RAW h +builtins.c:2439 builtin_json_path VAL_INT TEST h +builtins.c:2440 builtin_json_path eigs_num_arg READ h +builtins.c:2440 builtin_json_path eigs_num_text FORMAT h +builtins.c:2544 builtin_token_name val_is_number TEST a +builtins.c:2545 builtin_token_name eigs_num_arg READ b +builtins.c:2581 builtin_state_at val_is_number TEST i +builtins.c:2582 builtin_state_at eigs_num_arg READ i +builtins.c:2628 builtin_chr val_is_number TEST a +builtins.c:2632 builtin_chr eigs_num_arg READ b +builtins.c:2656 builtin_hex val_is_number TEST e +builtins.c:2657 builtin_hex eigs_num_arg READ e +builtins.c:2659 builtin_hex val_is_number TEST e +builtins.c:2660 builtin_hex val_is_number TEST e +builtins.c:2661 builtin_hex eigs_list_num READ e +builtins.c:2662 builtin_hex eigs_list_num READ e +builtins.c:2689 builtin_ord make_num PRODUCE c +builtins.c:2692 builtin_ord make_num PRODUCE c +builtins.c:2693 builtin_ord make_num PRODUCE c +builtins.c:2810 vm_desc_abi_error val_is_number TEST a +builtins.c:2818 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2823 vm_desc_abi_error eigs_num_arg READ b +builtins.c:2919 desc_isolate_const VAL_FLOAT CASE a +builtins.c:2920 desc_isolate_const VAL_INT CASE a +builtins.c:3037 vm_build_chunk_desc_body val_is_number TEST a +builtins.c:3042 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3098 vm_build_chunk_desc_body val_is_number TEST a +builtins.c:3099 vm_build_chunk_desc_body eigs_num_arg READ b +builtins.c:3416 builtin_sandbox_run val_is_number TEST a +builtins.c:3417 builtin_sandbox_run eigs_list_num READ b +builtins.c:3423 builtin_sandbox_run val_is_number TEST a +builtins.c:3424 builtin_sandbox_run eigs_list_num READ b +builtins.c:3425 builtin_sandbox_run eigs_list_num READ b +builtins.c:3432 builtin_sandbox_run val_is_number TEST a +builtins.c:3433 builtin_sandbox_run eigs_list_num READ b +builtins.c:3475 builtin_sandbox_run make_num PRODUCE c +builtins.c:3656 builtin_sandbox_run make_num PRODUCE c +builtins.c:3668 builtin_sandbox_run make_num PRODUCE c builtins.c:3682 builtin_sandbox_run make_num PRODUCE c -builtins.c:3696 builtin_sandbox_run make_num PRODUCE c -builtins.c:3730 builtin_sandbox_run make_num PRODUCE c -builtins.c:3756 builtin_record_history val_is_number TEST i -builtins.c:3762 builtin_record_history eigs_num_arg READ i -builtins.c:3767 builtin_record_history make_num PRODUCE i -builtins.c:3795 builtin_copy_into val_is_number TEST a -builtins.c:3800 builtin_copy_into eigs_num_arg READ b -builtins.c:3812 builtin_copy_into val_is_number TEST a -builtins.c:3817 builtin_copy_into eigs_num_arg READ b -builtins.c:3850 builtin_list_slice val_is_number TEST a -builtins.c:3850 builtin_list_slice val_is_number TEST a -builtins.c:3853 builtin_list_slice eigs_num_arg READ b -builtins.c:3854 builtin_list_slice eigs_num_arg READ b -builtins.c:3876 builtin_num_copy val_is_number TEST a -builtins.c:3877 builtin_num_copy eigs_num_arg READ b -builtins.c:3877 builtin_num_copy make_num PRODUCE c -builtins.c:3921 builtin_range val_is_number TEST a -builtins.c:3923 builtin_range eigs_num_arg READ b -builtins.c:3930 builtin_range val_is_number TEST a -builtins.c:3938 builtin_range eigs_list_num READ b -builtins.c:3941 builtin_range eigs_list_num READ b -builtins.c:3945 builtin_range eigs_list_num READ b -builtins.c:3989 builtin_range make_num PRODUCE c -builtins.c:4005 builtin_fill eigs_list_num READ b -builtins.c:4027 at_index val_is_number TEST a -builtins.c:4031 at_index eigs_num_arg READ b -builtins.c:4035 at_index eigs_num_arg READ b -builtins.c:4046 buf_at_index val_is_number TEST a -builtins.c:4051 buf_at_index eigs_num_arg READ b -builtins.c:4055 buf_at_index eigs_num_arg READ b -builtins.c:4095 builtin_set_at val_is_number TEST a -builtins.c:4100 builtin_set_at eigs_num_arg READ b -builtins.c:4161 builtin_get_at buffer_read_num READ b -builtins.c:4161 builtin_get_at make_num PRODUCE c -builtins.c:4169 builtin_get_at buffer_read_num READ b -builtins.c:4169 builtin_get_at make_num PRODUCE c -builtins.c:4553 builtin_spawn make_num PRODUCE c -builtins.c:4559 builtin_spawn make_num PRODUCE c -builtins.c:4560 builtin_spawn make_num PRODUCE c -builtins.c:4585 builtin_thread_join val_is_number TEST a -builtins.c:4589 builtin_thread_join eigs_num_arg READ b -builtins.c:4590 builtin_thread_join eigs_num_arg READ b -builtins.c:4590 builtin_thread_join val_is_number TEST a -builtins.c:4693 get_channel_why val_is_number TEST a -builtins.c:4694 get_channel_why eigs_num_arg READ b -builtins.c:4696 get_channel_why eigs_num_arg READ b -builtins.c:4696 get_channel_why val_is_number TEST a -builtins.c:4761 builtin_channel make_num PRODUCE c -builtins.c:4762 builtin_channel make_num PRODUCE c -builtins.c:4864 builtin_recv_timeout val_is_number TEST a -builtins.c:4868 builtin_recv_timeout eigs_num_arg READ b -builtins.c:5050 builtin_task_spawn make_num PRODUCE c -builtins.c:5060 task_handle_resolve val_is_number TEST a -builtins.c:5061 task_handle_resolve eigs_num_arg READ b -builtins.c:5112 builtin_task_join val_is_number TEST a -builtins.c:5157 builtin_task_send val_is_number TEST a -builtins.c:5165 builtin_task_send eigs_num_arg READ b -builtins.c:5188 builtin_task_kill val_is_number TEST a -builtins.c:5200 builtin_task_alive val_is_number TEST a -builtins.c:5222 builtin_task_sleep val_is_number TEST a -builtins.c:5228 builtin_task_sleep eigs_num_arg READ b -builtins.c:5260 builtin_task_self make_num PRODUCE c -builtins.c:5274 builtin_task_detach val_is_number TEST a -builtins.c:5279 builtin_task_detach make_num PRODUCE c -builtins.c:5282 builtin_task_detach make_num PRODUCE c -builtins.c:5293 builtin_task_sched_seed val_is_number TEST a -builtins.c:5297 builtin_task_sched_seed eigs_num_arg READ b -builtins.c:5446 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5447 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5448 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5449 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5450 builtin_nearest_in_range eigs_list_num READ b -builtins.c:5506 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5506 builtin_nearest_in_range val_is_number TEST a -builtins.c:5530 builtin_nearest_in_range eigs_num_arg_slow READ b -builtins.c:5533 builtin_nearest_in_range val_is_number TEST a -builtins.c:5533 builtin_nearest_in_range val_is_number TEST a -builtins.c:5535 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5536 builtin_nearest_in_range eigs_num_arg READ b -builtins.c:5550 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5551 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5552 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5553 builtin_nearest_in_range make_num PRODUCE c -builtins.c:5578 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5579 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5580 builtin_nearest_in_range_all eigs_list_num READ b -builtins.c:5635 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5635 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5655 builtin_nearest_in_range_all eigs_num_arg_slow READ b -builtins.c:5658 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5658 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5662 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5663 builtin_nearest_in_range_all eigs_num_arg READ b -builtins.c:5704 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5705 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5706 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5707 builtin_nearest_in_range_all make_num PRODUCE c -builtins.c:5730 builtin_sign_extend make_num PRODUCE c -builtins.c:5740 builtin_sign_extend make_num PRODUCE c -builtins.c:5740 builtin_sign_extend val_is_number TEST a -builtins.c:5740 builtin_sign_extend val_is_number TEST a -builtins.c:5741 builtin_sign_extend eigs_num_arg READ b -builtins.c:5742 builtin_sign_extend eigs_num_arg READ b -builtins.c:5743 builtin_sign_extend make_num PRODUCE c -builtins.c:5746 builtin_sign_extend make_num PRODUCE c -builtins.c:5747 builtin_sign_extend make_num PRODUCE c -builtins.c:5764 builtin_list_truncate val_is_number TEST a -builtins.c:5768 builtin_list_truncate eigs_num_arg READ b -builtins.c:5794 builtin_list_remove_at val_is_number TEST a -builtins.c:5795 builtin_list_remove_at eigs_num_arg READ b -builtins.c:5816 builtin_list_insert_at val_is_number TEST a -builtins.c:5817 builtin_list_insert_at eigs_num_arg READ b +builtins.c:3716 builtin_sandbox_run make_num PRODUCE c +builtins.c:3742 builtin_record_history val_is_number TEST i +builtins.c:3748 builtin_record_history eigs_num_arg READ i +builtins.c:3753 builtin_record_history make_num PRODUCE i +builtins.c:3781 builtin_copy_into val_is_number TEST a +builtins.c:3786 builtin_copy_into eigs_num_arg READ b +builtins.c:3798 builtin_copy_into val_is_number TEST a +builtins.c:3803 builtin_copy_into eigs_num_arg READ b +builtins.c:3836 builtin_list_slice val_is_number TEST a +builtins.c:3836 builtin_list_slice val_is_number TEST a +builtins.c:3839 builtin_list_slice eigs_num_arg READ b +builtins.c:3840 builtin_list_slice eigs_num_arg READ b +builtins.c:3862 builtin_num_copy val_is_number TEST a +builtins.c:3863 builtin_num_copy eigs_num_arg READ b +builtins.c:3863 builtin_num_copy make_num PRODUCE c +builtins.c:3907 builtin_range val_is_number TEST a +builtins.c:3909 builtin_range eigs_num_arg READ b +builtins.c:3916 builtin_range val_is_number TEST a +builtins.c:3924 builtin_range eigs_list_num READ b +builtins.c:3927 builtin_range eigs_list_num READ b +builtins.c:3931 builtin_range eigs_list_num READ b +builtins.c:3975 builtin_range make_num PRODUCE c +builtins.c:3991 builtin_fill eigs_list_num READ b +builtins.c:4013 at_index val_is_number TEST a +builtins.c:4017 at_index eigs_num_arg READ b +builtins.c:4021 at_index eigs_num_arg READ b +builtins.c:4032 buf_at_index val_is_number TEST a +builtins.c:4037 buf_at_index eigs_num_arg READ b +builtins.c:4041 buf_at_index eigs_num_arg READ b +builtins.c:4081 builtin_set_at val_is_number TEST a +builtins.c:4086 builtin_set_at eigs_num_arg READ b +builtins.c:4147 builtin_get_at buffer_read_num READ b +builtins.c:4147 builtin_get_at make_num PRODUCE c +builtins.c:4155 builtin_get_at buffer_read_num READ b +builtins.c:4155 builtin_get_at make_num PRODUCE c +builtins.c:4539 builtin_spawn make_num PRODUCE c +builtins.c:4545 builtin_spawn make_num PRODUCE c +builtins.c:4546 builtin_spawn make_num PRODUCE c +builtins.c:4571 builtin_thread_join val_is_number TEST a +builtins.c:4575 builtin_thread_join eigs_num_arg READ b +builtins.c:4576 builtin_thread_join eigs_num_arg READ b +builtins.c:4576 builtin_thread_join val_is_number TEST a +builtins.c:4679 get_channel_why val_is_number TEST a +builtins.c:4680 get_channel_why eigs_num_arg READ b +builtins.c:4682 get_channel_why eigs_num_arg READ b +builtins.c:4682 get_channel_why val_is_number TEST a +builtins.c:4747 builtin_channel make_num PRODUCE c +builtins.c:4748 builtin_channel make_num PRODUCE c +builtins.c:4850 builtin_recv_timeout val_is_number TEST a +builtins.c:4854 builtin_recv_timeout eigs_num_arg READ b +builtins.c:5036 builtin_task_spawn make_num PRODUCE c +builtins.c:5046 task_handle_resolve val_is_number TEST a +builtins.c:5047 task_handle_resolve eigs_num_arg READ b +builtins.c:5098 builtin_task_join val_is_number TEST a +builtins.c:5143 builtin_task_send val_is_number TEST a +builtins.c:5151 builtin_task_send eigs_num_arg READ b +builtins.c:5174 builtin_task_kill val_is_number TEST a +builtins.c:5186 builtin_task_alive val_is_number TEST a +builtins.c:5208 builtin_task_sleep val_is_number TEST a +builtins.c:5214 builtin_task_sleep eigs_num_arg READ b +builtins.c:5246 builtin_task_self make_num PRODUCE c +builtins.c:5260 builtin_task_detach val_is_number TEST a +builtins.c:5265 builtin_task_detach make_num PRODUCE c +builtins.c:5268 builtin_task_detach make_num PRODUCE c +builtins.c:5279 builtin_task_sched_seed val_is_number TEST a +builtins.c:5283 builtin_task_sched_seed eigs_num_arg READ b +builtins.c:5432 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5433 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5434 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5435 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5436 builtin_nearest_in_range eigs_list_num READ b +builtins.c:5492 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5492 builtin_nearest_in_range val_is_number TEST a +builtins.c:5516 builtin_nearest_in_range eigs_num_arg_slow READ b +builtins.c:5519 builtin_nearest_in_range val_is_number TEST a +builtins.c:5519 builtin_nearest_in_range val_is_number TEST a +builtins.c:5521 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5522 builtin_nearest_in_range eigs_num_arg READ b +builtins.c:5536 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5537 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5538 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5539 builtin_nearest_in_range make_num PRODUCE c +builtins.c:5564 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5565 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5566 builtin_nearest_in_range_all eigs_list_num READ b +builtins.c:5621 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5621 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5641 builtin_nearest_in_range_all eigs_num_arg_slow READ b +builtins.c:5644 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5644 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5648 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5649 builtin_nearest_in_range_all eigs_num_arg READ b +builtins.c:5690 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5691 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5692 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5693 builtin_nearest_in_range_all make_num PRODUCE c +builtins.c:5716 builtin_sign_extend make_num PRODUCE c +builtins.c:5726 builtin_sign_extend make_num PRODUCE c +builtins.c:5726 builtin_sign_extend val_is_number TEST a +builtins.c:5726 builtin_sign_extend val_is_number TEST a +builtins.c:5727 builtin_sign_extend eigs_num_arg READ b +builtins.c:5728 builtin_sign_extend eigs_num_arg READ b +builtins.c:5729 builtin_sign_extend make_num PRODUCE c +builtins.c:5732 builtin_sign_extend make_num PRODUCE c +builtins.c:5733 builtin_sign_extend make_num PRODUCE c +builtins.c:5750 builtin_list_truncate val_is_number TEST a +builtins.c:5754 builtin_list_truncate eigs_num_arg READ b +builtins.c:5780 builtin_list_remove_at val_is_number TEST a +builtins.c:5781 builtin_list_remove_at eigs_num_arg READ b +builtins.c:5802 builtin_list_insert_at val_is_number TEST a +builtins.c:5803 builtin_list_insert_at eigs_num_arg READ b +builtins.c:5830 builtin_list_index_of make_num PRODUCE f +builtins.c:5834 builtin_list_index_of make_num PRODUCE f +builtins.c:5840 builtin_list_index_of make_num PRODUCE f builtins.c:5844 builtin_list_index_of make_num PRODUCE f -builtins.c:5848 builtin_list_index_of make_num PRODUCE f -builtins.c:5854 builtin_list_index_of make_num PRODUCE f -builtins.c:5858 builtin_list_index_of make_num PRODUCE f -builtins.c:5929 builtin_sort_by val_is_number TEST f -builtins.c:5938 builtin_sort_by VAL_INT TEST f -builtins.c:5939 builtin_sort_by VAL_I64_RAW RAW f -builtins.c:5940 builtin_sort_by eigs_num_arg READ f -builtins.c:5962 sort_cmp_num VAL_INT TEST a -builtins.c:5962 sort_cmp_num VAL_INT TEST a -builtins.c:5963 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5963 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5963 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5963 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5964 sort_cmp_num VAL_INT TEST a -builtins.c:5965 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5965 sort_cmp_num eigs_num_arg READ b -builtins.c:5968 sort_cmp_num VAL_INT TEST a -builtins.c:5969 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:5969 sort_cmp_num eigs_num_arg READ b -builtins.c:5972 sort_cmp_num eigs_num_arg READ b -builtins.c:5972 sort_cmp_num eigs_num_arg READ b -builtins.c:5990 builtin_sort VAL_FLOAT TEST f -builtins.c:5990 builtin_sort VAL_INT TEST f -builtins.c:5991 builtin_sort val_is_number TEST f -builtins.c:5998 builtin_sort VAL_FLOAT TEST f -builtins.c:5998 builtin_sort VAL_INT TEST f -builtins.c:6019 builtin_dispatch val_is_number TEST a -builtins.c:6023 builtin_dispatch eigs_num_arg READ b -builtins.c:6024 builtin_dispatch eigs_num_arg READ b -builtins.c:6026 builtin_dispatch eigs_num_arg READ b -builtins.c:6049 builtin_dispatch val_is_number TEST a -builtins.c:6050 builtin_dispatch VAL_INT TEST a -builtins.c:6051 builtin_dispatch VAL_I64_RAW RAW b -builtins.c:6052 builtin_dispatch eigs_num_arg READ b -builtins.c:6052 builtin_dispatch make_num PRODUCE c +builtins.c:5915 builtin_sort_by val_is_number TEST f +builtins.c:5924 builtin_sort_by VAL_INT TEST f +builtins.c:5925 builtin_sort_by VAL_I64_RAW RAW f +builtins.c:5926 builtin_sort_by eigs_num_arg READ f +builtins.c:5948 sort_cmp_num VAL_INT TEST a +builtins.c:5948 sort_cmp_num VAL_INT TEST a +builtins.c:5949 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5949 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5949 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5949 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5950 sort_cmp_num VAL_INT TEST a +builtins.c:5951 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5951 sort_cmp_num eigs_num_arg READ b +builtins.c:5954 sort_cmp_num VAL_INT TEST a +builtins.c:5955 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:5955 sort_cmp_num eigs_num_arg READ b +builtins.c:5958 sort_cmp_num eigs_num_arg READ b +builtins.c:5958 sort_cmp_num eigs_num_arg READ b +builtins.c:5976 builtin_sort VAL_FLOAT TEST f +builtins.c:5976 builtin_sort VAL_INT TEST f +builtins.c:5977 builtin_sort val_is_number TEST f +builtins.c:5984 builtin_sort VAL_FLOAT TEST f +builtins.c:5984 builtin_sort VAL_INT TEST f +builtins.c:6005 builtin_dispatch val_is_number TEST a +builtins.c:6009 builtin_dispatch eigs_num_arg READ b +builtins.c:6010 builtin_dispatch eigs_num_arg READ b +builtins.c:6012 builtin_dispatch eigs_num_arg READ b +builtins.c:6035 builtin_dispatch val_is_number TEST a +builtins.c:6036 builtin_dispatch VAL_INT TEST a +builtins.c:6037 builtin_dispatch VAL_I64_RAW RAW b +builtins.c:6038 builtin_dispatch eigs_num_arg READ b +builtins.c:6038 builtin_dispatch make_num PRODUCE c +builtins.c:6114 builtin_dot make_num PRODUCE c +builtins.c:6117 builtin_dot make_num PRODUCE c +builtins.c:6122 builtin_dot buffer_read_num READ b +builtins.c:6124 builtin_dot buffer_read_num READ b +builtins.c:6126 builtin_dot num_guard GUARD c +builtins.c:6126 builtin_dot num_guard GUARD c builtins.c:6128 builtin_dot make_num PRODUCE c -builtins.c:6131 builtin_dot make_num PRODUCE c -builtins.c:6136 builtin_dot buffer_read_num READ b -builtins.c:6138 builtin_dot buffer_read_num READ b -builtins.c:6140 builtin_dot num_guard GUARD c -builtins.c:6140 builtin_dot num_guard GUARD c -builtins.c:6142 builtin_dot make_num PRODUCE c builtins_buf.c:35 builtin_buffer VAL_FLOAT TEST a builtins_buf.c:35 builtin_buffer VAL_INT TEST a builtins_buf.c:36 builtin_buffer VAL_FLOAT TEST a @@ -1549,12 +1543,12 @@ eigenscript.h:1900 buffer_read_num buffer_read_num READ b eigenscript.h:1901 buffer_read_num num_guard GUARD c eigenscript.h:1907 finite_num_to_byte finite_num_to_byte READ b eigenscript.h:1916 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:1925 buffer_read_byte buffer_read_byte READ b -eigenscript.h:1926 buffer_read_byte buffer_read_num READ b -eigenscript.h:1928 buffer_read_byte finite_num_to_byte READ b -eigenscript.h:1939 num_guard_named num_guard_named GUARD c -eigenscript.h:1945 num_guard_named num_guard GUARD c -eigenscript.h:2251 eigs_num_text FORMAT e +eigenscript.h:1935 buffer_read_byte buffer_read_byte READ b +eigenscript.h:1936 buffer_read_byte buffer_read_num READ b +eigenscript.h:1938 buffer_read_byte finite_num_to_byte READ b +eigenscript.h:1949 num_guard_named num_guard_named GUARD c +eigenscript.h:1955 num_guard_named num_guard GUARD c +eigenscript.h:2261 eigs_num_text FORMAT e eigs_embed.c:301 eigs_value_new_num make_num PRODUCE j eigs_embed.c:314 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:315 eigs_value_type VAL_INT CASE j @@ -2475,108 +2469,108 @@ vm.c:3663 vm_run_ex/CASE(MOD) eigs_num_arg READ b vm.c:3663 vm_run_ex/CASE(MOD) make_num PRODUCE c vm.c:3663 vm_run_ex/CASE(MOD) num_guard GUARD c vm.c:3669 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3697 #define INT_BINOP_R slot_f64_value READ b -vm.c:3701 #define INT_BINOP_R slot_from_f64 PRODUCE c -vm.c:3728 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3731 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3731 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3734 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3738 vm_run_ex/CASE(NEG) slot_int_value READ b -vm.c:3743 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c -vm.c:3748 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3770 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3774 vm_run_ex/CASE(BNOT) slot_from_f64 PRODUCE c -vm.c:3783 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3783 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3789 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3789 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3809 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3809 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3815 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3815 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3837 #define NUM_CMP slot_f64_value READ f -vm.c:3837 #define NUM_CMP slot_f64_value READ f -vm.c:4785 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4787 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4794 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4804 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4806 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4808 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:3685 #define INT_BINOP_R slot_from_int PRODUCE c +vm.c:3691 #define INT_BINOP_R slot_f64_value READ b +vm.c:3711 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3714 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3714 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3717 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3721 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3726 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3731 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3748 vm_run_ex/CASE(BNOT) slot_from_int PRODUCE c +vm.c:3753 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3766 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3766 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3772 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3772 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3792 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3792 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3798 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3798 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3820 #define NUM_CMP slot_f64_value READ f +vm.c:3820 #define NUM_CMP slot_f64_value READ f +vm.c:4768 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4770 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4777 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4787 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b +vm.c:4789 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4791 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4813 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4815 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4816 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4818 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4820 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b vm.c:4830 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a vm.c:4832 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4833 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4835 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4837 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4847 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4849 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4849 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4851 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4863 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4866 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4873 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4876 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4879 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4880 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4936 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4939 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:5000 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:5001 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5027 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:5027 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5133 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5134 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5207 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5211 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5211 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5550 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5551 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5552 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5586 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5587 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5588 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5652 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5653 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5653 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5653 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5657 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5658 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5659 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5660 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5664 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5678 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5679 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5680 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5681 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5701 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5727 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5730 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5731 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5734 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5750 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5758 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5761 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5766 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5786 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5787 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5788 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5789 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5919 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5919 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5936 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5937 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5939 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5946 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5950 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5953 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5954 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5957 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5968 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5971 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6565 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6566 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6567 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6570 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6580 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6581 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6583 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6587 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:4832 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c +vm.c:4834 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4846 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4849 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4856 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4859 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4862 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4863 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b +vm.c:4919 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4922 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4983 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4984 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5010 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b +vm.c:5010 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5116 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5117 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5190 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c +vm.c:5194 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b +vm.c:5194 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5533 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5534 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5535 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i +vm.c:5569 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5570 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5571 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i +vm.c:5635 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5636 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5636 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5636 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5640 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5641 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5642 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5643 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5647 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5661 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5662 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5663 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5664 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i +vm.c:5684 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5710 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5713 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5714 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5717 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i +vm.c:5733 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5741 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5744 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5749 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5769 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5770 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5771 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5772 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5902 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5902 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5919 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5920 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5922 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5929 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5933 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5936 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5937 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5940 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5951 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5954 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6548 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6549 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6550 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6553 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6563 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6564 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6566 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6570 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 16892e73f..c9e244511 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -732,7 +732,7 @@ result).** | `value_slot.h:slot_truthy_immediate` | smi-arm | an int is truthy when it is not 0, like a double (D1) | | `vm.c:#define ARITH_FAST` | guarded | an int is not a float (`slot_f64_value`): the arm's slow path pops it through `slot_bridge_unwrap`; R1.3 gives that path int arithmetic (D1) | | `vm.c:#define INT_ARITH` | smi-arm | two exact integer slots use checked int64 arithmetic; the result is an SMI when it fits and an owned int box otherwise, and overflow raises (R1.3) (D1) | -| `vm.c:#define INT_BINOP_R` | smi-arm | both operands use `vm_bit_operand`, retaining exact int64 bits and the transitional shift rules (R1.3) (D1) | +| `vm.c:#define INT_BINOP_R` | smi-arm | both operands use `vm_bit_operand`; R1.5 returns the int kind and uses `eigs_bit_shift` for Lua counts and logical right shift (D1) | | `vm.c:#define NUM_CMP` | smi-arm | the float fast path remains; integer and cross-kind operands use exact N2 comparison (R1.3) (D1) | | `vm.c:#define READ_SLICE_BOUND` | smi-arm | an int bound is its value when a C `int` holds it, else a value error (D1) | | `vm.c:jit_helper_dot_get` | guarded | a non-null field is pushed as its bits; an SMI is a valid stack slot (D3) | @@ -762,7 +762,7 @@ result).** | `vm.c:vm_leaf_accessor_exec/OP_LOCAL_DOT_GET` | guarded | a non-pointer target bails (`return 0`); a non-null field is borrowed as its bits, an SMI included (D2) | | `vm.c:vm_local_is_null` | guarded | exact null test (D3) | | `vm.c:vm_local_lift` | guarded | a non-pointer, non-null slot goes through `slot_to_value` (compile-forced) and is boxed on purpose (D2) | -| `vm.c:vm_run_ex/CASE(BNOT)` | smi-arm | an int64 operand is read exactly; the result retains the transitional float bridge until R1.5 (R1.3) (D1) | +| `vm.c:vm_run_ex/CASE(BNOT)` | smi-arm | an int64 operand is read exactly; R1.5 returns its exact complement as the int kind (D1) | | `vm.c:vm_run_ex/CASE(DESTRUCTURE_UNPACK)` | guarded | a non-pointer source takes the error path, which names the type through `slot_type_name` (D2) | | `vm.c:vm_run_ex/CASE(DISPATCH)` | smi-arm | an int key is its value when a C `int` holds it, else a value error; the result returns through `slot_bridge_unwrap` (D1) | | `vm.c:vm_run_ex/CASE(DOT_GET)` | guarded | exact null test of a field (D3) | @@ -1390,12 +1390,12 @@ current state behind several rows: | `audio_stream_queued` | int-preserving | - | - | sample count | | `audio_sweep` | float-producing | - | magnitude | float samples; frequencies and amplitude stay floats; the duration is continuous: a sample count the C int cannot hold raises (Q7 magnitude); the wave selector is integer-valued: N5 (Q1) | | `audio_volume` | int-requiring | - | bounded | channel index: N5 (Q1); the volume is a continuous gain: clamped to the mixer's range (Q7 bounded) | -| `bit_and` | int-requiring | LOSS | - | Lua `&` (§3.4.2): N5 operands, int64-pattern result (N8); today a double result | -| `bit_not` | int-requiring | LOSS | - | Lua unary `~` | -| `bit_or` | int-requiring | LOSS | - | Lua `\|` | -| `bit_shl` | int-requiring | LOSS | - | Lua `<<`; today masks the count mod 64, N8 needs >=64 gives 0 and negative shifts right | -| `bit_shr` | int-requiring | LOSS | - | Lua `>>` is logical (N8); today an arithmetic shift with `& 63` | -| `bit_xor` | int-requiring | LOSS | - | Lua binary `~` | +| `bit_and` | int-requiring | - | - | Lua `&` (§3.4.2): exact int64 operands, exact int64-pattern result (N8, R1.5) | +| `bit_not` | int-requiring | - | - | Lua unary `~` | +| `bit_or` | int-requiring | - | - | Lua `\|` | +| `bit_shl` | int-requiring | - | - | Lua `<<` (R1.5): |count| >=64 gives 0; a negative count shifts logically right | +| `bit_shr` | int-requiring | - | - | Lua `>>` (N8, R1.5) is logical; |count| >=64 gives 0; a negative count shifts left | +| `bit_xor` | int-requiring | - | - | Lua binary `~` | | `buf_copy` | int-requiring | - | - | offsets and counts | | `buf_deinterleave` | int-requiring | - | - | channel count and index | | `buf_dot` | float-producing | - | - | buffer dot product | @@ -1900,7 +1900,7 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: |---|---|---| | VM arithmetic, comparison, negation (N2, N3, N4b, (A)) | R1.1 forced the arms (`slot_as_double` deleted); R1.3 adds the int semantics | exact int64, overflow raises | | `/` and `%` | R1.3 (transitional) | converted to doubles, today's semantics, until R1.4 | -| bitwise operators | R1.3 (transitional) | exact int64 operands (#1740's rule), today's shift rule until R1.5 | +| bitwise operators | R1.5 | exact int64 operands (#1740), int results and Lua 5.4 shifts | | equality, ordering, hashing, the constant pool | R1.2 (forced arms) | by value across kinds (N2); the pool keys on kind | | printing (`value_to_string`, f-strings) | R1.2a (the exhaustive switch) | exact digits, as today for small ints | | `type of`, `num_type` | R1.2a (`val_type_name`), R1.3 (`num_type`) | `"num"`; `"int"` | diff --git a/docs/llms.txt b/docs/llms.txt index 829e1710c..0120925b2 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -218,8 +218,9 @@ sqrt(2) = 1.414213562373095 arithmetic converts to float, while cross-kind comparison is exact. True division `/` and most builtin results remain floats at this stage. Float overflow saturates at ±1e308. - Integer bit ops accept exact int64 operands; builtin results and infix - results still convert to float until the bitwise/builtin rounds. + Integer bit ops and bit_* builtins accept exact int64 operands and return ints. + Right shifts zero-fill, negative counts reverse direction, and counts outside + (-64,64) give zero (Lua 5.4). A bit-op operand that is not an exact integer (`1.5 | 0`, `1e30 & 1`) raises a `value` error; it is never truncated. Strict mode is the DEFAULT: out-of-domain math (`sqrt of -1`), a NaN @@ -237,6 +238,21 @@ sqrt(2) = 1.414213562373095 substitution. `str_from_bytes` stops at numeric NUL without inspecting later elements; byte codecs consume the complete list. +Bitwise operators and `bit_*` builtins return ints, including when an +operand is an integral float. They use Lua 5.4's 64-bit shift rules: `>>` +zero-fills; a negative count shifts in the opposite direction; a count of +64 or more, or -64 or less, gives zero. Each operand must be an exact int64; +a fractional or out-of-range float raises `value`. + +```eigenscript +print of [1 << 64, 1 << -1, -1 >> 1, 8 >> -1, 1 << 63] +print of [bit_shr of [-1, 1], bit_shl of [8, -1], num_type of (3.0 & 1)] +``` +```output +[0, 0, 9223372036854775807, 16, -9223372036854775808] +[9223372036854775807, 4, "int"] +``` + `//` floors the quotient; `%` has the divisor's sign. `//=` applies the same operation to its assignment target, like `/=`. Zero divisors raise `value` for all numeric operand kinds in this round. Two ints produce an int for diff --git a/src/builtins.c b/src/builtins.c index 9ae72242a..e109abdd9 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -330,23 +330,12 @@ Value* builtin_text_builder_to_string(Value *arg) { return make_str_owned(xstrdup(arg->data.text_builder.data ? arg->data.text_builder.data : "")); } -/* ==== Bitwise operations ==== - * Semantics: operate on 32-bit two's-complement ints. Shift amounts are - * masked to [0,31] so large/negative shifts are defined behavior, not UB. - * Non-numeric args raise a runtime error (consistent with the strict error - * model used by the arithmetic operators and the '& | ^ << >> ~' operators). */ - -/* The bit_* builtins are the SAME operation as the infix operators - * (& | ^ << >>): int64 two's-complement over the numeric value (vm.c's - * INT_BINOP). They used to be a second, divergent implementation — - * (uint32_t)(int32_t) conversion, UB for inputs >= 2^31 and - * sign-extended results — so `0xEDB88320 & x` worked while - * `bit_and of [0xEDB88320, x]` returned garbage (found by the CRC-32 - * stdlib module, the first consumer needing the full unsigned-32 - * range). Shift counts are masked to 0..63 like the hardware would. */ -/* #1740: an operand that is not an exact int64 raises `value` (Lua 5.4's - * rule, the same as the infix operators). Returns 0 after raising. */ -static int bit_int(double x, int64_t *out, const char *name) { +/* #1758 N8: the bit_* builtins share Lua's exact int64 bit patterns and + * shift-count rules with the operators. No int operand crosses double. */ +/* #1740: an operand without an exact int64 representation raises value. */ +static int bit_int(Value *v, int64_t *out, const char *name) { + if (v->type == VAL_INT) { *out = VAL_I64_RAW(v); return 1; } + double x = eigs_num_arg(v, __func__); /* caller proved VAL_FLOAT */ if (num_to_i64_exact(x, out)) return 1; rt_error(EK_VALUE, 0, EIGS_NO_INT_REP_FMT, name, x); return 0; @@ -359,8 +348,8 @@ static int bit_pair(Value *arg, int64_t *a_out, int64_t *b_out, const char *name Value *va = BUILTIN_LIST_VIEW(arg, 0); Value *vb = BUILTIN_LIST_VIEW(arg, 1); if (!va || !val_is_number(va) || !vb || !val_is_number(vb)) return 0; - if (!bit_int(eigs_num_arg(va, __func__), a_out, name) || - !bit_int(eigs_num_arg(vb, __func__), b_out, name)) return -1; + if (!bit_int(va, a_out, name) || + !bit_int(vb, b_out, name)) return -1; return 1; } @@ -369,7 +358,7 @@ Value* builtin_bit_and(Value *arg) { int64_t a, b; int ok = bit_pair(arg, &a, &b, "bit_and"); if (ok <= 0) { if (ok == 0) rt_error(EK_TYPE, 0, "bit_and expects [number, number]"); return make_null(); } - return make_num((double)(a & b)); + return make_int(a & b); } Value* builtin_bit_or(Value *arg) { @@ -377,7 +366,7 @@ Value* builtin_bit_or(Value *arg) { int64_t a, b; int ok = bit_pair(arg, &a, &b, "bit_or"); if (ok <= 0) { if (ok == 0) rt_error(EK_TYPE, 0, "bit_or expects [number, number]"); return make_null(); } - return make_num((double)(a | b)); + return make_int(a | b); } Value* builtin_bit_xor(Value *arg) { @@ -385,14 +374,14 @@ Value* builtin_bit_xor(Value *arg) { int64_t a, b; int ok = bit_pair(arg, &a, &b, "bit_xor"); if (ok <= 0) { if (ok == 0) rt_error(EK_TYPE, 0, "bit_xor expects [number, number]"); return make_null(); } - return make_num((double)(a ^ b)); + return make_int(a ^ b); } Value* builtin_bit_not(Value *arg) { if (!arg || !val_is_number(arg)) { rt_error(EK_TYPE, 0, "bit_not expects a number"); return make_null(); } int64_t a; - if (!bit_int(eigs_num_arg(arg, __func__), &a, "bit_not")) return make_null(); - return make_num((double)(~a)); + if (!bit_int(arg, &a, "bit_not")) return make_null(); + return make_int(~a); } Value* builtin_bit_shift_left(Value *arg) { @@ -400,7 +389,7 @@ Value* builtin_bit_shift_left(Value *arg) { int64_t a, b; int ok = bit_pair(arg, &a, &b, "bit_shl"); if (ok <= 0) { if (ok == 0) rt_error(EK_TYPE, 0, "bit_shl expects [number, number]"); return make_null(); } - return make_num((double)(int64_t)((uint64_t)a << (b & 63))); /* unsigned: no UB on negative a */ + return make_int(eigs_bit_shift(a, b, 0)); } Value* builtin_bit_shift_right(Value *arg) { @@ -408,10 +397,7 @@ Value* builtin_bit_shift_right(Value *arg) { int64_t a, b; int ok = bit_pair(arg, &a, &b, "bit_shr"); if (ok <= 0) { if (ok == 0) rt_error(EK_TYPE, 0, "bit_shr expects [number, number]"); return make_null(); } - /* Arithmetic shift, like the infix >> on int64 (negative operands - * keep their sign); mask a non-negative operand first for a - * logical u32 shift. */ - return make_num((double)(a >> (b & 63))); + return make_int(eigs_bit_shift(a, b, 1)); } /* monotonic_ns of null — nanoseconds from CLOCK_MONOTONIC */ diff --git a/src/eigenscript.h b/src/eigenscript.h index e81467801..431b94d46 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -1920,6 +1920,16 @@ static inline int num_to_i64_exact(double x, int64_t *out) { *out = i; return 1; } +/* #1758 N8: Lua 5.4 shifts operate on an unsigned 64-bit pattern. + * Bound the signed count BEFORE negating it (INT64_MIN is valid input). + * Convert the result pattern without an out-of-range unsigned-to-signed cast. */ +static inline int64_t eigs_bit_shift(int64_t a, int64_t count, int right) { + if (count <= -64 || count >= 64) return 0; + if (count < 0) { count = -count; right = !right; } + uint64_t bits = right ? (uint64_t)a >> count : (uint64_t)a << count; + return bits <= INT64_MAX ? (int64_t)bits : -1 - (int64_t)(UINT64_MAX - bits); +} + #define EIGS_NO_INT_REP_FMT "'%s': number %.17g has no integer representation" static inline unsigned char buffer_read_byte(const Value *buffer, int64_t index) { diff --git a/src/vm.c b/src/vm.c index 84bf253ce..6943ac725 100644 --- a/src/vm.c +++ b/src/vm.c @@ -900,7 +900,7 @@ static EigsSlot vm_int_arith(int64_t a, int64_t b, char op, int line) { return slot_from_int(r); } -/* A number as an int64 for the transitional bitwise operators (#1740). +/* A number as an int64 for the bitwise operators (#1740, #1758 N8). * An int never round-trips through double; float operands retain the exact * integer-representation rule. Return -1 for a type error, 0 for value. */ static int vm_bit_operand(EigsSlot s, int64_t *out) { @@ -3672,23 +3672,17 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, DISPATCH(); } -/* #1740: both operands must be exact integers in int64 (Lua 5.4's rule); - * a fractional or out-of-range one raises `value` (see num_to_i64_exact). - * RHS is the (possibly transformed) right operand _bi. For `& | ^` - * it is the plain int64 operand; for the shifts it is masked to [0,63] so a - * large or negative shift count is defined (mod-64), never C UB — the same - * `& 63` the bit_shl/bit_shr builtins apply, honoring the LANGUAGE_CONTRACT - * "shifts are defined, not UB" promise. Without the mask, `1 << 64` on the - * infix path is undefined behavior (UBSan trips; only untested counts hid it). */ -#define INT_BINOP_R(NAME, OP, OPNAME, RHS) \ +/* #1758 N8: exact int64 operands (#1740), integer results, Lua shifts. + * Both popped operands are owned, including boxed ints on raise paths. */ +#define INT_BINOP_R(NAME, OPNAME, EXPR) \ CASE(NAME): { \ EigsSlot _bs = g_vm.stack[g_vm.sp - 1]; \ EigsSlot _as = g_vm.stack[g_vm.sp - 2]; \ int64_t _ai, _bi; \ int _ak = vm_bit_operand(_as, &_ai), _bk = vm_bit_operand(_bs, &_bi); \ - double _r = 0.0; \ + EigsSlot _r = slot_null(); \ if (_ak == 1 && _bk == 1) { \ - _r = (double)(INT_OP_##NAME(_ai, (RHS))); \ + _r = slot_from_int(EXPR); \ } else if (_ak < 0 || _bk < 0) { \ rt_error(EK_TYPE, current_line, "cannot apply '%s' to %s and %s", \ OPNAME, slot_type_name(_as), slot_type_name(_bs)); \ @@ -3698,27 +3692,16 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, OPNAME, _bad); \ } \ slot_decref(_as); slot_decref(_bs); \ - g_vm.stack[g_vm.sp - 2] = slot_from_f64(_r); \ + g_vm.stack[g_vm.sp - 2] = _r; \ g_vm.sp--; \ DISPATCH(); \ } -/* SHL shifts unsigned: `<<` on a negative int64 is UB. Same bits as the - * JIT's `shl`. */ -#define INT_OP_BAND(a, b) ((a) & (b)) -#define INT_OP_BOR(a, b) ((a) | (b)) -#define INT_OP_BXOR(a, b) ((a) ^ (b)) -#define INT_OP_SHL(a, b) ((int64_t)((uint64_t)(a) << (b))) -#define INT_OP_SHR(a, b) ((a) >> (b)) - -/* Non-shift bitwise ops: RHS is the plain int64 operand. */ -#define INT_BINOP(NAME, OP, OPNAME) INT_BINOP_R(NAME, OP, OPNAME, _bi) - - INT_BINOP(BAND, &, "&") - INT_BINOP(BOR, |, "|") - INT_BINOP(BXOR, ^, "^") - INT_BINOP_R(SHL, <<, "<<", (_bi & 63)) - INT_BINOP_R(SHR, >>, ">>", (_bi & 63)) + INT_BINOP_R(BAND, "&", _ai & _bi) + INT_BINOP_R(BOR, "|", _ai | _bi) + INT_BINOP_R(BXOR, "^", _ai ^ _bi) + INT_BINOP_R(SHL, "<<", eigs_bit_shift(_ai, _bi, 0)) + INT_BINOP_R(SHR, ">>", eigs_bit_shift(_ai, _bi, 1)) /* ---- Unary ---- */ @@ -3761,8 +3744,8 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, EigsSlot s = g_vm.stack[g_vm.sp - 1]; int64_t i; int k = vm_bit_operand(s, &i); - double r = 0.0; - if (k == 1) r = (double)(~i); + EigsSlot r = slot_null(); + if (k == 1) r = slot_from_int(~i); else if (k < 0) rt_error(EK_TYPE, current_line, "cannot apply '~' to %s", slot_type_name(s)); else { @@ -3771,7 +3754,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, rt_error(EK_VALUE, current_line, EIGS_NO_INT_REP_FMT, "~", bad); } slot_decref(s); - g_vm.stack[g_vm.sp - 1] = slot_from_f64(r); + g_vm.stack[g_vm.sp - 1] = r; DISPATCH(); } diff --git a/tests/phase2/lua_bitwise_diff.py b/tests/phase2/lua_bitwise_diff.py new file mode 100644 index 000000000..07a70dc2e --- /dev/null +++ b/tests/phase2/lua_bitwise_diff.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""N8 differential: Lua 5.4 is the value/kind/error oracle, never Python. + +Usage: python3 tests/phase2/lua_bitwise_diff.py +Python enumerates source literals and compares records; it does no bitwise +arithmetic. Each builtin is compared directly with Lua's matching operator. +""" +import argparse +import json +import os +from pathlib import Path +import subprocess +import tempfile + +VALUES = ['0', '1', '-1', '2', '-2', '0x7F', '0xFF', '0xFFFF', + '2147483647', '2147483648', '2147483649', '4611686018427387904', + '9223372036854775807', '(-9223372036854775807 - 1)', '-256', + '9007199254740993', '140737488355327', '140737488355328', + '3.0', '3.5', '-3.0', '-3.5', '9223372036854775808.0'] +COUNTS = [str(x) for x in range(-70, 71)] + ['3.0', '3.5', '-3.0', '-3.5', + '9223372036854775807', '(-9223372036854775807 - 1)', + '9223372036854775808.0'] +OPS = [('&', '&', 'bit_and'), ('|', '|', 'bit_or'), ('^', '~', 'bit_xor'), + ('<<', '<<', 'bit_shl'), ('>>', '>>', 'bit_shr'), ('~', '~', 'bit_not')] + + +def cases(): + for eigs, lua, builtin in OPS: + pairs = [(v, '0') for v in VALUES] if eigs == '~' else [ + (a, b) for a in VALUES for b in (COUNTS if eigs in ('<<', '>>') else VALUES)] + for a, b in pairs: + want = f'{lua}({a})' if eigs == '~' else f'({a}) {lua} ({b})' + for form in ('op', 'builtin'): + got = (f'~({a})' if eigs == '~' else f'({a}) {eigs} ({b})') if form == 'op' else ( + f'{builtin} of ({a})' if eigs == '~' else f'{builtin} of [{a}, {b}]') + yield f'{eigs}/{form}({a}, {b})', want, got + + +def compare(expected, actual): + """Exact records include both kind and integer digits (or value error).""" + return [(i, a, b) for i, (a, b) in enumerate(zip(expected, actual)) if a != b] + + +def run(binary, path, env): + proc = subprocess.run([binary, str(path)], stdin=subprocess.DEVNULL, + capture_output=True, text=True, timeout=120, env=env) + if proc.returncode or proc.stderr: + raise RuntimeError(f'{binary}: rc={proc.returncode}\n{proc.stderr}\n{proc.stdout[-2000:]}') + return proc.stdout.splitlines() + + +def main(): + ap = argparse.ArgumentParser(description=__doc__) + ap.add_argument('lua') + ap.add_argument('eigenscript') + args = ap.parse_args() + lua, eigs = (str(Path(p).resolve()) for p in (args.lua, args.eigenscript)) + version = subprocess.check_output([lua, '-v'], text=True).strip() + if not version.startswith('Lua 5.4.'): + ap.error('the oracle must be Lua 5.4 itself: ' + version) + print(version, flush=True) + env = {k: v for k, v in os.environ.items() if not k.startswith('EIGS_')} + population = list(cases()) + mismatches = [] + agree = 0 + with tempfile.TemporaryDirectory(prefix='n8-lua-') as d: + for start in range(0, len(population), 120): + batch = population[start:start + 120] + lp, ep = Path(d) / 'oracle.lua', Path(d) / 'subject.eigs' + ls, es = [], [] + for i, (_, want, got) in enumerate(batch): + ls += ['do', f'local ok, r = pcall(function() return {want} end)', + 'if ok then', f'print({i} .. "\\tok\\t" .. math.type(r) .. "\\t" .. tostring(r))', + 'elseif tostring(r):find("no integer representation", 1, true) then', + f'print({i} .. "\\terr\\tvalue")', 'else error(r) end', 'end'] + es += ['try:', f' r is {got}', + f' print of [{i}, "ok", num_type of r, str of r]', + 'catch e:', f' print of [{i}, "err", e.kind]'] + lp.write_text('\n'.join(ls) + '\n') + ep.write_text('\n'.join(es) + '\n') + expected = [line.split('\t') for line in run(lua, lp, env)] + for row in expected: + row[0] = int(row[0]) + if row[1] == 'ok' and row[2] == 'integer': + row[2] = 'int' + actual = [json.loads(line) for line in run(eigs, ep, env)] + if len(expected) != len(batch) or len(actual) != len(batch): + raise RuntimeError(f'incomplete batch at {start}: expected={len(expected)} actual={len(actual)}') + for i, row in enumerate(expected): + if row[0] != i or actual[i][0] != i: + raise RuntimeError('missing, duplicate or reordered case id') + bad = compare(expected, actual) + agree += len(batch) - len(bad) + mismatches += [(population[start + i][0], a, b) for i, a, b in bad] + for label, want, got in mismatches[:24]: + print(f'MISMATCH {label}: Lua={want!r} EigenScript={got!r}') + print(f'cases={len(population)} agree={agree} mismatch={len(mismatches)}', flush=True) + return bool(mismatches) + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/tests/phase2/rows/N5.bitwise-fraction-raises.eigs b/tests/phase2/rows/N5.bitwise-fraction-raises.eigs new file mode 100644 index 000000000..de4bea7e6 --- /dev/null +++ b/tests/phase2/rows/N5.bitwise-fraction-raises.eigs @@ -0,0 +1,10 @@ +# ROW: N5.bitwise-fraction-raises +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +try: + print of (1.5 | 0) +catch e: + print of e.kind diff --git a/tests/phase2/rows/N5.bitwise-fraction-raises.out b/tests/phase2/rows/N5.bitwise-fraction-raises.out new file mode 100644 index 000000000..6d4e15079 --- /dev/null +++ b/tests/phase2/rows/N5.bitwise-fraction-raises.out @@ -0,0 +1 @@ +value diff --git a/tests/phase2/rows/N5.integral-float-converts.eigs b/tests/phase2/rows/N5.integral-float-converts.eigs new file mode 100644 index 000000000..6a21bec72 --- /dev/null +++ b/tests/phase2/rows/N5.integral-float-converts.eigs @@ -0,0 +1,7 @@ +# ROW: N5.integral-float-converts +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [6.0 | 1, num_type of (6.0 | 1), (list_slice of [[1, 2, 3], 1.0, 2.0])] diff --git a/tests/phase2/rows/N5.integral-float-converts.out b/tests/phase2/rows/N5.integral-float-converts.out new file mode 100644 index 000000000..abe7f6482 --- /dev/null +++ b/tests/phase2/rows/N5.integral-float-converts.out @@ -0,0 +1 @@ +[7, "int", [2]] diff --git a/tests/phase2/rows/N8.bit-builtins-int64.eigs b/tests/phase2/rows/N8.bit-builtins-int64.eigs new file mode 100644 index 000000000..09b15dc54 --- /dev/null +++ b/tests/phase2/rows/N8.bit-builtins-int64.eigs @@ -0,0 +1,7 @@ +# ROW: N8.bit-builtins-int64 +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [bit_or of [4611686018427387904, 1], bit_shl of [1, 64]] diff --git a/tests/phase2/rows/N8.bit-builtins-int64.out b/tests/phase2/rows/N8.bit-builtins-int64.out new file mode 100644 index 000000000..7efe080e3 --- /dev/null +++ b/tests/phase2/rows/N8.bit-builtins-int64.out @@ -0,0 +1 @@ +[4611686018427387905, 0] diff --git a/tests/phase2/rows/N8.bitwise-results-int.eigs b/tests/phase2/rows/N8.bitwise-results-int.eigs new file mode 100644 index 000000000..ba35629ce --- /dev/null +++ b/tests/phase2/rows/N8.bitwise-results-int.eigs @@ -0,0 +1,7 @@ +# ROW: N8.bitwise-results-int +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [6 & 3, 6 | 3, 6 ^ 3, ~0, num_type of (6 & 3)] diff --git a/tests/phase2/rows/N8.bitwise-results-int.out b/tests/phase2/rows/N8.bitwise-results-int.out new file mode 100644 index 000000000..4e7c00124 --- /dev/null +++ b/tests/phase2/rows/N8.bitwise-results-int.out @@ -0,0 +1 @@ +[2, 7, 5, -1, "int"] diff --git a/tests/phase2/rows/N8.fn-bitwise-all.eigs b/tests/phase2/rows/N8.fn-bitwise-all.eigs new file mode 100644 index 000000000..be3a1367e --- /dev/null +++ b/tests/phase2/rows/N8.fn-bitwise-all.eigs @@ -0,0 +1,17 @@ +# ROW: N8.fn-bitwise-all +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop bits BOR +# OPS: BOR +define bits(a, c) as: + o is a | c + x is a ^ c + l is a << 1 + r is a >> 1 + n is ~a + return [o, x, l, r, n] +r is 0 +for i in range of 60: + r is bits of [9007199254740993, 2] +print of r diff --git a/tests/phase2/rows/N8.fn-bitwise-all.out b/tests/phase2/rows/N8.fn-bitwise-all.out new file mode 100644 index 000000000..a1a6264da --- /dev/null +++ b/tests/phase2/rows/N8.fn-bitwise-all.out @@ -0,0 +1 @@ +[9007199254740995, 9007199254740995, 18014398509481986, 4503599627370496, -9007199254740994] diff --git a/tests/phase2/rows/N8.fn-bitwise.eigs b/tests/phase2/rows/N8.fn-bitwise.eigs new file mode 100644 index 000000000..a7d568b51 --- /dev/null +++ b/tests/phase2/rows/N8.fn-bitwise.eigs @@ -0,0 +1,13 @@ +# ROW: N8.fn-bitwise +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop b BAND +# OPS: BAND +define b(a, c) as: + t is a & c + return t +r is 0 +for i in range of 60: + r is b of [9007199254740993, 9007199254740993] +print of r diff --git a/tests/phase2/rows/N8.fn-bitwise.out b/tests/phase2/rows/N8.fn-bitwise.out new file mode 100644 index 000000000..ba278ab07 --- /dev/null +++ b/tests/phase2/rows/N8.fn-bitwise.out @@ -0,0 +1 @@ +9007199254740993 diff --git a/tests/phase2/rows/N8.lua-shifts.eigs b/tests/phase2/rows/N8.lua-shifts.eigs new file mode 100644 index 000000000..e4474d4c8 --- /dev/null +++ b/tests/phase2/rows/N8.lua-shifts.eigs @@ -0,0 +1,7 @@ +# ROW: N8.lua-shifts +# ITEMS: N8 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [1 << 64, 1 << 63, 1 << -1, -1 >> 1, 8 >> -1] diff --git a/tests/phase2/rows/N8.lua-shifts.out b/tests/phase2/rows/N8.lua-shifts.out new file mode 100644 index 000000000..a093aa2e4 --- /dev/null +++ b/tests/phase2/rows/N8.lua-shifts.out @@ -0,0 +1 @@ +[0, -9223372036854775808, 0, 9223372036854775807, 16] diff --git a/tests/test_bitwise.eigs b/tests/test_bitwise.eigs index 233e1a005..475a2e6c9 100644 --- a/tests/test_bitwise.eigs +++ b/tests/test_bitwise.eigs @@ -32,22 +32,20 @@ assert_eq of [bit_and of [unlocked, 1], 1, "bitmask bit 0 set"] assert_eq of [bit_and of [unlocked, 2], 0, "bitmask bit 1 clear"] assert_eq of [bit_and of [unlocked, 4], 4, "bitmask bit 2 set"] -# Shift amount masking — out-of-range shifts are defined, not UB -# int64 semantics (aligned with the infix operators): counts are real -# up to 63 — the old int32-era &31 masking (1<<32 == 1) is gone. -assert_eq of [bit_shl of [1, 32], 4294967296, "SHL 1 << 32 is 2^32 (int64, no 31-masking)"] -assert_eq of [bit_shl of [1, 33], 8589934592, "SHL 1 << 33 is 2^33"] -assert_eq of [bit_shr of [8, 35], 0, "SHR 8 >> 35 shifts out to 0"] - -# Out-of-range shift COUNTS are defined (masked & 63), not C UB — for BOTH the -# infix operators and the bit_* builtins. Count 64 == count 0 (64 & 63 == 0), -# count 65 == count 1, count 100 == count 36. Without the mask the infix path -# was undefined behavior (only untested counts kept UBSan quiet). -assert_eq of [1 << 64, 1, "infix << 64 masks to << 0 (defined, not UB)"] -assert_eq of [1 << 65, 2, "infix << 65 masks to << 1"] -assert_eq of [1 << 100, 68719476736, "infix << 100 masks to << 36 == 2^36"] -assert_eq of [bit_shl of [1, 64], 1, "bit_shl count 64 masks to 0 (matches infix)"] -assert_eq of [256 >> 64, 256, "infix >> 64 masks to >> 0"] +# N8: Lua 5.4 counts outside (-64,64) yield zero; negatives reverse. +assert_eq of [bit_shl of [1, 32], 4294967296, "N8 count 32"] +assert_eq of [bit_shl of [1, 33], 8589934592, "N8 count 33"] +assert_eq of [bit_shr of [8, 35], 0, "N8 shifts out to zero"] +assert_eq of [1 << 64, 0, "N8 << 64 is zero"] +assert_eq of [1 << 65, 0, "N8 << 65 is zero"] +assert_eq of [1 << 100, 0, "N8 << 100 is zero"] +assert_eq of [bit_shl of [1, 64], 0, "N8 builtin << 64 is zero"] +assert_eq of [256 >> 64, 0, "N8 >> 64 is zero"] +assert_eq of [-1 >> 1, 9223372036854775807, "N8 logical right shift"] +assert_eq of [8 >> -1, 16, "N8 negative right count shifts left"] +assert_eq of [-1 << -1, 9223372036854775807, "N8 negative left count shifts logically right"] +assert_eq of [1 >> -64, 0, "N8 negative wide count is zero"] +assert_eq of [1 << (-9223372036854775807 - 1), 0, "N8 minimum count cannot overflow"] # Type safety — non-numeric args raise (strict error model, not UB, not 0). # Builtins: @@ -186,13 +184,12 @@ assert_eq of [bw_raise of ["|", int64_min, 0], "no raise", "-2^63 | 0 is valid"] assert_eq of [int64_min | 0, int64_min, "-2^63 | 0 returns itself"] assert_eq of [bit_or of [int64_min, 0], int64_min, "bit_or of [-2^63, 0] returns itself"] assert_eq of [9223372036854774784 | 0, 9223372036854774784, "largest double below 2^63 is valid"] -# R1.3: bitwise results remain floats until N8 (R1.5); N2 compares the -# rounded float result exactly, so its expected value is explicitly float. -assert_eq of [~int64_min, 9223372036854775808.0, "~(-2^63) retains the transitional float result"] +# N8 retires the float result bridge; all 64 result bits survive. +assert_eq of [~int64_min, 9223372036854775807, "N8 complement is exact int64"] assert_eq of [(0 - 0) | 0, 0, "zero is valid"] assert_eq of [(0 - 1) << 1, 0 - 2, "SHL of a negative is defined (unsigned shift)"] assert_eq of [bit_shl of [0 - 1, 1], (0 - 1) << 1, "bit_shl matches infix on a negative"] -assert_eq of [1 << (0 - 1), int64_min, "a negative exact count is masked & 63"] +assert_eq of [1 << (0 - 1), 0, "N8 negative exact count reverses direction"] # --- All execution settings must raise exactly where the VM does --- # R1.3 intentionally scanner-refuses these operators until R5. The hot @@ -293,4 +290,23 @@ osr_ok is osr_loop of [9000, 0 - 1] assert_eq of [osr_ok[0], 9000, "OSR loop with exact integers completes"] assert_eq of [osr_ok[1], osr_oracle of 9000, "OSR loop with exact integers equals the builtin oracle"] +# N8: boxed operands, boxed results, and both operand positions on raises. +define n8_keep(x) as: + define n8_inner(dummy) as: + return x + return n8_inner +for n8_big in [9007199254740993, 9223372036854775807, (-9223372036854775807 - 1)]: + for n8_op in ["&", "|", "^", "<<", ">>", "~", "bit_and", "bit_or", "bit_xor", "bit_shl", "bit_shr", "bit_not"]: + if n8_op != "~" and n8_op != "bit_not": + assert_eq of [bw_raise of [n8_op, n8_big, 0.5], "value", "N8 boxed lhs released on count/value raise"] + assert_eq of [bw_raise of [n8_op, 0.5, n8_big], "value", "N8 boxed rhs released on lhs raise"] + n8_box is n8_big | 0 + n8_holder is {"values": [n8_box, ~n8_big, bit_or of [n8_big, 0]]} + n8_closure is n8_keep of n8_holder.values[0] + assert_eq of [n8_closure of null, n8_big, "N8 boxed bitwise result survives containers and closure"] + for n8_value in n8_holder.values: + assert_eq of [num_type of n8_value, "int", "N8 boxed result kind"] +for n8_value in [6 & 3, 6 | 3, 6 ^ 3, ~0, 1 << 63, -1 >> 1, bit_and of [6, 3], bit_or of [6, 3], bit_xor of [6, 3], bit_not of 0, bit_shl of [1, 63], bit_shr of [-1, 1], 3.0 & 1.0]: + assert_eq of [num_type of n8_value, "int", "N8 every operator and builtin returns int"] + test_summary of null diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py index 4ca4edb39..b64a136a5 100644 --- a/tests/test_doc_examples.py +++ b/tests/test_doc_examples.py @@ -324,10 +324,10 @@ def is_asan_build(): # --------------------------------------------------------------------------- POPULATION = { # file fences paired fragment nocheck value-comments - "README.md": ( 8, 4, 4, 0, 0), - "docs/llms.txt": ( 10, 7, 2, 1, 0), - "docs/SPEC.md": ( 86, 82, 1, 3, 0), # #1740: +1 paired (bitwise exact-int raises) - "docs/COMPARISON.md": ( 20, 19, 1, 0, 0), + "README.md": ( 9, 5, 4, 0, 0), + "docs/llms.txt": ( 11, 8, 2, 1, 0), + "docs/SPEC.md": ( 87, 83, 1, 3, 0), # #1740: +1 paired (bitwise exact-int raises) + "docs/COMPARISON.md": ( 21, 20, 1, 0, 0), "docs/CONCURRENCY.md": ( 8, 8, 0, 0, 0), # #1736: +1 paired (detached task catches its own error) "docs/STDLIB.md": ( 15, 7, 8, 0, 0), "docs/SYNTAX.md": ( 35, 15, 20, 0, 1), diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index 55fb3efe9..c9dc915cb 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -91,3 +91,4 @@ ext_db.c|db_build_query|1|VAL_INT parameters encode as exact digits after the ki vm.c|vm_value_index_is_int|2|Guarded exact VAL_INT-to-C-index conversion; the other numeric kind keeps the float integrality test (#1758 R1.2) builtins.c|builtin_abs|1|N4b: proved VAL_INT payload, refuse INT64_MIN before negating eigenscript.c|make_int|1|int constructor initializes the exact signed payload +builtins.c|bit_int|1|N8 exact bitwise operand reader: VAL_INT guard precedes the int payload; float operands use #1740 conversion From 40333a23ad0160bba725aacbe4517a701fc1f194 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 16:56:42 -0500 Subject: [PATCH 092/188] Close N8 oracle population and language-contract review gaps Reject missing or empty operator/form populations before comparing the Lua grid. Update LANGUAGE_CONTRACT's shift promise and JIT refusal status, and repair the builtin table's Markdown cells. Strip trailing whitespace from straight-line row headers. Validation: empty-generator plant rejected (exit 1), restored Lua 5.4.9 grid cases=16836 agree=16836 mismatch=0. Runtime unchanged from the build-green implementation; previous doc run checked 202/202 examples. Blind static review found no runtime ownership or shift defect. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/LANGUAGE_CONTRACT.md | 13 ++++++++----- docs/design/phase2-numbers.md | 4 ++-- tests/phase2/lua_bitwise_diff.py | 10 ++++++++++ tests/phase2/rows/N5.bitwise-fraction-raises.eigs | 2 +- tests/phase2/rows/N5.integral-float-converts.eigs | 2 +- tests/phase2/rows/N8.bit-builtins-int64.eigs | 2 +- tests/phase2/rows/N8.bitwise-results-int.eigs | 2 +- tests/phase2/rows/N8.lua-shifts.eigs | 2 +- 8 files changed, 25 insertions(+), 12 deletions(-) diff --git a/docs/LANGUAGE_CONTRACT.md b/docs/LANGUAGE_CONTRACT.md index da0af2f38..dc545b806 100644 --- a/docs/LANGUAGE_CONTRACT.md +++ b/docs/LANGUAGE_CONTRACT.md @@ -237,9 +237,10 @@ integers. Every operand, the shift count included, must be an **exact integer in `[-2^63, 2^63)`**; a fractional operand (`1.5 | 0`, `1 << 0.5`) or one outside that range (`1e30 | 0`, `9223372036854775808 | 0`) raises a catchable `value` error ("number has no integer representation"). This is Lua 5.4's rule (reference manual -§3.4.3); nothing is truncated or wrapped. `-9223372036854775808 | 0` is valid. A shift count -that passes the check is masked to `[0,63]`, so large or negative shifts -are defined, not UB (`1 << 64` == `1 << 0` == `1`; `1 << 100` == `1 << 36`). The +§3.4.3); operand conversion never truncates or wraps. Results are exact ints. +`-9223372036854775808 | 0` is valid. Shifts follow Lua 5.4: a count outside +`(-64,64)` gives zero, a negative count shifts in the opposite direction, +and right shifts zero-fill (`1 << 64` is `0`; `-1 >> 1` is `9223372036854775807`). The infix operators and the `bit_*` builtins agree bit-for-bit on the same operands — they were once a divergent `int32` implementation (`0xEDB88320`, CRC-32's polynomial, was the first casualty). Non-numeric operands **raise** a runtime @@ -249,9 +250,11 @@ operator … raises") hold for *every* operator with no exceptions. **Status:** Enforced — `tests/test_bitwise.eigs` (builtin == infix parity across the high-bit range and out-of-range shift counts; a `value` raise for every -non-integer operand form, in the VM, the builtins and JIT-compiled hot loops), +non-integer operand form, including hot functions and loops), `num_to_i64_exact` in `eigenscript.h`, `INT_BINOP_R` / `CASE(BNOT)` in `vm.c`, -`bit_*` builtins in `builtins.c`, and the exactness bail in `jit.c`'s bitwise arms. +`bit_*` builtins in `builtins.c`, and `eigs_bit_shift` in `eigenscript.h`. +The JIT scanner and leaf evaluator refuse bitwise opcodes during round 1; +the interpreter executes them with these same rules. ## Truthiness diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index c9e244511..c11a357de 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1393,8 +1393,8 @@ current state behind several rows: | `bit_and` | int-requiring | - | - | Lua `&` (§3.4.2): exact int64 operands, exact int64-pattern result (N8, R1.5) | | `bit_not` | int-requiring | - | - | Lua unary `~` | | `bit_or` | int-requiring | - | - | Lua `\|` | -| `bit_shl` | int-requiring | - | - | Lua `<<` (R1.5): |count| >=64 gives 0; a negative count shifts logically right | -| `bit_shr` | int-requiring | - | - | Lua `>>` (N8, R1.5) is logical; |count| >=64 gives 0; a negative count shifts left | +| `bit_shl` | int-requiring | - | - | Lua `<<` (R1.5): count >=64 or <=-64 gives 0; a negative count shifts logically right | +| `bit_shr` | int-requiring | - | - | Lua `>>` (N8, R1.5) is logical; count >=64 or <=-64 gives 0; a negative count shifts left | | `bit_xor` | int-requiring | - | - | Lua binary `~` | | `buf_copy` | int-requiring | - | - | offsets and counts | | `buf_deinterleave` | int-requiring | - | - | channel count and index | diff --git a/tests/phase2/lua_bitwise_diff.py b/tests/phase2/lua_bitwise_diff.py index 07a70dc2e..9d1889a47 100644 --- a/tests/phase2/lua_bitwise_diff.py +++ b/tests/phase2/lua_bitwise_diff.py @@ -6,6 +6,7 @@ arithmetic. Each builtin is compared directly with Lua's matching operator. """ import argparse +from collections import Counter import json import os from pathlib import Path @@ -61,6 +62,15 @@ def main(): print(version, flush=True) env = {k: v for k, v in os.environ.items() if not k.startswith('EIGS_')} population = list(cases()) + # Independently pin all twelve operator/form populations: a missing + # generator arm must never look like agreement on a smaller grid. + expected_counts = {f'{op}/{form}': n for op, n in + [('&', 529), ('|', 529), ('^', 529), + ('<<', 3404), ('>>', 3404), ('~', 23)] + for form in ('op', 'builtin')} + found = Counter(label.split('(', 1)[0] for label, _, _ in population) + if found != expected_counts: + raise RuntimeError(f'incomplete case populations: expected={expected_counts} actual={dict(found)}') mismatches = [] agree = 0 with tempfile.TemporaryDirectory(prefix='n8-lua-') as d: diff --git a/tests/phase2/rows/N5.bitwise-fraction-raises.eigs b/tests/phase2/rows/N5.bitwise-fraction-raises.eigs index de4bea7e6..996f9d0f3 100644 --- a/tests/phase2/rows/N5.bitwise-fraction-raises.eigs +++ b/tests/phase2/rows/N5.bitwise-fraction-raises.eigs @@ -3,7 +3,7 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: try: print of (1.5 | 0) catch e: diff --git a/tests/phase2/rows/N5.integral-float-converts.eigs b/tests/phase2/rows/N5.integral-float-converts.eigs index 6a21bec72..548e13bcb 100644 --- a/tests/phase2/rows/N5.integral-float-converts.eigs +++ b/tests/phase2/rows/N5.integral-float-converts.eigs @@ -3,5 +3,5 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: print of [6.0 | 1, num_type of (6.0 | 1), (list_slice of [[1, 2, 3], 1.0, 2.0])] diff --git a/tests/phase2/rows/N8.bit-builtins-int64.eigs b/tests/phase2/rows/N8.bit-builtins-int64.eigs index 09b15dc54..406d1d645 100644 --- a/tests/phase2/rows/N8.bit-builtins-int64.eigs +++ b/tests/phase2/rows/N8.bit-builtins-int64.eigs @@ -3,5 +3,5 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: print of [bit_or of [4611686018427387904, 1], bit_shl of [1, 64]] diff --git a/tests/phase2/rows/N8.bitwise-results-int.eigs b/tests/phase2/rows/N8.bitwise-results-int.eigs index ba35629ce..aa07bece7 100644 --- a/tests/phase2/rows/N8.bitwise-results-int.eigs +++ b/tests/phase2/rows/N8.bitwise-results-int.eigs @@ -3,5 +3,5 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: print of [6 & 3, 6 | 3, 6 ^ 3, ~0, num_type of (6 & 3)] diff --git a/tests/phase2/rows/N8.lua-shifts.eigs b/tests/phase2/rows/N8.lua-shifts.eigs index e4474d4c8..ab45d0a7b 100644 --- a/tests/phase2/rows/N8.lua-shifts.eigs +++ b/tests/phase2/rows/N8.lua-shifts.eigs @@ -3,5 +3,5 @@ # EXPECT-RC: 0 # SHAPE: S # WITNESS: none -# OPS: +# OPS: print of [1 << 64, 1 << 63, 1 << -1, -1 >> 1, 8 >> -1] From 4ac31e67b4694eea96f2f7151ecf8f9ee62f686d Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Tue, 20 Oct 2026 18:28:46 -0500 Subject: [PATCH 093/188] Record measured N8 costs and interpreter recovery obligations Keep the initial six-OVER receipt and measure all six affected rows against a fresh make build of exact R1.4 (2d6587ee). Update only those existing maxima by the design's measured-delta +0.2 points rounded up to0.1 rule, retaining R5 recovery. Distinguish the DMG-shaped benchmark's generic dictionary/boxing paths from shared VM/helper code-generation costs on workloads without bitwise operations. Record interpreter int/slot recovery explicitly for off-tier declarations. Validation: new full phase2_cost gate workloads=15 rows=30 over_declared_max=0 stale_declarations=0 PASS. Same runtime already passed release and strict-leak ASan focused Tests=181 Pass=181 Fail=0 and Lua5.4.9 cases=16836 agree=16836 mismatch=0 in both builds. MAP throughR1.5 mapped=72 controls=18 PASS; phase2_ci derivesR1.5 and libdiff lists12 undeclared0 stale0 PASS. Independent read-only cost audit verified all six counts/bounds and the actual diff. No runtime or benchmark source change in this commit. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 9 +++++++++ tests/phase2/cost_expect.txt | 12 ++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index c11a357de..6ee0e282b 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2084,6 +2084,15 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: ### Round 5 obligations (recorded by earlier rounds) Round 5 gives the JIT and the leaf evaluator their int fast paths (§4.4). +It must also recover the declared interpreter costs in +`tests/phase2/cost_expect.txt`: an `off` row runs with `EIGS_JIT_OFF=1`, so +native execution alone cannot recover it. R1.5's fresh R1.4 controls attribute +the DMG-shaped benchmark's N8 increment to exact-int state reaching generic +dictionary/boxed Value paths. The other moved rows have no bitwise operations; +their measured increment is shared VM/helper code generation, including an +out-of-line `slot_from_int`. Interpreter int/slot paths are therefore part of +R5's recovery obligation; each row retains its measured bound and component. + Until then a check that needs EMITTED code for an int program cannot fire, so its fixture runs a float program instead. Each such fixture gets its int twin back when R5 compiles ints: diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt index f796c3dd8..d4236011e 100644 --- a/tests/phase2/cost_expect.txt +++ b/tests/phase2/cost_expect.txt @@ -13,17 +13,17 @@ bench/scalar_loop.eigs off 127.6 R5 design §3: interpreted int arithmetic takes bench/string_build.eigs jit 11.6 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.2% (range-int control, measured at R1.3, against +9.9%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=82669260, R1.4 Ir=83813773, measured main delta=+11.3960%, bound=ceil(delta+0.2,0.1) bench/string_build.eigs off 10.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +23.5% (range-int control, measured at R1.3, against +8.5%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=85095023, R1.4 Ir=86239916, measured main delta=+9.9831%, bound=ceil(delta+0.2,0.1) bench/unobserved_armed_loop.eigs jit 66.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/unobserved_armed_loop.eigs off 9.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +3,000,000 Ir on both trees (600,000 stores; the assign-count bump moved inside its hold), which saves 2,400,031 in the branch's vm_run_ex (CAND +600,065, +0.06%) but 4,800,031 in main's (BASE -1,798,626, -0.21%); measured +8.85% at R1.3, +9.15% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=930827459, R1.4 Ir=928427649, measured main delta=+8.7891%, bound=ceil(delta+0.2,0.1) +bench/unobserved_armed_loop.eigs off 9.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +3,000,000 Ir on both trees (600,000 stores; the assign-count bump moved inside its hold), which saves 2,400,031 in the branch's vm_run_ex (CAND +600,065, +0.06%) but 4,800,031 in main's (BASE -1,798,626, -0.21%); measured +8.85% at R1.3, +9.15% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=930827459, R1.4 Ir=928427649, measured main delta=+8.7891%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM code-generation component (this workload has no bitwise ops): vm_run_ex +1799999 Ir; R5 interpreter int/slot fast paths must recover this off-tier cost; fresh2d6587ee control Ir=929028193, R1.5 Ir=930826815, measured main delta=+9.0703%, bound=ceil(delta+0.2,0.1) bench/unobserved_loop.eigs jit 4.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5 bench/unobserved_loop.eigs off 1.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5 tests/bench_buf_mix.eigs jit 311.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=2997588303, R1.4 Ir=3102110794, measured main delta=+311.4903%, bound=ceil(delta+0.2,0.1) tests/bench_buf_mix.eigs off 97.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=3014239251, R1.4 Ir=3118762031, measured main delta=+96.9936%, bound=ceil(delta+0.2,0.1) -tests/bench_buf_resample.eigs jit 196.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14070973095, R1.4 Ir=14341781156, measured main delta=+196.6971%, bound=ceil(delta+0.2,0.1) +tests/bench_buf_resample.eigs jit 197.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14070973095, R1.4 Ir=14341781156, measured main delta=+196.6971%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM code-generation component (this workload has no bitwise ops): vm_run_ex +16800000 Ir offset by eigs_num_arg -7200000 Ir; R5 int/slot fast paths must recover this shared VM cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=14344087931, R1.5 Ir=14353686973, measured main delta=+196.9435%, bound=ceil(delta+0.2,0.1) tests/bench_buf_resample.eigs off 67.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14114616143, R1.4 Ir=14385424763, measured main delta=+67.2701%, bound=ceil(delta+0.2,0.1) -tests/bench_dmg_shape.eigs jit 208.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; merge of 94657581 BASE component (#1171): jit_helper_call no longer calls the out-of-line slot_decref (0c16522f), so main's slot_decref drops 14,517,154 -> 28,754 Ir (BASE -14,503,457, -1.12%), while the branch runs this int code interpreted and does not reach it (CAND -445,382, -0.01%); measured +172.92% at R1.3, +175.98% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3527659645, R1.4 Ir=3944225152, measured main delta=+208.5522%, bound=ceil(delta+0.2,0.1) -tests/bench_dmg_shape.eigs off 66.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3546396130, R1.4 Ir=3963267113, measured main delta=+66.2412%, bound=ceil(delta+0.2,0.1) -tests/bench_idxset.eigs jit 455.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489963988, R1.4 Ir=531588673, measured main delta=+454.8994%, bound=ceil(delta+0.2,0.1) -tests/bench_idxset.eigs off 126.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489962938, R1.4 Ir=531587958, measured main delta=+126.6422%, bound=ceil(delta+0.2,0.1) +tests/bench_dmg_shape.eigs jit 230.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; merge of 94657581 BASE component (#1171): jit_helper_call no longer calls the out-of-line slot_decref (0c16522f), so main's slot_decref drops 14,517,154 -> 28,754 Ir (BASE -14,503,457, -1.12%), while the branch runs this int code interpreted and does not reach it (CAND -445,382, -0.01%); measured +172.92% at R1.3, +175.98% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3527659645, R1.4 Ir=3944225152, measured main delta=+208.5522%, bound=ceil(delta+0.2,0.1); R1.5 N8 component on the DMG-shaped benchmark: exact int bitwise results retain int state through generic dictionary/boxed Value paths (dict_set_cached +101124922 Ir and _int_malloc +38500014 Ir); R5 must recover these paths in the interpreter as well as JIT/leaf int execution; fresh2d6587ee control Ir=3943793833, R1.5 Ir=4216636333, measured main delta=+229.8625%, bound=ceil(delta+0.2,0.1) +tests/bench_dmg_shape.eigs off 76.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3546396130, R1.4 Ir=3963267113, measured main delta=+66.2412%, bound=ceil(delta+0.2,0.1); R1.5 N8 component on the DMG-shaped benchmark: exact int bitwise results retain int state through generic dictionary/boxed Value paths (dict_set_cached +101124922 Ir and _int_malloc +38500146 Ir); R5 must recover these paths in the interpreter as well as JIT/leaf int execution; fresh2d6587ee control Ir=3962833268, R1.5 Ir=4198461839, measured main delta=+76.1062%, bound=ceil(delta+0.2,0.1) +tests/bench_idxset.eigs jit 458.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489963988, R1.4 Ir=531588673, measured main delta=+454.8994%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM/helper code-generation component (this workload has no bitwise ops): slot_from_int becomes out of line (+1200000 Ir), eigs_slot_store_owned +1000000 Ir and vm_run_ex +599999 Ir; R5 interpreter int/slot fast paths must recover the off-tier cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=531584777, R1.5 Ir=534388413, measured main delta=+457.8236%, bound=ceil(delta+0.2,0.1) +tests/bench_idxset.eigs off 128.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489962938, R1.4 Ir=531587958, measured main delta=+126.6422%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM/helper code-generation component (this workload has no bitwise ops): slot_from_int becomes out of line (+1200000 Ir), eigs_slot_store_owned +1000000 Ir and vm_run_ex +599999 Ir; R5 interpreter int/slot fast paths must recover the off-tier cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=531588681, R1.5 Ir=534387392, measured main delta=+127.8315%, bound=ceil(delta+0.2,0.1) tests/bench_pcm_codec.eigs jit 376.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39010338030, measured main delta=+376.5029%, bound=ceil(delta+0.2,0.1) tests/bench_pcm_codec.eigs off 97.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +74,400,025 Ir against vm_run_ex -63,600,434 on the branch (CAND +10,800,129, +0.03%), while on main the same move saves (vm_run_ex -92,400,393, env_store_slot +66,000,030: BASE -26,400,939, -0.13%); measured +89.39% at R1.3, +89.70% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39192628174, measured main delta=+97.5413%, bound=ceil(delta+0.2,0.1) tests/bench_perf.eigs jit 15.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.4% (range-int control, measured at R1.3, against +15.7%) until R5 From d2437d6d435d40567974719be0ef16d42600f00c Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Wed, 21 Oct 2026 00:06:24 -0500 Subject: [PATCH 094/188] phase2 R1.6a: preserve the pre-registered builtin bar and rulings (#1758) Import 1,017 files byte-identical to the supplied, ruled bar. SHA256 proof is in the delivery report. No expectations changed. Baseline make at 1fd4422c: exit 0, warnings=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/builtins/BAR.md | 916 ++++++++++++++++++ tests/phase2/builtins/RULINGS.md | 74 ++ tests/phase2/builtins/builtins.tsv | 232 +++++ .../builtins/_hooks/observation_hooks.c | 159 +++ .../builtins/builtins/_profiles/db.eigs | 7 + .../builtins/builtins/_profiles/server.eigs | 24 + .../builtins/builtins/_profiles/zlib.eigs | 6 + tests/phase2/builtins/builtins/_stdin/hi | 1 + tests/phase2/builtins/builtins/abs.branch | 4 + tests/phase2/builtins/builtins/abs.eigs | 14 + tests/phase2/builtins/builtins/abs.pre | 4 + tests/phase2/builtins/builtins/abs.tag | 4 + tests/phase2/builtins/builtins/acos.branch | 3 + tests/phase2/builtins/builtins/acos.eigs | 10 + tests/phase2/builtins/builtins/acos.pre | 3 + tests/phase2/builtins/builtins/acos.tag | 3 + tests/phase2/builtins/builtins/add.branch | 5 + tests/phase2/builtins/builtins/add.eigs | 17 + tests/phase2/builtins/builtins/add.pre | 5 + tests/phase2/builtins/builtins/add.tag | 5 + tests/phase2/builtins/builtins/append.branch | 2 + tests/phase2/builtins/builtins/append.eigs | 10 + tests/phase2/builtins/builtins/append.pre | 2 + tests/phase2/builtins/builtins/append.tag | 2 + tests/phase2/builtins/builtins/asin.branch | 3 + tests/phase2/builtins/builtins/asin.eigs | 10 + tests/phase2/builtins/builtins/asin.pre | 3 + tests/phase2/builtins/builtins/asin.tag | 3 + tests/phase2/builtins/builtins/assert.branch | 3 + tests/phase2/builtins/builtins/assert.eigs | 15 + tests/phase2/builtins/builtins/assert.pre | 3 + tests/phase2/builtins/builtins/assert.tag | 3 + tests/phase2/builtins/builtins/atan.branch | 3 + tests/phase2/builtins/builtins/atan.eigs | 10 + tests/phase2/builtins/builtins/atan.pre | 3 + tests/phase2/builtins/builtins/atan.tag | 3 + tests/phase2/builtins/builtins/atan2.branch | 3 + tests/phase2/builtins/builtins/atan2.eigs | 10 + tests/phase2/builtins/builtins/atan2.pre | 3 + tests/phase2/builtins/builtins/atan2.tag | 3 + .../builtins/audio_capture_open.branch | 3 + .../builtins/builtins/audio_capture_open.eigs | 13 + .../builtins/builtins/audio_capture_open.pre | 3 + .../builtins/builtins/audio_capture_open.tag | 3 + .../builtins/builtins/audio_envelope.branch | 4 + .../builtins/builtins/audio_envelope.eigs | 16 + .../builtins/builtins/audio_envelope.pre | 4 + .../builtins/builtins/audio_envelope.tag | 4 + .../builtins/builtins/audio_gain.branch | 2 + .../phase2/builtins/builtins/audio_gain.eigs | 8 + tests/phase2/builtins/builtins/audio_gain.pre | 2 + tests/phase2/builtins/builtins/audio_gain.tag | 2 + .../phase2/builtins/builtins/audio_mix.branch | 2 + tests/phase2/builtins/builtins/audio_mix.eigs | 8 + tests/phase2/builtins/builtins/audio_mix.pre | 2 + tests/phase2/builtins/builtins/audio_mix.tag | 2 + .../builtins/builtins/audio_music_play.branch | 3 + .../builtins/builtins/audio_music_play.eigs | 14 + .../builtins/builtins/audio_music_play.pre | 3 + .../builtins/builtins/audio_music_play.tag | 3 + .../builtins/audio_music_volume.branch | 7 + .../builtins/builtins/audio_music_volume.eigs | 13 + .../builtins/builtins/audio_music_volume.pre | 7 + .../builtins/builtins/audio_music_volume.tag | 7 + .../builtins/builtins/audio_noise.branch | 3 + .../phase2/builtins/builtins/audio_noise.eigs | 13 + .../phase2/builtins/builtins/audio_noise.pre | 3 + .../phase2/builtins/builtins/audio_noise.tag | 3 + .../builtins/builtins/audio_open.branch | 4 + .../phase2/builtins/builtins/audio_open.eigs | 17 + tests/phase2/builtins/builtins/audio_open.pre | 4 + tests/phase2/builtins/builtins/audio_open.tag | 4 + .../builtins/builtins/audio_pause.branch | 3 + .../phase2/builtins/builtins/audio_pause.eigs | 14 + .../phase2/builtins/builtins/audio_pause.pre | 3 + .../phase2/builtins/builtins/audio_pause.tag | 3 + .../builtins/builtins/audio_play.branch | 5 + .../phase2/builtins/builtins/audio_play.eigs | 23 + tests/phase2/builtins/builtins/audio_play.pre | 5 + tests/phase2/builtins/builtins/audio_play.tag | 5 + .../builtins/builtins/audio_play_loop.branch | 6 + .../builtins/builtins/audio_play_loop.eigs | 27 + .../builtins/builtins/audio_play_loop.pre | 6 + .../builtins/builtins/audio_play_loop.tag | 6 + .../builtins/builtins/audio_queue_size.branch | 2 + .../builtins/builtins/audio_queue_size.eigs | 11 + .../builtins/builtins/audio_queue_size.pre | 2 + .../builtins/builtins/audio_queue_size.tag | 2 + .../phase2/builtins/builtins/audio_saw.branch | 3 + tests/phase2/builtins/builtins/audio_saw.eigs | 12 + tests/phase2/builtins/builtins/audio_saw.pre | 3 + tests/phase2/builtins/builtins/audio_saw.tag | 3 + .../builtins/builtins/audio_sine.branch | 3 + .../phase2/builtins/builtins/audio_sine.eigs | 12 + tests/phase2/builtins/builtins/audio_sine.pre | 3 + tests/phase2/builtins/builtins/audio_sine.tag | 3 + .../builtins/builtins/audio_square.branch | 3 + .../builtins/builtins/audio_square.eigs | 12 + .../phase2/builtins/builtins/audio_square.pre | 3 + .../phase2/builtins/builtins/audio_square.tag | 3 + .../builtins/builtins/audio_stop.branch | 3 + .../phase2/builtins/builtins/audio_stop.eigs | 16 + tests/phase2/builtins/builtins/audio_stop.pre | 3 + tests/phase2/builtins/builtins/audio_stop.tag | 3 + .../builtins/audio_stream_open.branch | 3 + .../builtins/builtins/audio_stream_open.eigs | 13 + .../builtins/builtins/audio_stream_open.pre | 3 + .../builtins/builtins/audio_stream_open.tag | 3 + .../builtins/audio_stream_push.branch | 4 + .../builtins/builtins/audio_stream_push.eigs | 11 + .../builtins/builtins/audio_stream_push.pre | 4 + .../builtins/builtins/audio_stream_push.tag | 4 + .../builtins/audio_stream_queued.branch | 2 + .../builtins/audio_stream_queued.eigs | 11 + .../builtins/builtins/audio_stream_queued.pre | 2 + .../builtins/builtins/audio_stream_queued.tag | 2 + .../builtins/builtins/audio_sweep.branch | 5 + .../phase2/builtins/builtins/audio_sweep.eigs | 17 + .../phase2/builtins/builtins/audio_sweep.pre | 5 + .../phase2/builtins/builtins/audio_sweep.tag | 5 + .../builtins/builtins/audio_volume.branch | 6 + .../builtins/builtins/audio_volume.eigs | 29 + .../phase2/builtins/builtins/audio_volume.pre | 6 + .../phase2/builtins/builtins/audio_volume.tag | 6 + tests/phase2/builtins/builtins/bit_and.branch | 4 + tests/phase2/builtins/builtins/bit_and.eigs | 14 + tests/phase2/builtins/builtins/bit_and.pre | 4 + tests/phase2/builtins/builtins/bit_and.tag | 4 + tests/phase2/builtins/builtins/bit_not.branch | 4 + tests/phase2/builtins/builtins/bit_not.eigs | 14 + tests/phase2/builtins/builtins/bit_not.pre | 4 + tests/phase2/builtins/builtins/bit_not.tag | 4 + tests/phase2/builtins/builtins/bit_or.branch | 4 + tests/phase2/builtins/builtins/bit_or.eigs | 14 + tests/phase2/builtins/builtins/bit_or.pre | 4 + tests/phase2/builtins/builtins/bit_or.tag | 4 + tests/phase2/builtins/builtins/bit_shl.branch | 5 + tests/phase2/builtins/builtins/bit_shl.eigs | 15 + tests/phase2/builtins/builtins/bit_shl.pre | 5 + tests/phase2/builtins/builtins/bit_shl.tag | 5 + tests/phase2/builtins/builtins/bit_shr.branch | 5 + tests/phase2/builtins/builtins/bit_shr.eigs | 15 + tests/phase2/builtins/builtins/bit_shr.pre | 5 + tests/phase2/builtins/builtins/bit_shr.tag | 5 + tests/phase2/builtins/builtins/bit_xor.branch | 4 + tests/phase2/builtins/builtins/bit_xor.eigs | 14 + tests/phase2/builtins/builtins/bit_xor.pre | 4 + tests/phase2/builtins/builtins/bit_xor.tag | 4 + .../phase2/builtins/builtins/buf_copy.branch | 5 + tests/phase2/builtins/builtins/buf_copy.eigs | 22 + tests/phase2/builtins/builtins/buf_copy.pre | 5 + tests/phase2/builtins/builtins/buf_copy.tag | 5 + .../builtins/builtins/buf_deinterleave.branch | 5 + .../builtins/builtins/buf_deinterleave.eigs | 19 + .../builtins/builtins/buf_deinterleave.pre | 5 + .../builtins/builtins/buf_deinterleave.tag | 5 + tests/phase2/builtins/builtins/buf_dot.branch | 4 + tests/phase2/builtins/builtins/buf_dot.eigs | 15 + tests/phase2/builtins/builtins/buf_dot.pre | 4 + tests/phase2/builtins/builtins/buf_dot.tag | 4 + .../phase2/builtins/builtins/buf_fill.branch | 5 + tests/phase2/builtins/builtins/buf_fill.eigs | 21 + tests/phase2/builtins/builtins/buf_fill.pre | 5 + tests/phase2/builtins/builtins/buf_fill.tag | 5 + .../builtins/builtins/buf_from_list.branch | 2 + .../builtins/builtins/buf_from_list.eigs | 8 + .../builtins/builtins/buf_from_list.pre | 2 + .../builtins/builtins/buf_from_list.tag | 2 + .../builtins/builtins/buf_from_pcm16le.branch | 5 + .../builtins/builtins/buf_from_pcm16le.eigs | 27 + .../builtins/builtins/buf_from_pcm16le.pre | 5 + .../builtins/builtins/buf_from_pcm16le.tag | 5 + tests/phase2/builtins/builtins/buf_get.branch | 4 + tests/phase2/builtins/builtins/buf_get.eigs | 15 + tests/phase2/builtins/builtins/buf_get.pre | 4 + tests/phase2/builtins/builtins/buf_get.tag | 4 + tests/phase2/builtins/builtins/buf_len.branch | 2 + tests/phase2/builtins/builtins/buf_len.eigs | 8 + tests/phase2/builtins/builtins/buf_len.pre | 2 + tests/phase2/builtins/builtins/buf_len.tag | 2 + tests/phase2/builtins/builtins/buf_mix.branch | 4 + tests/phase2/builtins/builtins/buf_mix.eigs | 17 + tests/phase2/builtins/builtins/buf_mix.pre | 4 + tests/phase2/builtins/builtins/buf_mix.tag | 4 + .../phase2/builtins/builtins/buf_peak.branch | 4 + tests/phase2/builtins/builtins/buf_peak.eigs | 14 + tests/phase2/builtins/builtins/buf_peak.pre | 4 + tests/phase2/builtins/builtins/buf_peak.tag | 4 + .../builtins/buf_resample_linear.branch | 4 + .../builtins/buf_resample_linear.eigs | 14 + .../builtins/builtins/buf_resample_linear.pre | 4 + .../builtins/builtins/buf_resample_linear.tag | 4 + .../builtins/builtins/buf_scale_range.branch | 4 + .../builtins/builtins/buf_scale_range.eigs | 16 + .../builtins/builtins/buf_scale_range.pre | 4 + .../builtins/builtins/buf_scale_range.tag | 4 + tests/phase2/builtins/builtins/buf_set.branch | 4 + tests/phase2/builtins/builtins/buf_set.eigs | 16 + tests/phase2/builtins/builtins/buf_set.pre | 4 + tests/phase2/builtins/builtins/buf_set.tag | 4 + .../builtins/builtins/buf_to_pcm16le.branch | 4 + .../builtins/builtins/buf_to_pcm16le.eigs | 17 + .../builtins/builtins/buf_to_pcm16le.pre | 4 + .../builtins/builtins/buf_to_pcm16le.tag | 4 + tests/phase2/builtins/builtins/buffer.branch | 5 + tests/phase2/builtins/builtins/buffer.eigs | 20 + tests/phase2/builtins/builtins/buffer.pre | 5 + tests/phase2/builtins/builtins/buffer.tag | 5 + .../builtins/builtins/build_corpus.branch | 4 + .../builtins/builtins/build_corpus.eigs | 18 + .../phase2/builtins/builtins/build_corpus.pre | 4 + .../phase2/builtins/builtins/build_corpus.tag | 4 + tests/phase2/builtins/builtins/ceil.branch | 4 + tests/phase2/builtins/builtins/ceil.eigs | 12 + tests/phase2/builtins/builtins/ceil.pre | 4 + tests/phase2/builtins/builtins/ceil.tag | 4 + tests/phase2/builtins/builtins/channel.branch | 3 + tests/phase2/builtins/builtins/channel.eigs | 12 + tests/phase2/builtins/builtins/channel.pre | 3 + tests/phase2/builtins/builtins/channel.tag | 3 + .../builtins/builtins/channel_closed.branch | 5 + .../builtins/builtins/channel_closed.eigs | 17 + .../builtins/builtins/channel_closed.pre | 5 + .../builtins/builtins/channel_closed.tag | 5 + tests/phase2/builtins/builtins/char_at.branch | 4 + tests/phase2/builtins/builtins/char_at.eigs | 12 + tests/phase2/builtins/builtins/char_at.pre | 4 + tests/phase2/builtins/builtins/char_at.tag | 4 + tests/phase2/builtins/builtins/chr.branch | 5 + tests/phase2/builtins/builtins/chr.eigs | 16 + tests/phase2/builtins/builtins/chr.pre | 5 + tests/phase2/builtins/builtins/chr.tag | 5 + .../builtins/builtins/clock_unix.branch | 2 + .../phase2/builtins/builtins/clock_unix.eigs | 8 + tests/phase2/builtins/builtins/clock_unix.pre | 2 + tests/phase2/builtins/builtins/clock_unix.tag | 2 + .../builtins/builtins/close_channel.branch | 3 + .../builtins/builtins/close_channel.eigs | 16 + .../builtins/builtins/close_channel.pre | 3 + .../builtins/builtins/close_channel.tag | 3 + .../phase2/builtins/builtins/copy_into.branch | 5 + tests/phase2/builtins/builtins/copy_into.eigs | 19 + tests/phase2/builtins/builtins/copy_into.pre | 5 + tests/phase2/builtins/builtins/copy_into.tag | 5 + tests/phase2/builtins/builtins/cos.branch | 3 + tests/phase2/builtins/builtins/cos.eigs | 10 + tests/phase2/builtins/builtins/cos.pre | 3 + tests/phase2/builtins/builtins/cos.tag | 3 + .../builtins/builtins/db_execute.branch | 3 + .../phase2/builtins/builtins/db_execute.eigs | 15 + tests/phase2/builtins/builtins/db_execute.pre | 1 + tests/phase2/builtins/builtins/db_execute.tag | 1 + .../builtins/builtins/db_query_json.branch | 3 + .../builtins/builtins/db_query_json.eigs | 14 + .../builtins/builtins/db_query_json.pre | 1 + .../builtins/builtins/db_query_json.tag | 1 + .../builtins/builtins/db_query_value.branch | 4 + .../builtins/builtins/db_query_value.eigs | 16 + .../builtins/builtins/db_query_value.pre | 1 + .../builtins/builtins/db_query_value.tag | 1 + .../phase2/builtins/builtins/dispatch.branch | 4 + tests/phase2/builtins/builtins/dispatch.eigs | 17 + tests/phase2/builtins/builtins/dispatch.pre | 4 + tests/phase2/builtins/builtins/dispatch.tag | 4 + tests/phase2/builtins/builtins/divide.branch | 3 + tests/phase2/builtins/builtins/divide.eigs | 10 + tests/phase2/builtins/builtins/divide.pre | 3 + tests/phase2/builtins/builtins/divide.tag | 3 + tests/phase2/builtins/builtins/dot.branch | 2 + tests/phase2/builtins/builtins/dot.eigs | 8 + tests/phase2/builtins/builtins/dot.pre | 2 + tests/phase2/builtins/builtins/dot.tag | 2 + .../builtins/builtins/eigen_eval_loss.branch | 6 + .../builtins/builtins/eigen_eval_loss.eigs | 33 + .../builtins/builtins/eigen_eval_loss.pre | 1 + .../builtins/builtins/eigen_eval_loss.tag | 1 + .../builtins/builtins/eigen_generate.branch | 6 + .../builtins/builtins/eigen_generate.eigs | 33 + .../builtins/builtins/eigen_generate.pre | 1 + .../builtins/builtins/eigen_generate.tag | 1 + .../builtins/builtins/eigen_model_load.branch | 4 + .../builtins/builtins/eigen_model_load.eigs | 33 + .../builtins/builtins/eigen_model_load.pre | 1 + .../builtins/builtins/eigen_model_load.tag | 1 + .../builtins/builtins/exec_capture.branch | 4 + .../builtins/builtins/exec_capture.eigs | 14 + .../phase2/builtins/builtins/exec_capture.pre | 4 + .../phase2/builtins/builtins/exec_capture.tag | 4 + tests/phase2/builtins/builtins/exit.branch | 4 + tests/phase2/builtins/builtins/exit.eigs | 16 + tests/phase2/builtins/builtins/exit.pre | 2 + tests/phase2/builtins/builtins/exit.tag | 2 + tests/phase2/builtins/builtins/exp.branch | 3 + tests/phase2/builtins/builtins/exp.eigs | 10 + tests/phase2/builtins/builtins/exp.pre | 3 + tests/phase2/builtins/builtins/exp.tag | 3 + .../builtins/builtins/f64_from_bytes.branch | 5 + .../builtins/builtins/f64_from_bytes.eigs | 18 + .../builtins/builtins/f64_from_bytes.pre | 5 + .../builtins/builtins/f64_from_bytes.tag | 5 + .../builtins/builtins/f64_to_bytes.branch | 4 + .../builtins/builtins/f64_to_bytes.eigs | 11 + .../phase2/builtins/builtins/f64_to_bytes.pre | 4 + .../phase2/builtins/builtins/f64_to_bytes.tag | 4 + tests/phase2/builtins/builtins/fill.branch | 4 + tests/phase2/builtins/builtins/fill.eigs | 12 + tests/phase2/builtins/builtins/fill.pre | 4 + tests/phase2/builtins/builtins/fill.tag | 4 + tests/phase2/builtins/builtins/floor.branch | 4 + tests/phase2/builtins/builtins/floor.eigs | 12 + tests/phase2/builtins/builtins/floor.pre | 4 + tests/phase2/builtins/builtins/floor.tag | 4 + tests/phase2/builtins/builtins/gather.branch | 5 + tests/phase2/builtins/builtins/gather.eigs | 25 + tests/phase2/builtins/builtins/gather.pre | 5 + tests/phase2/builtins/builtins/gather.tag | 5 + tests/phase2/builtins/builtins/get_at.branch | 7 + tests/phase2/builtins/builtins/get_at.eigs | 22 + tests/phase2/builtins/builtins/get_at.pre | 7 + tests/phase2/builtins/builtins/get_at.tag | 7 + .../builtins/get_observer_thresholds.branch | 3 + .../builtins/get_observer_thresholds.eigs | 9 + .../builtins/get_observer_thresholds.pre | 3 + .../builtins/get_observer_thresholds.tag | 3 + .../builtins/builtins/gfx_circle.branch | 4 + .../phase2/builtins/builtins/gfx_circle.eigs | 15 + tests/phase2/builtins/builtins/gfx_circle.pre | 4 + tests/phase2/builtins/builtins/gfx_circle.tag | 4 + .../phase2/builtins/builtins/gfx_clear.branch | 4 + tests/phase2/builtins/builtins/gfx_clear.eigs | 14 + tests/phase2/builtins/builtins/gfx_clear.pre | 4 + tests/phase2/builtins/builtins/gfx_clear.tag | 4 + .../phase2/builtins/builtins/gfx_clip.branch | 4 + tests/phase2/builtins/builtins/gfx_clip.eigs | 16 + tests/phase2/builtins/builtins/gfx_clip.pre | 4 + tests/phase2/builtins/builtins/gfx_clip.tag | 4 + .../phase2/builtins/builtins/gfx_delay.branch | 4 + tests/phase2/builtins/builtins/gfx_delay.eigs | 14 + tests/phase2/builtins/builtins/gfx_delay.pre | 4 + tests/phase2/builtins/builtins/gfx_delay.tag | 4 + tests/phase2/builtins/builtins/gfx_fb.branch | 8 + tests/phase2/builtins/builtins/gfx_fb.eigs | 35 + tests/phase2/builtins/builtins/gfx_fb.pre | 8 + tests/phase2/builtins/builtins/gfx_fb.tag | 8 + .../phase2/builtins/builtins/gfx_line.branch | 4 + tests/phase2/builtins/builtins/gfx_line.eigs | 14 + tests/phase2/builtins/builtins/gfx_line.pre | 4 + tests/phase2/builtins/builtins/gfx_line.tag | 4 + .../phase2/builtins/builtins/gfx_open.branch | 4 + tests/phase2/builtins/builtins/gfx_open.eigs | 16 + tests/phase2/builtins/builtins/gfx_open.pre | 4 + tests/phase2/builtins/builtins/gfx_open.tag | 4 + .../phase2/builtins/builtins/gfx_point.branch | 5 + tests/phase2/builtins/builtins/gfx_point.eigs | 16 + tests/phase2/builtins/builtins/gfx_point.pre | 5 + tests/phase2/builtins/builtins/gfx_point.tag | 5 + .../phase2/builtins/builtins/gfx_poll.branch | 5 + tests/phase2/builtins/builtins/gfx_poll.eigs | 16 + .../builtins/builtins/gfx_poll.empty.branch | 3 + .../builtins/builtins/gfx_poll.empty.eigs | 10 + .../builtins/builtins/gfx_poll.empty.pre | 3 + .../builtins/builtins/gfx_poll.empty.tag | 3 + tests/phase2/builtins/builtins/gfx_poll.pre | 5 + tests/phase2/builtins/builtins/gfx_poll.tag | 5 + .../phase2/builtins/builtins/gfx_read.branch | 6 + tests/phase2/builtins/builtins/gfx_read.eigs | 16 + tests/phase2/builtins/builtins/gfx_read.pre | 6 + tests/phase2/builtins/builtins/gfx_read.tag | 6 + .../phase2/builtins/builtins/gfx_rect.branch | 5 + tests/phase2/builtins/builtins/gfx_rect.eigs | 16 + tests/phase2/builtins/builtins/gfx_rect.pre | 5 + tests/phase2/builtins/builtins/gfx_rect.tag | 5 + .../phase2/builtins/builtins/gfx_rrect.branch | 4 + tests/phase2/builtins/builtins/gfx_rrect.eigs | 15 + tests/phase2/builtins/builtins/gfx_rrect.pre | 4 + tests/phase2/builtins/builtins/gfx_rrect.tag | 4 + .../phase2/builtins/builtins/gfx_text.branch | 5 + tests/phase2/builtins/builtins/gfx_text.eigs | 18 + tests/phase2/builtins/builtins/gfx_text.pre | 5 + tests/phase2/builtins/builtins/gfx_text.tag | 5 + .../builtins/builtins/gfx_text_height.branch | 5 + .../builtins/builtins/gfx_text_height.eigs | 14 + .../builtins/builtins/gfx_text_height.pre | 5 + .../builtins/builtins/gfx_text_height.tag | 5 + .../builtins/builtins/gfx_text_width.branch | 5 + .../builtins/builtins/gfx_text_width.eigs | 14 + .../builtins/builtins/gfx_text_width.pre | 5 + .../builtins/builtins/gfx_text_width.tag | 5 + .../phase2/builtins/builtins/gfx_ticks.branch | 3 + tests/phase2/builtins/builtins/gfx_ticks.eigs | 13 + tests/phase2/builtins/builtins/gfx_ticks.pre | 3 + tests/phase2/builtins/builtins/gfx_ticks.tag | 3 + tests/phase2/builtins/builtins/hex.branch | 7 + tests/phase2/builtins/builtins/hex.eigs | 21 + tests/phase2/builtins/builtins/hex.pre | 7 + tests/phase2/builtins/builtins/hex.tag | 7 + .../builtins/builtins/http_early_bind.branch | 5 + .../builtins/builtins/http_early_bind.eigs | 16 + .../builtins/builtins/http_early_bind.pre | 1 + .../builtins/builtins/http_early_bind.tag | 1 + .../phase2/builtins/builtins/http_post.branch | 2 + tests/phase2/builtins/builtins/http_post.eigs | 12 + tests/phase2/builtins/builtins/http_post.pre | 1 + tests/phase2/builtins/builtins/http_post.tag | 1 + .../builtins/builtins/http_route.branch | 3 + .../phase2/builtins/builtins/http_route.eigs | 12 + tests/phase2/builtins/builtins/http_route.pre | 1 + tests/phase2/builtins/builtins/http_route.tag | 1 + .../builtins/http_route_authed.branch | 3 + .../builtins/builtins/http_route_authed.eigs | 12 + .../builtins/builtins/http_route_authed.pre | 1 + .../builtins/builtins/http_route_authed.tag | 1 + .../builtins/builtins/http_serve.branch | 6 + .../phase2/builtins/builtins/http_serve.eigs | 18 + tests/phase2/builtins/builtins/http_serve.pre | 1 + tests/phase2/builtins/builtins/http_serve.tag | 1 + .../builtins/builtins/http_static.branch | 2 + .../phase2/builtins/builtins/http_static.eigs | 12 + .../phase2/builtins/builtins/http_static.pre | 1 + .../phase2/builtins/builtins/http_static.tag | 1 + .../phase2/builtins/builtins/index_of.branch | 3 + tests/phase2/builtins/builtins/index_of.eigs | 10 + tests/phase2/builtins/builtins/index_of.pre | 3 + tests/phase2/builtins/builtins/index_of.tag | 3 + tests/phase2/builtins/builtins/inflate.branch | 6 + tests/phase2/builtins/builtins/inflate.eigs | 22 + tests/phase2/builtins/builtins/inflate.pre | 1 + tests/phase2/builtins/builtins/inflate.tag | 1 + tests/phase2/builtins/builtins/join.branch | 2 + tests/phase2/builtins/builtins/join.eigs | 7 + tests/phase2/builtins/builtins/join.pre | 2 + tests/phase2/builtins/builtins/join.tag | 2 + .../builtins/builtins/json_build.branch | 2 + .../phase2/builtins/builtins/json_build.eigs | 7 + tests/phase2/builtins/builtins/json_build.pre | 2 + tests/phase2/builtins/builtins/json_build.tag | 2 + .../builtins/builtins/json_decode.branch | 3 + .../phase2/builtins/builtins/json_decode.eigs | 9 + .../phase2/builtins/builtins/json_decode.pre | 3 + .../phase2/builtins/builtins/json_decode.tag | 3 + .../builtins/builtins/json_encode.branch | 2 + .../phase2/builtins/builtins/json_encode.eigs | 7 + .../phase2/builtins/builtins/json_encode.pre | 2 + .../phase2/builtins/builtins/json_encode.tag | 2 + .../phase2/builtins/builtins/json_path.branch | 5 + tests/phase2/builtins/builtins/json_path.eigs | 15 + tests/phase2/builtins/builtins/json_path.pre | 5 + tests/phase2/builtins/builtins/json_path.tag | 5 + .../builtins/builtins/leaky_relu.branch | 2 + .../phase2/builtins/builtins/leaky_relu.eigs | 8 + tests/phase2/builtins/builtins/leaky_relu.pre | 2 + tests/phase2/builtins/builtins/leaky_relu.tag | 2 + tests/phase2/builtins/builtins/len.branch | 5 + tests/phase2/builtins/builtins/len.eigs | 14 + tests/phase2/builtins/builtins/len.pre | 5 + tests/phase2/builtins/builtins/len.tag | 5 + .../builtins/builtins/list_contains.branch | 2 + .../builtins/builtins/list_contains.eigs | 7 + .../builtins/builtins/list_contains.pre | 2 + .../builtins/builtins/list_contains.tag | 2 + .../builtins/builtins/list_index_of.branch | 4 + .../builtins/builtins/list_index_of.eigs | 12 + .../builtins/builtins/list_index_of.pre | 4 + .../builtins/builtins/list_index_of.tag | 4 + .../builtins/builtins/list_insert_at.branch | 4 + .../builtins/builtins/list_insert_at.eigs | 16 + .../builtins/builtins/list_insert_at.pre | 4 + .../builtins/builtins/list_insert_at.tag | 4 + .../builtins/builtins/list_remove_at.branch | 4 + .../builtins/builtins/list_remove_at.eigs | 16 + .../builtins/builtins/list_remove_at.pre | 4 + .../builtins/builtins/list_remove_at.tag | 4 + .../builtins/builtins/list_slice.branch | 5 + .../phase2/builtins/builtins/list_slice.eigs | 16 + tests/phase2/builtins/builtins/list_slice.pre | 5 + tests/phase2/builtins/builtins/list_slice.tag | 5 + .../builtins/builtins/list_truncate.branch | 4 + .../builtins/builtins/list_truncate.eigs | 16 + .../builtins/builtins/list_truncate.pre | 4 + .../builtins/builtins/list_truncate.tag | 4 + tests/phase2/builtins/builtins/log.branch | 3 + tests/phase2/builtins/builtins/log.eigs | 10 + tests/phase2/builtins/builtins/log.pre | 3 + tests/phase2/builtins/builtins/log.tag | 3 + .../builtins/builtins/log_softmax.branch | 2 + .../phase2/builtins/builtins/log_softmax.eigs | 8 + .../phase2/builtins/builtins/log_softmax.pre | 2 + .../phase2/builtins/builtins/log_softmax.tag | 2 + tests/phase2/builtins/builtins/matmul.branch | 2 + tests/phase2/builtins/builtins/matmul.eigs | 8 + tests/phase2/builtins/builtins/matmul.pre | 2 + tests/phase2/builtins/builtins/matmul.tag | 2 + .../phase2/builtins/builtins/matmul_at.branch | 2 + tests/phase2/builtins/builtins/matmul_at.eigs | 8 + tests/phase2/builtins/builtins/matmul_at.pre | 2 + tests/phase2/builtins/builtins/matmul_at.tag | 2 + .../phase2/builtins/builtins/matmul_bt.branch | 2 + tests/phase2/builtins/builtins/matmul_bt.eigs | 8 + tests/phase2/builtins/builtins/matmul_bt.pre | 2 + tests/phase2/builtins/builtins/matmul_bt.tag | 2 + tests/phase2/builtins/builtins/max.branch | 6 + tests/phase2/builtins/builtins/max.eigs | 15 + tests/phase2/builtins/builtins/max.pre | 6 + tests/phase2/builtins/builtins/max.tag | 6 + tests/phase2/builtins/builtins/mean.branch | 3 + tests/phase2/builtins/builtins/mean.eigs | 10 + tests/phase2/builtins/builtins/mean.pre | 3 + tests/phase2/builtins/builtins/mean.tag | 3 + tests/phase2/builtins/builtins/min.branch | 6 + tests/phase2/builtins/builtins/min.eigs | 15 + tests/phase2/builtins/builtins/min.pre | 6 + tests/phase2/builtins/builtins/min.tag | 6 + .../builtins/model_load_weights.branch | 4 + .../builtins/builtins/model_load_weights.eigs | 33 + .../builtins/builtins/model_load_weights.pre | 1 + .../builtins/builtins/model_load_weights.tag | 1 + .../builtins/builtins/monotonic_ms.branch | 2 + .../builtins/builtins/monotonic_ms.eigs | 9 + .../phase2/builtins/builtins/monotonic_ms.pre | 2 + .../phase2/builtins/builtins/monotonic_ms.tag | 2 + .../builtins/builtins/monotonic_ns.branch | 3 + .../builtins/builtins/monotonic_ns.eigs | 10 + .../phase2/builtins/builtins/monotonic_ns.pre | 3 + .../phase2/builtins/builtins/monotonic_ns.tag | 3 + .../phase2/builtins/builtins/multiply.branch | 4 + tests/phase2/builtins/builtins/multiply.eigs | 14 + tests/phase2/builtins/builtins/multiply.pre | 4 + tests/phase2/builtins/builtins/multiply.tag | 4 + .../builtins/native_train_step_builtin.branch | 7 + .../builtins/native_train_step_builtin.eigs | 33 + .../builtins/native_train_step_builtin.pre | 1 + .../builtins/native_train_step_builtin.tag | 1 + .../builtins/builtins/nearest_in_range.branch | 2 + .../builtins/builtins/nearest_in_range.eigs | 9 + .../builtins/builtins/nearest_in_range.pre | 2 + .../builtins/builtins/nearest_in_range.tag | 2 + .../builtins/nearest_in_range_all.branch | 2 + .../builtins/nearest_in_range_all.eigs | 9 + .../builtins/nearest_in_range_all.pre | 2 + .../builtins/nearest_in_range_all.tag | 2 + .../phase2/builtins/builtins/negative.branch | 4 + tests/phase2/builtins/builtins/negative.eigs | 14 + tests/phase2/builtins/builtins/negative.pre | 4 + tests/phase2/builtins/builtins/negative.tag | 4 + .../builtins/builtins/net_accept.branch | 3 + .../phase2/builtins/builtins/net_accept.eigs | 19 + tests/phase2/builtins/builtins/net_accept.pre | 1 + tests/phase2/builtins/builtins/net_accept.tag | 1 + .../phase2/builtins/builtins/net_close.branch | 3 + tests/phase2/builtins/builtins/net_close.eigs | 17 + tests/phase2/builtins/builtins/net_close.pre | 1 + tests/phase2/builtins/builtins/net_close.tag | 1 + .../phase2/builtins/builtins/net_dial.branch | 5 + tests/phase2/builtins/builtins/net_dial.eigs | 24 + tests/phase2/builtins/builtins/net_dial.pre | 1 + tests/phase2/builtins/builtins/net_dial.tag | 1 + .../builtins/builtins/net_listen.branch | 5 + .../phase2/builtins/builtins/net_listen.eigs | 23 + tests/phase2/builtins/builtins/net_listen.pre | 1 + tests/phase2/builtins/builtins/net_listen.tag | 1 + .../phase2/builtins/builtins/net_port.branch | 4 + tests/phase2/builtins/builtins/net_port.eigs | 18 + tests/phase2/builtins/builtins/net_port.pre | 1 + tests/phase2/builtins/builtins/net_port.tag | 1 + .../phase2/builtins/builtins/net_recv.branch | 4 + tests/phase2/builtins/builtins/net_recv.eigs | 25 + tests/phase2/builtins/builtins/net_recv.pre | 1 + tests/phase2/builtins/builtins/net_recv.tag | 1 + .../phase2/builtins/builtins/net_send.branch | 7 + tests/phase2/builtins/builtins/net_send.eigs | 32 + tests/phase2/builtins/builtins/net_send.pre | 1 + tests/phase2/builtins/builtins/net_send.tag | 1 + tests/phase2/builtins/builtins/norm.branch | 2 + tests/phase2/builtins/builtins/norm.eigs | 8 + tests/phase2/builtins/builtins/norm.pre | 2 + tests/phase2/builtins/builtins/norm.tag | 2 + tests/phase2/builtins/builtins/num.branch | 28 + tests/phase2/builtins/builtins/num.eigs | 18 + tests/phase2/builtins/builtins/num.pre | 28 + tests/phase2/builtins/builtins/num.tag | 28 + .../phase2/builtins/builtins/num_copy.branch | 3 + tests/phase2/builtins/builtins/num_copy.eigs | 10 + tests/phase2/builtins/builtins/num_copy.pre | 3 + tests/phase2/builtins/builtins/num_copy.tag | 3 + .../phase2/builtins/builtins/num_type.branch | 2 + tests/phase2/builtins/builtins/num_type.eigs | 7 + tests/phase2/builtins/builtins/num_type.pre | 2 + tests/phase2/builtins/builtins/num_type.tag | 1 + .../builtins/builtins/numerical_grad.branch | 2 + .../builtins/builtins/numerical_grad.eigs | 11 + .../builtins/builtins/numerical_grad.pre | 2 + .../builtins/builtins/numerical_grad.tag | 2 + .../builtins/numerical_grad_cols.branch | 4 + .../builtins/numerical_grad_cols.eigs | 16 + .../builtins/builtins/numerical_grad_cols.pre | 4 + .../builtins/builtins/numerical_grad_cols.tag | 4 + .../builtins/numerical_grad_rows.branch | 4 + .../builtins/numerical_grad_rows.eigs | 16 + .../builtins/builtins/numerical_grad_rows.pre | 4 + .../builtins/builtins/numerical_grad_rows.tag | 4 + tests/phase2/builtins/builtins/observe.branch | 2 + tests/phase2/builtins/builtins/observe.eigs | 9 + tests/phase2/builtins/builtins/observe.pre | 2 + tests/phase2/builtins/builtins/observe.tag | 2 + tests/phase2/builtins/builtins/ord.branch | 3 + tests/phase2/builtins/builtins/ord.eigs | 10 + tests/phase2/builtins/builtins/ord.pre | 3 + tests/phase2/builtins/builtins/ord.tag | 3 + tests/phase2/builtins/builtins/pi.branch | 2 + tests/phase2/builtins/builtins/pi.eigs | 8 + tests/phase2/builtins/builtins/pi.pre | 2 + tests/phase2/builtins/builtins/pi.tag | 2 + tests/phase2/builtins/builtins/pow.branch | 3 + tests/phase2/builtins/builtins/pow.eigs | 10 + tests/phase2/builtins/builtins/pow.pre | 3 + tests/phase2/builtins/builtins/pow.tag | 3 + .../builtins/builtins/ppu_render_frame.branch | 5 + .../builtins/builtins/ppu_render_frame.eigs | 27 + .../builtins/builtins/ppu_render_frame.pre | 5 + .../builtins/builtins/ppu_render_frame.tag | 5 + tests/phase2/builtins/builtins/print.branch | 5 + tests/phase2/builtins/builtins/print.eigs | 10 + tests/phase2/builtins/builtins/print.pre | 5 + tests/phase2/builtins/builtins/print.tag | 5 + .../builtins/builtins/proc_read_buf.branch | 5 + .../builtins/builtins/proc_read_buf.eigs | 16 + .../builtins/builtins/proc_read_buf.hi.branch | 3 + .../builtins/builtins/proc_read_buf.hi.eigs | 9 + .../builtins/builtins/proc_read_buf.hi.pre | 3 + .../builtins/builtins/proc_read_buf.hi.tag | 3 + .../builtins/builtins/proc_read_buf.pre | 5 + .../builtins/builtins/proc_read_buf.tag | 5 + tests/phase2/builtins/builtins/random.branch | 2 + tests/phase2/builtins/builtins/random.eigs | 9 + tests/phase2/builtins/builtins/random.pre | 2 + tests/phase2/builtins/builtins/random.tag | 2 + .../builtins/builtins/random_hex.branch | 4 + .../phase2/builtins/builtins/random_hex.eigs | 12 + tests/phase2/builtins/builtins/random_hex.pre | 4 + tests/phase2/builtins/builtins/random_hex.tag | 4 + .../builtins/builtins/random_int.branch | 5 + .../phase2/builtins/builtins/random_int.eigs | 17 + tests/phase2/builtins/builtins/random_int.pre | 5 + tests/phase2/builtins/builtins/random_int.tag | 5 + .../builtins/builtins/random_normal.branch | 6 + .../builtins/builtins/random_normal.eigs | 20 + .../builtins/builtins/random_normal.pre | 6 + .../builtins/builtins/random_normal.tag | 6 + tests/phase2/builtins/builtins/range.branch | 4 + tests/phase2/builtins/builtins/range.eigs | 14 + tests/phase2/builtins/builtins/range.pre | 4 + tests/phase2/builtins/builtins/range.tag | 4 + .../builtins/builtins/read_bytes.branch | 2 + .../phase2/builtins/builtins/read_bytes.eigs | 11 + tests/phase2/builtins/builtins/read_bytes.pre | 2 + tests/phase2/builtins/builtins/read_bytes.tag | 2 + .../builtins/builtins/read_bytes_buf.branch | 4 + .../builtins/builtins/read_bytes_buf.eigs | 18 + .../builtins/builtins/read_bytes_buf.pre | 4 + .../builtins/builtins/read_bytes_buf.tag | 4 + .../builtins/builtins/record_history.branch | 3 + .../builtins/builtins/record_history.eigs | 12 + .../builtins/builtins/record_history.pre | 3 + .../builtins/builtins/record_history.tag | 3 + tests/phase2/builtins/builtins/recv.branch | 3 + tests/phase2/builtins/builtins/recv.eigs | 17 + tests/phase2/builtins/builtins/recv.pre | 3 + tests/phase2/builtins/builtins/recv.tag | 3 + .../builtins/builtins/recv_timeout.branch | 6 + .../builtins/builtins/recv_timeout.eigs | 27 + .../phase2/builtins/builtins/recv_timeout.pre | 6 + .../phase2/builtins/builtins/recv_timeout.tag | 6 + tests/phase2/builtins/builtins/relu.branch | 3 + tests/phase2/builtins/builtins/relu.eigs | 10 + tests/phase2/builtins/builtins/relu.pre | 3 + tests/phase2/builtins/builtins/relu.tag | 3 + tests/phase2/builtins/builtins/reshape.branch | 4 + tests/phase2/builtins/builtins/reshape.eigs | 14 + tests/phase2/builtins/builtins/reshape.pre | 4 + tests/phase2/builtins/builtins/reshape.tag | 4 + tests/phase2/builtins/builtins/round.branch | 5 + tests/phase2/builtins/builtins/round.eigs | 14 + tests/phase2/builtins/builtins/round.pre | 5 + tests/phase2/builtins/builtins/round.tag | 5 + .../builtins/builtins/sandbox_run.branch | 5 + .../phase2/builtins/builtins/sandbox_run.eigs | 15 + .../phase2/builtins/builtins/sandbox_run.pre | 5 + .../phase2/builtins/builtins/sandbox_run.tag | 5 + .../builtins/builtins/scan_int_tokens.branch | 4 + .../builtins/builtins/scan_int_tokens.eigs | 13 + .../builtins/builtins/scan_int_tokens.pre | 4 + .../builtins/builtins/scan_int_tokens.tag | 4 + .../phase2/builtins/builtins/scan_ints.branch | 5 + tests/phase2/builtins/builtins/scan_ints.eigs | 15 + tests/phase2/builtins/builtins/scan_ints.pre | 5 + tests/phase2/builtins/builtins/scan_ints.tag | 5 + .../builtins/builtins/scatter_add.branch | 4 + .../phase2/builtins/builtins/scatter_add.eigs | 16 + .../phase2/builtins/builtins/scatter_add.pre | 4 + .../phase2/builtins/builtins/scatter_add.tag | 4 + .../builtins/builtins/seed_random.branch | 5 + .../phase2/builtins/builtins/seed_random.eigs | 22 + .../phase2/builtins/builtins/seed_random.pre | 5 + .../phase2/builtins/builtins/seed_random.tag | 5 + tests/phase2/builtins/builtins/send.branch | 4 + tests/phase2/builtins/builtins/send.eigs | 22 + tests/phase2/builtins/builtins/send.pre | 4 + tests/phase2/builtins/builtins/send.tag | 4 + tests/phase2/builtins/builtins/set_at.branch | 5 + tests/phase2/builtins/builtins/set_at.eigs | 19 + tests/phase2/builtins/builtins/set_at.pre | 5 + tests/phase2/builtins/builtins/set_at.tag | 5 + .../builtins/builtins/sgd_update.branch | 2 + .../phase2/builtins/builtins/sgd_update.eigs | 8 + tests/phase2/builtins/builtins/sgd_update.pre | 2 + tests/phase2/builtins/builtins/sgd_update.tag | 2 + .../builtins/builtins/sgd_update_cols.branch | 4 + .../builtins/builtins/sgd_update_cols.eigs | 17 + .../builtins/builtins/sgd_update_cols.pre | 4 + .../builtins/builtins/sgd_update_cols.tag | 4 + .../builtins/builtins/sgd_update_rows.branch | 4 + .../builtins/builtins/sgd_update_rows.eigs | 17 + .../builtins/builtins/sgd_update_rows.pre | 4 + .../builtins/builtins/sgd_update_rows.tag | 4 + tests/phase2/builtins/builtins/shape.branch | 4 + tests/phase2/builtins/builtins/shape.eigs | 12 + tests/phase2/builtins/builtins/shape.pre | 4 + tests/phase2/builtins/builtins/shape.tag | 4 + .../builtins/builtins/shared_delete.branch | 2 + .../builtins/builtins/shared_delete.eigs | 14 + .../builtins/builtins/shared_delete.pre | 1 + .../builtins/builtins/shared_delete.tag | 1 + .../builtins/builtins/shared_incr.branch | 4 + .../phase2/builtins/builtins/shared_incr.eigs | 20 + .../phase2/builtins/builtins/shared_incr.pre | 1 + .../phase2/builtins/builtins/shared_incr.tag | 1 + .../builtins/builtins/shared_size.branch | 2 + .../phase2/builtins/builtins/shared_size.eigs | 14 + .../phase2/builtins/builtins/shared_size.pre | 1 + .../phase2/builtins/builtins/shared_size.tag | 1 + .../builtins/builtins/sign_extend.branch | 6 + .../phase2/builtins/builtins/sign_extend.eigs | 20 + .../phase2/builtins/builtins/sign_extend.pre | 6 + .../phase2/builtins/builtins/sign_extend.tag | 6 + tests/phase2/builtins/builtins/sin.branch | 3 + tests/phase2/builtins/builtins/sin.eigs | 10 + tests/phase2/builtins/builtins/sin.pre | 3 + tests/phase2/builtins/builtins/sin.tag | 3 + tests/phase2/builtins/builtins/softmax.branch | 2 + tests/phase2/builtins/builtins/softmax.eigs | 8 + tests/phase2/builtins/builtins/softmax.pre | 2 + tests/phase2/builtins/builtins/softmax.tag | 2 + tests/phase2/builtins/builtins/sort.branch | 3 + tests/phase2/builtins/builtins/sort.eigs | 10 + tests/phase2/builtins/builtins/sort.pre | 3 + tests/phase2/builtins/builtins/sort.tag | 3 + tests/phase2/builtins/builtins/sort_by.branch | 2 + tests/phase2/builtins/builtins/sort_by.eigs | 11 + tests/phase2/builtins/builtins/sort_by.pre | 2 + tests/phase2/builtins/builtins/sort_by.tag | 2 + tests/phase2/builtins/builtins/spawn.branch | 3 + tests/phase2/builtins/builtins/spawn.eigs | 12 + tests/phase2/builtins/builtins/spawn.pre | 3 + tests/phase2/builtins/builtins/spawn.tag | 3 + tests/phase2/builtins/builtins/sqrt.branch | 3 + tests/phase2/builtins/builtins/sqrt.eigs | 10 + tests/phase2/builtins/builtins/sqrt.pre | 3 + tests/phase2/builtins/builtins/sqrt.tag | 3 + .../phase2/builtins/builtins/state_at.branch | 4 + tests/phase2/builtins/builtins/state_at.eigs | 17 + tests/phase2/builtins/builtins/state_at.pre | 4 + tests/phase2/builtins/builtins/state_at.tag | 4 + .../builtins/builtins/store_close.branch | 4 + .../phase2/builtins/builtins/store_close.eigs | 21 + .../phase2/builtins/builtins/store_close.pre | 4 + .../phase2/builtins/builtins/store_close.tag | 4 + .../builtins/store_collections.branch | 4 + .../builtins/builtins/store_collections.eigs | 16 + .../builtins/builtins/store_collections.pre | 4 + .../builtins/builtins/store_collections.tag | 4 + .../builtins/builtins/store_count.branch | 4 + .../phase2/builtins/builtins/store_count.eigs | 18 + .../phase2/builtins/builtins/store_count.pre | 4 + .../phase2/builtins/builtins/store_count.tag | 4 + .../builtins/builtins/store_delete.branch | 5 + .../builtins/builtins/store_delete.eigs | 20 + .../phase2/builtins/builtins/store_delete.pre | 5 + .../phase2/builtins/builtins/store_delete.tag | 5 + .../builtins/builtins/store_drop.branch | 3 + .../phase2/builtins/builtins/store_drop.eigs | 16 + tests/phase2/builtins/builtins/store_drop.pre | 3 + tests/phase2/builtins/builtins/store_drop.tag | 3 + .../phase2/builtins/builtins/store_get.branch | 6 + tests/phase2/builtins/builtins/store_get.eigs | 24 + tests/phase2/builtins/builtins/store_get.pre | 6 + tests/phase2/builtins/builtins/store_get.tag | 6 + .../builtins/builtins/store_open.branch | 2 + .../phase2/builtins/builtins/store_open.eigs | 10 + tests/phase2/builtins/builtins/store_open.pre | 2 + tests/phase2/builtins/builtins/store_open.tag | 2 + .../phase2/builtins/builtins/store_put.branch | 3 + tests/phase2/builtins/builtins/store_put.eigs | 13 + tests/phase2/builtins/builtins/store_put.pre | 3 + tests/phase2/builtins/builtins/store_put.tag | 3 + .../builtins/builtins/store_query.branch | 2 + .../phase2/builtins/builtins/store_query.eigs | 13 + .../phase2/builtins/builtins/store_query.pre | 2 + .../phase2/builtins/builtins/store_query.tag | 2 + .../builtins/builtins/store_update.branch | 5 + .../builtins/builtins/store_update.eigs | 22 + .../phase2/builtins/builtins/store_update.pre | 5 + .../phase2/builtins/builtins/store_update.tag | 5 + tests/phase2/builtins/builtins/str.branch | 2 + tests/phase2/builtins/builtins/str.eigs | 7 + tests/phase2/builtins/builtins/str.pre | 2 + tests/phase2/builtins/builtins/str.tag | 2 + .../builtins/builtins/str_from_bytes.branch | 6 + .../builtins/builtins/str_from_bytes.eigs | 17 + .../builtins/builtins/str_from_bytes.pre | 6 + .../builtins/builtins/str_from_bytes.tag | 6 + .../builtins/builtins/stream_open.branch | 5 + .../phase2/builtins/builtins/stream_open.eigs | 19 + .../phase2/builtins/builtins/stream_open.pre | 5 + .../phase2/builtins/builtins/stream_open.tag | 5 + .../builtins/builtins/stream_write.branch | 3 + .../builtins/builtins/stream_write.eigs | 11 + .../phase2/builtins/builtins/stream_write.pre | 3 + .../phase2/builtins/builtins/stream_write.tag | 3 + tests/phase2/builtins/builtins/substr.branch | 5 + tests/phase2/builtins/builtins/substr.eigs | 16 + tests/phase2/builtins/builtins/substr.pre | 5 + tests/phase2/builtins/builtins/substr.tag | 5 + .../phase2/builtins/builtins/subtract.branch | 4 + tests/phase2/builtins/builtins/subtract.eigs | 14 + tests/phase2/builtins/builtins/subtract.pre | 4 + tests/phase2/builtins/builtins/subtract.tag | 4 + tests/phase2/builtins/builtins/sum.branch | 6 + tests/phase2/builtins/builtins/sum.eigs | 18 + tests/phase2/builtins/builtins/sum.pre | 6 + tests/phase2/builtins/builtins/sum.tag | 6 + tests/phase2/builtins/builtins/tan.branch | 3 + tests/phase2/builtins/builtins/tan.eigs | 10 + tests/phase2/builtins/builtins/tan.pre | 3 + tests/phase2/builtins/builtins/tan.tag | 3 + .../builtins/builtins/task_alive.branch | 4 + .../phase2/builtins/builtins/task_alive.eigs | 16 + tests/phase2/builtins/builtins/task_alive.pre | 4 + tests/phase2/builtins/builtins/task_alive.tag | 4 + .../builtins/builtins/task_detach.branch | 3 + .../phase2/builtins/builtins/task_detach.eigs | 15 + .../phase2/builtins/builtins/task_detach.pre | 3 + .../phase2/builtins/builtins/task_detach.tag | 3 + .../phase2/builtins/builtins/task_join.branch | 3 + tests/phase2/builtins/builtins/task_join.eigs | 15 + tests/phase2/builtins/builtins/task_join.pre | 3 + tests/phase2/builtins/builtins/task_join.tag | 3 + .../phase2/builtins/builtins/task_kill.branch | 3 + tests/phase2/builtins/builtins/task_kill.eigs | 14 + tests/phase2/builtins/builtins/task_kill.pre | 3 + tests/phase2/builtins/builtins/task_kill.tag | 3 + .../builtins/builtins/task_sched_seed.branch | 4 + .../builtins/builtins/task_sched_seed.eigs | 31 + .../builtins/builtins/task_sched_seed.pre | 4 + .../builtins/builtins/task_sched_seed.tag | 4 + .../phase2/builtins/builtins/task_self.branch | 3 + tests/phase2/builtins/builtins/task_self.eigs | 13 + tests/phase2/builtins/builtins/task_self.pre | 3 + tests/phase2/builtins/builtins/task_self.tag | 3 + .../phase2/builtins/builtins/task_send.branch | 4 + tests/phase2/builtins/builtins/task_send.eigs | 16 + tests/phase2/builtins/builtins/task_send.pre | 4 + tests/phase2/builtins/builtins/task_send.tag | 4 + .../builtins/builtins/task_sleep.branch | 2 + .../phase2/builtins/builtins/task_sleep.eigs | 15 + tests/phase2/builtins/builtins/task_sleep.pre | 2 + tests/phase2/builtins/builtins/task_sleep.tag | 2 + .../builtins/builtins/task_spawn.branch | 3 + .../phase2/builtins/builtins/task_spawn.eigs | 12 + tests/phase2/builtins/builtins/task_spawn.pre | 3 + tests/phase2/builtins/builtins/task_spawn.tag | 3 + .../builtins/builtins/tensor_load.branch | 2 + .../phase2/builtins/builtins/tensor_load.eigs | 11 + .../phase2/builtins/builtins/tensor_load.pre | 2 + .../phase2/builtins/builtins/tensor_load.tag | 2 + .../builtins/builtins/tensor_save.branch | 3 + .../phase2/builtins/builtins/tensor_save.eigs | 11 + .../phase2/builtins/builtins/tensor_save.pre | 3 + .../phase2/builtins/builtins/tensor_save.tag | 3 + .../builtins/text_builder_append.branch | 2 + .../builtins/text_builder_append.eigs | 13 + .../builtins/builtins/text_builder_append.pre | 2 + .../builtins/builtins/text_builder_append.tag | 2 + .../builtins/text_builder_append_line.branch | 3 + .../builtins/text_builder_append_line.eigs | 10 + .../builtins/text_builder_append_line.pre | 3 + .../builtins/text_builder_append_line.tag | 3 + .../builtins/builtins/thread_join.branch | 3 + .../phase2/builtins/builtins/thread_join.eigs | 18 + .../phase2/builtins/builtins/thread_join.pre | 3 + .../phase2/builtins/builtins/thread_join.tag | 3 + tests/phase2/builtins/builtins/throw.branch | 3 + tests/phase2/builtins/builtins/throw.eigs | 14 + tests/phase2/builtins/builtins/throw.pre | 3 + tests/phase2/builtins/builtins/throw.tag | 3 + .../builtins/builtins/token_name.branch | 4 + .../phase2/builtins/builtins/token_name.eigs | 12 + tests/phase2/builtins/builtins/token_name.pre | 4 + tests/phase2/builtins/builtins/token_name.tag | 4 + .../phase2/builtins/builtins/try_recv.branch | 5 + tests/phase2/builtins/builtins/try_recv.eigs | 19 + tests/phase2/builtins/builtins/try_recv.pre | 5 + tests/phase2/builtins/builtins/try_recv.tag | 5 + tests/phase2/builtins/builtins/type.branch | 2 + tests/phase2/builtins/builtins/type.eigs | 7 + tests/phase2/builtins/builtins/type.pre | 2 + tests/phase2/builtins/builtins/type.tag | 2 + tests/phase2/builtins/builtins/usleep.branch | 4 + tests/phase2/builtins/builtins/usleep.eigs | 12 + tests/phase2/builtins/builtins/usleep.pre | 4 + tests/phase2/builtins/builtins/usleep.tag | 4 + .../builtins/builtins/vm_run_bytecode.branch | 6 + .../builtins/builtins/vm_run_bytecode.eigs | 22 + .../builtins/builtins/vm_run_bytecode.pre | 6 + .../builtins/builtins/vm_run_bytecode.tag | 6 + tests/phase2/builtins/builtins/write.branch | 2 + tests/phase2/builtins/builtins/write.eigs | 12 + tests/phase2/builtins/builtins/write.pre | 2 + tests/phase2/builtins/builtins/write.tag | 2 + .../builtins/builtins/write_bytes.branch | 5 + .../phase2/builtins/builtins/write_bytes.eigs | 20 + .../phase2/builtins/builtins/write_bytes.pre | 5 + .../phase2/builtins/builtins/write_bytes.tag | 5 + tests/phase2/builtins/builtins/zeros.branch | 6 + tests/phase2/builtins/builtins/zeros.eigs | 19 + tests/phase2/builtins/builtins/zeros.pre | 6 + tests/phase2/builtins/builtins/zeros.tag | 6 + .../builtins/builtins/zeros_like.branch | 3 + .../phase2/builtins/builtins/zeros_like.eigs | 10 + tests/phase2/builtins/builtins/zeros_like.pre | 3 + tests/phase2/builtins/builtins/zeros_like.tag | 3 + tests/phase2/builtins/cases.tsv | 234 +++++ tests/phase2/builtins/make_table.py | 212 ++++ tests/phase2/builtins/oracle/abs.lua | 4 + tests/phase2/builtins/oracle/abs.lua.out | 3 + tests/phase2/builtins/oracle/acos.lua | 2 + tests/phase2/builtins/oracle/acos.lua.out | 2 + tests/phase2/builtins/oracle/asin.lua | 2 + tests/phase2/builtins/oracle/asin.lua.out | 2 + tests/phase2/builtins/oracle/atan.lua | 2 + tests/phase2/builtins/oracle/atan.lua.out | 2 + tests/phase2/builtins/oracle/atan2.lua | 3 + tests/phase2/builtins/oracle/atan2.lua.out | 2 + tests/phase2/builtins/oracle/bit_and.lua | 4 + tests/phase2/builtins/oracle/bit_and.lua.out | 3 + tests/phase2/builtins/oracle/bit_not.lua | 4 + tests/phase2/builtins/oracle/bit_not.lua.out | 3 + tests/phase2/builtins/oracle/bit_or.lua | 4 + tests/phase2/builtins/oracle/bit_or.lua.out | 3 + tests/phase2/builtins/oracle/bit_shl.lua | 5 + tests/phase2/builtins/oracle/bit_shl.lua.out | 4 + tests/phase2/builtins/oracle/bit_shr.lua | 5 + tests/phase2/builtins/oracle/bit_shr.lua.out | 4 + tests/phase2/builtins/oracle/bit_xor.lua | 4 + tests/phase2/builtins/oracle/bit_xor.lua.out | 3 + tests/phase2/builtins/oracle/ceil.lua | 4 + tests/phase2/builtins/oracle/ceil.lua.out | 3 + tests/phase2/builtins/oracle/char_at.lua | 4 + tests/phase2/builtins/oracle/char_at.lua.out | 3 + tests/phase2/builtins/oracle/chr.lua | 4 + tests/phase2/builtins/oracle/chr.lua.out | 4 + tests/phase2/builtins/oracle/cos.lua | 2 + tests/phase2/builtins/oracle/cos.lua.out | 2 + tests/phase2/builtins/oracle/divide.lua | 3 + tests/phase2/builtins/oracle/divide.lua.out | 2 + tests/phase2/builtins/oracle/exp.lua | 3 + tests/phase2/builtins/oracle/exp.lua.out | 2 + tests/phase2/builtins/oracle/floor.lua | 4 + tests/phase2/builtins/oracle/floor.lua.out | 3 + tests/phase2/builtins/oracle/len.lua | 3 + tests/phase2/builtins/oracle/len.lua.out | 2 + .../phase2/builtins/oracle/list_insert_at.lua | 5 + .../builtins/oracle/list_insert_at.lua.out | 3 + .../phase2/builtins/oracle/list_remove_at.lua | 5 + .../builtins/oracle/list_remove_at.lua.out | 3 + tests/phase2/builtins/oracle/log.lua | 3 + tests/phase2/builtins/oracle/log.lua.out | 2 + tests/phase2/builtins/oracle/max.lua | 7 + tests/phase2/builtins/oracle/max.lua.out | 6 + tests/phase2/builtins/oracle/min.lua | 7 + tests/phase2/builtins/oracle/min.lua.out | 6 + tests/phase2/builtins/oracle/num.lua | 4 + tests/phase2/builtins/oracle/num.lua.out | 25 + tests/phase2/builtins/oracle/ord.lua | 3 + tests/phase2/builtins/oracle/ord.lua.out | 2 + tests/phase2/builtins/oracle/pi.lua | 1 + tests/phase2/builtins/oracle/pi.lua.out | 1 + tests/phase2/builtins/oracle/pow.lua | 3 + tests/phase2/builtins/oracle/pow.lua.out | 2 + tests/phase2/builtins/oracle/random.lua | 3 + tests/phase2/builtins/oracle/random.lua.out | 1 + tests/phase2/builtins/oracle/random_int.lua | 6 + .../phase2/builtins/oracle/random_int.lua.out | 4 + tests/phase2/builtins/oracle/seed_random.lua | 7 + .../builtins/oracle/seed_random.lua.out | 3 + tests/phase2/builtins/oracle/sin.lua | 2 + tests/phase2/builtins/oracle/sin.lua.out | 2 + tests/phase2/builtins/oracle/sqrt.lua | 3 + tests/phase2/builtins/oracle/sqrt.lua.out | 2 + .../phase2/builtins/oracle/str_from_bytes.lua | 4 + .../builtins/oracle/str_from_bytes.lua.out | 4 + tests/phase2/builtins/oracle/substr.lua | 5 + tests/phase2/builtins/oracle/substr.lua.out | 4 + tests/phase2/builtins/oracle/tan.lua | 2 + tests/phase2/builtins/oracle/tan.lua.out | 2 + tests/phase2/builtins/plants.sh | 132 +++ tests/phase2/builtins/rowmeta.tsv | 232 +++++ tests/phase2/builtins/run_probes.sh | 94 ++ 1017 files changed, 8624 insertions(+) create mode 100644 tests/phase2/builtins/BAR.md create mode 100644 tests/phase2/builtins/RULINGS.md create mode 100644 tests/phase2/builtins/builtins.tsv create mode 100644 tests/phase2/builtins/builtins/_hooks/observation_hooks.c create mode 100644 tests/phase2/builtins/builtins/_profiles/db.eigs create mode 100644 tests/phase2/builtins/builtins/_profiles/server.eigs create mode 100644 tests/phase2/builtins/builtins/_profiles/zlib.eigs create mode 100644 tests/phase2/builtins/builtins/_stdin/hi create mode 100644 tests/phase2/builtins/builtins/abs.branch create mode 100644 tests/phase2/builtins/builtins/abs.eigs create mode 100644 tests/phase2/builtins/builtins/abs.pre create mode 100644 tests/phase2/builtins/builtins/abs.tag create mode 100644 tests/phase2/builtins/builtins/acos.branch create mode 100644 tests/phase2/builtins/builtins/acos.eigs create mode 100644 tests/phase2/builtins/builtins/acos.pre create mode 100644 tests/phase2/builtins/builtins/acos.tag create mode 100644 tests/phase2/builtins/builtins/add.branch create mode 100644 tests/phase2/builtins/builtins/add.eigs create mode 100644 tests/phase2/builtins/builtins/add.pre create mode 100644 tests/phase2/builtins/builtins/add.tag create mode 100644 tests/phase2/builtins/builtins/append.branch create mode 100644 tests/phase2/builtins/builtins/append.eigs create mode 100644 tests/phase2/builtins/builtins/append.pre create mode 100644 tests/phase2/builtins/builtins/append.tag create mode 100644 tests/phase2/builtins/builtins/asin.branch create mode 100644 tests/phase2/builtins/builtins/asin.eigs create mode 100644 tests/phase2/builtins/builtins/asin.pre create mode 100644 tests/phase2/builtins/builtins/asin.tag create mode 100644 tests/phase2/builtins/builtins/assert.branch create mode 100644 tests/phase2/builtins/builtins/assert.eigs create mode 100644 tests/phase2/builtins/builtins/assert.pre create mode 100644 tests/phase2/builtins/builtins/assert.tag create mode 100644 tests/phase2/builtins/builtins/atan.branch create mode 100644 tests/phase2/builtins/builtins/atan.eigs create mode 100644 tests/phase2/builtins/builtins/atan.pre create mode 100644 tests/phase2/builtins/builtins/atan.tag create mode 100644 tests/phase2/builtins/builtins/atan2.branch create mode 100644 tests/phase2/builtins/builtins/atan2.eigs create mode 100644 tests/phase2/builtins/builtins/atan2.pre create mode 100644 tests/phase2/builtins/builtins/atan2.tag create mode 100644 tests/phase2/builtins/builtins/audio_capture_open.branch create mode 100644 tests/phase2/builtins/builtins/audio_capture_open.eigs create mode 100644 tests/phase2/builtins/builtins/audio_capture_open.pre create mode 100644 tests/phase2/builtins/builtins/audio_capture_open.tag create mode 100644 tests/phase2/builtins/builtins/audio_envelope.branch create mode 100644 tests/phase2/builtins/builtins/audio_envelope.eigs create mode 100644 tests/phase2/builtins/builtins/audio_envelope.pre create mode 100644 tests/phase2/builtins/builtins/audio_envelope.tag create mode 100644 tests/phase2/builtins/builtins/audio_gain.branch create mode 100644 tests/phase2/builtins/builtins/audio_gain.eigs create mode 100644 tests/phase2/builtins/builtins/audio_gain.pre create mode 100644 tests/phase2/builtins/builtins/audio_gain.tag create mode 100644 tests/phase2/builtins/builtins/audio_mix.branch create mode 100644 tests/phase2/builtins/builtins/audio_mix.eigs create mode 100644 tests/phase2/builtins/builtins/audio_mix.pre create mode 100644 tests/phase2/builtins/builtins/audio_mix.tag create mode 100644 tests/phase2/builtins/builtins/audio_music_play.branch create mode 100644 tests/phase2/builtins/builtins/audio_music_play.eigs create mode 100644 tests/phase2/builtins/builtins/audio_music_play.pre create mode 100644 tests/phase2/builtins/builtins/audio_music_play.tag create mode 100644 tests/phase2/builtins/builtins/audio_music_volume.branch create mode 100644 tests/phase2/builtins/builtins/audio_music_volume.eigs create mode 100644 tests/phase2/builtins/builtins/audio_music_volume.pre create mode 100644 tests/phase2/builtins/builtins/audio_music_volume.tag create mode 100644 tests/phase2/builtins/builtins/audio_noise.branch create mode 100644 tests/phase2/builtins/builtins/audio_noise.eigs create mode 100644 tests/phase2/builtins/builtins/audio_noise.pre create mode 100644 tests/phase2/builtins/builtins/audio_noise.tag create mode 100644 tests/phase2/builtins/builtins/audio_open.branch create mode 100644 tests/phase2/builtins/builtins/audio_open.eigs create mode 100644 tests/phase2/builtins/builtins/audio_open.pre create mode 100644 tests/phase2/builtins/builtins/audio_open.tag create mode 100644 tests/phase2/builtins/builtins/audio_pause.branch create mode 100644 tests/phase2/builtins/builtins/audio_pause.eigs create mode 100644 tests/phase2/builtins/builtins/audio_pause.pre create mode 100644 tests/phase2/builtins/builtins/audio_pause.tag create mode 100644 tests/phase2/builtins/builtins/audio_play.branch create mode 100644 tests/phase2/builtins/builtins/audio_play.eigs create mode 100644 tests/phase2/builtins/builtins/audio_play.pre create mode 100644 tests/phase2/builtins/builtins/audio_play.tag create mode 100644 tests/phase2/builtins/builtins/audio_play_loop.branch create mode 100644 tests/phase2/builtins/builtins/audio_play_loop.eigs create mode 100644 tests/phase2/builtins/builtins/audio_play_loop.pre create mode 100644 tests/phase2/builtins/builtins/audio_play_loop.tag create mode 100644 tests/phase2/builtins/builtins/audio_queue_size.branch create mode 100644 tests/phase2/builtins/builtins/audio_queue_size.eigs create mode 100644 tests/phase2/builtins/builtins/audio_queue_size.pre create mode 100644 tests/phase2/builtins/builtins/audio_queue_size.tag create mode 100644 tests/phase2/builtins/builtins/audio_saw.branch create mode 100644 tests/phase2/builtins/builtins/audio_saw.eigs create mode 100644 tests/phase2/builtins/builtins/audio_saw.pre create mode 100644 tests/phase2/builtins/builtins/audio_saw.tag create mode 100644 tests/phase2/builtins/builtins/audio_sine.branch create mode 100644 tests/phase2/builtins/builtins/audio_sine.eigs create mode 100644 tests/phase2/builtins/builtins/audio_sine.pre create mode 100644 tests/phase2/builtins/builtins/audio_sine.tag create mode 100644 tests/phase2/builtins/builtins/audio_square.branch create mode 100644 tests/phase2/builtins/builtins/audio_square.eigs create mode 100644 tests/phase2/builtins/builtins/audio_square.pre create mode 100644 tests/phase2/builtins/builtins/audio_square.tag create mode 100644 tests/phase2/builtins/builtins/audio_stop.branch create mode 100644 tests/phase2/builtins/builtins/audio_stop.eigs create mode 100644 tests/phase2/builtins/builtins/audio_stop.pre create mode 100644 tests/phase2/builtins/builtins/audio_stop.tag create mode 100644 tests/phase2/builtins/builtins/audio_stream_open.branch create mode 100644 tests/phase2/builtins/builtins/audio_stream_open.eigs create mode 100644 tests/phase2/builtins/builtins/audio_stream_open.pre create mode 100644 tests/phase2/builtins/builtins/audio_stream_open.tag create mode 100644 tests/phase2/builtins/builtins/audio_stream_push.branch create mode 100644 tests/phase2/builtins/builtins/audio_stream_push.eigs create mode 100644 tests/phase2/builtins/builtins/audio_stream_push.pre create mode 100644 tests/phase2/builtins/builtins/audio_stream_push.tag create mode 100644 tests/phase2/builtins/builtins/audio_stream_queued.branch create mode 100644 tests/phase2/builtins/builtins/audio_stream_queued.eigs create mode 100644 tests/phase2/builtins/builtins/audio_stream_queued.pre create mode 100644 tests/phase2/builtins/builtins/audio_stream_queued.tag create mode 100644 tests/phase2/builtins/builtins/audio_sweep.branch create mode 100644 tests/phase2/builtins/builtins/audio_sweep.eigs create mode 100644 tests/phase2/builtins/builtins/audio_sweep.pre create mode 100644 tests/phase2/builtins/builtins/audio_sweep.tag create mode 100644 tests/phase2/builtins/builtins/audio_volume.branch create mode 100644 tests/phase2/builtins/builtins/audio_volume.eigs create mode 100644 tests/phase2/builtins/builtins/audio_volume.pre create mode 100644 tests/phase2/builtins/builtins/audio_volume.tag create mode 100644 tests/phase2/builtins/builtins/bit_and.branch create mode 100644 tests/phase2/builtins/builtins/bit_and.eigs create mode 100644 tests/phase2/builtins/builtins/bit_and.pre create mode 100644 tests/phase2/builtins/builtins/bit_and.tag create mode 100644 tests/phase2/builtins/builtins/bit_not.branch create mode 100644 tests/phase2/builtins/builtins/bit_not.eigs create mode 100644 tests/phase2/builtins/builtins/bit_not.pre create mode 100644 tests/phase2/builtins/builtins/bit_not.tag create mode 100644 tests/phase2/builtins/builtins/bit_or.branch create mode 100644 tests/phase2/builtins/builtins/bit_or.eigs create mode 100644 tests/phase2/builtins/builtins/bit_or.pre create mode 100644 tests/phase2/builtins/builtins/bit_or.tag create mode 100644 tests/phase2/builtins/builtins/bit_shl.branch create mode 100644 tests/phase2/builtins/builtins/bit_shl.eigs create mode 100644 tests/phase2/builtins/builtins/bit_shl.pre create mode 100644 tests/phase2/builtins/builtins/bit_shl.tag create mode 100644 tests/phase2/builtins/builtins/bit_shr.branch create mode 100644 tests/phase2/builtins/builtins/bit_shr.eigs create mode 100644 tests/phase2/builtins/builtins/bit_shr.pre create mode 100644 tests/phase2/builtins/builtins/bit_shr.tag create mode 100644 tests/phase2/builtins/builtins/bit_xor.branch create mode 100644 tests/phase2/builtins/builtins/bit_xor.eigs create mode 100644 tests/phase2/builtins/builtins/bit_xor.pre create mode 100644 tests/phase2/builtins/builtins/bit_xor.tag create mode 100644 tests/phase2/builtins/builtins/buf_copy.branch create mode 100644 tests/phase2/builtins/builtins/buf_copy.eigs create mode 100644 tests/phase2/builtins/builtins/buf_copy.pre create mode 100644 tests/phase2/builtins/builtins/buf_copy.tag create mode 100644 tests/phase2/builtins/builtins/buf_deinterleave.branch create mode 100644 tests/phase2/builtins/builtins/buf_deinterleave.eigs create mode 100644 tests/phase2/builtins/builtins/buf_deinterleave.pre create mode 100644 tests/phase2/builtins/builtins/buf_deinterleave.tag create mode 100644 tests/phase2/builtins/builtins/buf_dot.branch create mode 100644 tests/phase2/builtins/builtins/buf_dot.eigs create mode 100644 tests/phase2/builtins/builtins/buf_dot.pre create mode 100644 tests/phase2/builtins/builtins/buf_dot.tag create mode 100644 tests/phase2/builtins/builtins/buf_fill.branch create mode 100644 tests/phase2/builtins/builtins/buf_fill.eigs create mode 100644 tests/phase2/builtins/builtins/buf_fill.pre create mode 100644 tests/phase2/builtins/builtins/buf_fill.tag create mode 100644 tests/phase2/builtins/builtins/buf_from_list.branch create mode 100644 tests/phase2/builtins/builtins/buf_from_list.eigs create mode 100644 tests/phase2/builtins/builtins/buf_from_list.pre create mode 100644 tests/phase2/builtins/builtins/buf_from_list.tag create mode 100644 tests/phase2/builtins/builtins/buf_from_pcm16le.branch create mode 100644 tests/phase2/builtins/builtins/buf_from_pcm16le.eigs create mode 100644 tests/phase2/builtins/builtins/buf_from_pcm16le.pre create mode 100644 tests/phase2/builtins/builtins/buf_from_pcm16le.tag create mode 100644 tests/phase2/builtins/builtins/buf_get.branch create mode 100644 tests/phase2/builtins/builtins/buf_get.eigs create mode 100644 tests/phase2/builtins/builtins/buf_get.pre create mode 100644 tests/phase2/builtins/builtins/buf_get.tag create mode 100644 tests/phase2/builtins/builtins/buf_len.branch create mode 100644 tests/phase2/builtins/builtins/buf_len.eigs create mode 100644 tests/phase2/builtins/builtins/buf_len.pre create mode 100644 tests/phase2/builtins/builtins/buf_len.tag create mode 100644 tests/phase2/builtins/builtins/buf_mix.branch create mode 100644 tests/phase2/builtins/builtins/buf_mix.eigs create mode 100644 tests/phase2/builtins/builtins/buf_mix.pre create mode 100644 tests/phase2/builtins/builtins/buf_mix.tag create mode 100644 tests/phase2/builtins/builtins/buf_peak.branch create mode 100644 tests/phase2/builtins/builtins/buf_peak.eigs create mode 100644 tests/phase2/builtins/builtins/buf_peak.pre create mode 100644 tests/phase2/builtins/builtins/buf_peak.tag create mode 100644 tests/phase2/builtins/builtins/buf_resample_linear.branch create mode 100644 tests/phase2/builtins/builtins/buf_resample_linear.eigs create mode 100644 tests/phase2/builtins/builtins/buf_resample_linear.pre create mode 100644 tests/phase2/builtins/builtins/buf_resample_linear.tag create mode 100644 tests/phase2/builtins/builtins/buf_scale_range.branch create mode 100644 tests/phase2/builtins/builtins/buf_scale_range.eigs create mode 100644 tests/phase2/builtins/builtins/buf_scale_range.pre create mode 100644 tests/phase2/builtins/builtins/buf_scale_range.tag create mode 100644 tests/phase2/builtins/builtins/buf_set.branch create mode 100644 tests/phase2/builtins/builtins/buf_set.eigs create mode 100644 tests/phase2/builtins/builtins/buf_set.pre create mode 100644 tests/phase2/builtins/builtins/buf_set.tag create mode 100644 tests/phase2/builtins/builtins/buf_to_pcm16le.branch create mode 100644 tests/phase2/builtins/builtins/buf_to_pcm16le.eigs create mode 100644 tests/phase2/builtins/builtins/buf_to_pcm16le.pre create mode 100644 tests/phase2/builtins/builtins/buf_to_pcm16le.tag create mode 100644 tests/phase2/builtins/builtins/buffer.branch create mode 100644 tests/phase2/builtins/builtins/buffer.eigs create mode 100644 tests/phase2/builtins/builtins/buffer.pre create mode 100644 tests/phase2/builtins/builtins/buffer.tag create mode 100644 tests/phase2/builtins/builtins/build_corpus.branch create mode 100644 tests/phase2/builtins/builtins/build_corpus.eigs create mode 100644 tests/phase2/builtins/builtins/build_corpus.pre create mode 100644 tests/phase2/builtins/builtins/build_corpus.tag create mode 100644 tests/phase2/builtins/builtins/ceil.branch create mode 100644 tests/phase2/builtins/builtins/ceil.eigs create mode 100644 tests/phase2/builtins/builtins/ceil.pre create mode 100644 tests/phase2/builtins/builtins/ceil.tag create mode 100644 tests/phase2/builtins/builtins/channel.branch create mode 100644 tests/phase2/builtins/builtins/channel.eigs create mode 100644 tests/phase2/builtins/builtins/channel.pre create mode 100644 tests/phase2/builtins/builtins/channel.tag create mode 100644 tests/phase2/builtins/builtins/channel_closed.branch create mode 100644 tests/phase2/builtins/builtins/channel_closed.eigs create mode 100644 tests/phase2/builtins/builtins/channel_closed.pre create mode 100644 tests/phase2/builtins/builtins/channel_closed.tag create mode 100644 tests/phase2/builtins/builtins/char_at.branch create mode 100644 tests/phase2/builtins/builtins/char_at.eigs create mode 100644 tests/phase2/builtins/builtins/char_at.pre create mode 100644 tests/phase2/builtins/builtins/char_at.tag create mode 100644 tests/phase2/builtins/builtins/chr.branch create mode 100644 tests/phase2/builtins/builtins/chr.eigs create mode 100644 tests/phase2/builtins/builtins/chr.pre create mode 100644 tests/phase2/builtins/builtins/chr.tag create mode 100644 tests/phase2/builtins/builtins/clock_unix.branch create mode 100644 tests/phase2/builtins/builtins/clock_unix.eigs create mode 100644 tests/phase2/builtins/builtins/clock_unix.pre create mode 100644 tests/phase2/builtins/builtins/clock_unix.tag create mode 100644 tests/phase2/builtins/builtins/close_channel.branch create mode 100644 tests/phase2/builtins/builtins/close_channel.eigs create mode 100644 tests/phase2/builtins/builtins/close_channel.pre create mode 100644 tests/phase2/builtins/builtins/close_channel.tag create mode 100644 tests/phase2/builtins/builtins/copy_into.branch create mode 100644 tests/phase2/builtins/builtins/copy_into.eigs create mode 100644 tests/phase2/builtins/builtins/copy_into.pre create mode 100644 tests/phase2/builtins/builtins/copy_into.tag create mode 100644 tests/phase2/builtins/builtins/cos.branch create mode 100644 tests/phase2/builtins/builtins/cos.eigs create mode 100644 tests/phase2/builtins/builtins/cos.pre create mode 100644 tests/phase2/builtins/builtins/cos.tag create mode 100644 tests/phase2/builtins/builtins/db_execute.branch create mode 100644 tests/phase2/builtins/builtins/db_execute.eigs create mode 100644 tests/phase2/builtins/builtins/db_execute.pre create mode 100644 tests/phase2/builtins/builtins/db_execute.tag create mode 100644 tests/phase2/builtins/builtins/db_query_json.branch create mode 100644 tests/phase2/builtins/builtins/db_query_json.eigs create mode 100644 tests/phase2/builtins/builtins/db_query_json.pre create mode 100644 tests/phase2/builtins/builtins/db_query_json.tag create mode 100644 tests/phase2/builtins/builtins/db_query_value.branch create mode 100644 tests/phase2/builtins/builtins/db_query_value.eigs create mode 100644 tests/phase2/builtins/builtins/db_query_value.pre create mode 100644 tests/phase2/builtins/builtins/db_query_value.tag create mode 100644 tests/phase2/builtins/builtins/dispatch.branch create mode 100644 tests/phase2/builtins/builtins/dispatch.eigs create mode 100644 tests/phase2/builtins/builtins/dispatch.pre create mode 100644 tests/phase2/builtins/builtins/dispatch.tag create mode 100644 tests/phase2/builtins/builtins/divide.branch create mode 100644 tests/phase2/builtins/builtins/divide.eigs create mode 100644 tests/phase2/builtins/builtins/divide.pre create mode 100644 tests/phase2/builtins/builtins/divide.tag create mode 100644 tests/phase2/builtins/builtins/dot.branch create mode 100644 tests/phase2/builtins/builtins/dot.eigs create mode 100644 tests/phase2/builtins/builtins/dot.pre create mode 100644 tests/phase2/builtins/builtins/dot.tag create mode 100644 tests/phase2/builtins/builtins/eigen_eval_loss.branch create mode 100644 tests/phase2/builtins/builtins/eigen_eval_loss.eigs create mode 100644 tests/phase2/builtins/builtins/eigen_eval_loss.pre create mode 100644 tests/phase2/builtins/builtins/eigen_eval_loss.tag create mode 100644 tests/phase2/builtins/builtins/eigen_generate.branch create mode 100644 tests/phase2/builtins/builtins/eigen_generate.eigs create mode 100644 tests/phase2/builtins/builtins/eigen_generate.pre create mode 100644 tests/phase2/builtins/builtins/eigen_generate.tag create mode 100644 tests/phase2/builtins/builtins/eigen_model_load.branch create mode 100644 tests/phase2/builtins/builtins/eigen_model_load.eigs create mode 100644 tests/phase2/builtins/builtins/eigen_model_load.pre create mode 100644 tests/phase2/builtins/builtins/eigen_model_load.tag create mode 100644 tests/phase2/builtins/builtins/exec_capture.branch create mode 100644 tests/phase2/builtins/builtins/exec_capture.eigs create mode 100644 tests/phase2/builtins/builtins/exec_capture.pre create mode 100644 tests/phase2/builtins/builtins/exec_capture.tag create mode 100644 tests/phase2/builtins/builtins/exit.branch create mode 100644 tests/phase2/builtins/builtins/exit.eigs create mode 100644 tests/phase2/builtins/builtins/exit.pre create mode 100644 tests/phase2/builtins/builtins/exit.tag create mode 100644 tests/phase2/builtins/builtins/exp.branch create mode 100644 tests/phase2/builtins/builtins/exp.eigs create mode 100644 tests/phase2/builtins/builtins/exp.pre create mode 100644 tests/phase2/builtins/builtins/exp.tag create mode 100644 tests/phase2/builtins/builtins/f64_from_bytes.branch create mode 100644 tests/phase2/builtins/builtins/f64_from_bytes.eigs create mode 100644 tests/phase2/builtins/builtins/f64_from_bytes.pre create mode 100644 tests/phase2/builtins/builtins/f64_from_bytes.tag create mode 100644 tests/phase2/builtins/builtins/f64_to_bytes.branch create mode 100644 tests/phase2/builtins/builtins/f64_to_bytes.eigs create mode 100644 tests/phase2/builtins/builtins/f64_to_bytes.pre create mode 100644 tests/phase2/builtins/builtins/f64_to_bytes.tag create mode 100644 tests/phase2/builtins/builtins/fill.branch create mode 100644 tests/phase2/builtins/builtins/fill.eigs create mode 100644 tests/phase2/builtins/builtins/fill.pre create mode 100644 tests/phase2/builtins/builtins/fill.tag create mode 100644 tests/phase2/builtins/builtins/floor.branch create mode 100644 tests/phase2/builtins/builtins/floor.eigs create mode 100644 tests/phase2/builtins/builtins/floor.pre create mode 100644 tests/phase2/builtins/builtins/floor.tag create mode 100644 tests/phase2/builtins/builtins/gather.branch create mode 100644 tests/phase2/builtins/builtins/gather.eigs create mode 100644 tests/phase2/builtins/builtins/gather.pre create mode 100644 tests/phase2/builtins/builtins/gather.tag create mode 100644 tests/phase2/builtins/builtins/get_at.branch create mode 100644 tests/phase2/builtins/builtins/get_at.eigs create mode 100644 tests/phase2/builtins/builtins/get_at.pre create mode 100644 tests/phase2/builtins/builtins/get_at.tag create mode 100644 tests/phase2/builtins/builtins/get_observer_thresholds.branch create mode 100644 tests/phase2/builtins/builtins/get_observer_thresholds.eigs create mode 100644 tests/phase2/builtins/builtins/get_observer_thresholds.pre create mode 100644 tests/phase2/builtins/builtins/get_observer_thresholds.tag create mode 100644 tests/phase2/builtins/builtins/gfx_circle.branch create mode 100644 tests/phase2/builtins/builtins/gfx_circle.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_circle.pre create mode 100644 tests/phase2/builtins/builtins/gfx_circle.tag create mode 100644 tests/phase2/builtins/builtins/gfx_clear.branch create mode 100644 tests/phase2/builtins/builtins/gfx_clear.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_clear.pre create mode 100644 tests/phase2/builtins/builtins/gfx_clear.tag create mode 100644 tests/phase2/builtins/builtins/gfx_clip.branch create mode 100644 tests/phase2/builtins/builtins/gfx_clip.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_clip.pre create mode 100644 tests/phase2/builtins/builtins/gfx_clip.tag create mode 100644 tests/phase2/builtins/builtins/gfx_delay.branch create mode 100644 tests/phase2/builtins/builtins/gfx_delay.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_delay.pre create mode 100644 tests/phase2/builtins/builtins/gfx_delay.tag create mode 100644 tests/phase2/builtins/builtins/gfx_fb.branch create mode 100644 tests/phase2/builtins/builtins/gfx_fb.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_fb.pre create mode 100644 tests/phase2/builtins/builtins/gfx_fb.tag create mode 100644 tests/phase2/builtins/builtins/gfx_line.branch create mode 100644 tests/phase2/builtins/builtins/gfx_line.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_line.pre create mode 100644 tests/phase2/builtins/builtins/gfx_line.tag create mode 100644 tests/phase2/builtins/builtins/gfx_open.branch create mode 100644 tests/phase2/builtins/builtins/gfx_open.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_open.pre create mode 100644 tests/phase2/builtins/builtins/gfx_open.tag create mode 100644 tests/phase2/builtins/builtins/gfx_point.branch create mode 100644 tests/phase2/builtins/builtins/gfx_point.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_point.pre create mode 100644 tests/phase2/builtins/builtins/gfx_point.tag create mode 100644 tests/phase2/builtins/builtins/gfx_poll.branch create mode 100644 tests/phase2/builtins/builtins/gfx_poll.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_poll.empty.branch create mode 100644 tests/phase2/builtins/builtins/gfx_poll.empty.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_poll.empty.pre create mode 100644 tests/phase2/builtins/builtins/gfx_poll.empty.tag create mode 100644 tests/phase2/builtins/builtins/gfx_poll.pre create mode 100644 tests/phase2/builtins/builtins/gfx_poll.tag create mode 100644 tests/phase2/builtins/builtins/gfx_read.branch create mode 100644 tests/phase2/builtins/builtins/gfx_read.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_read.pre create mode 100644 tests/phase2/builtins/builtins/gfx_read.tag create mode 100644 tests/phase2/builtins/builtins/gfx_rect.branch create mode 100644 tests/phase2/builtins/builtins/gfx_rect.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_rect.pre create mode 100644 tests/phase2/builtins/builtins/gfx_rect.tag create mode 100644 tests/phase2/builtins/builtins/gfx_rrect.branch create mode 100644 tests/phase2/builtins/builtins/gfx_rrect.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_rrect.pre create mode 100644 tests/phase2/builtins/builtins/gfx_rrect.tag create mode 100644 tests/phase2/builtins/builtins/gfx_text.branch create mode 100644 tests/phase2/builtins/builtins/gfx_text.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_text.pre create mode 100644 tests/phase2/builtins/builtins/gfx_text.tag create mode 100644 tests/phase2/builtins/builtins/gfx_text_height.branch create mode 100644 tests/phase2/builtins/builtins/gfx_text_height.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_text_height.pre create mode 100644 tests/phase2/builtins/builtins/gfx_text_height.tag create mode 100644 tests/phase2/builtins/builtins/gfx_text_width.branch create mode 100644 tests/phase2/builtins/builtins/gfx_text_width.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_text_width.pre create mode 100644 tests/phase2/builtins/builtins/gfx_text_width.tag create mode 100644 tests/phase2/builtins/builtins/gfx_ticks.branch create mode 100644 tests/phase2/builtins/builtins/gfx_ticks.eigs create mode 100644 tests/phase2/builtins/builtins/gfx_ticks.pre create mode 100644 tests/phase2/builtins/builtins/gfx_ticks.tag create mode 100644 tests/phase2/builtins/builtins/hex.branch create mode 100644 tests/phase2/builtins/builtins/hex.eigs create mode 100644 tests/phase2/builtins/builtins/hex.pre create mode 100644 tests/phase2/builtins/builtins/hex.tag create mode 100644 tests/phase2/builtins/builtins/http_early_bind.branch create mode 100644 tests/phase2/builtins/builtins/http_early_bind.eigs create mode 100644 tests/phase2/builtins/builtins/http_early_bind.pre create mode 100644 tests/phase2/builtins/builtins/http_early_bind.tag create mode 100644 tests/phase2/builtins/builtins/http_post.branch create mode 100644 tests/phase2/builtins/builtins/http_post.eigs create mode 100644 tests/phase2/builtins/builtins/http_post.pre create mode 100644 tests/phase2/builtins/builtins/http_post.tag create mode 100644 tests/phase2/builtins/builtins/http_route.branch create mode 100644 tests/phase2/builtins/builtins/http_route.eigs create mode 100644 tests/phase2/builtins/builtins/http_route.pre create mode 100644 tests/phase2/builtins/builtins/http_route.tag create mode 100644 tests/phase2/builtins/builtins/http_route_authed.branch create mode 100644 tests/phase2/builtins/builtins/http_route_authed.eigs create mode 100644 tests/phase2/builtins/builtins/http_route_authed.pre create mode 100644 tests/phase2/builtins/builtins/http_route_authed.tag create mode 100644 tests/phase2/builtins/builtins/http_serve.branch create mode 100644 tests/phase2/builtins/builtins/http_serve.eigs create mode 100644 tests/phase2/builtins/builtins/http_serve.pre create mode 100644 tests/phase2/builtins/builtins/http_serve.tag create mode 100644 tests/phase2/builtins/builtins/http_static.branch create mode 100644 tests/phase2/builtins/builtins/http_static.eigs create mode 100644 tests/phase2/builtins/builtins/http_static.pre create mode 100644 tests/phase2/builtins/builtins/http_static.tag create mode 100644 tests/phase2/builtins/builtins/index_of.branch create mode 100644 tests/phase2/builtins/builtins/index_of.eigs create mode 100644 tests/phase2/builtins/builtins/index_of.pre create mode 100644 tests/phase2/builtins/builtins/index_of.tag create mode 100644 tests/phase2/builtins/builtins/inflate.branch create mode 100644 tests/phase2/builtins/builtins/inflate.eigs create mode 100644 tests/phase2/builtins/builtins/inflate.pre create mode 100644 tests/phase2/builtins/builtins/inflate.tag create mode 100644 tests/phase2/builtins/builtins/join.branch create mode 100644 tests/phase2/builtins/builtins/join.eigs create mode 100644 tests/phase2/builtins/builtins/join.pre create mode 100644 tests/phase2/builtins/builtins/join.tag create mode 100644 tests/phase2/builtins/builtins/json_build.branch create mode 100644 tests/phase2/builtins/builtins/json_build.eigs create mode 100644 tests/phase2/builtins/builtins/json_build.pre create mode 100644 tests/phase2/builtins/builtins/json_build.tag create mode 100644 tests/phase2/builtins/builtins/json_decode.branch create mode 100644 tests/phase2/builtins/builtins/json_decode.eigs create mode 100644 tests/phase2/builtins/builtins/json_decode.pre create mode 100644 tests/phase2/builtins/builtins/json_decode.tag create mode 100644 tests/phase2/builtins/builtins/json_encode.branch create mode 100644 tests/phase2/builtins/builtins/json_encode.eigs create mode 100644 tests/phase2/builtins/builtins/json_encode.pre create mode 100644 tests/phase2/builtins/builtins/json_encode.tag create mode 100644 tests/phase2/builtins/builtins/json_path.branch create mode 100644 tests/phase2/builtins/builtins/json_path.eigs create mode 100644 tests/phase2/builtins/builtins/json_path.pre create mode 100644 tests/phase2/builtins/builtins/json_path.tag create mode 100644 tests/phase2/builtins/builtins/leaky_relu.branch create mode 100644 tests/phase2/builtins/builtins/leaky_relu.eigs create mode 100644 tests/phase2/builtins/builtins/leaky_relu.pre create mode 100644 tests/phase2/builtins/builtins/leaky_relu.tag create mode 100644 tests/phase2/builtins/builtins/len.branch create mode 100644 tests/phase2/builtins/builtins/len.eigs create mode 100644 tests/phase2/builtins/builtins/len.pre create mode 100644 tests/phase2/builtins/builtins/len.tag create mode 100644 tests/phase2/builtins/builtins/list_contains.branch create mode 100644 tests/phase2/builtins/builtins/list_contains.eigs create mode 100644 tests/phase2/builtins/builtins/list_contains.pre create mode 100644 tests/phase2/builtins/builtins/list_contains.tag create mode 100644 tests/phase2/builtins/builtins/list_index_of.branch create mode 100644 tests/phase2/builtins/builtins/list_index_of.eigs create mode 100644 tests/phase2/builtins/builtins/list_index_of.pre create mode 100644 tests/phase2/builtins/builtins/list_index_of.tag create mode 100644 tests/phase2/builtins/builtins/list_insert_at.branch create mode 100644 tests/phase2/builtins/builtins/list_insert_at.eigs create mode 100644 tests/phase2/builtins/builtins/list_insert_at.pre create mode 100644 tests/phase2/builtins/builtins/list_insert_at.tag create mode 100644 tests/phase2/builtins/builtins/list_remove_at.branch create mode 100644 tests/phase2/builtins/builtins/list_remove_at.eigs create mode 100644 tests/phase2/builtins/builtins/list_remove_at.pre create mode 100644 tests/phase2/builtins/builtins/list_remove_at.tag create mode 100644 tests/phase2/builtins/builtins/list_slice.branch create mode 100644 tests/phase2/builtins/builtins/list_slice.eigs create mode 100644 tests/phase2/builtins/builtins/list_slice.pre create mode 100644 tests/phase2/builtins/builtins/list_slice.tag create mode 100644 tests/phase2/builtins/builtins/list_truncate.branch create mode 100644 tests/phase2/builtins/builtins/list_truncate.eigs create mode 100644 tests/phase2/builtins/builtins/list_truncate.pre create mode 100644 tests/phase2/builtins/builtins/list_truncate.tag create mode 100644 tests/phase2/builtins/builtins/log.branch create mode 100644 tests/phase2/builtins/builtins/log.eigs create mode 100644 tests/phase2/builtins/builtins/log.pre create mode 100644 tests/phase2/builtins/builtins/log.tag create mode 100644 tests/phase2/builtins/builtins/log_softmax.branch create mode 100644 tests/phase2/builtins/builtins/log_softmax.eigs create mode 100644 tests/phase2/builtins/builtins/log_softmax.pre create mode 100644 tests/phase2/builtins/builtins/log_softmax.tag create mode 100644 tests/phase2/builtins/builtins/matmul.branch create mode 100644 tests/phase2/builtins/builtins/matmul.eigs create mode 100644 tests/phase2/builtins/builtins/matmul.pre create mode 100644 tests/phase2/builtins/builtins/matmul.tag create mode 100644 tests/phase2/builtins/builtins/matmul_at.branch create mode 100644 tests/phase2/builtins/builtins/matmul_at.eigs create mode 100644 tests/phase2/builtins/builtins/matmul_at.pre create mode 100644 tests/phase2/builtins/builtins/matmul_at.tag create mode 100644 tests/phase2/builtins/builtins/matmul_bt.branch create mode 100644 tests/phase2/builtins/builtins/matmul_bt.eigs create mode 100644 tests/phase2/builtins/builtins/matmul_bt.pre create mode 100644 tests/phase2/builtins/builtins/matmul_bt.tag create mode 100644 tests/phase2/builtins/builtins/max.branch create mode 100644 tests/phase2/builtins/builtins/max.eigs create mode 100644 tests/phase2/builtins/builtins/max.pre create mode 100644 tests/phase2/builtins/builtins/max.tag create mode 100644 tests/phase2/builtins/builtins/mean.branch create mode 100644 tests/phase2/builtins/builtins/mean.eigs create mode 100644 tests/phase2/builtins/builtins/mean.pre create mode 100644 tests/phase2/builtins/builtins/mean.tag create mode 100644 tests/phase2/builtins/builtins/min.branch create mode 100644 tests/phase2/builtins/builtins/min.eigs create mode 100644 tests/phase2/builtins/builtins/min.pre create mode 100644 tests/phase2/builtins/builtins/min.tag create mode 100644 tests/phase2/builtins/builtins/model_load_weights.branch create mode 100644 tests/phase2/builtins/builtins/model_load_weights.eigs create mode 100644 tests/phase2/builtins/builtins/model_load_weights.pre create mode 100644 tests/phase2/builtins/builtins/model_load_weights.tag create mode 100644 tests/phase2/builtins/builtins/monotonic_ms.branch create mode 100644 tests/phase2/builtins/builtins/monotonic_ms.eigs create mode 100644 tests/phase2/builtins/builtins/monotonic_ms.pre create mode 100644 tests/phase2/builtins/builtins/monotonic_ms.tag create mode 100644 tests/phase2/builtins/builtins/monotonic_ns.branch create mode 100644 tests/phase2/builtins/builtins/monotonic_ns.eigs create mode 100644 tests/phase2/builtins/builtins/monotonic_ns.pre create mode 100644 tests/phase2/builtins/builtins/monotonic_ns.tag create mode 100644 tests/phase2/builtins/builtins/multiply.branch create mode 100644 tests/phase2/builtins/builtins/multiply.eigs create mode 100644 tests/phase2/builtins/builtins/multiply.pre create mode 100644 tests/phase2/builtins/builtins/multiply.tag create mode 100644 tests/phase2/builtins/builtins/native_train_step_builtin.branch create mode 100644 tests/phase2/builtins/builtins/native_train_step_builtin.eigs create mode 100644 tests/phase2/builtins/builtins/native_train_step_builtin.pre create mode 100644 tests/phase2/builtins/builtins/native_train_step_builtin.tag create mode 100644 tests/phase2/builtins/builtins/nearest_in_range.branch create mode 100644 tests/phase2/builtins/builtins/nearest_in_range.eigs create mode 100644 tests/phase2/builtins/builtins/nearest_in_range.pre create mode 100644 tests/phase2/builtins/builtins/nearest_in_range.tag create mode 100644 tests/phase2/builtins/builtins/nearest_in_range_all.branch create mode 100644 tests/phase2/builtins/builtins/nearest_in_range_all.eigs create mode 100644 tests/phase2/builtins/builtins/nearest_in_range_all.pre create mode 100644 tests/phase2/builtins/builtins/nearest_in_range_all.tag create mode 100644 tests/phase2/builtins/builtins/negative.branch create mode 100644 tests/phase2/builtins/builtins/negative.eigs create mode 100644 tests/phase2/builtins/builtins/negative.pre create mode 100644 tests/phase2/builtins/builtins/negative.tag create mode 100644 tests/phase2/builtins/builtins/net_accept.branch create mode 100644 tests/phase2/builtins/builtins/net_accept.eigs create mode 100644 tests/phase2/builtins/builtins/net_accept.pre create mode 100644 tests/phase2/builtins/builtins/net_accept.tag create mode 100644 tests/phase2/builtins/builtins/net_close.branch create mode 100644 tests/phase2/builtins/builtins/net_close.eigs create mode 100644 tests/phase2/builtins/builtins/net_close.pre create mode 100644 tests/phase2/builtins/builtins/net_close.tag create mode 100644 tests/phase2/builtins/builtins/net_dial.branch create mode 100644 tests/phase2/builtins/builtins/net_dial.eigs create mode 100644 tests/phase2/builtins/builtins/net_dial.pre create mode 100644 tests/phase2/builtins/builtins/net_dial.tag create mode 100644 tests/phase2/builtins/builtins/net_listen.branch create mode 100644 tests/phase2/builtins/builtins/net_listen.eigs create mode 100644 tests/phase2/builtins/builtins/net_listen.pre create mode 100644 tests/phase2/builtins/builtins/net_listen.tag create mode 100644 tests/phase2/builtins/builtins/net_port.branch create mode 100644 tests/phase2/builtins/builtins/net_port.eigs create mode 100644 tests/phase2/builtins/builtins/net_port.pre create mode 100644 tests/phase2/builtins/builtins/net_port.tag create mode 100644 tests/phase2/builtins/builtins/net_recv.branch create mode 100644 tests/phase2/builtins/builtins/net_recv.eigs create mode 100644 tests/phase2/builtins/builtins/net_recv.pre create mode 100644 tests/phase2/builtins/builtins/net_recv.tag create mode 100644 tests/phase2/builtins/builtins/net_send.branch create mode 100644 tests/phase2/builtins/builtins/net_send.eigs create mode 100644 tests/phase2/builtins/builtins/net_send.pre create mode 100644 tests/phase2/builtins/builtins/net_send.tag create mode 100644 tests/phase2/builtins/builtins/norm.branch create mode 100644 tests/phase2/builtins/builtins/norm.eigs create mode 100644 tests/phase2/builtins/builtins/norm.pre create mode 100644 tests/phase2/builtins/builtins/norm.tag create mode 100644 tests/phase2/builtins/builtins/num.branch create mode 100644 tests/phase2/builtins/builtins/num.eigs create mode 100644 tests/phase2/builtins/builtins/num.pre create mode 100644 tests/phase2/builtins/builtins/num.tag create mode 100644 tests/phase2/builtins/builtins/num_copy.branch create mode 100644 tests/phase2/builtins/builtins/num_copy.eigs create mode 100644 tests/phase2/builtins/builtins/num_copy.pre create mode 100644 tests/phase2/builtins/builtins/num_copy.tag create mode 100644 tests/phase2/builtins/builtins/num_type.branch create mode 100644 tests/phase2/builtins/builtins/num_type.eigs create mode 100644 tests/phase2/builtins/builtins/num_type.pre create mode 100644 tests/phase2/builtins/builtins/num_type.tag create mode 100644 tests/phase2/builtins/builtins/numerical_grad.branch create mode 100644 tests/phase2/builtins/builtins/numerical_grad.eigs create mode 100644 tests/phase2/builtins/builtins/numerical_grad.pre create mode 100644 tests/phase2/builtins/builtins/numerical_grad.tag create mode 100644 tests/phase2/builtins/builtins/numerical_grad_cols.branch create mode 100644 tests/phase2/builtins/builtins/numerical_grad_cols.eigs create mode 100644 tests/phase2/builtins/builtins/numerical_grad_cols.pre create mode 100644 tests/phase2/builtins/builtins/numerical_grad_cols.tag create mode 100644 tests/phase2/builtins/builtins/numerical_grad_rows.branch create mode 100644 tests/phase2/builtins/builtins/numerical_grad_rows.eigs create mode 100644 tests/phase2/builtins/builtins/numerical_grad_rows.pre create mode 100644 tests/phase2/builtins/builtins/numerical_grad_rows.tag create mode 100644 tests/phase2/builtins/builtins/observe.branch create mode 100644 tests/phase2/builtins/builtins/observe.eigs create mode 100644 tests/phase2/builtins/builtins/observe.pre create mode 100644 tests/phase2/builtins/builtins/observe.tag create mode 100644 tests/phase2/builtins/builtins/ord.branch create mode 100644 tests/phase2/builtins/builtins/ord.eigs create mode 100644 tests/phase2/builtins/builtins/ord.pre create mode 100644 tests/phase2/builtins/builtins/ord.tag create mode 100644 tests/phase2/builtins/builtins/pi.branch create mode 100644 tests/phase2/builtins/builtins/pi.eigs create mode 100644 tests/phase2/builtins/builtins/pi.pre create mode 100644 tests/phase2/builtins/builtins/pi.tag create mode 100644 tests/phase2/builtins/builtins/pow.branch create mode 100644 tests/phase2/builtins/builtins/pow.eigs create mode 100644 tests/phase2/builtins/builtins/pow.pre create mode 100644 tests/phase2/builtins/builtins/pow.tag create mode 100644 tests/phase2/builtins/builtins/ppu_render_frame.branch create mode 100644 tests/phase2/builtins/builtins/ppu_render_frame.eigs create mode 100644 tests/phase2/builtins/builtins/ppu_render_frame.pre create mode 100644 tests/phase2/builtins/builtins/ppu_render_frame.tag create mode 100644 tests/phase2/builtins/builtins/print.branch create mode 100644 tests/phase2/builtins/builtins/print.eigs create mode 100644 tests/phase2/builtins/builtins/print.pre create mode 100644 tests/phase2/builtins/builtins/print.tag create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.branch create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.eigs create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.hi.branch create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.hi.eigs create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.hi.pre create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.hi.tag create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.pre create mode 100644 tests/phase2/builtins/builtins/proc_read_buf.tag create mode 100644 tests/phase2/builtins/builtins/random.branch create mode 100644 tests/phase2/builtins/builtins/random.eigs create mode 100644 tests/phase2/builtins/builtins/random.pre create mode 100644 tests/phase2/builtins/builtins/random.tag create mode 100644 tests/phase2/builtins/builtins/random_hex.branch create mode 100644 tests/phase2/builtins/builtins/random_hex.eigs create mode 100644 tests/phase2/builtins/builtins/random_hex.pre create mode 100644 tests/phase2/builtins/builtins/random_hex.tag create mode 100644 tests/phase2/builtins/builtins/random_int.branch create mode 100644 tests/phase2/builtins/builtins/random_int.eigs create mode 100644 tests/phase2/builtins/builtins/random_int.pre create mode 100644 tests/phase2/builtins/builtins/random_int.tag create mode 100644 tests/phase2/builtins/builtins/random_normal.branch create mode 100644 tests/phase2/builtins/builtins/random_normal.eigs create mode 100644 tests/phase2/builtins/builtins/random_normal.pre create mode 100644 tests/phase2/builtins/builtins/random_normal.tag create mode 100644 tests/phase2/builtins/builtins/range.branch create mode 100644 tests/phase2/builtins/builtins/range.eigs create mode 100644 tests/phase2/builtins/builtins/range.pre create mode 100644 tests/phase2/builtins/builtins/range.tag create mode 100644 tests/phase2/builtins/builtins/read_bytes.branch create mode 100644 tests/phase2/builtins/builtins/read_bytes.eigs create mode 100644 tests/phase2/builtins/builtins/read_bytes.pre create mode 100644 tests/phase2/builtins/builtins/read_bytes.tag create mode 100644 tests/phase2/builtins/builtins/read_bytes_buf.branch create mode 100644 tests/phase2/builtins/builtins/read_bytes_buf.eigs create mode 100644 tests/phase2/builtins/builtins/read_bytes_buf.pre create mode 100644 tests/phase2/builtins/builtins/read_bytes_buf.tag create mode 100644 tests/phase2/builtins/builtins/record_history.branch create mode 100644 tests/phase2/builtins/builtins/record_history.eigs create mode 100644 tests/phase2/builtins/builtins/record_history.pre create mode 100644 tests/phase2/builtins/builtins/record_history.tag create mode 100644 tests/phase2/builtins/builtins/recv.branch create mode 100644 tests/phase2/builtins/builtins/recv.eigs create mode 100644 tests/phase2/builtins/builtins/recv.pre create mode 100644 tests/phase2/builtins/builtins/recv.tag create mode 100644 tests/phase2/builtins/builtins/recv_timeout.branch create mode 100644 tests/phase2/builtins/builtins/recv_timeout.eigs create mode 100644 tests/phase2/builtins/builtins/recv_timeout.pre create mode 100644 tests/phase2/builtins/builtins/recv_timeout.tag create mode 100644 tests/phase2/builtins/builtins/relu.branch create mode 100644 tests/phase2/builtins/builtins/relu.eigs create mode 100644 tests/phase2/builtins/builtins/relu.pre create mode 100644 tests/phase2/builtins/builtins/relu.tag create mode 100644 tests/phase2/builtins/builtins/reshape.branch create mode 100644 tests/phase2/builtins/builtins/reshape.eigs create mode 100644 tests/phase2/builtins/builtins/reshape.pre create mode 100644 tests/phase2/builtins/builtins/reshape.tag create mode 100644 tests/phase2/builtins/builtins/round.branch create mode 100644 tests/phase2/builtins/builtins/round.eigs create mode 100644 tests/phase2/builtins/builtins/round.pre create mode 100644 tests/phase2/builtins/builtins/round.tag create mode 100644 tests/phase2/builtins/builtins/sandbox_run.branch create mode 100644 tests/phase2/builtins/builtins/sandbox_run.eigs create mode 100644 tests/phase2/builtins/builtins/sandbox_run.pre create mode 100644 tests/phase2/builtins/builtins/sandbox_run.tag create mode 100644 tests/phase2/builtins/builtins/scan_int_tokens.branch create mode 100644 tests/phase2/builtins/builtins/scan_int_tokens.eigs create mode 100644 tests/phase2/builtins/builtins/scan_int_tokens.pre create mode 100644 tests/phase2/builtins/builtins/scan_int_tokens.tag create mode 100644 tests/phase2/builtins/builtins/scan_ints.branch create mode 100644 tests/phase2/builtins/builtins/scan_ints.eigs create mode 100644 tests/phase2/builtins/builtins/scan_ints.pre create mode 100644 tests/phase2/builtins/builtins/scan_ints.tag create mode 100644 tests/phase2/builtins/builtins/scatter_add.branch create mode 100644 tests/phase2/builtins/builtins/scatter_add.eigs create mode 100644 tests/phase2/builtins/builtins/scatter_add.pre create mode 100644 tests/phase2/builtins/builtins/scatter_add.tag create mode 100644 tests/phase2/builtins/builtins/seed_random.branch create mode 100644 tests/phase2/builtins/builtins/seed_random.eigs create mode 100644 tests/phase2/builtins/builtins/seed_random.pre create mode 100644 tests/phase2/builtins/builtins/seed_random.tag create mode 100644 tests/phase2/builtins/builtins/send.branch create mode 100644 tests/phase2/builtins/builtins/send.eigs create mode 100644 tests/phase2/builtins/builtins/send.pre create mode 100644 tests/phase2/builtins/builtins/send.tag create mode 100644 tests/phase2/builtins/builtins/set_at.branch create mode 100644 tests/phase2/builtins/builtins/set_at.eigs create mode 100644 tests/phase2/builtins/builtins/set_at.pre create mode 100644 tests/phase2/builtins/builtins/set_at.tag create mode 100644 tests/phase2/builtins/builtins/sgd_update.branch create mode 100644 tests/phase2/builtins/builtins/sgd_update.eigs create mode 100644 tests/phase2/builtins/builtins/sgd_update.pre create mode 100644 tests/phase2/builtins/builtins/sgd_update.tag create mode 100644 tests/phase2/builtins/builtins/sgd_update_cols.branch create mode 100644 tests/phase2/builtins/builtins/sgd_update_cols.eigs create mode 100644 tests/phase2/builtins/builtins/sgd_update_cols.pre create mode 100644 tests/phase2/builtins/builtins/sgd_update_cols.tag create mode 100644 tests/phase2/builtins/builtins/sgd_update_rows.branch create mode 100644 tests/phase2/builtins/builtins/sgd_update_rows.eigs create mode 100644 tests/phase2/builtins/builtins/sgd_update_rows.pre create mode 100644 tests/phase2/builtins/builtins/sgd_update_rows.tag create mode 100644 tests/phase2/builtins/builtins/shape.branch create mode 100644 tests/phase2/builtins/builtins/shape.eigs create mode 100644 tests/phase2/builtins/builtins/shape.pre create mode 100644 tests/phase2/builtins/builtins/shape.tag create mode 100644 tests/phase2/builtins/builtins/shared_delete.branch create mode 100644 tests/phase2/builtins/builtins/shared_delete.eigs create mode 100644 tests/phase2/builtins/builtins/shared_delete.pre create mode 100644 tests/phase2/builtins/builtins/shared_delete.tag create mode 100644 tests/phase2/builtins/builtins/shared_incr.branch create mode 100644 tests/phase2/builtins/builtins/shared_incr.eigs create mode 100644 tests/phase2/builtins/builtins/shared_incr.pre create mode 100644 tests/phase2/builtins/builtins/shared_incr.tag create mode 100644 tests/phase2/builtins/builtins/shared_size.branch create mode 100644 tests/phase2/builtins/builtins/shared_size.eigs create mode 100644 tests/phase2/builtins/builtins/shared_size.pre create mode 100644 tests/phase2/builtins/builtins/shared_size.tag create mode 100644 tests/phase2/builtins/builtins/sign_extend.branch create mode 100644 tests/phase2/builtins/builtins/sign_extend.eigs create mode 100644 tests/phase2/builtins/builtins/sign_extend.pre create mode 100644 tests/phase2/builtins/builtins/sign_extend.tag create mode 100644 tests/phase2/builtins/builtins/sin.branch create mode 100644 tests/phase2/builtins/builtins/sin.eigs create mode 100644 tests/phase2/builtins/builtins/sin.pre create mode 100644 tests/phase2/builtins/builtins/sin.tag create mode 100644 tests/phase2/builtins/builtins/softmax.branch create mode 100644 tests/phase2/builtins/builtins/softmax.eigs create mode 100644 tests/phase2/builtins/builtins/softmax.pre create mode 100644 tests/phase2/builtins/builtins/softmax.tag create mode 100644 tests/phase2/builtins/builtins/sort.branch create mode 100644 tests/phase2/builtins/builtins/sort.eigs create mode 100644 tests/phase2/builtins/builtins/sort.pre create mode 100644 tests/phase2/builtins/builtins/sort.tag create mode 100644 tests/phase2/builtins/builtins/sort_by.branch create mode 100644 tests/phase2/builtins/builtins/sort_by.eigs create mode 100644 tests/phase2/builtins/builtins/sort_by.pre create mode 100644 tests/phase2/builtins/builtins/sort_by.tag create mode 100644 tests/phase2/builtins/builtins/spawn.branch create mode 100644 tests/phase2/builtins/builtins/spawn.eigs create mode 100644 tests/phase2/builtins/builtins/spawn.pre create mode 100644 tests/phase2/builtins/builtins/spawn.tag create mode 100644 tests/phase2/builtins/builtins/sqrt.branch create mode 100644 tests/phase2/builtins/builtins/sqrt.eigs create mode 100644 tests/phase2/builtins/builtins/sqrt.pre create mode 100644 tests/phase2/builtins/builtins/sqrt.tag create mode 100644 tests/phase2/builtins/builtins/state_at.branch create mode 100644 tests/phase2/builtins/builtins/state_at.eigs create mode 100644 tests/phase2/builtins/builtins/state_at.pre create mode 100644 tests/phase2/builtins/builtins/state_at.tag create mode 100644 tests/phase2/builtins/builtins/store_close.branch create mode 100644 tests/phase2/builtins/builtins/store_close.eigs create mode 100644 tests/phase2/builtins/builtins/store_close.pre create mode 100644 tests/phase2/builtins/builtins/store_close.tag create mode 100644 tests/phase2/builtins/builtins/store_collections.branch create mode 100644 tests/phase2/builtins/builtins/store_collections.eigs create mode 100644 tests/phase2/builtins/builtins/store_collections.pre create mode 100644 tests/phase2/builtins/builtins/store_collections.tag create mode 100644 tests/phase2/builtins/builtins/store_count.branch create mode 100644 tests/phase2/builtins/builtins/store_count.eigs create mode 100644 tests/phase2/builtins/builtins/store_count.pre create mode 100644 tests/phase2/builtins/builtins/store_count.tag create mode 100644 tests/phase2/builtins/builtins/store_delete.branch create mode 100644 tests/phase2/builtins/builtins/store_delete.eigs create mode 100644 tests/phase2/builtins/builtins/store_delete.pre create mode 100644 tests/phase2/builtins/builtins/store_delete.tag create mode 100644 tests/phase2/builtins/builtins/store_drop.branch create mode 100644 tests/phase2/builtins/builtins/store_drop.eigs create mode 100644 tests/phase2/builtins/builtins/store_drop.pre create mode 100644 tests/phase2/builtins/builtins/store_drop.tag create mode 100644 tests/phase2/builtins/builtins/store_get.branch create mode 100644 tests/phase2/builtins/builtins/store_get.eigs create mode 100644 tests/phase2/builtins/builtins/store_get.pre create mode 100644 tests/phase2/builtins/builtins/store_get.tag create mode 100644 tests/phase2/builtins/builtins/store_open.branch create mode 100644 tests/phase2/builtins/builtins/store_open.eigs create mode 100644 tests/phase2/builtins/builtins/store_open.pre create mode 100644 tests/phase2/builtins/builtins/store_open.tag create mode 100644 tests/phase2/builtins/builtins/store_put.branch create mode 100644 tests/phase2/builtins/builtins/store_put.eigs create mode 100644 tests/phase2/builtins/builtins/store_put.pre create mode 100644 tests/phase2/builtins/builtins/store_put.tag create mode 100644 tests/phase2/builtins/builtins/store_query.branch create mode 100644 tests/phase2/builtins/builtins/store_query.eigs create mode 100644 tests/phase2/builtins/builtins/store_query.pre create mode 100644 tests/phase2/builtins/builtins/store_query.tag create mode 100644 tests/phase2/builtins/builtins/store_update.branch create mode 100644 tests/phase2/builtins/builtins/store_update.eigs create mode 100644 tests/phase2/builtins/builtins/store_update.pre create mode 100644 tests/phase2/builtins/builtins/store_update.tag create mode 100644 tests/phase2/builtins/builtins/str.branch create mode 100644 tests/phase2/builtins/builtins/str.eigs create mode 100644 tests/phase2/builtins/builtins/str.pre create mode 100644 tests/phase2/builtins/builtins/str.tag create mode 100644 tests/phase2/builtins/builtins/str_from_bytes.branch create mode 100644 tests/phase2/builtins/builtins/str_from_bytes.eigs create mode 100644 tests/phase2/builtins/builtins/str_from_bytes.pre create mode 100644 tests/phase2/builtins/builtins/str_from_bytes.tag create mode 100644 tests/phase2/builtins/builtins/stream_open.branch create mode 100644 tests/phase2/builtins/builtins/stream_open.eigs create mode 100644 tests/phase2/builtins/builtins/stream_open.pre create mode 100644 tests/phase2/builtins/builtins/stream_open.tag create mode 100644 tests/phase2/builtins/builtins/stream_write.branch create mode 100644 tests/phase2/builtins/builtins/stream_write.eigs create mode 100644 tests/phase2/builtins/builtins/stream_write.pre create mode 100644 tests/phase2/builtins/builtins/stream_write.tag create mode 100644 tests/phase2/builtins/builtins/substr.branch create mode 100644 tests/phase2/builtins/builtins/substr.eigs create mode 100644 tests/phase2/builtins/builtins/substr.pre create mode 100644 tests/phase2/builtins/builtins/substr.tag create mode 100644 tests/phase2/builtins/builtins/subtract.branch create mode 100644 tests/phase2/builtins/builtins/subtract.eigs create mode 100644 tests/phase2/builtins/builtins/subtract.pre create mode 100644 tests/phase2/builtins/builtins/subtract.tag create mode 100644 tests/phase2/builtins/builtins/sum.branch create mode 100644 tests/phase2/builtins/builtins/sum.eigs create mode 100644 tests/phase2/builtins/builtins/sum.pre create mode 100644 tests/phase2/builtins/builtins/sum.tag create mode 100644 tests/phase2/builtins/builtins/tan.branch create mode 100644 tests/phase2/builtins/builtins/tan.eigs create mode 100644 tests/phase2/builtins/builtins/tan.pre create mode 100644 tests/phase2/builtins/builtins/tan.tag create mode 100644 tests/phase2/builtins/builtins/task_alive.branch create mode 100644 tests/phase2/builtins/builtins/task_alive.eigs create mode 100644 tests/phase2/builtins/builtins/task_alive.pre create mode 100644 tests/phase2/builtins/builtins/task_alive.tag create mode 100644 tests/phase2/builtins/builtins/task_detach.branch create mode 100644 tests/phase2/builtins/builtins/task_detach.eigs create mode 100644 tests/phase2/builtins/builtins/task_detach.pre create mode 100644 tests/phase2/builtins/builtins/task_detach.tag create mode 100644 tests/phase2/builtins/builtins/task_join.branch create mode 100644 tests/phase2/builtins/builtins/task_join.eigs create mode 100644 tests/phase2/builtins/builtins/task_join.pre create mode 100644 tests/phase2/builtins/builtins/task_join.tag create mode 100644 tests/phase2/builtins/builtins/task_kill.branch create mode 100644 tests/phase2/builtins/builtins/task_kill.eigs create mode 100644 tests/phase2/builtins/builtins/task_kill.pre create mode 100644 tests/phase2/builtins/builtins/task_kill.tag create mode 100644 tests/phase2/builtins/builtins/task_sched_seed.branch create mode 100644 tests/phase2/builtins/builtins/task_sched_seed.eigs create mode 100644 tests/phase2/builtins/builtins/task_sched_seed.pre create mode 100644 tests/phase2/builtins/builtins/task_sched_seed.tag create mode 100644 tests/phase2/builtins/builtins/task_self.branch create mode 100644 tests/phase2/builtins/builtins/task_self.eigs create mode 100644 tests/phase2/builtins/builtins/task_self.pre create mode 100644 tests/phase2/builtins/builtins/task_self.tag create mode 100644 tests/phase2/builtins/builtins/task_send.branch create mode 100644 tests/phase2/builtins/builtins/task_send.eigs create mode 100644 tests/phase2/builtins/builtins/task_send.pre create mode 100644 tests/phase2/builtins/builtins/task_send.tag create mode 100644 tests/phase2/builtins/builtins/task_sleep.branch create mode 100644 tests/phase2/builtins/builtins/task_sleep.eigs create mode 100644 tests/phase2/builtins/builtins/task_sleep.pre create mode 100644 tests/phase2/builtins/builtins/task_sleep.tag create mode 100644 tests/phase2/builtins/builtins/task_spawn.branch create mode 100644 tests/phase2/builtins/builtins/task_spawn.eigs create mode 100644 tests/phase2/builtins/builtins/task_spawn.pre create mode 100644 tests/phase2/builtins/builtins/task_spawn.tag create mode 100644 tests/phase2/builtins/builtins/tensor_load.branch create mode 100644 tests/phase2/builtins/builtins/tensor_load.eigs create mode 100644 tests/phase2/builtins/builtins/tensor_load.pre create mode 100644 tests/phase2/builtins/builtins/tensor_load.tag create mode 100644 tests/phase2/builtins/builtins/tensor_save.branch create mode 100644 tests/phase2/builtins/builtins/tensor_save.eigs create mode 100644 tests/phase2/builtins/builtins/tensor_save.pre create mode 100644 tests/phase2/builtins/builtins/tensor_save.tag create mode 100644 tests/phase2/builtins/builtins/text_builder_append.branch create mode 100644 tests/phase2/builtins/builtins/text_builder_append.eigs create mode 100644 tests/phase2/builtins/builtins/text_builder_append.pre create mode 100644 tests/phase2/builtins/builtins/text_builder_append.tag create mode 100644 tests/phase2/builtins/builtins/text_builder_append_line.branch create mode 100644 tests/phase2/builtins/builtins/text_builder_append_line.eigs create mode 100644 tests/phase2/builtins/builtins/text_builder_append_line.pre create mode 100644 tests/phase2/builtins/builtins/text_builder_append_line.tag create mode 100644 tests/phase2/builtins/builtins/thread_join.branch create mode 100644 tests/phase2/builtins/builtins/thread_join.eigs create mode 100644 tests/phase2/builtins/builtins/thread_join.pre create mode 100644 tests/phase2/builtins/builtins/thread_join.tag create mode 100644 tests/phase2/builtins/builtins/throw.branch create mode 100644 tests/phase2/builtins/builtins/throw.eigs create mode 100644 tests/phase2/builtins/builtins/throw.pre create mode 100644 tests/phase2/builtins/builtins/throw.tag create mode 100644 tests/phase2/builtins/builtins/token_name.branch create mode 100644 tests/phase2/builtins/builtins/token_name.eigs create mode 100644 tests/phase2/builtins/builtins/token_name.pre create mode 100644 tests/phase2/builtins/builtins/token_name.tag create mode 100644 tests/phase2/builtins/builtins/try_recv.branch create mode 100644 tests/phase2/builtins/builtins/try_recv.eigs create mode 100644 tests/phase2/builtins/builtins/try_recv.pre create mode 100644 tests/phase2/builtins/builtins/try_recv.tag create mode 100644 tests/phase2/builtins/builtins/type.branch create mode 100644 tests/phase2/builtins/builtins/type.eigs create mode 100644 tests/phase2/builtins/builtins/type.pre create mode 100644 tests/phase2/builtins/builtins/type.tag create mode 100644 tests/phase2/builtins/builtins/usleep.branch create mode 100644 tests/phase2/builtins/builtins/usleep.eigs create mode 100644 tests/phase2/builtins/builtins/usleep.pre create mode 100644 tests/phase2/builtins/builtins/usleep.tag create mode 100644 tests/phase2/builtins/builtins/vm_run_bytecode.branch create mode 100644 tests/phase2/builtins/builtins/vm_run_bytecode.eigs create mode 100644 tests/phase2/builtins/builtins/vm_run_bytecode.pre create mode 100644 tests/phase2/builtins/builtins/vm_run_bytecode.tag create mode 100644 tests/phase2/builtins/builtins/write.branch create mode 100644 tests/phase2/builtins/builtins/write.eigs create mode 100644 tests/phase2/builtins/builtins/write.pre create mode 100644 tests/phase2/builtins/builtins/write.tag create mode 100644 tests/phase2/builtins/builtins/write_bytes.branch create mode 100644 tests/phase2/builtins/builtins/write_bytes.eigs create mode 100644 tests/phase2/builtins/builtins/write_bytes.pre create mode 100644 tests/phase2/builtins/builtins/write_bytes.tag create mode 100644 tests/phase2/builtins/builtins/zeros.branch create mode 100644 tests/phase2/builtins/builtins/zeros.eigs create mode 100644 tests/phase2/builtins/builtins/zeros.pre create mode 100644 tests/phase2/builtins/builtins/zeros.tag create mode 100644 tests/phase2/builtins/builtins/zeros_like.branch create mode 100644 tests/phase2/builtins/builtins/zeros_like.eigs create mode 100644 tests/phase2/builtins/builtins/zeros_like.pre create mode 100644 tests/phase2/builtins/builtins/zeros_like.tag create mode 100644 tests/phase2/builtins/cases.tsv create mode 100644 tests/phase2/builtins/make_table.py create mode 100644 tests/phase2/builtins/oracle/abs.lua create mode 100644 tests/phase2/builtins/oracle/abs.lua.out create mode 100644 tests/phase2/builtins/oracle/acos.lua create mode 100644 tests/phase2/builtins/oracle/acos.lua.out create mode 100644 tests/phase2/builtins/oracle/asin.lua create mode 100644 tests/phase2/builtins/oracle/asin.lua.out create mode 100644 tests/phase2/builtins/oracle/atan.lua create mode 100644 tests/phase2/builtins/oracle/atan.lua.out create mode 100644 tests/phase2/builtins/oracle/atan2.lua create mode 100644 tests/phase2/builtins/oracle/atan2.lua.out create mode 100644 tests/phase2/builtins/oracle/bit_and.lua create mode 100644 tests/phase2/builtins/oracle/bit_and.lua.out create mode 100644 tests/phase2/builtins/oracle/bit_not.lua create mode 100644 tests/phase2/builtins/oracle/bit_not.lua.out create mode 100644 tests/phase2/builtins/oracle/bit_or.lua create mode 100644 tests/phase2/builtins/oracle/bit_or.lua.out create mode 100644 tests/phase2/builtins/oracle/bit_shl.lua create mode 100644 tests/phase2/builtins/oracle/bit_shl.lua.out create mode 100644 tests/phase2/builtins/oracle/bit_shr.lua create mode 100644 tests/phase2/builtins/oracle/bit_shr.lua.out create mode 100644 tests/phase2/builtins/oracle/bit_xor.lua create mode 100644 tests/phase2/builtins/oracle/bit_xor.lua.out create mode 100644 tests/phase2/builtins/oracle/ceil.lua create mode 100644 tests/phase2/builtins/oracle/ceil.lua.out create mode 100644 tests/phase2/builtins/oracle/char_at.lua create mode 100644 tests/phase2/builtins/oracle/char_at.lua.out create mode 100644 tests/phase2/builtins/oracle/chr.lua create mode 100644 tests/phase2/builtins/oracle/chr.lua.out create mode 100644 tests/phase2/builtins/oracle/cos.lua create mode 100644 tests/phase2/builtins/oracle/cos.lua.out create mode 100644 tests/phase2/builtins/oracle/divide.lua create mode 100644 tests/phase2/builtins/oracle/divide.lua.out create mode 100644 tests/phase2/builtins/oracle/exp.lua create mode 100644 tests/phase2/builtins/oracle/exp.lua.out create mode 100644 tests/phase2/builtins/oracle/floor.lua create mode 100644 tests/phase2/builtins/oracle/floor.lua.out create mode 100644 tests/phase2/builtins/oracle/len.lua create mode 100644 tests/phase2/builtins/oracle/len.lua.out create mode 100644 tests/phase2/builtins/oracle/list_insert_at.lua create mode 100644 tests/phase2/builtins/oracle/list_insert_at.lua.out create mode 100644 tests/phase2/builtins/oracle/list_remove_at.lua create mode 100644 tests/phase2/builtins/oracle/list_remove_at.lua.out create mode 100644 tests/phase2/builtins/oracle/log.lua create mode 100644 tests/phase2/builtins/oracle/log.lua.out create mode 100644 tests/phase2/builtins/oracle/max.lua create mode 100644 tests/phase2/builtins/oracle/max.lua.out create mode 100644 tests/phase2/builtins/oracle/min.lua create mode 100644 tests/phase2/builtins/oracle/min.lua.out create mode 100644 tests/phase2/builtins/oracle/num.lua create mode 100644 tests/phase2/builtins/oracle/num.lua.out create mode 100644 tests/phase2/builtins/oracle/ord.lua create mode 100644 tests/phase2/builtins/oracle/ord.lua.out create mode 100644 tests/phase2/builtins/oracle/pi.lua create mode 100644 tests/phase2/builtins/oracle/pi.lua.out create mode 100644 tests/phase2/builtins/oracle/pow.lua create mode 100644 tests/phase2/builtins/oracle/pow.lua.out create mode 100644 tests/phase2/builtins/oracle/random.lua create mode 100644 tests/phase2/builtins/oracle/random.lua.out create mode 100644 tests/phase2/builtins/oracle/random_int.lua create mode 100644 tests/phase2/builtins/oracle/random_int.lua.out create mode 100644 tests/phase2/builtins/oracle/seed_random.lua create mode 100644 tests/phase2/builtins/oracle/seed_random.lua.out create mode 100644 tests/phase2/builtins/oracle/sin.lua create mode 100644 tests/phase2/builtins/oracle/sin.lua.out create mode 100644 tests/phase2/builtins/oracle/sqrt.lua create mode 100644 tests/phase2/builtins/oracle/sqrt.lua.out create mode 100644 tests/phase2/builtins/oracle/str_from_bytes.lua create mode 100644 tests/phase2/builtins/oracle/str_from_bytes.lua.out create mode 100644 tests/phase2/builtins/oracle/substr.lua create mode 100644 tests/phase2/builtins/oracle/substr.lua.out create mode 100644 tests/phase2/builtins/oracle/tan.lua create mode 100644 tests/phase2/builtins/oracle/tan.lua.out create mode 100644 tests/phase2/builtins/plants.sh create mode 100644 tests/phase2/builtins/rowmeta.tsv create mode 100755 tests/phase2/builtins/run_probes.sh diff --git a/tests/phase2/builtins/BAR.md b/tests/phase2/builtins/BAR.md new file mode 100644 index 000000000..1eb3c08ae --- /dev/null +++ b/tests/phase2/builtins/BAR.md @@ -0,0 +1,916 @@ +# R1.6 per-builtin behaviour table: the pre-registered bar (#1758, design §9.4) + +Written before any R1.6 migration. Every `.branch` is derived from the design +(`docs/design/phase2-numbers.md` §6, §2.6, §9.4, §11 at `4ac31e67`), from the +#1758 decisions (comment 6304880619 for N10), from the orchestrator's rulings +(`RULINGS.md`) and from Lua 5.4.9. No `.branch` was copied from a binary. The +binaries only produced `.pre` (R1.5 tip `4ac31e67`, +`/home/jon/src/wt/r15-critic/build/release/eigenscript`) and `.tag` (v0.46.0 +release binary). Where a row should not change, its `.branch` equals `.pre`. +That agreement checks the derivation; it is not where the expectation came +from. Every `.branch` that changed after its first observation is listed under +"Corrections log", with its reason. + +**Fix round, 2026-10-20.** The blind critic found the first version DEFECTIVE +(witness defects F1-F8, and no wrong scalar expectation). This version applies +the orchestrator's FINAL rulings (`RULINGS.md`): A1-A5 (table structure), +B1-B6 (witnesses), and C1-C10 plus the agreed answers (semantics). Each changed +`.branch` names its ruling in the Corrections log. The hook rows' `.pre` and +`.tag` were recorded with the test shim preloaded, on the same two binaries. +The 25 non-release rows' `.pre` and `.tag` read `PENDING-PROFILE `; +R1.6a records them on matched builds. + +## Files +- `builtins.tsv`, 231 rows: `builtin file class loss q7 round closed_in + profile hook stdin changes_vs_pre changes_vs_tag`. `make_table.py` writes + it. Rows come from the §6 table, checked both ways against the inventory's + `## Builtins` list, field by field. `file` is the `src/*.c` file that + defines the inventory's C function. `round` follows the plan's rule, and the + counts are checked against b 45, c 75, d 53, e 38, f 20. The other columns: + - `closed_in` (ruling A2) and `profile` (A3) come from `rowmeta.tsv`; + - `hook` (A4) and `stdin` (A5) list the hooks and the stdin fixtures of the + row's cases, in case order. `-` means none, and stdin `-` is `/dev/null`; + - `changes_vs_pre` (A1) is `yes` when `.branch` differs from `.pre` on any + of the row's cases. It is the R1.6 migration delta, and the vacuity guard + uses it. It reads `pending-profile` while a non-release row waits for its + matched build; + - `changes_vs_tag` (A1) is the same comparison against `.tag`, §9.4's + original one. It is recorded as an observation and never checked, because + every probe calls `num_type` and the tag has no `num_type`. +- `rowmeta.tsv`: `builtin closed_in profile`, one line per table row. +- `cases.tsv`: `case builtin hook stdin`, 233 cases. A row's primary case is + `builtins/`. A second case is `builtins/.

CI Release diff --git a/changes/added/1758-n9-width-arithmetic.md b/changes/added/1758-n9-width-arithmetic.md new file mode 100644 index 000000000..437d46488 --- /dev/null +++ b/changes/added/1758-n9-width-arithmetic.md @@ -0,0 +1 @@ +- Add explicit wrapping, checked and saturating add/sub/mul for signed and unsigned 8/16/32/64-bit widths, unsigned u64 comparison/division/remainder/decimal formatting, and float32 rounding with `fround` (#1758 N9). Operands use N5 exact conversion and type range checks; width results are ints. diff --git a/docs/BUILTINS.md b/docs/BUILTINS.md index f7c5ed0ce..ad4733c0b 100644 --- a/docs/BUILTINS.md +++ b/docs/BUILTINS.md @@ -167,6 +167,102 @@ builtin-call forms below are retained for backward compatibility. | `bit_shr` | `bit_shr of [a, b]` | Unsigned right shift (prefer `a >> b`) | | `sign_extend` | `sign_extend of [val, bits]` | Exact int64 result from the existing 1..32-bit sign-extension operation; value and width follow N5 (integral floats convert, fractions raise). Its subtraction is checked: int64 underflow raises `value`, naming `sign_extend` (R1.6b-D1). Bits above the width retain the existing behavior (#1896 is separate). | +### Width arithmetic (N9) + +Binary width operations take exactly `[a, b]`. Integral floats convert by N5; +fractions, floats outside int64 and operands outside the named type raise +`value`. Wrong shapes and non-number operands raise `type_mismatch` in both +strict modes. There is no operand masking. `i64` and `u64` accept every int64; +a `u64` uses its int64 bit pattern (`-1` is unsigned max). Wrapping reduces +modulo the width; checked overflow raises `value` naming the builtin; +saturating clamps to the type range. Width results are ints. Unsigned division +and remainder by zero raise `value` with `division by zero`. + +`u64_to_string` and `fround` are unary and accept the usual one-element list +form. `fround` converts an int to double first, then through float32 and back +to double. Until R2.2, float32 overflow follows the current float-result guard +(clamp at ±1e308 and set `math_flags.overflow`). Rust std is the numeric oracle. + +| Function | Usage | Description | +|---|---|---| +| `i8_wrapping_add` | `i8_wrapping_add of [a, b]` | N9: i8 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `i8_wrapping_sub` | `i8_wrapping_sub of [a, b]` | N9: i8 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `i8_wrapping_mul` | `i8_wrapping_mul of [a, b]` | N9: i8 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `i8_checked_add` | `i8_checked_add of [a, b]` | N9: i8 checked add; N5 then type range without masking; exact int result (Rust std). | +| `i8_checked_sub` | `i8_checked_sub of [a, b]` | N9: i8 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `i8_checked_mul` | `i8_checked_mul of [a, b]` | N9: i8 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `i8_saturating_add` | `i8_saturating_add of [a, b]` | N9: i8 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `i8_saturating_sub` | `i8_saturating_sub of [a, b]` | N9: i8 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `i8_saturating_mul` | `i8_saturating_mul of [a, b]` | N9: i8 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `i16_wrapping_add` | `i16_wrapping_add of [a, b]` | N9: i16 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `i16_wrapping_sub` | `i16_wrapping_sub of [a, b]` | N9: i16 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `i16_wrapping_mul` | `i16_wrapping_mul of [a, b]` | N9: i16 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `i16_checked_add` | `i16_checked_add of [a, b]` | N9: i16 checked add; N5 then type range without masking; exact int result (Rust std). | +| `i16_checked_sub` | `i16_checked_sub of [a, b]` | N9: i16 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `i16_checked_mul` | `i16_checked_mul of [a, b]` | N9: i16 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `i16_saturating_add` | `i16_saturating_add of [a, b]` | N9: i16 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `i16_saturating_sub` | `i16_saturating_sub of [a, b]` | N9: i16 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `i16_saturating_mul` | `i16_saturating_mul of [a, b]` | N9: i16 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `i32_wrapping_add` | `i32_wrapping_add of [a, b]` | N9: i32 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `i32_wrapping_sub` | `i32_wrapping_sub of [a, b]` | N9: i32 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `i32_wrapping_mul` | `i32_wrapping_mul of [a, b]` | N9: i32 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `i32_checked_add` | `i32_checked_add of [a, b]` | N9: i32 checked add; N5 then type range without masking; exact int result (Rust std). | +| `i32_checked_sub` | `i32_checked_sub of [a, b]` | N9: i32 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `i32_checked_mul` | `i32_checked_mul of [a, b]` | N9: i32 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `i32_saturating_add` | `i32_saturating_add of [a, b]` | N9: i32 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `i32_saturating_sub` | `i32_saturating_sub of [a, b]` | N9: i32 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `i32_saturating_mul` | `i32_saturating_mul of [a, b]` | N9: i32 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `i64_wrapping_add` | `i64_wrapping_add of [a, b]` | N9: i64 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `i64_wrapping_sub` | `i64_wrapping_sub of [a, b]` | N9: i64 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `i64_wrapping_mul` | `i64_wrapping_mul of [a, b]` | N9: i64 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `i64_checked_add` | `i64_checked_add of [a, b]` | N9: i64 checked add; N5 then type range without masking; exact int result (Rust std). | +| `i64_checked_sub` | `i64_checked_sub of [a, b]` | N9: i64 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `i64_checked_mul` | `i64_checked_mul of [a, b]` | N9: i64 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `i64_saturating_add` | `i64_saturating_add of [a, b]` | N9: i64 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `i64_saturating_sub` | `i64_saturating_sub of [a, b]` | N9: i64 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `i64_saturating_mul` | `i64_saturating_mul of [a, b]` | N9: i64 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `u8_wrapping_add` | `u8_wrapping_add of [a, b]` | N9: u8 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `u8_wrapping_sub` | `u8_wrapping_sub of [a, b]` | N9: u8 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `u8_wrapping_mul` | `u8_wrapping_mul of [a, b]` | N9: u8 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `u8_checked_add` | `u8_checked_add of [a, b]` | N9: u8 checked add; N5 then type range without masking; exact int result (Rust std). | +| `u8_checked_sub` | `u8_checked_sub of [a, b]` | N9: u8 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `u8_checked_mul` | `u8_checked_mul of [a, b]` | N9: u8 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `u8_saturating_add` | `u8_saturating_add of [a, b]` | N9: u8 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `u8_saturating_sub` | `u8_saturating_sub of [a, b]` | N9: u8 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `u8_saturating_mul` | `u8_saturating_mul of [a, b]` | N9: u8 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `u16_wrapping_add` | `u16_wrapping_add of [a, b]` | N9: u16 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `u16_wrapping_sub` | `u16_wrapping_sub of [a, b]` | N9: u16 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `u16_wrapping_mul` | `u16_wrapping_mul of [a, b]` | N9: u16 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `u16_checked_add` | `u16_checked_add of [a, b]` | N9: u16 checked add; N5 then type range without masking; exact int result (Rust std). | +| `u16_checked_sub` | `u16_checked_sub of [a, b]` | N9: u16 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `u16_checked_mul` | `u16_checked_mul of [a, b]` | N9: u16 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `u16_saturating_add` | `u16_saturating_add of [a, b]` | N9: u16 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `u16_saturating_sub` | `u16_saturating_sub of [a, b]` | N9: u16 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `u16_saturating_mul` | `u16_saturating_mul of [a, b]` | N9: u16 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `u32_wrapping_add` | `u32_wrapping_add of [a, b]` | N9: u32 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `u32_wrapping_sub` | `u32_wrapping_sub of [a, b]` | N9: u32 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `u32_wrapping_mul` | `u32_wrapping_mul of [a, b]` | N9: u32 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `u32_checked_add` | `u32_checked_add of [a, b]` | N9: u32 checked add; N5 then type range without masking; exact int result (Rust std). | +| `u32_checked_sub` | `u32_checked_sub of [a, b]` | N9: u32 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `u32_checked_mul` | `u32_checked_mul of [a, b]` | N9: u32 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `u32_saturating_add` | `u32_saturating_add of [a, b]` | N9: u32 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `u32_saturating_sub` | `u32_saturating_sub of [a, b]` | N9: u32 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `u32_saturating_mul` | `u32_saturating_mul of [a, b]` | N9: u32 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `u64_wrapping_add` | `u64_wrapping_add of [a, b]` | N9: u64 wrapping add; N5 then type range without masking; exact int result (Rust std). | +| `u64_wrapping_sub` | `u64_wrapping_sub of [a, b]` | N9: u64 wrapping sub; N5 then type range without masking; exact int result (Rust std). | +| `u64_wrapping_mul` | `u64_wrapping_mul of [a, b]` | N9: u64 wrapping mul; N5 then type range without masking; exact int result (Rust std). | +| `u64_checked_add` | `u64_checked_add of [a, b]` | N9: u64 checked add; N5 then type range without masking; exact int result (Rust std). | +| `u64_checked_sub` | `u64_checked_sub of [a, b]` | N9: u64 checked sub; N5 then type range without masking; exact int result (Rust std). | +| `u64_checked_mul` | `u64_checked_mul of [a, b]` | N9: u64 checked mul; N5 then type range without masking; exact int result (Rust std). | +| `u64_saturating_add` | `u64_saturating_add of [a, b]` | N9: u64 saturating add; N5 then type range without masking; exact int result (Rust std). | +| `u64_saturating_sub` | `u64_saturating_sub of [a, b]` | N9: u64 saturating sub; N5 then type range without masking; exact int result (Rust std). | +| `u64_saturating_mul` | `u64_saturating_mul of [a, b]` | N9: u64 saturating mul; N5 then type range without masking; exact int result (Rust std). | +| `u64_compare` | `u64_compare of [a, b]` | N9: N5 int64 bit patterns; unsigned order gives int -1, 0 or 1 (Rust std). | +| `u64_div` | `u64_div of [a, b]` | N9: N5 int64 bit patterns; unsigned quotient as int64 bits; zero raises value (Rust std). | +| `u64_rem` | `u64_rem of [a, b]` | N9: N5 int64 bit patterns; unsigned remainder as int64 bits; zero raises value (Rust std). | +| `u64_to_string` | `u64_to_string of x` | N9: N5 int64 bit pattern to unsigned decimal string (Rust std). | +| `fround` | `fround of x` | N9: int converts to f64 first; f64 to f32 to f64, float result; current result guard until R2.2. | + ### Buffers Compact typed arrays of doubles with O(1) indexed access. Iterable with diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index 181d70fe4..80b0c60f8 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -1,5 +1,21 @@ # EigenScript compared to Python, JavaScript, Rust, and Lisp + +Width arithmetic uses explicit wrapping, checked and saturating builtins. +N5 converts integral floats, then checks the named type range without masking. +Width results are ints; checked overflow raises `value`. `u64` uses int64 bit +patterns. `fround` returns a float after double-to-float32-to-double conversion +(ints convert to double first). See [the width builtins](BUILTINS.md#width-arithmetic-n9). + +```eigenscript +print of [i64_wrapping_add of [9223372036854775807, 1], u8_wrapping_add of [255, 1]] +print of (fround of 0.1) +``` +```output +[-9223372036854775808, 0] +0.10000000149011612 +``` + A translation guide: each section shows the same program in a language you already know, then in EigenScript. Every EigenScript block followed by an `output` block is executed by the test suite diff --git a/docs/SPEC.md b/docs/SPEC.md index 75f196d02..102c28fa1 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -1,5 +1,21 @@ # EigenScript Language Specification + +Width arithmetic uses explicit wrapping, checked and saturating builtins. +N5 converts integral floats, then checks the named type range without masking. +Width results are ints; checked overflow raises `value`. `u64` uses int64 bit +patterns. `fround` returns a float after double-to-float32-to-double conversion +(ints convert to double first). See [the width builtins](BUILTINS.md#width-arithmetic-n9). + +```eigenscript +print of [i64_wrapping_add of [9223372036854775807, 1], u8_wrapping_add of [255, 1]] +print of (fround of 0.1) +``` +```output +[-9223372036854775808, 0] +0.10000000149011612 +``` + This is the canonical, executable specification of EigenScript. **Every** `eigenscript` code block here is EXECUTED by the test suite (`tests/test_doc_examples.py`, suite section [89]) — the gate is opt-OUT. diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 9ad6bd955..5721d4075 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -1619,12 +1619,92 @@ current state behind several rows: | `write_bytes` | int-requiring | - | - | byte values: N5, then 0..255 (Q1; the modulo-256 wrap is gone); returns bytes written | | `zeros` | int-requiring | - | - | size or [rows, cols]; elements are float 0.0 | | `zeros_like` | float-producing | - | - | float zeros | +| `i8_wrapping_add` | int-requiring | - | - | N9: i8 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `i8_wrapping_sub` | int-requiring | - | - | N9: i8 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `i8_wrapping_mul` | int-requiring | - | - | N9: i8 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `i8_checked_add` | int-requiring | - | - | N9: i8 checked add; N5 then type range without masking; exact int result (Rust std) | +| `i8_checked_sub` | int-requiring | - | - | N9: i8 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `i8_checked_mul` | int-requiring | - | - | N9: i8 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `i8_saturating_add` | int-requiring | - | - | N9: i8 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `i8_saturating_sub` | int-requiring | - | - | N9: i8 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `i8_saturating_mul` | int-requiring | - | - | N9: i8 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `i16_wrapping_add` | int-requiring | - | - | N9: i16 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `i16_wrapping_sub` | int-requiring | - | - | N9: i16 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `i16_wrapping_mul` | int-requiring | - | - | N9: i16 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `i16_checked_add` | int-requiring | - | - | N9: i16 checked add; N5 then type range without masking; exact int result (Rust std) | +| `i16_checked_sub` | int-requiring | - | - | N9: i16 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `i16_checked_mul` | int-requiring | - | - | N9: i16 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `i16_saturating_add` | int-requiring | - | - | N9: i16 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `i16_saturating_sub` | int-requiring | - | - | N9: i16 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `i16_saturating_mul` | int-requiring | - | - | N9: i16 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `i32_wrapping_add` | int-requiring | - | - | N9: i32 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `i32_wrapping_sub` | int-requiring | - | - | N9: i32 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `i32_wrapping_mul` | int-requiring | - | - | N9: i32 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `i32_checked_add` | int-requiring | - | - | N9: i32 checked add; N5 then type range without masking; exact int result (Rust std) | +| `i32_checked_sub` | int-requiring | - | - | N9: i32 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `i32_checked_mul` | int-requiring | - | - | N9: i32 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `i32_saturating_add` | int-requiring | - | - | N9: i32 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `i32_saturating_sub` | int-requiring | - | - | N9: i32 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `i32_saturating_mul` | int-requiring | - | - | N9: i32 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `i64_wrapping_add` | int-requiring | - | - | N9: i64 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `i64_wrapping_sub` | int-requiring | - | - | N9: i64 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `i64_wrapping_mul` | int-requiring | - | - | N9: i64 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `i64_checked_add` | int-requiring | - | - | N9: i64 checked add; N5 then type range without masking; exact int result (Rust std) | +| `i64_checked_sub` | int-requiring | - | - | N9: i64 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `i64_checked_mul` | int-requiring | - | - | N9: i64 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `i64_saturating_add` | int-requiring | - | - | N9: i64 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `i64_saturating_sub` | int-requiring | - | - | N9: i64 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `i64_saturating_mul` | int-requiring | - | - | N9: i64 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `u8_wrapping_add` | int-requiring | - | - | N9: u8 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `u8_wrapping_sub` | int-requiring | - | - | N9: u8 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `u8_wrapping_mul` | int-requiring | - | - | N9: u8 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `u8_checked_add` | int-requiring | - | - | N9: u8 checked add; N5 then type range without masking; exact int result (Rust std) | +| `u8_checked_sub` | int-requiring | - | - | N9: u8 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `u8_checked_mul` | int-requiring | - | - | N9: u8 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `u8_saturating_add` | int-requiring | - | - | N9: u8 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `u8_saturating_sub` | int-requiring | - | - | N9: u8 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `u8_saturating_mul` | int-requiring | - | - | N9: u8 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `u16_wrapping_add` | int-requiring | - | - | N9: u16 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `u16_wrapping_sub` | int-requiring | - | - | N9: u16 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `u16_wrapping_mul` | int-requiring | - | - | N9: u16 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `u16_checked_add` | int-requiring | - | - | N9: u16 checked add; N5 then type range without masking; exact int result (Rust std) | +| `u16_checked_sub` | int-requiring | - | - | N9: u16 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `u16_checked_mul` | int-requiring | - | - | N9: u16 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `u16_saturating_add` | int-requiring | - | - | N9: u16 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `u16_saturating_sub` | int-requiring | - | - | N9: u16 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `u16_saturating_mul` | int-requiring | - | - | N9: u16 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `u32_wrapping_add` | int-requiring | - | - | N9: u32 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `u32_wrapping_sub` | int-requiring | - | - | N9: u32 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `u32_wrapping_mul` | int-requiring | - | - | N9: u32 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `u32_checked_add` | int-requiring | - | - | N9: u32 checked add; N5 then type range without masking; exact int result (Rust std) | +| `u32_checked_sub` | int-requiring | - | - | N9: u32 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `u32_checked_mul` | int-requiring | - | - | N9: u32 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `u32_saturating_add` | int-requiring | - | - | N9: u32 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `u32_saturating_sub` | int-requiring | - | - | N9: u32 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `u32_saturating_mul` | int-requiring | - | - | N9: u32 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `u64_wrapping_add` | int-requiring | - | - | N9: u64 wrapping add; N5 then type range without masking; exact int result (Rust std) | +| `u64_wrapping_sub` | int-requiring | - | - | N9: u64 wrapping sub; N5 then type range without masking; exact int result (Rust std) | +| `u64_wrapping_mul` | int-requiring | - | - | N9: u64 wrapping mul; N5 then type range without masking; exact int result (Rust std) | +| `u64_checked_add` | int-requiring | - | - | N9: u64 checked add; N5 then type range without masking; exact int result (Rust std) | +| `u64_checked_sub` | int-requiring | - | - | N9: u64 checked sub; N5 then type range without masking; exact int result (Rust std) | +| `u64_checked_mul` | int-requiring | - | - | N9: u64 checked mul; N5 then type range without masking; exact int result (Rust std) | +| `u64_saturating_add` | int-requiring | - | - | N9: u64 saturating add; N5 then type range without masking; exact int result (Rust std) | +| `u64_saturating_sub` | int-requiring | - | - | N9: u64 saturating sub; N5 then type range without masking; exact int result (Rust std) | +| `u64_saturating_mul` | int-requiring | - | - | N9: u64 saturating mul; N5 then type range without masking; exact int result (Rust std) | +| `u64_compare` | int-requiring | - | - | N9: N5 int64 bit patterns; unsigned order gives int -1, 0 or 1 (Rust std) | +| `u64_div` | int-requiring | - | - | N9: N5 int64 bit patterns; unsigned quotient as int64 bits; zero raises value (Rust std) | +| `u64_rem` | int-requiring | - | - | N9: N5 int64 bit patterns; unsigned remainder as int64 bits; zero raises value (Rust std) | +| `u64_to_string` | int-requiring | - | - | N9: N5 int64 bit pattern to unsigned decimal string (Rust std) | +| `fround` | float-producing | - | - | N9: int converts to f64 first; f64 to f32 to f64, float result; current result guard until R2.2 | **Builtins to add**, outside the checked table until they exist: - `num_type` (N7); - `f64_bits` and `f64_from_bits`, plus buffer bits get/set (N12); -- N9's decided width family ([#1758 comment 6304880619](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6304880619)): + +**N9 width family (R1.6g, in the checked table above):** + +The decided width family ([#1758 comment 6304880619](https://github.com/InauguralSystems/EigenScript/issues/1758#issuecomment-6304880619)): `__`, with types `i8 i16 i32 i64 u8 u16 u32 u64`, modes `wrapping checked saturating`, and ops `add sub mul` (72 builtins, one table-driven implementation in `builtins_int.c`). Examples: diff --git a/docs/llms.txt b/docs/llms.txt index 6723bae7e..36484c71b 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -1,5 +1,21 @@ # EigenScript — single-file reference for language models + +Width arithmetic uses explicit wrapping, checked and saturating builtins. +N5 converts integral floats, then checks the named type range without masking. +Width results are ints; checked overflow raises `value`. `u64` uses int64 bit +patterns. `fround` returns a float after double-to-float32-to-double conversion +(ints convert to double first). See [the width builtins](BUILTINS.md#width-arithmetic-n9). + +```eigenscript +print of [i64_wrapping_add of [9223372036854775807, 1], u8_wrapping_add of [255, 1]] +print of (fround of 0.1) +``` +```output +[-9223372036854775808, 0] +0.10000000149011612 +``` + > EigenScript is a small dynamically-typed language with one distinctive > feature: an **observer** tracks every value's entropy/trend on each > assignment, so convergence, stability, and oscillation are first-class. This diff --git a/src/builtins.c b/src/builtins.c index ffe4af4b3..041921cd2 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -3303,6 +3303,84 @@ static const char *SANDBOX_ALLOW[] = { "zeros_like", "fill", "leaky_relu", "relu", "softmax", "log_softmax", "sgd_update", "sgd_update_cols", "sgd_update_rows", "numerical_grad", "numerical_grad_cols", "numerical_grad_rows", + /* N9 pure width arithmetic */ + "i8_wrapping_add", + "i8_wrapping_sub", + "i8_wrapping_mul", + "i8_checked_add", + "i8_checked_sub", + "i8_checked_mul", + "i8_saturating_add", + "i8_saturating_sub", + "i8_saturating_mul", + "i16_wrapping_add", + "i16_wrapping_sub", + "i16_wrapping_mul", + "i16_checked_add", + "i16_checked_sub", + "i16_checked_mul", + "i16_saturating_add", + "i16_saturating_sub", + "i16_saturating_mul", + "i32_wrapping_add", + "i32_wrapping_sub", + "i32_wrapping_mul", + "i32_checked_add", + "i32_checked_sub", + "i32_checked_mul", + "i32_saturating_add", + "i32_saturating_sub", + "i32_saturating_mul", + "i64_wrapping_add", + "i64_wrapping_sub", + "i64_wrapping_mul", + "i64_checked_add", + "i64_checked_sub", + "i64_checked_mul", + "i64_saturating_add", + "i64_saturating_sub", + "i64_saturating_mul", + "u8_wrapping_add", + "u8_wrapping_sub", + "u8_wrapping_mul", + "u8_checked_add", + "u8_checked_sub", + "u8_checked_mul", + "u8_saturating_add", + "u8_saturating_sub", + "u8_saturating_mul", + "u16_wrapping_add", + "u16_wrapping_sub", + "u16_wrapping_mul", + "u16_checked_add", + "u16_checked_sub", + "u16_checked_mul", + "u16_saturating_add", + "u16_saturating_sub", + "u16_saturating_mul", + "u32_wrapping_add", + "u32_wrapping_sub", + "u32_wrapping_mul", + "u32_checked_add", + "u32_checked_sub", + "u32_checked_mul", + "u32_saturating_add", + "u32_saturating_sub", + "u32_saturating_mul", + "u64_wrapping_add", + "u64_wrapping_sub", + "u64_wrapping_mul", + "u64_checked_add", + "u64_checked_sub", + "u64_checked_mul", + "u64_saturating_add", + "u64_saturating_sub", + "u64_saturating_mul", + "u64_compare", + "u64_div", + "u64_rem", + "u64_to_string", + "fround", /* bit ops */ "bit_and", "bit_not", "bit_or", "bit_shl", "bit_shr", "bit_xor", /* list / sequence (operate on the value handed in) */ @@ -6351,6 +6429,85 @@ int eigs_bool_gate_slow(BuiltinFn fn, const Value *arg) { void register_builtins(Env *env) { /* ---- Core language builtins (always available) ---- */ + /* #1758 N9: width operations and unsigned bit-pattern utilities. */ + env_set_local_owned(env, "i8_wrapping_add", make_builtin(builtin_i8_wrapping_add)); + env_set_local_owned(env, "i8_wrapping_sub", make_builtin(builtin_i8_wrapping_sub)); + env_set_local_owned(env, "i8_wrapping_mul", make_builtin(builtin_i8_wrapping_mul)); + env_set_local_owned(env, "i8_checked_add", make_builtin(builtin_i8_checked_add)); + env_set_local_owned(env, "i8_checked_sub", make_builtin(builtin_i8_checked_sub)); + env_set_local_owned(env, "i8_checked_mul", make_builtin(builtin_i8_checked_mul)); + env_set_local_owned(env, "i8_saturating_add", make_builtin(builtin_i8_saturating_add)); + env_set_local_owned(env, "i8_saturating_sub", make_builtin(builtin_i8_saturating_sub)); + env_set_local_owned(env, "i8_saturating_mul", make_builtin(builtin_i8_saturating_mul)); + env_set_local_owned(env, "i16_wrapping_add", make_builtin(builtin_i16_wrapping_add)); + env_set_local_owned(env, "i16_wrapping_sub", make_builtin(builtin_i16_wrapping_sub)); + env_set_local_owned(env, "i16_wrapping_mul", make_builtin(builtin_i16_wrapping_mul)); + env_set_local_owned(env, "i16_checked_add", make_builtin(builtin_i16_checked_add)); + env_set_local_owned(env, "i16_checked_sub", make_builtin(builtin_i16_checked_sub)); + env_set_local_owned(env, "i16_checked_mul", make_builtin(builtin_i16_checked_mul)); + env_set_local_owned(env, "i16_saturating_add", make_builtin(builtin_i16_saturating_add)); + env_set_local_owned(env, "i16_saturating_sub", make_builtin(builtin_i16_saturating_sub)); + env_set_local_owned(env, "i16_saturating_mul", make_builtin(builtin_i16_saturating_mul)); + env_set_local_owned(env, "i32_wrapping_add", make_builtin(builtin_i32_wrapping_add)); + env_set_local_owned(env, "i32_wrapping_sub", make_builtin(builtin_i32_wrapping_sub)); + env_set_local_owned(env, "i32_wrapping_mul", make_builtin(builtin_i32_wrapping_mul)); + env_set_local_owned(env, "i32_checked_add", make_builtin(builtin_i32_checked_add)); + env_set_local_owned(env, "i32_checked_sub", make_builtin(builtin_i32_checked_sub)); + env_set_local_owned(env, "i32_checked_mul", make_builtin(builtin_i32_checked_mul)); + env_set_local_owned(env, "i32_saturating_add", make_builtin(builtin_i32_saturating_add)); + env_set_local_owned(env, "i32_saturating_sub", make_builtin(builtin_i32_saturating_sub)); + env_set_local_owned(env, "i32_saturating_mul", make_builtin(builtin_i32_saturating_mul)); + env_set_local_owned(env, "i64_wrapping_add", make_builtin(builtin_i64_wrapping_add)); + env_set_local_owned(env, "i64_wrapping_sub", make_builtin(builtin_i64_wrapping_sub)); + env_set_local_owned(env, "i64_wrapping_mul", make_builtin(builtin_i64_wrapping_mul)); + env_set_local_owned(env, "i64_checked_add", make_builtin(builtin_i64_checked_add)); + env_set_local_owned(env, "i64_checked_sub", make_builtin(builtin_i64_checked_sub)); + env_set_local_owned(env, "i64_checked_mul", make_builtin(builtin_i64_checked_mul)); + env_set_local_owned(env, "i64_saturating_add", make_builtin(builtin_i64_saturating_add)); + env_set_local_owned(env, "i64_saturating_sub", make_builtin(builtin_i64_saturating_sub)); + env_set_local_owned(env, "i64_saturating_mul", make_builtin(builtin_i64_saturating_mul)); + env_set_local_owned(env, "u8_wrapping_add", make_builtin(builtin_u8_wrapping_add)); + env_set_local_owned(env, "u8_wrapping_sub", make_builtin(builtin_u8_wrapping_sub)); + env_set_local_owned(env, "u8_wrapping_mul", make_builtin(builtin_u8_wrapping_mul)); + env_set_local_owned(env, "u8_checked_add", make_builtin(builtin_u8_checked_add)); + env_set_local_owned(env, "u8_checked_sub", make_builtin(builtin_u8_checked_sub)); + env_set_local_owned(env, "u8_checked_mul", make_builtin(builtin_u8_checked_mul)); + env_set_local_owned(env, "u8_saturating_add", make_builtin(builtin_u8_saturating_add)); + env_set_local_owned(env, "u8_saturating_sub", make_builtin(builtin_u8_saturating_sub)); + env_set_local_owned(env, "u8_saturating_mul", make_builtin(builtin_u8_saturating_mul)); + env_set_local_owned(env, "u16_wrapping_add", make_builtin(builtin_u16_wrapping_add)); + env_set_local_owned(env, "u16_wrapping_sub", make_builtin(builtin_u16_wrapping_sub)); + env_set_local_owned(env, "u16_wrapping_mul", make_builtin(builtin_u16_wrapping_mul)); + env_set_local_owned(env, "u16_checked_add", make_builtin(builtin_u16_checked_add)); + env_set_local_owned(env, "u16_checked_sub", make_builtin(builtin_u16_checked_sub)); + env_set_local_owned(env, "u16_checked_mul", make_builtin(builtin_u16_checked_mul)); + env_set_local_owned(env, "u16_saturating_add", make_builtin(builtin_u16_saturating_add)); + env_set_local_owned(env, "u16_saturating_sub", make_builtin(builtin_u16_saturating_sub)); + env_set_local_owned(env, "u16_saturating_mul", make_builtin(builtin_u16_saturating_mul)); + env_set_local_owned(env, "u32_wrapping_add", make_builtin(builtin_u32_wrapping_add)); + env_set_local_owned(env, "u32_wrapping_sub", make_builtin(builtin_u32_wrapping_sub)); + env_set_local_owned(env, "u32_wrapping_mul", make_builtin(builtin_u32_wrapping_mul)); + env_set_local_owned(env, "u32_checked_add", make_builtin(builtin_u32_checked_add)); + env_set_local_owned(env, "u32_checked_sub", make_builtin(builtin_u32_checked_sub)); + env_set_local_owned(env, "u32_checked_mul", make_builtin(builtin_u32_checked_mul)); + env_set_local_owned(env, "u32_saturating_add", make_builtin(builtin_u32_saturating_add)); + env_set_local_owned(env, "u32_saturating_sub", make_builtin(builtin_u32_saturating_sub)); + env_set_local_owned(env, "u32_saturating_mul", make_builtin(builtin_u32_saturating_mul)); + env_set_local_owned(env, "u64_wrapping_add", make_builtin(builtin_u64_wrapping_add)); + env_set_local_owned(env, "u64_wrapping_sub", make_builtin(builtin_u64_wrapping_sub)); + env_set_local_owned(env, "u64_wrapping_mul", make_builtin(builtin_u64_wrapping_mul)); + env_set_local_owned(env, "u64_checked_add", make_builtin(builtin_u64_checked_add)); + env_set_local_owned(env, "u64_checked_sub", make_builtin(builtin_u64_checked_sub)); + env_set_local_owned(env, "u64_checked_mul", make_builtin(builtin_u64_checked_mul)); + env_set_local_owned(env, "u64_saturating_add", make_builtin(builtin_u64_saturating_add)); + env_set_local_owned(env, "u64_saturating_sub", make_builtin(builtin_u64_saturating_sub)); + env_set_local_owned(env, "u64_saturating_mul", make_builtin(builtin_u64_saturating_mul)); + env_set_local_owned(env, "u64_compare", make_builtin(builtin_u64_compare)); + env_set_local_owned(env, "u64_div", make_builtin(builtin_u64_div)); + env_set_local_owned(env, "u64_rem", make_builtin(builtin_u64_rem)); + env_set_local_owned(env, "u64_to_string", make_builtin(builtin_u64_to_string)); + env_set_local_owned(env, "fround", make_builtin(builtin_fround)); + env_set_local_owned(env, "print", make_builtin(builtin_print)); env_set_local_owned(env, "write", make_builtin(builtin_write)); env_set_local_owned(env, "flush", make_builtin(builtin_flush)); diff --git a/src/builtins_int.c b/src/builtins_int.c new file mode 100644 index 000000000..6c301064f --- /dev/null +++ b/src/builtins_int.c @@ -0,0 +1,577 @@ +/* #1758 N9: all width operations share this descriptor table and engine. + * N5/range validation precedes arithmetic; unsigned intermediates avoid UB. */ +#include "eigenscript.h" +#include "container.h" +#include "builtins_internal.h" +#include +#include +#include + +typedef enum { N9_WRAP, N9_CHECK, N9_SAT } N9Mode; +typedef enum { N9_ADD, N9_SUB, N9_MUL } N9Op; +typedef struct { + const char *name; + unsigned width; + int is_signed; + N9Mode mode; + N9Op op; + int64_t lo, hi; +} N9Spec; +static const N9Spec n9_specs[] = { + {"i8_wrapping_add", 8, 1, N9_WRAP, N9_ADD, (-INT64_C(128)), INT64_C(127)}, + {"i8_wrapping_sub", 8, 1, N9_WRAP, N9_SUB, (-INT64_C(128)), INT64_C(127)}, + {"i8_wrapping_mul", 8, 1, N9_WRAP, N9_MUL, (-INT64_C(128)), INT64_C(127)}, + {"i8_checked_add", 8, 1, N9_CHECK, N9_ADD, (-INT64_C(128)), INT64_C(127)}, + {"i8_checked_sub", 8, 1, N9_CHECK, N9_SUB, (-INT64_C(128)), INT64_C(127)}, + {"i8_checked_mul", 8, 1, N9_CHECK, N9_MUL, (-INT64_C(128)), INT64_C(127)}, + {"i8_saturating_add", 8, 1, N9_SAT, N9_ADD, (-INT64_C(128)), INT64_C(127)}, + {"i8_saturating_sub", 8, 1, N9_SAT, N9_SUB, (-INT64_C(128)), INT64_C(127)}, + {"i8_saturating_mul", 8, 1, N9_SAT, N9_MUL, (-INT64_C(128)), INT64_C(127)}, + {"i16_wrapping_add", 16, 1, N9_WRAP, N9_ADD, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_wrapping_sub", 16, 1, N9_WRAP, N9_SUB, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_wrapping_mul", 16, 1, N9_WRAP, N9_MUL, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_checked_add", 16, 1, N9_CHECK, N9_ADD, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_checked_sub", 16, 1, N9_CHECK, N9_SUB, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_checked_mul", 16, 1, N9_CHECK, N9_MUL, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_saturating_add", 16, 1, N9_SAT, N9_ADD, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_saturating_sub", 16, 1, N9_SAT, N9_SUB, (-INT64_C(32768)), INT64_C(32767)}, + {"i16_saturating_mul", 16, 1, N9_SAT, N9_MUL, (-INT64_C(32768)), INT64_C(32767)}, + {"i32_wrapping_add", 32, 1, N9_WRAP, N9_ADD, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_wrapping_sub", 32, 1, N9_WRAP, N9_SUB, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_wrapping_mul", 32, 1, N9_WRAP, N9_MUL, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_checked_add", 32, 1, N9_CHECK, N9_ADD, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_checked_sub", 32, 1, N9_CHECK, N9_SUB, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_checked_mul", 32, 1, N9_CHECK, N9_MUL, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_saturating_add", 32, 1, N9_SAT, N9_ADD, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_saturating_sub", 32, 1, N9_SAT, N9_SUB, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i32_saturating_mul", 32, 1, N9_SAT, N9_MUL, (-INT64_C(2147483648)), INT64_C(2147483647)}, + {"i64_wrapping_add", 64, 1, N9_WRAP, N9_ADD, INT64_MIN, INT64_MAX}, + {"i64_wrapping_sub", 64, 1, N9_WRAP, N9_SUB, INT64_MIN, INT64_MAX}, + {"i64_wrapping_mul", 64, 1, N9_WRAP, N9_MUL, INT64_MIN, INT64_MAX}, + {"i64_checked_add", 64, 1, N9_CHECK, N9_ADD, INT64_MIN, INT64_MAX}, + {"i64_checked_sub", 64, 1, N9_CHECK, N9_SUB, INT64_MIN, INT64_MAX}, + {"i64_checked_mul", 64, 1, N9_CHECK, N9_MUL, INT64_MIN, INT64_MAX}, + {"i64_saturating_add", 64, 1, N9_SAT, N9_ADD, INT64_MIN, INT64_MAX}, + {"i64_saturating_sub", 64, 1, N9_SAT, N9_SUB, INT64_MIN, INT64_MAX}, + {"i64_saturating_mul", 64, 1, N9_SAT, N9_MUL, INT64_MIN, INT64_MAX}, + {"u8_wrapping_add", 8, 0, N9_WRAP, N9_ADD, INT64_C(0), INT64_C(255)}, + {"u8_wrapping_sub", 8, 0, N9_WRAP, N9_SUB, INT64_C(0), INT64_C(255)}, + {"u8_wrapping_mul", 8, 0, N9_WRAP, N9_MUL, INT64_C(0), INT64_C(255)}, + {"u8_checked_add", 8, 0, N9_CHECK, N9_ADD, INT64_C(0), INT64_C(255)}, + {"u8_checked_sub", 8, 0, N9_CHECK, N9_SUB, INT64_C(0), INT64_C(255)}, + {"u8_checked_mul", 8, 0, N9_CHECK, N9_MUL, INT64_C(0), INT64_C(255)}, + {"u8_saturating_add", 8, 0, N9_SAT, N9_ADD, INT64_C(0), INT64_C(255)}, + {"u8_saturating_sub", 8, 0, N9_SAT, N9_SUB, INT64_C(0), INT64_C(255)}, + {"u8_saturating_mul", 8, 0, N9_SAT, N9_MUL, INT64_C(0), INT64_C(255)}, + {"u16_wrapping_add", 16, 0, N9_WRAP, N9_ADD, INT64_C(0), INT64_C(65535)}, + {"u16_wrapping_sub", 16, 0, N9_WRAP, N9_SUB, INT64_C(0), INT64_C(65535)}, + {"u16_wrapping_mul", 16, 0, N9_WRAP, N9_MUL, INT64_C(0), INT64_C(65535)}, + {"u16_checked_add", 16, 0, N9_CHECK, N9_ADD, INT64_C(0), INT64_C(65535)}, + {"u16_checked_sub", 16, 0, N9_CHECK, N9_SUB, INT64_C(0), INT64_C(65535)}, + {"u16_checked_mul", 16, 0, N9_CHECK, N9_MUL, INT64_C(0), INT64_C(65535)}, + {"u16_saturating_add", 16, 0, N9_SAT, N9_ADD, INT64_C(0), INT64_C(65535)}, + {"u16_saturating_sub", 16, 0, N9_SAT, N9_SUB, INT64_C(0), INT64_C(65535)}, + {"u16_saturating_mul", 16, 0, N9_SAT, N9_MUL, INT64_C(0), INT64_C(65535)}, + {"u32_wrapping_add", 32, 0, N9_WRAP, N9_ADD, INT64_C(0), INT64_C(4294967295)}, + {"u32_wrapping_sub", 32, 0, N9_WRAP, N9_SUB, INT64_C(0), INT64_C(4294967295)}, + {"u32_wrapping_mul", 32, 0, N9_WRAP, N9_MUL, INT64_C(0), INT64_C(4294967295)}, + {"u32_checked_add", 32, 0, N9_CHECK, N9_ADD, INT64_C(0), INT64_C(4294967295)}, + {"u32_checked_sub", 32, 0, N9_CHECK, N9_SUB, INT64_C(0), INT64_C(4294967295)}, + {"u32_checked_mul", 32, 0, N9_CHECK, N9_MUL, INT64_C(0), INT64_C(4294967295)}, + {"u32_saturating_add", 32, 0, N9_SAT, N9_ADD, INT64_C(0), INT64_C(4294967295)}, + {"u32_saturating_sub", 32, 0, N9_SAT, N9_SUB, INT64_C(0), INT64_C(4294967295)}, + {"u32_saturating_mul", 32, 0, N9_SAT, N9_MUL, INT64_C(0), INT64_C(4294967295)}, + {"u64_wrapping_add", 64, 0, N9_WRAP, N9_ADD, INT64_MIN, INT64_MAX}, + {"u64_wrapping_sub", 64, 0, N9_WRAP, N9_SUB, INT64_MIN, INT64_MAX}, + {"u64_wrapping_mul", 64, 0, N9_WRAP, N9_MUL, INT64_MIN, INT64_MAX}, + {"u64_checked_add", 64, 0, N9_CHECK, N9_ADD, INT64_MIN, INT64_MAX}, + {"u64_checked_sub", 64, 0, N9_CHECK, N9_SUB, INT64_MIN, INT64_MAX}, + {"u64_checked_mul", 64, 0, N9_CHECK, N9_MUL, INT64_MIN, INT64_MAX}, + {"u64_saturating_add", 64, 0, N9_SAT, N9_ADD, INT64_MIN, INT64_MAX}, + {"u64_saturating_sub", 64, 0, N9_SAT, N9_SUB, INT64_MIN, INT64_MAX}, + {"u64_saturating_mul", 64, 0, N9_SAT, N9_MUL, INT64_MIN, INT64_MAX}, +}; + +static int n9_pair(Value *arg, int64_t lo, int64_t hi, + int64_t *a, int64_t *b, const char *who) { + if (!arg || arg->type != VAL_LIST || arg->data.list.count < 2) { + rt_error(EK_TYPE, 0, "%s: expected [a, b]", who); + return 0; + } + if (arg->data.list.count > 2) { + rt_error(EK_TYPE, 0, "%s: expected a fixed-shape list with at most 2 elements", who); + return 0; + } + EigsView av, bv; + return eigs_int_arg_range(list_get_view(arg, 0, &av), lo, hi, a, who) + && eigs_int_arg_range(list_get_view(arg, 1, &bv), lo, hi, b, who); +} + +/* Decode bits without an out-of-range unsigned-to-signed cast. */ +static int64_t n9_i64_bits(uint64_t bits) { + int64_t value; + memcpy(&value, &bits, sizeof(value)); + return value; +} + +static Value *n9_width(Value *arg, const N9Spec *s) { + int64_t a, b; + if (!n9_pair(arg, s->lo, s->hi, &a, &b, s->name)) return make_null(); + uint64_t ua = (uint64_t)a, ub = (uint64_t)b; + uint64_t mask = s->width == 64 ? UINT64_MAX : (UINT64_C(1) << s->width) - 1; + uint64_t bits = 0; + switch (s->op) { + case N9_ADD: bits = ua + ub; break; + case N9_SUB: bits = ua - ub; break; + case N9_MUL: bits = ua * ub; break; + } + if (s->mode != N9_WRAP) { + int overflow = 0, high = 0; + if (s->is_signed) { + int64_t result = 0; + switch (s->op) { + case N9_ADD: + overflow = __builtin_add_overflow(a, b, &result); + high = b > 0; + break; + case N9_SUB: + overflow = __builtin_sub_overflow(a, b, &result); + high = b < 0; + break; + case N9_MUL: + overflow = __builtin_mul_overflow(a, b, &result); + high = (a < 0) == (b < 0); + break; + } + if (!overflow) { + overflow = result < s->lo || result > s->hi; + high = result > s->hi; + } + } else { + switch (s->op) { + case N9_ADD: overflow = bits < ua || bits > mask; high = 1; break; + case N9_SUB: overflow = ua < ub; high = 0; break; + case N9_MUL: overflow = ub != 0 && ua > mask / ub; high = 1; break; + } + } + if (overflow) { + if (s->mode == N9_CHECK) { + rt_error(EK_VALUE, 0, "%s: integer overflow", s->name); + return make_null(); + } + if (s->is_signed) return make_int(high ? s->hi : s->lo); + return make_int(high ? n9_i64_bits(mask) : 0); + } + } + bits &= mask; + if (s->is_signed && s->width < 64 && (bits & (UINT64_C(1) << (s->width - 1)))) + return make_int(-1 - (int64_t)(mask - bits)); + return make_int(n9_i64_bits(bits)); +} + +/* i8_wrapping_add of [a, b] — i8 wrapping add; N5 operands, int result */ +Value* builtin_i8_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[0]); +} + +/* i8_wrapping_sub of [a, b] — i8 wrapping sub; N5 operands, int result */ +Value* builtin_i8_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[1]); +} + +/* i8_wrapping_mul of [a, b] — i8 wrapping mul; N5 operands, int result */ +Value* builtin_i8_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[2]); +} + +/* i8_checked_add of [a, b] — i8 checked add; N5 operands, int result */ +Value* builtin_i8_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[3]); +} + +/* i8_checked_sub of [a, b] — i8 checked sub; N5 operands, int result */ +Value* builtin_i8_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[4]); +} + +/* i8_checked_mul of [a, b] — i8 checked mul; N5 operands, int result */ +Value* builtin_i8_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[5]); +} + +/* i8_saturating_add of [a, b] — i8 saturating add; N5 operands, int result */ +Value* builtin_i8_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[6]); +} + +/* i8_saturating_sub of [a, b] — i8 saturating sub; N5 operands, int result */ +Value* builtin_i8_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[7]); +} + +/* i8_saturating_mul of [a, b] — i8 saturating mul; N5 operands, int result */ +Value* builtin_i8_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[8]); +} + +/* i16_wrapping_add of [a, b] — i16 wrapping add; N5 operands, int result */ +Value* builtin_i16_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[9]); +} + +/* i16_wrapping_sub of [a, b] — i16 wrapping sub; N5 operands, int result */ +Value* builtin_i16_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[10]); +} + +/* i16_wrapping_mul of [a, b] — i16 wrapping mul; N5 operands, int result */ +Value* builtin_i16_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[11]); +} + +/* i16_checked_add of [a, b] — i16 checked add; N5 operands, int result */ +Value* builtin_i16_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[12]); +} + +/* i16_checked_sub of [a, b] — i16 checked sub; N5 operands, int result */ +Value* builtin_i16_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[13]); +} + +/* i16_checked_mul of [a, b] — i16 checked mul; N5 operands, int result */ +Value* builtin_i16_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[14]); +} + +/* i16_saturating_add of [a, b] — i16 saturating add; N5 operands, int result */ +Value* builtin_i16_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[15]); +} + +/* i16_saturating_sub of [a, b] — i16 saturating sub; N5 operands, int result */ +Value* builtin_i16_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[16]); +} + +/* i16_saturating_mul of [a, b] — i16 saturating mul; N5 operands, int result */ +Value* builtin_i16_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[17]); +} + +/* i32_wrapping_add of [a, b] — i32 wrapping add; N5 operands, int result */ +Value* builtin_i32_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[18]); +} + +/* i32_wrapping_sub of [a, b] — i32 wrapping sub; N5 operands, int result */ +Value* builtin_i32_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[19]); +} + +/* i32_wrapping_mul of [a, b] — i32 wrapping mul; N5 operands, int result */ +Value* builtin_i32_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[20]); +} + +/* i32_checked_add of [a, b] — i32 checked add; N5 operands, int result */ +Value* builtin_i32_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[21]); +} + +/* i32_checked_sub of [a, b] — i32 checked sub; N5 operands, int result */ +Value* builtin_i32_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[22]); +} + +/* i32_checked_mul of [a, b] — i32 checked mul; N5 operands, int result */ +Value* builtin_i32_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[23]); +} + +/* i32_saturating_add of [a, b] — i32 saturating add; N5 operands, int result */ +Value* builtin_i32_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[24]); +} + +/* i32_saturating_sub of [a, b] — i32 saturating sub; N5 operands, int result */ +Value* builtin_i32_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[25]); +} + +/* i32_saturating_mul of [a, b] — i32 saturating mul; N5 operands, int result */ +Value* builtin_i32_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[26]); +} + +/* i64_wrapping_add of [a, b] — i64 wrapping add; N5 operands, int result */ +Value* builtin_i64_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[27]); +} + +/* i64_wrapping_sub of [a, b] — i64 wrapping sub; N5 operands, int result */ +Value* builtin_i64_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[28]); +} + +/* i64_wrapping_mul of [a, b] — i64 wrapping mul; N5 operands, int result */ +Value* builtin_i64_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[29]); +} + +/* i64_checked_add of [a, b] — i64 checked add; N5 operands, int result */ +Value* builtin_i64_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[30]); +} + +/* i64_checked_sub of [a, b] — i64 checked sub; N5 operands, int result */ +Value* builtin_i64_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[31]); +} + +/* i64_checked_mul of [a, b] — i64 checked mul; N5 operands, int result */ +Value* builtin_i64_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[32]); +} + +/* i64_saturating_add of [a, b] — i64 saturating add; N5 operands, int result */ +Value* builtin_i64_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[33]); +} + +/* i64_saturating_sub of [a, b] — i64 saturating sub; N5 operands, int result */ +Value* builtin_i64_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[34]); +} + +/* i64_saturating_mul of [a, b] — i64 saturating mul; N5 operands, int result */ +Value* builtin_i64_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[35]); +} + +/* u8_wrapping_add of [a, b] — u8 wrapping add; N5 operands, int result */ +Value* builtin_u8_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[36]); +} + +/* u8_wrapping_sub of [a, b] — u8 wrapping sub; N5 operands, int result */ +Value* builtin_u8_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[37]); +} + +/* u8_wrapping_mul of [a, b] — u8 wrapping mul; N5 operands, int result */ +Value* builtin_u8_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[38]); +} + +/* u8_checked_add of [a, b] — u8 checked add; N5 operands, int result */ +Value* builtin_u8_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[39]); +} + +/* u8_checked_sub of [a, b] — u8 checked sub; N5 operands, int result */ +Value* builtin_u8_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[40]); +} + +/* u8_checked_mul of [a, b] — u8 checked mul; N5 operands, int result */ +Value* builtin_u8_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[41]); +} + +/* u8_saturating_add of [a, b] — u8 saturating add; N5 operands, int result */ +Value* builtin_u8_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[42]); +} + +/* u8_saturating_sub of [a, b] — u8 saturating sub; N5 operands, int result */ +Value* builtin_u8_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[43]); +} + +/* u8_saturating_mul of [a, b] — u8 saturating mul; N5 operands, int result */ +Value* builtin_u8_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[44]); +} + +/* u16_wrapping_add of [a, b] — u16 wrapping add; N5 operands, int result */ +Value* builtin_u16_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[45]); +} + +/* u16_wrapping_sub of [a, b] — u16 wrapping sub; N5 operands, int result */ +Value* builtin_u16_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[46]); +} + +/* u16_wrapping_mul of [a, b] — u16 wrapping mul; N5 operands, int result */ +Value* builtin_u16_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[47]); +} + +/* u16_checked_add of [a, b] — u16 checked add; N5 operands, int result */ +Value* builtin_u16_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[48]); +} + +/* u16_checked_sub of [a, b] — u16 checked sub; N5 operands, int result */ +Value* builtin_u16_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[49]); +} + +/* u16_checked_mul of [a, b] — u16 checked mul; N5 operands, int result */ +Value* builtin_u16_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[50]); +} + +/* u16_saturating_add of [a, b] — u16 saturating add; N5 operands, int result */ +Value* builtin_u16_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[51]); +} + +/* u16_saturating_sub of [a, b] — u16 saturating sub; N5 operands, int result */ +Value* builtin_u16_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[52]); +} + +/* u16_saturating_mul of [a, b] — u16 saturating mul; N5 operands, int result */ +Value* builtin_u16_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[53]); +} + +/* u32_wrapping_add of [a, b] — u32 wrapping add; N5 operands, int result */ +Value* builtin_u32_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[54]); +} + +/* u32_wrapping_sub of [a, b] — u32 wrapping sub; N5 operands, int result */ +Value* builtin_u32_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[55]); +} + +/* u32_wrapping_mul of [a, b] — u32 wrapping mul; N5 operands, int result */ +Value* builtin_u32_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[56]); +} + +/* u32_checked_add of [a, b] — u32 checked add; N5 operands, int result */ +Value* builtin_u32_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[57]); +} + +/* u32_checked_sub of [a, b] — u32 checked sub; N5 operands, int result */ +Value* builtin_u32_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[58]); +} + +/* u32_checked_mul of [a, b] — u32 checked mul; N5 operands, int result */ +Value* builtin_u32_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[59]); +} + +/* u32_saturating_add of [a, b] — u32 saturating add; N5 operands, int result */ +Value* builtin_u32_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[60]); +} + +/* u32_saturating_sub of [a, b] — u32 saturating sub; N5 operands, int result */ +Value* builtin_u32_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[61]); +} + +/* u32_saturating_mul of [a, b] — u32 saturating mul; N5 operands, int result */ +Value* builtin_u32_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[62]); +} + +/* u64_wrapping_add of [a, b] — u64 wrapping add; N5 operands, int result */ +Value* builtin_u64_wrapping_add(Value *arg) { + return n9_width(arg, &n9_specs[63]); +} + +/* u64_wrapping_sub of [a, b] — u64 wrapping sub; N5 operands, int result */ +Value* builtin_u64_wrapping_sub(Value *arg) { + return n9_width(arg, &n9_specs[64]); +} + +/* u64_wrapping_mul of [a, b] — u64 wrapping mul; N5 operands, int result */ +Value* builtin_u64_wrapping_mul(Value *arg) { + return n9_width(arg, &n9_specs[65]); +} + +/* u64_checked_add of [a, b] — u64 checked add; N5 operands, int result */ +Value* builtin_u64_checked_add(Value *arg) { + return n9_width(arg, &n9_specs[66]); +} + +/* u64_checked_sub of [a, b] — u64 checked sub; N5 operands, int result */ +Value* builtin_u64_checked_sub(Value *arg) { + return n9_width(arg, &n9_specs[67]); +} + +/* u64_checked_mul of [a, b] — u64 checked mul; N5 operands, int result */ +Value* builtin_u64_checked_mul(Value *arg) { + return n9_width(arg, &n9_specs[68]); +} + +/* u64_saturating_add of [a, b] — u64 saturating add; N5 operands, int result */ +Value* builtin_u64_saturating_add(Value *arg) { + return n9_width(arg, &n9_specs[69]); +} + +/* u64_saturating_sub of [a, b] — u64 saturating sub; N5 operands, int result */ +Value* builtin_u64_saturating_sub(Value *arg) { + return n9_width(arg, &n9_specs[70]); +} + +/* u64_saturating_mul of [a, b] — u64 saturating mul; N5 operands, int result */ +Value* builtin_u64_saturating_mul(Value *arg) { + return n9_width(arg, &n9_specs[71]); +} + +/* u64_compare of [a, b] — unsigned ordering of int64 bit patterns */ +Value* builtin_u64_compare(Value *arg) { + int64_t a, b; + if (!n9_pair(arg, INT64_MIN, INT64_MAX, &a, &b, "u64_compare")) return make_null(); + return make_int(((uint64_t)a > (uint64_t)b) - ((uint64_t)a < (uint64_t)b)); +} +static Value *n9_unsigned_div(Value *arg, int remainder, const char *who) { + int64_t a, b; + if (!n9_pair(arg, INT64_MIN, INT64_MAX, &a, &b, who)) return make_null(); + if (b == 0) { + rt_error(EK_VALUE, 0, "division by zero"); + return make_null(); + } + uint64_t value = remainder ? (uint64_t)a % (uint64_t)b : (uint64_t)a / (uint64_t)b; + return make_int(n9_i64_bits(value)); +} +/* u64_div of [a, b] — unsigned division; zero raises value */ +Value* builtin_u64_div(Value *arg) { + return n9_unsigned_div(arg, 0, "u64_div"); +} +/* u64_rem of [a, b] — unsigned remainder; zero raises value */ +Value* builtin_u64_rem(Value *arg) { + return n9_unsigned_div(arg, 1, "u64_rem"); +} +/* u64_to_string of x — unsigned decimal text from an int64 bit pattern */ +Value* builtin_u64_to_string(Value *arg) { + EigsView view; + if (arg && arg->type == VAL_LIST && arg->data.list.count == 1) + arg = list_get_view(arg, 0, &view); + int64_t value = eigs_int_arg(arg, "u64_to_string"); + if (g_has_error) return make_null(); + char text[21]; + snprintf(text, sizeof(text), "%llu", (unsigned long long)(uint64_t)value); + return make_str(text); +} +/* fround of x — binary64 to binary32 to binary64, returning float kind */ +Value* builtin_fround(Value *arg) { + EigsView view; + if (arg && arg->type == VAL_LIST && arg->data.list.count == 1) + arg = list_get_view(arg, 0, &view); + double value = eigs_float_arg(arg, "fround"); + if (g_has_error) return make_null(); + /* Preserve int -> f64 -> f32 -> f64 double rounding. make_float keeps + * today's overflow guard and math flag until the IEEE round R2.2. */ + return make_float((double)(float)value); +} diff --git a/src/builtins_internal.h b/src/builtins_internal.h index b658fbe10..27e5eac1b 100644 --- a/src/builtins_internal.h +++ b/src/builtins_internal.h @@ -9,6 +9,85 @@ #include "eigenscript.h" +/* #1758 N9 — builtins_int.c, shared table-driven width engine. */ +Value* builtin_i8_wrapping_add(Value *arg); +Value* builtin_i8_wrapping_sub(Value *arg); +Value* builtin_i8_wrapping_mul(Value *arg); +Value* builtin_i8_checked_add(Value *arg); +Value* builtin_i8_checked_sub(Value *arg); +Value* builtin_i8_checked_mul(Value *arg); +Value* builtin_i8_saturating_add(Value *arg); +Value* builtin_i8_saturating_sub(Value *arg); +Value* builtin_i8_saturating_mul(Value *arg); +Value* builtin_i16_wrapping_add(Value *arg); +Value* builtin_i16_wrapping_sub(Value *arg); +Value* builtin_i16_wrapping_mul(Value *arg); +Value* builtin_i16_checked_add(Value *arg); +Value* builtin_i16_checked_sub(Value *arg); +Value* builtin_i16_checked_mul(Value *arg); +Value* builtin_i16_saturating_add(Value *arg); +Value* builtin_i16_saturating_sub(Value *arg); +Value* builtin_i16_saturating_mul(Value *arg); +Value* builtin_i32_wrapping_add(Value *arg); +Value* builtin_i32_wrapping_sub(Value *arg); +Value* builtin_i32_wrapping_mul(Value *arg); +Value* builtin_i32_checked_add(Value *arg); +Value* builtin_i32_checked_sub(Value *arg); +Value* builtin_i32_checked_mul(Value *arg); +Value* builtin_i32_saturating_add(Value *arg); +Value* builtin_i32_saturating_sub(Value *arg); +Value* builtin_i32_saturating_mul(Value *arg); +Value* builtin_i64_wrapping_add(Value *arg); +Value* builtin_i64_wrapping_sub(Value *arg); +Value* builtin_i64_wrapping_mul(Value *arg); +Value* builtin_i64_checked_add(Value *arg); +Value* builtin_i64_checked_sub(Value *arg); +Value* builtin_i64_checked_mul(Value *arg); +Value* builtin_i64_saturating_add(Value *arg); +Value* builtin_i64_saturating_sub(Value *arg); +Value* builtin_i64_saturating_mul(Value *arg); +Value* builtin_u8_wrapping_add(Value *arg); +Value* builtin_u8_wrapping_sub(Value *arg); +Value* builtin_u8_wrapping_mul(Value *arg); +Value* builtin_u8_checked_add(Value *arg); +Value* builtin_u8_checked_sub(Value *arg); +Value* builtin_u8_checked_mul(Value *arg); +Value* builtin_u8_saturating_add(Value *arg); +Value* builtin_u8_saturating_sub(Value *arg); +Value* builtin_u8_saturating_mul(Value *arg); +Value* builtin_u16_wrapping_add(Value *arg); +Value* builtin_u16_wrapping_sub(Value *arg); +Value* builtin_u16_wrapping_mul(Value *arg); +Value* builtin_u16_checked_add(Value *arg); +Value* builtin_u16_checked_sub(Value *arg); +Value* builtin_u16_checked_mul(Value *arg); +Value* builtin_u16_saturating_add(Value *arg); +Value* builtin_u16_saturating_sub(Value *arg); +Value* builtin_u16_saturating_mul(Value *arg); +Value* builtin_u32_wrapping_add(Value *arg); +Value* builtin_u32_wrapping_sub(Value *arg); +Value* builtin_u32_wrapping_mul(Value *arg); +Value* builtin_u32_checked_add(Value *arg); +Value* builtin_u32_checked_sub(Value *arg); +Value* builtin_u32_checked_mul(Value *arg); +Value* builtin_u32_saturating_add(Value *arg); +Value* builtin_u32_saturating_sub(Value *arg); +Value* builtin_u32_saturating_mul(Value *arg); +Value* builtin_u64_wrapping_add(Value *arg); +Value* builtin_u64_wrapping_sub(Value *arg); +Value* builtin_u64_wrapping_mul(Value *arg); +Value* builtin_u64_checked_add(Value *arg); +Value* builtin_u64_checked_sub(Value *arg); +Value* builtin_u64_checked_mul(Value *arg); +Value* builtin_u64_saturating_add(Value *arg); +Value* builtin_u64_saturating_sub(Value *arg); +Value* builtin_u64_saturating_mul(Value *arg); +Value* builtin_u64_compare(Value *arg); +Value* builtin_u64_div(Value *arg); +Value* builtin_u64_rem(Value *arg); +Value* builtin_u64_to_string(Value *arg); +Value* builtin_fround(Value *arg); + /* Tensor builtins — implemented in builtins_tensor.c */ Value* builtin_tensor_add(Value *arg); Value* builtin_tensor_subtract(Value *arg); diff --git a/src/lsp_builtin_index.h b/src/lsp_builtin_index.h index 1d40f62f5..4687b2a94 100644 --- a/src/lsp_builtin_index.h +++ b/src/lsp_builtin_index.h @@ -105,6 +105,7 @@ static const char *builtin_docs[][2] = { {"fill", "fill of [count, value] — create a list of `count` elements all set to `value`."}, {"floor", "floor — builtin; see docs/BUILTINS.md"}, {"flush", "flush of null — flush stdout"}, + {"fround", "fround of x — binary64 to binary32 to binary64, returning float kind"}, {"gather", "gather of [tensor, indices, dim] -> select one element per row by index."}, {"get_at", "get_at of [list, index] or get_at of [list, row, col]"}, {"get_observer_thresholds", "get_observer_thresholds — builtin; see docs/BUILTINS.md"}, @@ -141,6 +142,42 @@ static const char *builtin_docs[][2] = { {"http_serve", "http_serve — http extension builtin; see docs/BUILTINS.md"}, {"http_session_id", "http_session_id — http_request extension builtin; see docs/BUILTINS.md"}, {"http_static", "http_static — http extension builtin; see docs/BUILTINS.md"}, + {"i16_checked_add", "i16_checked_add of [a, b] — i16 checked add; N5 operands, int result"}, + {"i16_checked_mul", "i16_checked_mul of [a, b] — i16 checked mul; N5 operands, int result"}, + {"i16_checked_sub", "i16_checked_sub of [a, b] — i16 checked sub; N5 operands, int result"}, + {"i16_saturating_add", "i16_saturating_add of [a, b] — i16 saturating add; N5 operands, int result"}, + {"i16_saturating_mul", "i16_saturating_mul of [a, b] — i16 saturating mul; N5 operands, int result"}, + {"i16_saturating_sub", "i16_saturating_sub of [a, b] — i16 saturating sub; N5 operands, int result"}, + {"i16_wrapping_add", "i16_wrapping_add of [a, b] — i16 wrapping add; N5 operands, int result"}, + {"i16_wrapping_mul", "i16_wrapping_mul of [a, b] — i16 wrapping mul; N5 operands, int result"}, + {"i16_wrapping_sub", "i16_wrapping_sub of [a, b] — i16 wrapping sub; N5 operands, int result"}, + {"i32_checked_add", "i32_checked_add of [a, b] — i32 checked add; N5 operands, int result"}, + {"i32_checked_mul", "i32_checked_mul of [a, b] — i32 checked mul; N5 operands, int result"}, + {"i32_checked_sub", "i32_checked_sub of [a, b] — i32 checked sub; N5 operands, int result"}, + {"i32_saturating_add", "i32_saturating_add of [a, b] — i32 saturating add; N5 operands, int result"}, + {"i32_saturating_mul", "i32_saturating_mul of [a, b] — i32 saturating mul; N5 operands, int result"}, + {"i32_saturating_sub", "i32_saturating_sub of [a, b] — i32 saturating sub; N5 operands, int result"}, + {"i32_wrapping_add", "i32_wrapping_add of [a, b] — i32 wrapping add; N5 operands, int result"}, + {"i32_wrapping_mul", "i32_wrapping_mul of [a, b] — i32 wrapping mul; N5 operands, int result"}, + {"i32_wrapping_sub", "i32_wrapping_sub of [a, b] — i32 wrapping sub; N5 operands, int result"}, + {"i64_checked_add", "i64_checked_add of [a, b] — i64 checked add; N5 operands, int result"}, + {"i64_checked_mul", "i64_checked_mul of [a, b] — i64 checked mul; N5 operands, int result"}, + {"i64_checked_sub", "i64_checked_sub of [a, b] — i64 checked sub; N5 operands, int result"}, + {"i64_saturating_add", "i64_saturating_add of [a, b] — i64 saturating add; N5 operands, int result"}, + {"i64_saturating_mul", "i64_saturating_mul of [a, b] — i64 saturating mul; N5 operands, int result"}, + {"i64_saturating_sub", "i64_saturating_sub of [a, b] — i64 saturating sub; N5 operands, int result"}, + {"i64_wrapping_add", "i64_wrapping_add of [a, b] — i64 wrapping add; N5 operands, int result"}, + {"i64_wrapping_mul", "i64_wrapping_mul of [a, b] — i64 wrapping mul; N5 operands, int result"}, + {"i64_wrapping_sub", "i64_wrapping_sub of [a, b] — i64 wrapping sub; N5 operands, int result"}, + {"i8_checked_add", "i8_checked_add of [a, b] — i8 checked add; N5 operands, int result"}, + {"i8_checked_mul", "i8_checked_mul of [a, b] — i8 checked mul; N5 operands, int result"}, + {"i8_checked_sub", "i8_checked_sub of [a, b] — i8 checked sub; N5 operands, int result"}, + {"i8_saturating_add", "i8_saturating_add of [a, b] — i8 saturating add; N5 operands, int result"}, + {"i8_saturating_mul", "i8_saturating_mul of [a, b] — i8 saturating mul; N5 operands, int result"}, + {"i8_saturating_sub", "i8_saturating_sub of [a, b] — i8 saturating sub; N5 operands, int result"}, + {"i8_wrapping_add", "i8_wrapping_add of [a, b] — i8 wrapping add; N5 operands, int result"}, + {"i8_wrapping_mul", "i8_wrapping_mul of [a, b] — i8 wrapping mul; N5 operands, int result"}, + {"i8_wrapping_sub", "i8_wrapping_sub of [a, b] — i8 wrapping sub; N5 operands, int result"}, {"index_of", "index_of of [haystack, needle] → first index, or -1. Non-string operands"}, {"inflate", "inflate — builtin; see docs/BUILTINS.md"}, {"is_dir", "is_dir of path — 1 if path names a directory, 0 for a plain file, a"}, @@ -307,6 +344,46 @@ static const char *builtin_docs[][2] = { {"try_parse", "try_parse of string → 1 if valid EigenScript syntax, 0 if not."}, {"try_recv", "try_recv of channel — non-blocking receive, returns null if empty"}, {"type", "type — builtin; see docs/BUILTINS.md"}, + {"u16_checked_add", "u16_checked_add of [a, b] — u16 checked add; N5 operands, int result"}, + {"u16_checked_mul", "u16_checked_mul of [a, b] — u16 checked mul; N5 operands, int result"}, + {"u16_checked_sub", "u16_checked_sub of [a, b] — u16 checked sub; N5 operands, int result"}, + {"u16_saturating_add", "u16_saturating_add of [a, b] — u16 saturating add; N5 operands, int result"}, + {"u16_saturating_mul", "u16_saturating_mul of [a, b] — u16 saturating mul; N5 operands, int result"}, + {"u16_saturating_sub", "u16_saturating_sub of [a, b] — u16 saturating sub; N5 operands, int result"}, + {"u16_wrapping_add", "u16_wrapping_add of [a, b] — u16 wrapping add; N5 operands, int result"}, + {"u16_wrapping_mul", "u16_wrapping_mul of [a, b] — u16 wrapping mul; N5 operands, int result"}, + {"u16_wrapping_sub", "u16_wrapping_sub of [a, b] — u16 wrapping sub; N5 operands, int result"}, + {"u32_checked_add", "u32_checked_add of [a, b] — u32 checked add; N5 operands, int result"}, + {"u32_checked_mul", "u32_checked_mul of [a, b] — u32 checked mul; N5 operands, int result"}, + {"u32_checked_sub", "u32_checked_sub of [a, b] — u32 checked sub; N5 operands, int result"}, + {"u32_saturating_add", "u32_saturating_add of [a, b] — u32 saturating add; N5 operands, int result"}, + {"u32_saturating_mul", "u32_saturating_mul of [a, b] — u32 saturating mul; N5 operands, int result"}, + {"u32_saturating_sub", "u32_saturating_sub of [a, b] — u32 saturating sub; N5 operands, int result"}, + {"u32_wrapping_add", "u32_wrapping_add of [a, b] — u32 wrapping add; N5 operands, int result"}, + {"u32_wrapping_mul", "u32_wrapping_mul of [a, b] — u32 wrapping mul; N5 operands, int result"}, + {"u32_wrapping_sub", "u32_wrapping_sub of [a, b] — u32 wrapping sub; N5 operands, int result"}, + {"u64_checked_add", "u64_checked_add of [a, b] — u64 checked add; N5 operands, int result"}, + {"u64_checked_mul", "u64_checked_mul of [a, b] — u64 checked mul; N5 operands, int result"}, + {"u64_checked_sub", "u64_checked_sub of [a, b] — u64 checked sub; N5 operands, int result"}, + {"u64_compare", "u64_compare of [a, b] — unsigned ordering of int64 bit patterns"}, + {"u64_div", "u64_div of [a, b] — unsigned division; zero raises value"}, + {"u64_rem", "u64_rem of [a, b] — unsigned remainder; zero raises value"}, + {"u64_saturating_add", "u64_saturating_add of [a, b] — u64 saturating add; N5 operands, int result"}, + {"u64_saturating_mul", "u64_saturating_mul of [a, b] — u64 saturating mul; N5 operands, int result"}, + {"u64_saturating_sub", "u64_saturating_sub of [a, b] — u64 saturating sub; N5 operands, int result"}, + {"u64_to_string", "u64_to_string of x — unsigned decimal text from an int64 bit pattern"}, + {"u64_wrapping_add", "u64_wrapping_add of [a, b] — u64 wrapping add; N5 operands, int result"}, + {"u64_wrapping_mul", "u64_wrapping_mul of [a, b] — u64 wrapping mul; N5 operands, int result"}, + {"u64_wrapping_sub", "u64_wrapping_sub of [a, b] — u64 wrapping sub; N5 operands, int result"}, + {"u8_checked_add", "u8_checked_add of [a, b] — u8 checked add; N5 operands, int result"}, + {"u8_checked_mul", "u8_checked_mul of [a, b] — u8 checked mul; N5 operands, int result"}, + {"u8_checked_sub", "u8_checked_sub of [a, b] — u8 checked sub; N5 operands, int result"}, + {"u8_saturating_add", "u8_saturating_add of [a, b] — u8 saturating add; N5 operands, int result"}, + {"u8_saturating_mul", "u8_saturating_mul of [a, b] — u8 saturating mul; N5 operands, int result"}, + {"u8_saturating_sub", "u8_saturating_sub of [a, b] — u8 saturating sub; N5 operands, int result"}, + {"u8_wrapping_add", "u8_wrapping_add of [a, b] — u8 wrapping add; N5 operands, int result"}, + {"u8_wrapping_mul", "u8_wrapping_mul of [a, b] — u8 wrapping mul; N5 operands, int result"}, + {"u8_wrapping_sub", "u8_wrapping_sub of [a, b] — u8 wrapping sub; N5 operands, int result"}, {"usleep", "usleep of microseconds — pause execution"}, {"values", "values — builtin; see docs/BUILTINS.md"}, {"vm_run_bytecode", "vm_run_bytecode of — assemble a chunk (and its nested"}, diff --git a/tests/phase2/builtins/builtins.tsv b/tests/phase2/builtins/builtins.tsv index a73b6ef93..347162661 100644 --- a/tests/phase2/builtins/builtins.tsv +++ b/tests/phase2/builtins/builtins.tsv @@ -75,6 +75,7 @@ f64_from_bytes builtins_buf.c int-requiring - - d - release - - yes yes f64_to_bytes builtins_buf.c other - - d - release - - yes yes fill builtins.c int-requiring - - c - release - - yes yes floor builtins.c int-preserving LOSS - b - release - - yes yes +fround builtins_int.c float-producing - - g - release - - yes yes gather builtins_tensor.c int-requiring - - d - release - - yes yes get_at builtins.c int-requiring - - c - release - - yes yes get_observer_thresholds builtins.c float-producing - - c - release - - no yes @@ -101,6 +102,42 @@ http_route ext_http.c other - - f - server - - no no http_route_authed ext_http.c other - - f - server - - no no http_serve ext_http.c int-requiring - - f - server - - yes yes http_static ext_http.c other - - f - server - - no no +i16_checked_add builtins_int.c int-requiring - - g - release - - yes yes +i16_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +i16_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +i16_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +i16_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +i16_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +i16_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +i16_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +i16_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes +i32_checked_add builtins_int.c int-requiring - - g - release - - yes yes +i32_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +i32_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +i32_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +i32_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +i32_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +i32_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +i32_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +i32_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes +i64_checked_add builtins_int.c int-requiring - - g - release - - yes yes +i64_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +i64_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +i64_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +i64_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +i64_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +i64_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +i64_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +i64_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes +i8_checked_add builtins_int.c int-requiring - - g - release - - yes yes +i8_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +i8_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +i8_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +i8_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +i8_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +i8_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +i8_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +i8_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes index_of builtins.c int-preserving - - b - release - - yes yes inflate builtins_buf.c int-requiring - - d - zlib - - yes yes join builtins.c other - - c - release - - no yes @@ -226,6 +263,46 @@ throw builtins.c other - - c - release - - no yes token_name builtins.c int-requiring - - c - release - - yes yes try_recv builtins.c int-requiring - - c - release - - yes yes type builtins.c other - - c - release - - no no +u16_checked_add builtins_int.c int-requiring - - g - release - - yes yes +u16_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +u16_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +u16_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +u16_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +u16_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +u16_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +u16_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +u16_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes +u32_checked_add builtins_int.c int-requiring - - g - release - - yes yes +u32_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +u32_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +u32_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +u32_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +u32_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +u32_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +u32_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +u32_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes +u64_checked_add builtins_int.c int-requiring - - g - release - - yes yes +u64_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +u64_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +u64_compare builtins_int.c int-requiring - - g - release - - yes yes +u64_div builtins_int.c int-requiring - - g - release - - yes yes +u64_rem builtins_int.c int-requiring - - g - release - - yes yes +u64_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +u64_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +u64_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +u64_to_string builtins_int.c int-requiring - - g - release - - yes yes +u64_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +u64_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +u64_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes +u8_checked_add builtins_int.c int-requiring - - g - release - - yes yes +u8_checked_mul builtins_int.c int-requiring - - g - release - - yes yes +u8_checked_sub builtins_int.c int-requiring - - g - release - - yes yes +u8_saturating_add builtins_int.c int-requiring - - g - release - - yes yes +u8_saturating_mul builtins_int.c int-requiring - - g - release - - yes yes +u8_saturating_sub builtins_int.c int-requiring - - g - release - - yes yes +u8_wrapping_add builtins_int.c int-requiring - - g - release - - yes yes +u8_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes +u8_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes usleep builtins.c other - magnitude c - release - - yes yes vm_run_bytecode builtins.c int-requiring - - c - release - - yes yes write builtins.c other - - c - release - - no yes diff --git a/tests/phase2/builtins/cases.tsv b/tests/phase2/builtins/cases.tsv index 85ce18b48..04cc75e34 100644 --- a/tests/phase2/builtins/cases.tsv +++ b/tests/phase2/builtins/cases.tsv @@ -234,3 +234,80 @@ write write - - write_bytes write_bytes - - zeros zeros - - zeros_like zeros_like - - +i8_wrapping_add i8_wrapping_add - - +i8_wrapping_sub i8_wrapping_sub - - +i8_wrapping_mul i8_wrapping_mul - - +i8_checked_add i8_checked_add - - +i8_checked_sub i8_checked_sub - - +i8_checked_mul i8_checked_mul - - +i8_saturating_add i8_saturating_add - - +i8_saturating_sub i8_saturating_sub - - +i8_saturating_mul i8_saturating_mul - - +i16_wrapping_add i16_wrapping_add - - +i16_wrapping_sub i16_wrapping_sub - - +i16_wrapping_mul i16_wrapping_mul - - +i16_checked_add i16_checked_add - - +i16_checked_sub i16_checked_sub - - +i16_checked_mul i16_checked_mul - - +i16_saturating_add i16_saturating_add - - +i16_saturating_sub i16_saturating_sub - - +i16_saturating_mul i16_saturating_mul - - +i32_wrapping_add i32_wrapping_add - - +i32_wrapping_sub i32_wrapping_sub - - +i32_wrapping_mul i32_wrapping_mul - - +i32_checked_add i32_checked_add - - +i32_checked_sub i32_checked_sub - - +i32_checked_mul i32_checked_mul - - +i32_saturating_add i32_saturating_add - - +i32_saturating_sub i32_saturating_sub - - +i32_saturating_mul i32_saturating_mul - - +i64_wrapping_add i64_wrapping_add - - +i64_wrapping_sub i64_wrapping_sub - - +i64_wrapping_mul i64_wrapping_mul - - +i64_checked_add i64_checked_add - - +i64_checked_sub i64_checked_sub - - +i64_checked_mul i64_checked_mul - - +i64_saturating_add i64_saturating_add - - +i64_saturating_sub i64_saturating_sub - - +i64_saturating_mul i64_saturating_mul - - +u8_wrapping_add u8_wrapping_add - - +u8_wrapping_sub u8_wrapping_sub - - +u8_wrapping_mul u8_wrapping_mul - - +u8_checked_add u8_checked_add - - +u8_checked_sub u8_checked_sub - - +u8_checked_mul u8_checked_mul - - +u8_saturating_add u8_saturating_add - - +u8_saturating_sub u8_saturating_sub - - +u8_saturating_mul u8_saturating_mul - - +u16_wrapping_add u16_wrapping_add - - +u16_wrapping_sub u16_wrapping_sub - - +u16_wrapping_mul u16_wrapping_mul - - +u16_checked_add u16_checked_add - - +u16_checked_sub u16_checked_sub - - +u16_checked_mul u16_checked_mul - - +u16_saturating_add u16_saturating_add - - +u16_saturating_sub u16_saturating_sub - - +u16_saturating_mul u16_saturating_mul - - +u32_wrapping_add u32_wrapping_add - - +u32_wrapping_sub u32_wrapping_sub - - +u32_wrapping_mul u32_wrapping_mul - - +u32_checked_add u32_checked_add - - +u32_checked_sub u32_checked_sub - - +u32_checked_mul u32_checked_mul - - +u32_saturating_add u32_saturating_add - - +u32_saturating_sub u32_saturating_sub - - +u32_saturating_mul u32_saturating_mul - - +u64_wrapping_add u64_wrapping_add - - +u64_wrapping_sub u64_wrapping_sub - - +u64_wrapping_mul u64_wrapping_mul - - +u64_checked_add u64_checked_add - - +u64_checked_sub u64_checked_sub - - +u64_checked_mul u64_checked_mul - - +u64_saturating_add u64_saturating_add - - +u64_saturating_sub u64_saturating_sub - - +u64_saturating_mul u64_saturating_mul - - +u64_compare u64_compare - - +u64_div u64_div - - +u64_rem u64_rem - - +u64_to_string u64_to_string - - +fround fround - - diff --git a/tests/phase2/builtins/make_table.py b/tests/phase2/builtins/make_table.py index 7351c222f..7ae195c2e 100644 --- a/tests/phase2/builtins/make_table.py +++ b/tests/phase2/builtins/make_table.py @@ -167,6 +167,7 @@ def round_of(file, cls, loss): if loss == "LOSS" or (file == "builtins.c" and cls == "int-preserving"): return "b" if file in ("builtins.c", "builtins_host.c", "vm.c"): return "c" if file in ("builtins_tensor.c", "builtins_buf.c") or file.startswith("model_"): return "d" + if file == "builtins_int.c": return "g" if file == "ext_gfx.c": return "e" if file in ("ext_store.c", "ext_db.c", "ext_http.c", "ext_net.c"): return "f" fail.append("no round for file " + file); return "?" diff --git a/tests/phase2/builtins/rowmeta.tsv b/tests/phase2/builtins/rowmeta.tsv index 614f6d661..ac23175d8 100644 --- a/tests/phase2/builtins/rowmeta.tsv +++ b/tests/phase2/builtins/rowmeta.tsv @@ -232,3 +232,80 @@ write - release write_bytes - release zeros - release zeros_like - release +i8_wrapping_add - release +i8_wrapping_sub - release +i8_wrapping_mul - release +i8_checked_add - release +i8_checked_sub - release +i8_checked_mul - release +i8_saturating_add - release +i8_saturating_sub - release +i8_saturating_mul - release +i16_wrapping_add - release +i16_wrapping_sub - release +i16_wrapping_mul - release +i16_checked_add - release +i16_checked_sub - release +i16_checked_mul - release +i16_saturating_add - release +i16_saturating_sub - release +i16_saturating_mul - release +i32_wrapping_add - release +i32_wrapping_sub - release +i32_wrapping_mul - release +i32_checked_add - release +i32_checked_sub - release +i32_checked_mul - release +i32_saturating_add - release +i32_saturating_sub - release +i32_saturating_mul - release +i64_wrapping_add - release +i64_wrapping_sub - release +i64_wrapping_mul - release +i64_checked_add - release +i64_checked_sub - release +i64_checked_mul - release +i64_saturating_add - release +i64_saturating_sub - release +i64_saturating_mul - release +u8_wrapping_add - release +u8_wrapping_sub - release +u8_wrapping_mul - release +u8_checked_add - release +u8_checked_sub - release +u8_checked_mul - release +u8_saturating_add - release +u8_saturating_sub - release +u8_saturating_mul - release +u16_wrapping_add - release +u16_wrapping_sub - release +u16_wrapping_mul - release +u16_checked_add - release +u16_checked_sub - release +u16_checked_mul - release +u16_saturating_add - release +u16_saturating_sub - release +u16_saturating_mul - release +u32_wrapping_add - release +u32_wrapping_sub - release +u32_wrapping_mul - release +u32_checked_add - release +u32_checked_sub - release +u32_checked_mul - release +u32_saturating_add - release +u32_saturating_sub - release +u32_saturating_mul - release +u64_wrapping_add - release +u64_wrapping_sub - release +u64_wrapping_mul - release +u64_checked_add - release +u64_checked_sub - release +u64_checked_mul - release +u64_saturating_add - release +u64_saturating_sub - release +u64_saturating_mul - release +u64_compare - release +u64_div - release +u64_rem - release +u64_to_string - release +fround - release diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py index 9993d806d..fabd89bac 100644 --- a/tests/test_doc_examples.py +++ b/tests/test_doc_examples.py @@ -324,10 +324,10 @@ def is_asan_build(): # --------------------------------------------------------------------------- POPULATION = { # file fences paired fragment nocheck value-comments - "README.md": (14, 10, 4, 0, 0), # R1.6e: +1 paired Q7 magnitude refusal example - "docs/llms.txt": (16, 13, 2, 1, 0), # R1.6e: +1 paired Q7 magnitude refusal example - "docs/SPEC.md": (94, 90, 1, 3, 0), # R1.6e: +1 paired Q7 magnitude refusal example - "docs/COMPARISON.md": (26, 25, 1, 0, 0), # R1.6e: +1 paired Q7 magnitude refusal example + "README.md": (15, 11, 4, 0, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/llms.txt": (17, 14, 2, 1, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/SPEC.md": (95, 91, 1, 3, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/COMPARISON.md": (27, 26, 1, 0, 0), # R1.6g: +1 paired Rust-derived N9 example "docs/CONCURRENCY.md": ( 8, 8, 0, 0, 0), # #1736: +1 paired (detached task catches its own error) "docs/STDLIB.md": ( 15, 7, 8, 0, 0), "docs/SYNTAX.md": ( 35, 15, 20, 0, 1), diff --git a/tools/gen_lsp_builtin_index.sh b/tools/gen_lsp_builtin_index.sh index d73773c12..167211c4f 100755 --- a/tools/gen_lsp_builtin_index.sh +++ b/tools/gen_lsp_builtin_index.sh @@ -45,7 +45,7 @@ export LC_ALL CORE_SRCS="src/builtins.c src/builtins_host.c src/hash.c src/ext_store.c" # TUs scanned for `name of ...` signature comments (core + every extension). -DOC_SRCS="src/builtins.c src/builtins_buf.c src/builtins_host.c src/builtins_tensor.c \ +DOC_SRCS="src/builtins.c src/builtins_int.c src/builtins_buf.c src/builtins_host.c src/builtins_tensor.c \ src/hash.c src/ext_store.c src/ext_gfx.c src/ext_http.c \ src/ext_db.c src/ext_net.c src/model_train.c" diff --git a/web/build.sh b/web/build.sh index 1b60416d3..22c1ace3b 100755 --- a/web/build.sh +++ b/web/build.sh @@ -24,7 +24,7 @@ mkdir -p web/dist # units, which depend on HTTP/sockets/threads not available in WASM. SOURCES=( src/eigenscript.c src/lexer.c src/parser.c - src/builtins.c src/builtins_buf.c src/builtins_host.c src/builtins_tensor.c + src/builtins.c src/builtins_int.c src/builtins_buf.c src/builtins_host.c src/builtins_tensor.c src/fsutil.c src/hash.c src/alloc.c src/state.c src/strbuf.c src/ext_store.c src/fmt.c src/lint.c src/lint_host.c From bab928d41d5370d87f12ba25344a71f2c6d8abab Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 03:35:05 -0500 Subject: [PATCH 165/188] Land R1.6g and refresh the 310-row numeric inventory #1758 N9. Declare R1.6g landed, planned g=77, total=310 rows/312 cases, release-profile=285, registered builtins=389. Refresh inventory and table; classify the stronger unconditional N9 shape boundary with source-pinned contracts. No existing contract repins or frozen branch edits. Inventory/table/shape checks rc=0; release build warnings=0. Inventory reads the bank indexed C/header tree, proven byte-identical to cwd (whose .git is read-only). Full train receipts recorded separately. Final acceptance counts (actual logs): phase2-builtins-all-profiles: phase2-builtins: PASS rows=310 landed=R1.6b,R1.6c,R1.6d,R1.6e,R1.6f,R1.6g migrated=310 unchanged=0 phase2-check: tier=default examined=93 rows tag_fail=93 branch_pass=93 vacuous=0 tag_timeout=0 tag_signal=0 phase2-check: tier=osr examined=93 rows tag_fail=93 branch_pass=93 vacuous=0 tag_timeout=0 tag_signal=0 phase2-check: tier=trace examined=88 rows tag_fail=88 branch_pass=88 vacuous=0 tag_timeout=0 tag_signal=0 phase2-check: phase2-check: PASS phase2-ci: phase2-ci: PASS (through=R1.6g) lib-diff: phase2-lib-diff: range=[-3, 110] modules=78 importable=66 functions=889 via_reexport=95 no_params=24 calls=281423 examined=281423 unexamined=0 both_ok=124575 both_raise=156668 improved=0 lib-diff: phase2-lib-diff: N4 source_functions=28 exported_functions=19 calls=4631 both_ok=2500 changed_functions=11 lib-diff: phase2-lib-diff: listed_functions=13 undeclared=0 stale=0 PASS corpus-diff: corpus-diff: branch /tmp/es-r16g-bank/src/eigenscript (0.46.0) sha256 326b494a4bc3bc81 corpus-diff: corpus-diff: files=577 excluded=315 declared_nonzero=44 corpus-diff: corpus-diff: examined=577 excluded=315 same=565 same_nonzero=43 same_under_replay=4 nondet=1 diff=6 new=6 new_failed=0 modified=0 modified_failed=0 branch_only=5 deleted=0 crash_both=0 timeout_both=1 conditioned=16 incomplete=0 undeclared=0 stale=0 ledger_refused=0 unpinned=1 capped=15 corpus-diff: corpus-diff: FAIL full-release-make-test: RESULTS: 4596/4596 passed, 0 failed, 10 skipped extensions-suite: RESULTS: 4839/4839 passed, 0 failed, 5 skipped cost-measure: phase2-cost: workloads=15 rows=30 over_declared_max=0 stale_declarations=0 PASS Rust differential: 77 ops, 18784 oracle values, both strict modes, mismatches=0; 5/5 required runtime plants killed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 393 ++++-- docs/design/phase2-numbers.md | 14 +- tests/phase2/builtins/BAR.md | 28 +- tests/phase2/builtins/make_table.py | 2 +- tests/phase2/builtins_landed.txt | 1 + tools/strict_shape_contracts.json | 1993 +++++++++++++++++++++++++++ 6 files changed, 2263 insertions(+), 168 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 20d9b171f..85bf7df2f 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,13 +1,13 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2186 classified=2186 unclassified=0 -files=64 tokens=116 role_rules=8 derived_accessors=32 wrappers=8 +examined=2197 classified=2197 unclassified=0 +files=65 tokens=116 role_rules=8 derived_accessors=32 wrappers=8 # Retired (required absent): buffer_read_byte -- R1.6e: gfx_fb and ppu_render_frame use buffer_byte_at ## Per category (a) type tests 511 CASE=61 DATA=4 TEST=443 YIELD=3 -(b) payload reads 628 RAW=136 READ=492 -(c) producers 551 GUARD=79 PARSE=3 PRODUCE=441 TAGSET=9 WRITE=19 +(b) payload reads 632 RAW=136 READ=496 +(c) producers 558 GUARD=79 PARSE=3 PRODUCE=448 TAGSET=9 WRITE=19 (d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 18 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=5 (f) equality, ordering and hashing 53 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=23 @@ -17,11 +17,11 @@ files=64 tokens=116 role_rules=8 derived_accessors=32 wrappers=8 (j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 ## Per token -make_int 206 +make_int 212 val_is_number 183 VAL_INT 157 VAL_FLOAT 154 -make_float 138 +make_float 139 SLOT_F64_RAW 84 num_guard 68 make_num 63 @@ -29,13 +29,13 @@ VAL_F64_RAW 57 AST_NUM 53 VAL_I64_RAW 51 slot_is_f64 50 -eigs_float_arg 48 +eigs_float_arg 49 eigs_value_as_num 48 eigs_list_float 47 slot_from_f64 47 -eigs_int_arg 33 +eigs_int_arg 34 +eigs_int_arg_range 34 slot_is_smi 33 -eigs_int_arg_range 32 eigs_num_arg 29 number 26 eigs_number_arg 23 @@ -160,6 +160,7 @@ ext_net.c 22 a=4 b=11 c=7 chunk.c 20 a=4 e=4 f=12 model_infer.c 18 a=2 b=7 c=9 ext_http.c 14 a=3 b=4 c=7 +builtins_int.c 11 b=4 c=7 eigs_embed.c 11 j=11 lexer.c 11 b=10 c=1 model_train.c 8 a=2 b=4 c=1 i=1 @@ -373,8 +374,8 @@ D3 vm.c:vm_run_ex/CASE(INT_CONST) not-a-classifier SLOT_SMI_MAX=1 SL D3 vm.c:vm_run_ex/CASE(LOCAL_IDX_DOT_GET) guarded slot_is_null=1 ## Builtins -registered=312 numeric=233 classified=233 unclassified=0 stale=0 -classes: float-producing=57 int-preserving=37 int-requiring=86 other=53 +registered=389 numeric=310 classified=310 unclassified=0 stale=0 +classes: float-producing=58 int-preserving=37 int-requiring=162 other=53 LOSS (37): abs add ceil db_execute db_query_json db_query_value floor hex http_post json_build json_decode json_encode json_path max min monotonic_ns multiply negative num num_copy random_int round scan_int_tokens scan_ints seed_random shared_incr sign_extend sort sort_by store_delete store_get store_put store_query store_update subtract sum task_sched_seed Q7: geometry=9 bounded=13 magnitude=13 abs builtin_abs int-preserving LOSS - eigs_number_arg,make_float,make_int,val_is_number @@ -453,6 +454,7 @@ f64_from_bytes builtin_f64_from_bytes int-requiring f64_to_bytes builtin_f64_to_bytes other - - eigs_float_arg,make_int,val_is_number fill builtin_fill int-requiring - - eigs_int_arg_range floor builtin_floor int-preserving LOSS - eigs_number_arg,make_float,make_int,num_to_i64_exact,val_is_number +fround builtin_fround float-producing - - eigs_float_arg,make_float gather builtin_tensor_gather int-requiring - - VAL_FLOAT,VAL_INT,buffer_index_at,buffer_read_f64,eigs_float_arg,eigs_int_arg,eigs_slot_elem_number,eigs_slot_int,make_float,make_int,val_is_number get_at builtin_get_at int-requiring - - buffer_read_f64,eigs_int_arg_range,make_float,val_is_number get_observer_thresholds builtin_get_observer_thresholds float-producing - - make_float @@ -479,6 +481,42 @@ http_route builtin_http_route other http_route_authed builtin_http_route_authed other - - eigs_num_text http_serve builtin_http_serve int-requiring - - eigs_int_arg_range,eigs_num_text http_static builtin_http_static other - - eigs_num_text +i16_checked_add builtin_i16_checked_add int-requiring - - eigs_int_arg_range,make_int +i16_checked_mul builtin_i16_checked_mul int-requiring - - eigs_int_arg_range,make_int +i16_checked_sub builtin_i16_checked_sub int-requiring - - eigs_int_arg_range,make_int +i16_saturating_add builtin_i16_saturating_add int-requiring - - eigs_int_arg_range,make_int +i16_saturating_mul builtin_i16_saturating_mul int-requiring - - eigs_int_arg_range,make_int +i16_saturating_sub builtin_i16_saturating_sub int-requiring - - eigs_int_arg_range,make_int +i16_wrapping_add builtin_i16_wrapping_add int-requiring - - eigs_int_arg_range,make_int +i16_wrapping_mul builtin_i16_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +i16_wrapping_sub builtin_i16_wrapping_sub int-requiring - - eigs_int_arg_range,make_int +i32_checked_add builtin_i32_checked_add int-requiring - - eigs_int_arg_range,make_int +i32_checked_mul builtin_i32_checked_mul int-requiring - - eigs_int_arg_range,make_int +i32_checked_sub builtin_i32_checked_sub int-requiring - - eigs_int_arg_range,make_int +i32_saturating_add builtin_i32_saturating_add int-requiring - - eigs_int_arg_range,make_int +i32_saturating_mul builtin_i32_saturating_mul int-requiring - - eigs_int_arg_range,make_int +i32_saturating_sub builtin_i32_saturating_sub int-requiring - - eigs_int_arg_range,make_int +i32_wrapping_add builtin_i32_wrapping_add int-requiring - - eigs_int_arg_range,make_int +i32_wrapping_mul builtin_i32_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +i32_wrapping_sub builtin_i32_wrapping_sub int-requiring - - eigs_int_arg_range,make_int +i64_checked_add builtin_i64_checked_add int-requiring - - eigs_int_arg_range,make_int +i64_checked_mul builtin_i64_checked_mul int-requiring - - eigs_int_arg_range,make_int +i64_checked_sub builtin_i64_checked_sub int-requiring - - eigs_int_arg_range,make_int +i64_saturating_add builtin_i64_saturating_add int-requiring - - eigs_int_arg_range,make_int +i64_saturating_mul builtin_i64_saturating_mul int-requiring - - eigs_int_arg_range,make_int +i64_saturating_sub builtin_i64_saturating_sub int-requiring - - eigs_int_arg_range,make_int +i64_wrapping_add builtin_i64_wrapping_add int-requiring - - eigs_int_arg_range,make_int +i64_wrapping_mul builtin_i64_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +i64_wrapping_sub builtin_i64_wrapping_sub int-requiring - - eigs_int_arg_range,make_int +i8_checked_add builtin_i8_checked_add int-requiring - - eigs_int_arg_range,make_int +i8_checked_mul builtin_i8_checked_mul int-requiring - - eigs_int_arg_range,make_int +i8_checked_sub builtin_i8_checked_sub int-requiring - - eigs_int_arg_range,make_int +i8_saturating_add builtin_i8_saturating_add int-requiring - - eigs_int_arg_range,make_int +i8_saturating_mul builtin_i8_saturating_mul int-requiring - - eigs_int_arg_range,make_int +i8_saturating_sub builtin_i8_saturating_sub int-requiring - - eigs_int_arg_range,make_int +i8_wrapping_add builtin_i8_wrapping_add int-requiring - - eigs_int_arg_range,make_int +i8_wrapping_mul builtin_i8_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +i8_wrapping_sub builtin_i8_wrapping_sub int-requiring - - eigs_int_arg_range,make_int index_of builtin_index_of int-preserving - - make_float,make_int inflate builtin_inflate int-requiring - - VAL_FLOAT,VAL_INT,buffer_byte_at,eigs_byte_arg,eigs_slot_byte,make_int,val_is_number join builtin_join other - - eigs_num_text @@ -604,6 +642,46 @@ throw builtin_throw other token_name builtin_token_name int-requiring - - eigs_int_arg_range,val_is_number try_recv builtin_try_recv int-requiring - - eigs_int_arg_range,val_is_number type builtin_type other - - VAL_FLOAT,VAL_INT +u16_checked_add builtin_u16_checked_add int-requiring - - eigs_int_arg_range,make_int +u16_checked_mul builtin_u16_checked_mul int-requiring - - eigs_int_arg_range,make_int +u16_checked_sub builtin_u16_checked_sub int-requiring - - eigs_int_arg_range,make_int +u16_saturating_add builtin_u16_saturating_add int-requiring - - eigs_int_arg_range,make_int +u16_saturating_mul builtin_u16_saturating_mul int-requiring - - eigs_int_arg_range,make_int +u16_saturating_sub builtin_u16_saturating_sub int-requiring - - eigs_int_arg_range,make_int +u16_wrapping_add builtin_u16_wrapping_add int-requiring - - eigs_int_arg_range,make_int +u16_wrapping_mul builtin_u16_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +u16_wrapping_sub builtin_u16_wrapping_sub int-requiring - - eigs_int_arg_range,make_int +u32_checked_add builtin_u32_checked_add int-requiring - - eigs_int_arg_range,make_int +u32_checked_mul builtin_u32_checked_mul int-requiring - - eigs_int_arg_range,make_int +u32_checked_sub builtin_u32_checked_sub int-requiring - - eigs_int_arg_range,make_int +u32_saturating_add builtin_u32_saturating_add int-requiring - - eigs_int_arg_range,make_int +u32_saturating_mul builtin_u32_saturating_mul int-requiring - - eigs_int_arg_range,make_int +u32_saturating_sub builtin_u32_saturating_sub int-requiring - - eigs_int_arg_range,make_int +u32_wrapping_add builtin_u32_wrapping_add int-requiring - - eigs_int_arg_range,make_int +u32_wrapping_mul builtin_u32_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +u32_wrapping_sub builtin_u32_wrapping_sub int-requiring - - eigs_int_arg_range,make_int +u64_checked_add builtin_u64_checked_add int-requiring - - eigs_int_arg_range,make_int +u64_checked_mul builtin_u64_checked_mul int-requiring - - eigs_int_arg_range,make_int +u64_checked_sub builtin_u64_checked_sub int-requiring - - eigs_int_arg_range,make_int +u64_compare builtin_u64_compare int-requiring - - eigs_int_arg_range,make_int +u64_div builtin_u64_div int-requiring - - eigs_int_arg_range,make_int +u64_rem builtin_u64_rem int-requiring - - eigs_int_arg_range,make_int +u64_saturating_add builtin_u64_saturating_add int-requiring - - eigs_int_arg_range,make_int +u64_saturating_mul builtin_u64_saturating_mul int-requiring - - eigs_int_arg_range,make_int +u64_saturating_sub builtin_u64_saturating_sub int-requiring - - eigs_int_arg_range,make_int +u64_to_string builtin_u64_to_string int-requiring - - eigs_int_arg +u64_wrapping_add builtin_u64_wrapping_add int-requiring - - eigs_int_arg_range,make_int +u64_wrapping_mul builtin_u64_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +u64_wrapping_sub builtin_u64_wrapping_sub int-requiring - - eigs_int_arg_range,make_int +u8_checked_add builtin_u8_checked_add int-requiring - - eigs_int_arg_range,make_int +u8_checked_mul builtin_u8_checked_mul int-requiring - - eigs_int_arg_range,make_int +u8_checked_sub builtin_u8_checked_sub int-requiring - - eigs_int_arg_range,make_int +u8_saturating_add builtin_u8_saturating_add int-requiring - - eigs_int_arg_range,make_int +u8_saturating_mul builtin_u8_saturating_mul int-requiring - - eigs_int_arg_range,make_int +u8_saturating_sub builtin_u8_saturating_sub int-requiring - - eigs_int_arg_range,make_int +u8_wrapping_add builtin_u8_wrapping_add int-requiring - - eigs_int_arg_range,make_int +u8_wrapping_mul builtin_u8_wrapping_mul int-requiring - - eigs_int_arg_range,make_int +u8_wrapping_sub builtin_u8_wrapping_sub int-requiring - - eigs_int_arg_range,make_int usleep builtin_usleep other - magnitude eigs_magnitude_arg,val_is_number vm_run_bytecode builtin_vm_run_bytecode int-requiring - - VAL_FLOAT,VAL_INT,eigs_byte_arg,eigs_int_arg_range,val_is_number write builtin_write other - - eigs_num_text @@ -792,147 +870,147 @@ builtins.c:2948 desc_isolate_const VAL_INT CASE a builtins.c:3065 vm_build_chunk_desc_body val_is_number TEST a builtins.c:3070 vm_build_chunk_desc_body eigs_byte_arg READ b builtins.c:3128 vm_build_chunk_desc_body val_is_number TEST a -builtins.c:3448 builtin_sandbox_run val_is_number TEST a -builtins.c:3456 builtin_sandbox_run val_is_number TEST a -builtins.c:3457 builtin_sandbox_run eigs_list_int READ b -builtins.c:3473 builtin_sandbox_run val_is_number TEST a -builtins.c:3474 builtin_sandbox_run eigs_list_int READ b -builtins.c:3531 builtin_sandbox_run make_int PRODUCE c -builtins.c:3712 builtin_sandbox_run make_int PRODUCE c -builtins.c:3724 builtin_sandbox_run make_int PRODUCE c -builtins.c:3738 builtin_sandbox_run make_int PRODUCE c -builtins.c:3772 builtin_sandbox_run make_int PRODUCE c -builtins.c:3798 builtin_record_history val_is_number TEST i -builtins.c:3804 builtin_record_history eigs_float_arg READ i -builtins.c:3811 builtin_record_history make_int PRODUCE i -builtins.c:3839 builtin_copy_into val_is_number TEST a -builtins.c:3857 builtin_copy_into val_is_number TEST a -builtins.c:3862 builtin_copy_into eigs_float_arg READ b -builtins.c:3897 builtin_list_slice val_is_number TEST a -builtins.c:3897 builtin_list_slice val_is_number TEST a -builtins.c:3924 builtin_num_copy val_is_number TEST a -builtins.c:3925 builtin_num_copy eigs_number_arg READ b -builtins.c:3957 range_bound eigs_int_arg_range READ b -builtins.c:3968 builtin_range val_is_number TEST a -builtins.c:3977 builtin_range val_is_number TEST a -builtins.c:4039 builtin_range make_int PRODUCE c -builtins.c:4077 at_index val_is_number TEST a -builtins.c:4097 buf_at_index val_is_number TEST a -builtins.c:4147 builtin_set_at val_is_number TEST a -builtins.c:4152 builtin_set_at eigs_float_arg READ b -builtins.c:4215 builtin_get_at buffer_read_f64 READ b -builtins.c:4215 builtin_get_at make_float PRODUCE c -builtins.c:4223 builtin_get_at buffer_read_f64 READ b -builtins.c:4223 builtin_get_at make_float PRODUCE c -builtins.c:4607 builtin_spawn make_int PRODUCE c -builtins.c:4613 builtin_spawn make_int PRODUCE c -builtins.c:4614 builtin_spawn make_int PRODUCE c -builtins.c:4639 builtin_thread_join val_is_number TEST a -builtins.c:4645 builtin_thread_join eigs_int_arg_range READ b -builtins.c:4645 builtin_thread_join val_is_number TEST a -builtins.c:4750 get_channel_why val_is_number TEST a -builtins.c:4754 get_channel_why eigs_int_arg_range READ b -builtins.c:4754 get_channel_why val_is_number TEST a -builtins.c:4820 builtin_channel make_int PRODUCE c -builtins.c:4821 builtin_channel make_int PRODUCE c -builtins.c:4920 builtin_recv_timeout val_is_number TEST a -builtins.c:4925 builtin_recv_timeout eigs_magnitude_arg READ b -builtins.c:5099 builtin_task_spawn make_int PRODUCE c -builtins.c:5109 task_handle_resolve val_is_number TEST a -builtins.c:5110 task_handle_resolve eigs_int_arg READ b -builtins.c:5164 builtin_task_join val_is_number TEST a -builtins.c:5165 builtin_task_join eigs_int_arg READ b -builtins.c:5211 builtin_task_send val_is_number TEST a -builtins.c:5215 builtin_task_send eigs_int_arg READ b -builtins.c:5243 builtin_task_kill val_is_number TEST a -builtins.c:5246 builtin_task_kill eigs_int_arg READ b -builtins.c:5256 builtin_task_alive val_is_number TEST a -builtins.c:5278 builtin_task_sleep val_is_number TEST a -builtins.c:5282 builtin_task_sleep eigs_float_arg READ b -builtins.c:5317 builtin_task_self make_int PRODUCE c -builtins.c:5331 builtin_task_detach val_is_number TEST a -builtins.c:5336 builtin_task_detach make_int PRODUCE c -builtins.c:5339 builtin_task_detach make_int PRODUCE c -builtins.c:5350 builtin_task_sched_seed val_is_number TEST a -builtins.c:5354 builtin_task_sched_seed eigs_int_arg READ b -builtins.c:5505 builtin_nearest_in_range eigs_list_float READ b -builtins.c:5506 builtin_nearest_in_range eigs_list_float READ b -builtins.c:5507 builtin_nearest_in_range eigs_list_float READ b -builtins.c:5508 builtin_nearest_in_range eigs_list_float READ b -builtins.c:5509 builtin_nearest_in_range eigs_list_float READ b -builtins.c:5566 builtin_nearest_in_range eigs_float_arg READ b -builtins.c:5566 builtin_nearest_in_range val_is_number TEST a -builtins.c:5590 builtin_nearest_in_range eigs_float_arg READ b -builtins.c:5593 builtin_nearest_in_range val_is_number TEST a -builtins.c:5593 builtin_nearest_in_range val_is_number TEST a -builtins.c:5595 builtin_nearest_in_range eigs_float_arg READ b -builtins.c:5596 builtin_nearest_in_range eigs_float_arg READ b -builtins.c:5611 builtin_nearest_in_range make_int PRODUCE c -builtins.c:5612 builtin_nearest_in_range make_float PRODUCE c -builtins.c:5613 builtin_nearest_in_range make_float PRODUCE c -builtins.c:5614 builtin_nearest_in_range make_float PRODUCE c -builtins.c:5639 builtin_nearest_in_range_all eigs_list_float READ b -builtins.c:5640 builtin_nearest_in_range_all eigs_list_float READ b -builtins.c:5641 builtin_nearest_in_range_all eigs_list_float READ b -builtins.c:5696 builtin_nearest_in_range_all eigs_float_arg READ b -builtins.c:5696 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5716 builtin_nearest_in_range_all eigs_float_arg READ b -builtins.c:5719 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5719 builtin_nearest_in_range_all val_is_number TEST a -builtins.c:5723 builtin_nearest_in_range_all eigs_float_arg READ b -builtins.c:5724 builtin_nearest_in_range_all eigs_float_arg READ b -builtins.c:5766 builtin_nearest_in_range_all make_int PRODUCE c -builtins.c:5767 builtin_nearest_in_range_all make_float PRODUCE c -builtins.c:5768 builtin_nearest_in_range_all make_float PRODUCE c -builtins.c:5769 builtin_nearest_in_range_all make_float PRODUCE c -builtins.c:5792 builtin_sign_extend make_float PRODUCE c -builtins.c:5794 builtin_sign_extend make_float PRODUCE c -builtins.c:5794 builtin_sign_extend val_is_number TEST a -builtins.c:5794 builtin_sign_extend val_is_number TEST a -builtins.c:5795 builtin_sign_extend eigs_list_int READ b -builtins.c:5796 builtin_sign_extend eigs_list_int READ b -builtins.c:5798 builtin_sign_extend make_int PRODUCE c -builtins.c:5805 builtin_sign_extend make_int PRODUCE c -builtins.c:5807 builtin_sign_extend make_int PRODUCE c -builtins.c:5824 builtin_list_truncate val_is_number TEST a -builtins.c:5855 builtin_list_remove_at val_is_number TEST a -builtins.c:5878 builtin_list_insert_at val_is_number TEST a -builtins.c:5907 builtin_list_index_of make_float PRODUCE f -builtins.c:5911 builtin_list_index_of make_float PRODUCE f -builtins.c:5917 builtin_list_index_of make_int PRODUCE f -builtins.c:5921 builtin_list_index_of make_int PRODUCE f -builtins.c:5992 builtin_sort_by val_is_number TEST f -builtins.c:6001 builtin_sort_by VAL_INT TEST f -builtins.c:6002 builtin_sort_by VAL_I64_RAW RAW f -builtins.c:6003 builtin_sort_by eigs_float_arg READ f -builtins.c:6025 sort_cmp_num VAL_INT TEST a -builtins.c:6025 sort_cmp_num VAL_INT TEST a -builtins.c:6026 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:6026 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:6026 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:6026 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:6027 sort_cmp_num VAL_INT TEST a -builtins.c:6028 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:6028 sort_cmp_num eigs_float_arg READ b -builtins.c:6031 sort_cmp_num VAL_INT TEST a -builtins.c:6032 sort_cmp_num VAL_I64_RAW RAW b -builtins.c:6032 sort_cmp_num eigs_float_arg READ b -builtins.c:6035 sort_cmp_num eigs_float_arg READ b -builtins.c:6035 sort_cmp_num eigs_float_arg READ b -builtins.c:6053 builtin_sort VAL_FLOAT TEST f -builtins.c:6053 builtin_sort VAL_INT TEST f -builtins.c:6054 builtin_sort val_is_number TEST f -builtins.c:6061 builtin_sort VAL_FLOAT TEST f -builtins.c:6061 builtin_sort VAL_INT TEST f -builtins.c:6082 builtin_dispatch val_is_number TEST a -builtins.c:6108 builtin_dispatch val_is_number TEST a -builtins.c:6190 builtin_dot make_float PRODUCE c -builtins.c:6193 builtin_dot make_float PRODUCE c -builtins.c:6198 builtin_dot buffer_read_f64 READ b -builtins.c:6200 builtin_dot buffer_read_f64 READ b -builtins.c:6202 builtin_dot num_guard GUARD c -builtins.c:6202 builtin_dot num_guard GUARD c -builtins.c:6204 builtin_dot make_float PRODUCE c +builtins.c:3526 builtin_sandbox_run val_is_number TEST a +builtins.c:3534 builtin_sandbox_run val_is_number TEST a +builtins.c:3535 builtin_sandbox_run eigs_list_int READ b +builtins.c:3551 builtin_sandbox_run val_is_number TEST a +builtins.c:3552 builtin_sandbox_run eigs_list_int READ b +builtins.c:3609 builtin_sandbox_run make_int PRODUCE c +builtins.c:3790 builtin_sandbox_run make_int PRODUCE c +builtins.c:3802 builtin_sandbox_run make_int PRODUCE c +builtins.c:3816 builtin_sandbox_run make_int PRODUCE c +builtins.c:3850 builtin_sandbox_run make_int PRODUCE c +builtins.c:3876 builtin_record_history val_is_number TEST i +builtins.c:3882 builtin_record_history eigs_float_arg READ i +builtins.c:3889 builtin_record_history make_int PRODUCE i +builtins.c:3917 builtin_copy_into val_is_number TEST a +builtins.c:3935 builtin_copy_into val_is_number TEST a +builtins.c:3940 builtin_copy_into eigs_float_arg READ b +builtins.c:3975 builtin_list_slice val_is_number TEST a +builtins.c:3975 builtin_list_slice val_is_number TEST a +builtins.c:4002 builtin_num_copy val_is_number TEST a +builtins.c:4003 builtin_num_copy eigs_number_arg READ b +builtins.c:4035 range_bound eigs_int_arg_range READ b +builtins.c:4046 builtin_range val_is_number TEST a +builtins.c:4055 builtin_range val_is_number TEST a +builtins.c:4117 builtin_range make_int PRODUCE c +builtins.c:4155 at_index val_is_number TEST a +builtins.c:4175 buf_at_index val_is_number TEST a +builtins.c:4225 builtin_set_at val_is_number TEST a +builtins.c:4230 builtin_set_at eigs_float_arg READ b +builtins.c:4293 builtin_get_at buffer_read_f64 READ b +builtins.c:4293 builtin_get_at make_float PRODUCE c +builtins.c:4301 builtin_get_at buffer_read_f64 READ b +builtins.c:4301 builtin_get_at make_float PRODUCE c +builtins.c:4685 builtin_spawn make_int PRODUCE c +builtins.c:4691 builtin_spawn make_int PRODUCE c +builtins.c:4692 builtin_spawn make_int PRODUCE c +builtins.c:4717 builtin_thread_join val_is_number TEST a +builtins.c:4723 builtin_thread_join eigs_int_arg_range READ b +builtins.c:4723 builtin_thread_join val_is_number TEST a +builtins.c:4828 get_channel_why val_is_number TEST a +builtins.c:4832 get_channel_why eigs_int_arg_range READ b +builtins.c:4832 get_channel_why val_is_number TEST a +builtins.c:4898 builtin_channel make_int PRODUCE c +builtins.c:4899 builtin_channel make_int PRODUCE c +builtins.c:4998 builtin_recv_timeout val_is_number TEST a +builtins.c:5003 builtin_recv_timeout eigs_magnitude_arg READ b +builtins.c:5177 builtin_task_spawn make_int PRODUCE c +builtins.c:5187 task_handle_resolve val_is_number TEST a +builtins.c:5188 task_handle_resolve eigs_int_arg READ b +builtins.c:5242 builtin_task_join val_is_number TEST a +builtins.c:5243 builtin_task_join eigs_int_arg READ b +builtins.c:5289 builtin_task_send val_is_number TEST a +builtins.c:5293 builtin_task_send eigs_int_arg READ b +builtins.c:5321 builtin_task_kill val_is_number TEST a +builtins.c:5324 builtin_task_kill eigs_int_arg READ b +builtins.c:5334 builtin_task_alive val_is_number TEST a +builtins.c:5356 builtin_task_sleep val_is_number TEST a +builtins.c:5360 builtin_task_sleep eigs_float_arg READ b +builtins.c:5395 builtin_task_self make_int PRODUCE c +builtins.c:5409 builtin_task_detach val_is_number TEST a +builtins.c:5414 builtin_task_detach make_int PRODUCE c +builtins.c:5417 builtin_task_detach make_int PRODUCE c +builtins.c:5428 builtin_task_sched_seed val_is_number TEST a +builtins.c:5432 builtin_task_sched_seed eigs_int_arg READ b +builtins.c:5583 builtin_nearest_in_range eigs_list_float READ b +builtins.c:5584 builtin_nearest_in_range eigs_list_float READ b +builtins.c:5585 builtin_nearest_in_range eigs_list_float READ b +builtins.c:5586 builtin_nearest_in_range eigs_list_float READ b +builtins.c:5587 builtin_nearest_in_range eigs_list_float READ b +builtins.c:5644 builtin_nearest_in_range eigs_float_arg READ b +builtins.c:5644 builtin_nearest_in_range val_is_number TEST a +builtins.c:5668 builtin_nearest_in_range eigs_float_arg READ b +builtins.c:5671 builtin_nearest_in_range val_is_number TEST a +builtins.c:5671 builtin_nearest_in_range val_is_number TEST a +builtins.c:5673 builtin_nearest_in_range eigs_float_arg READ b +builtins.c:5674 builtin_nearest_in_range eigs_float_arg READ b +builtins.c:5689 builtin_nearest_in_range make_int PRODUCE c +builtins.c:5690 builtin_nearest_in_range make_float PRODUCE c +builtins.c:5691 builtin_nearest_in_range make_float PRODUCE c +builtins.c:5692 builtin_nearest_in_range make_float PRODUCE c +builtins.c:5717 builtin_nearest_in_range_all eigs_list_float READ b +builtins.c:5718 builtin_nearest_in_range_all eigs_list_float READ b +builtins.c:5719 builtin_nearest_in_range_all eigs_list_float READ b +builtins.c:5774 builtin_nearest_in_range_all eigs_float_arg READ b +builtins.c:5774 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5794 builtin_nearest_in_range_all eigs_float_arg READ b +builtins.c:5797 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5797 builtin_nearest_in_range_all val_is_number TEST a +builtins.c:5801 builtin_nearest_in_range_all eigs_float_arg READ b +builtins.c:5802 builtin_nearest_in_range_all eigs_float_arg READ b +builtins.c:5844 builtin_nearest_in_range_all make_int PRODUCE c +builtins.c:5845 builtin_nearest_in_range_all make_float PRODUCE c +builtins.c:5846 builtin_nearest_in_range_all make_float PRODUCE c +builtins.c:5847 builtin_nearest_in_range_all make_float PRODUCE c +builtins.c:5870 builtin_sign_extend make_float PRODUCE c +builtins.c:5872 builtin_sign_extend make_float PRODUCE c +builtins.c:5872 builtin_sign_extend val_is_number TEST a +builtins.c:5872 builtin_sign_extend val_is_number TEST a +builtins.c:5873 builtin_sign_extend eigs_list_int READ b +builtins.c:5874 builtin_sign_extend eigs_list_int READ b +builtins.c:5876 builtin_sign_extend make_int PRODUCE c +builtins.c:5883 builtin_sign_extend make_int PRODUCE c +builtins.c:5885 builtin_sign_extend make_int PRODUCE c +builtins.c:5902 builtin_list_truncate val_is_number TEST a +builtins.c:5933 builtin_list_remove_at val_is_number TEST a +builtins.c:5956 builtin_list_insert_at val_is_number TEST a +builtins.c:5985 builtin_list_index_of make_float PRODUCE f +builtins.c:5989 builtin_list_index_of make_float PRODUCE f +builtins.c:5995 builtin_list_index_of make_int PRODUCE f +builtins.c:5999 builtin_list_index_of make_int PRODUCE f +builtins.c:6070 builtin_sort_by val_is_number TEST f +builtins.c:6079 builtin_sort_by VAL_INT TEST f +builtins.c:6080 builtin_sort_by VAL_I64_RAW RAW f +builtins.c:6081 builtin_sort_by eigs_float_arg READ f +builtins.c:6103 sort_cmp_num VAL_INT TEST a +builtins.c:6103 sort_cmp_num VAL_INT TEST a +builtins.c:6104 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:6104 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:6104 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:6104 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:6105 sort_cmp_num VAL_INT TEST a +builtins.c:6106 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:6106 sort_cmp_num eigs_float_arg READ b +builtins.c:6109 sort_cmp_num VAL_INT TEST a +builtins.c:6110 sort_cmp_num VAL_I64_RAW RAW b +builtins.c:6110 sort_cmp_num eigs_float_arg READ b +builtins.c:6113 sort_cmp_num eigs_float_arg READ b +builtins.c:6113 sort_cmp_num eigs_float_arg READ b +builtins.c:6131 builtin_sort VAL_FLOAT TEST f +builtins.c:6131 builtin_sort VAL_INT TEST f +builtins.c:6132 builtin_sort val_is_number TEST f +builtins.c:6139 builtin_sort VAL_FLOAT TEST f +builtins.c:6139 builtin_sort VAL_INT TEST f +builtins.c:6160 builtin_dispatch val_is_number TEST a +builtins.c:6186 builtin_dispatch val_is_number TEST a +builtins.c:6268 builtin_dot make_float PRODUCE c +builtins.c:6271 builtin_dot make_float PRODUCE c +builtins.c:6276 builtin_dot buffer_read_f64 READ b +builtins.c:6278 builtin_dot buffer_read_f64 READ b +builtins.c:6280 builtin_dot num_guard GUARD c +builtins.c:6280 builtin_dot num_guard GUARD c +builtins.c:6282 builtin_dot make_float PRODUCE c builtins_buf.c:35 builtin_buffer VAL_FLOAT TEST a builtins_buf.c:35 builtin_buffer VAL_INT TEST a builtins_buf.c:36 builtin_buffer VAL_FLOAT TEST a @@ -1096,6 +1174,17 @@ builtins_host.c:1913 builtin_write_bytes VAL_INT TEST a builtins_host.c:1920 builtin_write_bytes eigs_slot_elem_byte READ b builtins_host.c:1922 builtin_write_bytes buffer_byte_at READ b builtins_host.c:1944 builtin_write_bytes make_int PRODUCE c +builtins_int.c:106 n9_pair eigs_int_arg_range READ b +builtins_int.c:107 n9_pair eigs_int_arg_range READ b +builtins_int.c:162 n9_width make_int PRODUCE c +builtins_int.c:163 n9_width make_int PRODUCE c +builtins_int.c:168 n9_width make_int PRODUCE c +builtins_int.c:169 n9_width make_int PRODUCE c +builtins_int.c:536 builtin_u64_compare make_int PRODUCE c +builtins_int.c:546 n9_unsigned_div make_int PRODUCE c +builtins_int.c:561 builtin_u64_to_string eigs_int_arg READ b +builtins_int.c:572 builtin_fround eigs_float_arg READ b +builtins_int.c:576 builtin_fround make_float PRODUCE c builtins_tensor.c:229 tensor_dims VAL_FLOAT TEST a builtins_tensor.c:229 tensor_dims VAL_INT TEST a builtins_tensor.c:257 #define FLAT_BAD VAL_FLOAT TEST a diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 5721d4075..55566efad 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -203,12 +203,12 @@ tree has: **Builtins.** The registration table is derived from the `env_set_local_owned(env, "name", make_builtin(fn))` lines plus the -`ext_names.h` X-lists. It holds 312 names after sync #5. The initial 311-name population was +`ext_names.h` X-lists. It holds 389 names after R1.6g (312 after sync #5). The initial 311-name population was calibrated against the runtime's own `eigenscript --api --json` (223 core + 88 extension = 311; equal in both directions). A builtin is numeric when a site is contained in its function, in a same-file function it calls or names as a value (a comparator, an op-table entry; closure depth 4), or in the shared formatter -or equality it calls. The current population is 233 numeric builtins (R1.6-S2), and §6 +or equality it calls. The current population is 310 numeric builtins (R1.6g N9), and §6 classifies every one. (The closure does not follow a call into another file, so a header helper that reads a number must itself be in the vocabulary for its callers to count: `buffer_read_byte` entered the @@ -1347,8 +1347,8 @@ column against the note both ways: a row's note says "continuous" exactly when its `q7` column is not `-`. Counts: geometry 9, bounded 13, magnitude 13. **Counts** (from the table below, checked by `tools/phase2_inventory.py`, -which prints them): 233 numeric builtins (including `set_exit_code`, R1.6-S2). By class: 37 -int-preserving, 57 float-producing, 86 int-requiring, 53 other. The decided Q1 moved 16 rows +which prints them): 310 numeric builtins (including N9, R1.6g). By class: 37 +int-preserving, 58 float-producing, 162 int-requiring, 53 other. The decided Q1 moved 16 rows from other to int-requiring (counts, byte values, handles, flags and selectors); `ppu_render_frame` is a new int-requiring row; design round 3 moved `buf_from_pcm16le` from float-producing to int-requiring (its inputs are @@ -1719,7 +1719,7 @@ The decided width family ([#1758 comment 6304880619](https://github.com/Inaugura `as u64` / `as i64` mapping the bit pattern. No width-family negation, shifts, division, remainder or power are added. - `fround`: `(double)(float)x`, converting an int first and returning a - float (JavaScript's `Math.fround`). Together these are 77 new builtins. + float (JavaScript's `Math.fround`). Together these are the 77 builtins added by R1.6g. --- @@ -2167,11 +2167,11 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: | R1.6g | N9's 77 new width-family builtins in `builtins_int.c`, Rust std oracle | +77 | `N9.wrapping`, `N9.checked-raises`, `N9.saturating`, `N9.unsigned-ops`, `N9.fround` | | R1.6z | Remaining bridge sites in runtime, containers, embed, trace, compiler and task; delete all 21 tokens and all helpers left without callers | none | mechanical: deletion compile and final full table | - The existing rows sum to 233. Ruling R1.6a-D1 added `read_text`, already + The pre-N9 rows sum to 233; R1.6g adds 77 for a total of 310. Ruling R1.6a-D1 added `read_text`, already present in the R1.6a start (`1fd4422c`) through main's #1841/#1668, to round c: the original plan's c=75 and total=231 became c=76 and total=232 at that import. Sync #5's R1.6-S2 adds main's `set_exit_code` to round c, - so the current counts are c=77 and total=233; `rm` had no table row and + so the pre-N9 counts became c=77 and total=233; `rm` had no table row and its deletion under R1.6-S1 does not change the counts. `tools/phase2_builtins.sh` derives and checks the sub-round by this rule. Every sub-round uses the table gate (§9.4); later builders add their completed round to diff --git a/tests/phase2/builtins/BAR.md b/tests/phase2/builtins/BAR.md index 271657bca..a3d72c8c8 100644 --- a/tests/phase2/builtins/BAR.md +++ b/tests/phase2/builtins/BAR.md @@ -32,13 +32,13 @@ chooses; `net_port`'s port line and its siblings print a predicate instead. **Sync #5, R1.6-S1/S2.** Main's `rm` deletion removes no table row: the number-reading bar never included it. R1.6-S2 adds main's `set_exit_code` as an int-requiring release-profile row in round c, closed by main #1909. -The current population is 233 rows and 235 cases, with round counts b 46, -c 77, d 53, e 38 and f 19 (b/f include R1.6b-D3's `http_post` correction). +The current population is 310 rows and 312 cases, with round counts b 46, +c 77, d 53, e 38, f 19 and g 77 (b/f include R1.6b-D3's `http_post` correction). The new `.branch` is an authorized addition recorded by SHA-256 under R1.6-S2 in `../builtins_changes.md`; existing frozen expectations stay fixed. ## Files -- `builtins.tsv`, 233 rows: `builtin file class loss q7 round closed_in +- `builtins.tsv`, 310 rows: `builtin file class loss q7 round closed_in profile hook stdin changes_vs_pre changes_vs_tag`. `make_table.py` writes it. Rows come from the §6 table, checked both ways against the inventory's `## Builtins` list, field by field. Both files and `src/` are extracted with @@ -48,7 +48,7 @@ R1.6-S2 in `../builtins_changes.md`; existing frozen expectations stay fixed. checkout's state; `EIGS_TREE` overrides it for the plants. `file` is the `src/*.c` file that defines the inventory's C function. `round` follows the plan's rule, and the counts are checked against b 46, c 77, d 53, e 38, - f 19 (R1.6b-D3 and R1.6-S2). The other columns: + f 19 and g 77 (R1.6b-D3, R1.6-S2 and R1.6g-D1). The other columns: - `closed_in` (ruling A2) and `profile` (A3) come from `rowmeta.tsv`; - `hook` (A4) and `stdin` (A5) list the hooks and the stdin fixtures of the row's cases, in case order. `-` means none, and stdin `-` is `/dev/null`; @@ -60,7 +60,7 @@ R1.6-S2 in `../builtins_changes.md`; existing frozen expectations stay fixed. original one. It is recorded as an observation and never checked, because the tag has no `num_type`, and `set_exit_code` also postdates the tag. - `rowmeta.tsv`: `builtin closed_in profile`, one line per table row. -- `cases.tsv`: `case builtin hook stdin`, 235 cases. A row's primary case is +- `cases.tsv`: `case builtin hook stdin`, 312 cases. A row's primary case is `builtins/`. A second case is `builtins/.

` and `TAG_BIN_

` (`P` is @@ -945,7 +945,7 @@ Each item is filed or closed with a reason (the out-of-scope ledger, 2026-10-20) scratch script, so R1.6a can run the same check on its matched builds). Total 144 -> 634 -> 687. At that R1.6a import, `rowmeta.tsv` and `cases.tsv` were declarations of 232 and 234 lines plus headers; - R1.6-S2's current populations are 233 and 235. + R1.6g's current populations are 310 and 312. - `run_probes.sh`: - The first version wrote stdout through a relative path after its `cd`, so every `.pre` and `.tag` held only `rc=0`. It writes an absolute path, @@ -1021,7 +1021,7 @@ Each item is filed or closed with a reason (the out-of-scope ledger, 2026-10-20) The following counts and transcripts describe the population at `1fd4422c`. They are retained as recorded, including the then-pending profile observations; they are not current checker results. Sync #5's S2 addition makes the current -table 233 rows (c 77) and its case files 235 each, as described above. +pre-N9 table 233 rows (c 77) and case files 235 each; R1.6g adds 77, as described above. Population, both directions, at `1fd4422c`: - §6's table equals the inventory's `## Builtins` list: 232 = 232, no name missing either way, and class/loss/q7 equal on every row. @@ -1054,3 +1054,15 @@ Columns: `closed_in` on 17 rows; profile release 207, server 21, db 3, zlib `read_text`'s `yes` in round c is against a `.pre` that predates #1841; see its derivation. + +## R1.6g N9 addition + +R1.6g-D1 and #1758 comment 6304880619 add 77 release-profile rows, sourced +from the N9 definitions in builtins_int.c: 76 int-requiring and fround +float-producing. The live table has 310 rows and 312 cases (release 285, +server 21, db 3, zlib 1). All new branches were captured from Rust std plus +the explicit operand/shape rulings BEFORE builtins_int.c existed; their exact +SHA-256 amendments are in builtins_changes.md. Existing frozen branches remain +unchanged. oracle/n9.rs, its input TSVs and verbatim stdout capture the Rust +arithmetic; the supplemental test_n9_contract pins double rounding and exact +zero-divisor messages. The one-time broader grid stays in the round artifacts. diff --git a/tests/phase2/builtins/make_table.py b/tests/phase2/builtins/make_table.py index 7ae195c2e..2388d2eba 100644 --- a/tests/phase2/builtins/make_table.py +++ b/tests/phase2/builtins/make_table.py @@ -331,7 +331,7 @@ def agg(b, kind): for kind, v in (("pre", vs_pre), ("tag", vs_tag)): tally[(r, kind, v)] = tally.get((r, kind, v), 0) + 1 - want = {"b": 46, "c": 77, "d": 53, "e": 38, "f": 19} # R1.6a-D1 read_text; R1.6b-D3 http_post LOSS; R1.6-S2 set_exit_code + want = {"b": 46, "c": 77, "d": 53, "e": 38, "f": 19, "g": 77} # R1.6a-D1 read_text; R1.6b-D3 http_post LOSS; R1.6-S2 set_exit_code if counts != want: fail.append("round counts %s, the plan says %s" % (counts, want)) if not rows or len(rows) != len(sec6): fail.append("examined=%d table=%d" % (len(rows), len(sec6))) if guard["guarded"] != guard["yes"] + guard["closed_in"] + guard["pending-profile"] + guard["vacuous"]: diff --git a/tests/phase2/builtins_landed.txt b/tests/phase2/builtins_landed.txt index da624bae6..2f6c05e7f 100644 --- a/tests/phase2/builtins_landed.txt +++ b/tests/phase2/builtins_landed.txt @@ -5,3 +5,4 @@ R1.6c R1.6d R1.6e R1.6f +R1.6g diff --git a/tools/strict_shape_contracts.json b/tools/strict_shape_contracts.json index 26421b22b..05378eefe 100644 --- a/tools/strict_shape_contracts.json +++ b/tools/strict_shape_contracts.json @@ -2925,5 +2925,1998 @@ "write_text" ], "disposition": "guarded" + }, + { + "function": "builtin_i8_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "f0bf42b49fcb4838067036dea5acf4576ae7cdd2b35f30780f3766a11ea52a1a" + ], + "source_sha256": { + "builtin_i8_wrapping_add": [ + "f0bf42b49fcb4838067036dea5acf4576ae7cdd2b35f30780f3766a11ea52a1a" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "8026918dd4ba0381e6e33b01fa846eed5efa48572800f87acb2003751ae6c5c6" + ], + "source_sha256": { + "builtin_i8_wrapping_sub": [ + "8026918dd4ba0381e6e33b01fa846eed5efa48572800f87acb2003751ae6c5c6" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "43fa370dfb97f7828a4a9c39aa24a1f3ab9e7636333375a58b9150edd05f9a82" + ], + "source_sha256": { + "builtin_i8_wrapping_mul": [ + "43fa370dfb97f7828a4a9c39aa24a1f3ab9e7636333375a58b9150edd05f9a82" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "227fa410a727991f1602d6da36a6a2fc219dac2c6ff88f50102b763b1f815d0e" + ], + "source_sha256": { + "builtin_i8_checked_add": [ + "227fa410a727991f1602d6da36a6a2fc219dac2c6ff88f50102b763b1f815d0e" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "50eb06dffb84c91e00a7b6bb822ccea67b566405acc79d271f59b1b5edecf6f5" + ], + "source_sha256": { + "builtin_i8_checked_sub": [ + "50eb06dffb84c91e00a7b6bb822ccea67b566405acc79d271f59b1b5edecf6f5" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "4e6a7d813177dee79e8e8fe10590687dfe3e91d92f14820ecfd743b7277a63f8" + ], + "source_sha256": { + "builtin_i8_checked_mul": [ + "4e6a7d813177dee79e8e8fe10590687dfe3e91d92f14820ecfd743b7277a63f8" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "c5fad38153cf30d940e918baccdb39238acd0317a9f4965712192a296a37a360" + ], + "source_sha256": { + "builtin_i8_saturating_add": [ + "c5fad38153cf30d940e918baccdb39238acd0317a9f4965712192a296a37a360" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "92fd15a3aba2630f4847fc391479a293adc259c149b6c3e7e69fd794875d69ee" + ], + "source_sha256": { + "builtin_i8_saturating_sub": [ + "92fd15a3aba2630f4847fc391479a293adc259c149b6c3e7e69fd794875d69ee" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i8_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i8_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "f72dea371eb1c4d5dde2315a3ade824dbcc547bccd0ba9a075b9a2f83bf8a183" + ], + "source_sha256": { + "builtin_i8_saturating_mul": [ + "f72dea371eb1c4d5dde2315a3ade824dbcc547bccd0ba9a075b9a2f83bf8a183" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "b4c0d2551c2b82f7a44751ff7931f910ec8875ecec915b3bf7cda80cecbe7b2a" + ], + "source_sha256": { + "builtin_i16_wrapping_add": [ + "b4c0d2551c2b82f7a44751ff7931f910ec8875ecec915b3bf7cda80cecbe7b2a" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "30f5404300e406a15df565aeb7917e71e9801ed98021885ac5b7bae605dff380" + ], + "source_sha256": { + "builtin_i16_wrapping_sub": [ + "30f5404300e406a15df565aeb7917e71e9801ed98021885ac5b7bae605dff380" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "2599cf06616a8329219619051d0a874a95d6bf36cfc72e1b2054799ef09a49fb" + ], + "source_sha256": { + "builtin_i16_wrapping_mul": [ + "2599cf06616a8329219619051d0a874a95d6bf36cfc72e1b2054799ef09a49fb" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "131258cdee5c6406329af7a6b846c804f5068a99ecf8d5c3ce5e819724ba2648" + ], + "source_sha256": { + "builtin_i16_checked_add": [ + "131258cdee5c6406329af7a6b846c804f5068a99ecf8d5c3ce5e819724ba2648" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "caefc26a1663a5d18ad3f31251a23f44c932d1fb7081761d3e23b6f77eac8c4e" + ], + "source_sha256": { + "builtin_i16_checked_sub": [ + "caefc26a1663a5d18ad3f31251a23f44c932d1fb7081761d3e23b6f77eac8c4e" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "ad1e105e8d1801670db2f0fa70e568202d8017ccf42f0c88ded6f3d0df01ff42" + ], + "source_sha256": { + "builtin_i16_checked_mul": [ + "ad1e105e8d1801670db2f0fa70e568202d8017ccf42f0c88ded6f3d0df01ff42" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "4a7a46a78a840fe4e8fd4d9a7e2589a93a406c64d7858540ff9712aa3408b473" + ], + "source_sha256": { + "builtin_i16_saturating_add": [ + "4a7a46a78a840fe4e8fd4d9a7e2589a93a406c64d7858540ff9712aa3408b473" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "2c77c5497b90bd1cebe0aa94d928bde0e8645a25064c9f07d134ea18ac5be787" + ], + "source_sha256": { + "builtin_i16_saturating_sub": [ + "2c77c5497b90bd1cebe0aa94d928bde0e8645a25064c9f07d134ea18ac5be787" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i16_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i16_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "1ecfedf4ed1f1c6c42e86a4442c73af60e00da64bbf3ad052995032da158a3ea" + ], + "source_sha256": { + "builtin_i16_saturating_mul": [ + "1ecfedf4ed1f1c6c42e86a4442c73af60e00da64bbf3ad052995032da158a3ea" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "fe73ffa477cb2b81534d5c9629554f714004bfef8634c12d19f288f20166c710" + ], + "source_sha256": { + "builtin_i32_wrapping_add": [ + "fe73ffa477cb2b81534d5c9629554f714004bfef8634c12d19f288f20166c710" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "f8b4d7ec37df1c7f8022aaa23887839f1fe3e358060ea2ebc5a0c2d086244d31" + ], + "source_sha256": { + "builtin_i32_wrapping_sub": [ + "f8b4d7ec37df1c7f8022aaa23887839f1fe3e358060ea2ebc5a0c2d086244d31" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "f1d59333384a34396d9e7c177e83d6c2ff87d5eb6de458edee770d053960e358" + ], + "source_sha256": { + "builtin_i32_wrapping_mul": [ + "f1d59333384a34396d9e7c177e83d6c2ff87d5eb6de458edee770d053960e358" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "ce6fb1239f24af2a80c46114256292b4450d147fa7aa102b0b9c580d74698376" + ], + "source_sha256": { + "builtin_i32_checked_add": [ + "ce6fb1239f24af2a80c46114256292b4450d147fa7aa102b0b9c580d74698376" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "bdc60ff804374d4d56e4520066c01717040075bb0eaaff9758861a450c84767a" + ], + "source_sha256": { + "builtin_i32_checked_sub": [ + "bdc60ff804374d4d56e4520066c01717040075bb0eaaff9758861a450c84767a" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "fff3ae6bf1fc4fdc37e58b0e4fc7e241a7bb77ad35cda37f1fde00077a850381" + ], + "source_sha256": { + "builtin_i32_checked_mul": [ + "fff3ae6bf1fc4fdc37e58b0e4fc7e241a7bb77ad35cda37f1fde00077a850381" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "60d0cd371afa2dbf1d9ebdcc0aa971f9ba21916254a98cf746f85766052a0c21" + ], + "source_sha256": { + "builtin_i32_saturating_add": [ + "60d0cd371afa2dbf1d9ebdcc0aa971f9ba21916254a98cf746f85766052a0c21" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "514b5e5c7f2c524643f0a5de5de6bfd20f8837fb5b0127c71d712cb8331ba047" + ], + "source_sha256": { + "builtin_i32_saturating_sub": [ + "514b5e5c7f2c524643f0a5de5de6bfd20f8837fb5b0127c71d712cb8331ba047" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i32_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i32_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "19fc530a73dfda8cccc698ed6e6cba38d063ffd4282ecd8a6237a1051019d9a8" + ], + "source_sha256": { + "builtin_i32_saturating_mul": [ + "19fc530a73dfda8cccc698ed6e6cba38d063ffd4282ecd8a6237a1051019d9a8" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "990fe34099f92dfac167e12c7d52f96b689299897a2702b0ea8d0c056c5fe4ba" + ], + "source_sha256": { + "builtin_i64_wrapping_add": [ + "990fe34099f92dfac167e12c7d52f96b689299897a2702b0ea8d0c056c5fe4ba" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "dfdaa9258176fe228de9190324338db1f8f796192d05d980e7bd384f70564280" + ], + "source_sha256": { + "builtin_i64_wrapping_sub": [ + "dfdaa9258176fe228de9190324338db1f8f796192d05d980e7bd384f70564280" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "20b44c05e8c7e64aa0edc390ba555bf8e0b727cf15fe93b989e4f26b06e59d4d" + ], + "source_sha256": { + "builtin_i64_wrapping_mul": [ + "20b44c05e8c7e64aa0edc390ba555bf8e0b727cf15fe93b989e4f26b06e59d4d" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "38dd3ae48ac6863d8ca35aa31750800dd2e18a4a93be1e60c51015f63a15c9ac" + ], + "source_sha256": { + "builtin_i64_checked_add": [ + "38dd3ae48ac6863d8ca35aa31750800dd2e18a4a93be1e60c51015f63a15c9ac" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "f2dd5a133e73e8090f4afd2c2f69332f897e9182aa8819587a7284bd02db1fff" + ], + "source_sha256": { + "builtin_i64_checked_sub": [ + "f2dd5a133e73e8090f4afd2c2f69332f897e9182aa8819587a7284bd02db1fff" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "d15851d2c5a2af48582a01ede31f5aea3d774641887991f3c6b60678f854b22f" + ], + "source_sha256": { + "builtin_i64_checked_mul": [ + "d15851d2c5a2af48582a01ede31f5aea3d774641887991f3c6b60678f854b22f" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "1692c8e134735a7a201f35975087fcc2ed72a08b4ecd56f38c4e207be2112876" + ], + "source_sha256": { + "builtin_i64_saturating_add": [ + "1692c8e134735a7a201f35975087fcc2ed72a08b4ecd56f38c4e207be2112876" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "2b02e019530ac6b57c0eb155a45dee57f85a4df5fcb2137a0f1f7de7f4dda1f5" + ], + "source_sha256": { + "builtin_i64_saturating_sub": [ + "2b02e019530ac6b57c0eb155a45dee57f85a4df5fcb2137a0f1f7de7f4dda1f5" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_i64_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "i64_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "24da3c405047ca6e5ced53171b4889d12cfa38c6698faf70187b4fc521567ce3" + ], + "source_sha256": { + "builtin_i64_saturating_mul": [ + "24da3c405047ca6e5ced53171b4889d12cfa38c6698faf70187b4fc521567ce3" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "5b76dc930f2eb9b201e1b3ee5066b5e99ebc723c9c2c4807ebf21cfe56bd4dfe" + ], + "source_sha256": { + "builtin_u8_wrapping_add": [ + "5b76dc930f2eb9b201e1b3ee5066b5e99ebc723c9c2c4807ebf21cfe56bd4dfe" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "a4882b2a0b5224f2c15a4c6957a051368295f4acd87017e0520329b4937843b2" + ], + "source_sha256": { + "builtin_u8_wrapping_sub": [ + "a4882b2a0b5224f2c15a4c6957a051368295f4acd87017e0520329b4937843b2" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "4ca7cc1cf9ac68c602fea973effcd03db5786bc7675859a14bcfe72c2a4e15c0" + ], + "source_sha256": { + "builtin_u8_wrapping_mul": [ + "4ca7cc1cf9ac68c602fea973effcd03db5786bc7675859a14bcfe72c2a4e15c0" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "eb97c3bd29938ee18026db2dbe391e60947ed16ceca99dad6850162369dc5a56" + ], + "source_sha256": { + "builtin_u8_checked_add": [ + "eb97c3bd29938ee18026db2dbe391e60947ed16ceca99dad6850162369dc5a56" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "cbbdcdafa71f04ea354f051059f753a42b3ebf078833ff456a2a031e46efe038" + ], + "source_sha256": { + "builtin_u8_checked_sub": [ + "cbbdcdafa71f04ea354f051059f753a42b3ebf078833ff456a2a031e46efe038" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "21eee924ace0310f985be7bc38a2c26136ade5852c6533dc51124c28d767e78c" + ], + "source_sha256": { + "builtin_u8_checked_mul": [ + "21eee924ace0310f985be7bc38a2c26136ade5852c6533dc51124c28d767e78c" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "1e6615858e79ca93f8c3a2e54c633a8aa6a55a3516970ba6e7cdaa57799e9d77" + ], + "source_sha256": { + "builtin_u8_saturating_add": [ + "1e6615858e79ca93f8c3a2e54c633a8aa6a55a3516970ba6e7cdaa57799e9d77" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "ad1f10a6bed3c64ac259da7fe5c64b1d69ad7ffef340d61bd29372c773f9f1e4" + ], + "source_sha256": { + "builtin_u8_saturating_sub": [ + "ad1f10a6bed3c64ac259da7fe5c64b1d69ad7ffef340d61bd29372c773f9f1e4" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u8_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u8_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "169b971b1408165d9f9773dfb6ff96ef29909143a64cd92e22cd9f95f55c4aea" + ], + "source_sha256": { + "builtin_u8_saturating_mul": [ + "169b971b1408165d9f9773dfb6ff96ef29909143a64cd92e22cd9f95f55c4aea" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "b9a5bf400e14f6ae7767196295adf9adfe878d1f14e383cc2ce68b85a2953270" + ], + "source_sha256": { + "builtin_u16_wrapping_add": [ + "b9a5bf400e14f6ae7767196295adf9adfe878d1f14e383cc2ce68b85a2953270" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "fd4acd5aad52054ebedd5bcaabb5572e693f251ff2b8697dbe15672b87caf676" + ], + "source_sha256": { + "builtin_u16_wrapping_sub": [ + "fd4acd5aad52054ebedd5bcaabb5572e693f251ff2b8697dbe15672b87caf676" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "2334a24239ecb604f4e7a96a7ba274ec49c5f18349c5b5f6000404c731d72205" + ], + "source_sha256": { + "builtin_u16_wrapping_mul": [ + "2334a24239ecb604f4e7a96a7ba274ec49c5f18349c5b5f6000404c731d72205" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "f305d1275c5a5f0a8344a61cca8b4c279b13f22a298a7dd7c6515c6673e74127" + ], + "source_sha256": { + "builtin_u16_checked_add": [ + "f305d1275c5a5f0a8344a61cca8b4c279b13f22a298a7dd7c6515c6673e74127" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "a55aaa8ab469c28044db653ce97afed2c760114d316001be7630d94b432710fb" + ], + "source_sha256": { + "builtin_u16_checked_sub": [ + "a55aaa8ab469c28044db653ce97afed2c760114d316001be7630d94b432710fb" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "5874c8a1d91a634c42a27464065c168839c2c3f9c3c152cc77960296b0c054fd" + ], + "source_sha256": { + "builtin_u16_checked_mul": [ + "5874c8a1d91a634c42a27464065c168839c2c3f9c3c152cc77960296b0c054fd" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "e07518c885e707ae403088b4a23613ac4382d6a3a89a07c55a3de872c08ac427" + ], + "source_sha256": { + "builtin_u16_saturating_add": [ + "e07518c885e707ae403088b4a23613ac4382d6a3a89a07c55a3de872c08ac427" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "3009ceb0109e10377622bdd3177b56d7212b6455a0b9a2171819d850a85adcf9" + ], + "source_sha256": { + "builtin_u16_saturating_sub": [ + "3009ceb0109e10377622bdd3177b56d7212b6455a0b9a2171819d850a85adcf9" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u16_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u16_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "b893ab12e5ce3e543a4cd51448c0654a05ae21788ed6e04d8eaeb2683656ca8d" + ], + "source_sha256": { + "builtin_u16_saturating_mul": [ + "b893ab12e5ce3e543a4cd51448c0654a05ae21788ed6e04d8eaeb2683656ca8d" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "418ce01e4aa3fcf68db140c59314c12de0cabdf22d2b1911af326a5811d0e462" + ], + "source_sha256": { + "builtin_u32_wrapping_add": [ + "418ce01e4aa3fcf68db140c59314c12de0cabdf22d2b1911af326a5811d0e462" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "9b1e12bf124906579c8ad597e1ceabd467e44f67bb8476b723fc126ba53be4f0" + ], + "source_sha256": { + "builtin_u32_wrapping_sub": [ + "9b1e12bf124906579c8ad597e1ceabd467e44f67bb8476b723fc126ba53be4f0" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "4beaf65ed241acf17a3a312ff30680aa613fc1c0991b6502610440c9476cff59" + ], + "source_sha256": { + "builtin_u32_wrapping_mul": [ + "4beaf65ed241acf17a3a312ff30680aa613fc1c0991b6502610440c9476cff59" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "bbb7069dbe9687428090973817224ae65214a388f12b93a8b713158f608bd844" + ], + "source_sha256": { + "builtin_u32_checked_add": [ + "bbb7069dbe9687428090973817224ae65214a388f12b93a8b713158f608bd844" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "bc590d814b9b07d572bf3c92b6822cdca431b3cc5037722215775a7df96b2496" + ], + "source_sha256": { + "builtin_u32_checked_sub": [ + "bc590d814b9b07d572bf3c92b6822cdca431b3cc5037722215775a7df96b2496" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "4f3b7267edf676990388045b5f4f142891ac19ae77962e8c13240489f73b5e54" + ], + "source_sha256": { + "builtin_u32_checked_mul": [ + "4f3b7267edf676990388045b5f4f142891ac19ae77962e8c13240489f73b5e54" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "8a3e85fded0e51e4aac6221b358745624b56608c52da3c26e81c2857bdafc25e" + ], + "source_sha256": { + "builtin_u32_saturating_add": [ + "8a3e85fded0e51e4aac6221b358745624b56608c52da3c26e81c2857bdafc25e" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "f54998022452ce28bc262059ff34ff3702da8818094ee2110579d68252135b58" + ], + "source_sha256": { + "builtin_u32_saturating_sub": [ + "f54998022452ce28bc262059ff34ff3702da8818094ee2110579d68252135b58" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u32_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u32_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "6b28a2182a4ef7021add5a53bcfa9b778b5b5a879fad7b06100cdbb011e7a318" + ], + "source_sha256": { + "builtin_u32_saturating_mul": [ + "6b28a2182a4ef7021add5a53bcfa9b778b5b5a879fad7b06100cdbb011e7a318" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_wrapping_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_wrapping_add" + ], + "disposition": "exempt", + "body_sha256": [ + "b2446b4af754eb06ae9436e2335147c619fa037753c0f00842a3884aa7c27a53" + ], + "source_sha256": { + "builtin_u64_wrapping_add": [ + "b2446b4af754eb06ae9436e2335147c619fa037753c0f00842a3884aa7c27a53" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_wrapping_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_wrapping_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "1fe33ce02eacb0e812362ada8ea560cf6661d58d268e78f3aa1e3b342d125f09" + ], + "source_sha256": { + "builtin_u64_wrapping_sub": [ + "1fe33ce02eacb0e812362ada8ea560cf6661d58d268e78f3aa1e3b342d125f09" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_wrapping_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_wrapping_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "4655b0ec9f0c3ca1c9fa855a9b125c7e8e9f8b31d93f7ac6b1a387bdf2a01956" + ], + "source_sha256": { + "builtin_u64_wrapping_mul": [ + "4655b0ec9f0c3ca1c9fa855a9b125c7e8e9f8b31d93f7ac6b1a387bdf2a01956" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_checked_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_checked_add" + ], + "disposition": "exempt", + "body_sha256": [ + "41ff97af2e97f25be01460129b9891ecf1f03e6de52e0b7f62707b66feab6fe8" + ], + "source_sha256": { + "builtin_u64_checked_add": [ + "41ff97af2e97f25be01460129b9891ecf1f03e6de52e0b7f62707b66feab6fe8" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_checked_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_checked_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "685f433cd6116baafca3faf7377a5198144153d5188ddb41f373509bb88beff9" + ], + "source_sha256": { + "builtin_u64_checked_sub": [ + "685f433cd6116baafca3faf7377a5198144153d5188ddb41f373509bb88beff9" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_checked_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_checked_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "410a1c5a01c8374ffc06c8a97a16dc524e3767487bb2f64a996e968391f74b51" + ], + "source_sha256": { + "builtin_u64_checked_mul": [ + "410a1c5a01c8374ffc06c8a97a16dc524e3767487bb2f64a996e968391f74b51" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_saturating_add", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_saturating_add" + ], + "disposition": "exempt", + "body_sha256": [ + "144489654dd2e30cb06f8b45e7a26066f2b6faa67d52d24f06cb26181c59fe9c" + ], + "source_sha256": { + "builtin_u64_saturating_add": [ + "144489654dd2e30cb06f8b45e7a26066f2b6faa67d52d24f06cb26181c59fe9c" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_saturating_sub", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_saturating_sub" + ], + "disposition": "exempt", + "body_sha256": [ + "128f0d2fa75454709f64056b253ca7fcbcb9588e5709b1888ee0a6f97fddfafc" + ], + "source_sha256": { + "builtin_u64_saturating_sub": [ + "128f0d2fa75454709f64056b253ca7fcbcb9588e5709b1888ee0a6f97fddfafc" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_saturating_mul", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_saturating_mul" + ], + "disposition": "exempt", + "body_sha256": [ + "49c8d514be2a32a27e51f9b6f5af15c8d7223f498d9831821bd50fa7b026b0ae" + ], + "source_sha256": { + "builtin_u64_saturating_mul": [ + "49c8d514be2a32a27e51f9b6f5af15c8d7223f498d9831821bd50fa7b026b0ae" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_width": [ + "617d873a423493135c72077abd3ffe38796e72959b910fa7b13b703c8e4fc02c" + ] + } + }, + { + "function": "builtin_u64_compare", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_compare" + ], + "disposition": "exempt", + "body_sha256": [ + "f16184f6838ba4735de015f97583f0ce4588a446296820e32eb75fe60b61ea58" + ], + "source_sha256": { + "builtin_u64_compare": [ + "f16184f6838ba4735de015f97583f0ce4588a446296820e32eb75fe60b61ea58" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ] + } + }, + { + "function": "builtin_u64_div", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_div" + ], + "disposition": "exempt", + "body_sha256": [ + "44b8d1cdfd55ee9f3779e18b22df0da19e583e76ac63e42325cae9282b809ac3" + ], + "source_sha256": { + "builtin_u64_div": [ + "44b8d1cdfd55ee9f3779e18b22df0da19e583e76ac63e42325cae9282b809ac3" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_unsigned_div": [ + "51c36fc72631106fa40637fb36b3598cc95ded63edd8198b452a66d235188cf7" + ] + } + }, + { + "function": "builtin_u64_rem", + "file": "src/builtins_int.c", + "category": "fixed", + "minimum": 2, + "maximum": 2, + "reason": "N9 R1.6g-D1: shared n9_pair unconditionally refuses surplus and missing binary operands before N5/range reads; both strict modes are covered by frozen probes and Rust differential.", + "public_names": [ + "u64_rem" + ], + "disposition": "exempt", + "body_sha256": [ + "6e4e24ae90c92c5bb123c3cce46f0048ba6047b27cc3fe115f635ad03982f319" + ], + "source_sha256": { + "builtin_u64_rem": [ + "6e4e24ae90c92c5bb123c3cce46f0048ba6047b27cc3fe115f635ad03982f319" + ], + "n9_pair": [ + "f09c77e4a13a694f4102cf084feadbb152214d0e98211317fedc8f7e814941cd" + ], + "n9_unsigned_div": [ + "51c36fc72631106fa40637fb36b3598cc95ded63edd8198b452a66d235188cf7" + ] + } + }, + { + "function": "builtin_u64_to_string", + "file": "src/builtins_int.c", + "category": "unary", + "minimum": 1, + "maximum": 1, + "reason": "N9 R1.6g-D1: scalar unary reader with one-element list unwrap; every other list is a non-number and raises in both strict modes.", + "public_names": [ + "u64_to_string" + ], + "disposition": "exempt", + "body_sha256": [ + "a24cc8bdd026992ab71b5ebcd3a8c6f9d7e2146fced994713fbc4996b1c2f745" + ], + "source_sha256": { + "builtin_u64_to_string": [ + "a24cc8bdd026992ab71b5ebcd3a8c6f9d7e2146fced994713fbc4996b1c2f745" + ], + "eigs_int_arg": [ + "edf4be05d4866ca3b2d0b9292b4f38e721050e3690882351b4c7d5bc4a082875" + ] + } + }, + { + "function": "builtin_fround", + "file": "src/builtins_int.c", + "category": "unary", + "minimum": 1, + "maximum": 1, + "reason": "N9 R1.6g-D1: scalar unary reader with one-element list unwrap; every other list is a non-number and raises in both strict modes.", + "public_names": [ + "fround" + ], + "disposition": "exempt", + "body_sha256": [ + "a3cffe3635ebeadf8d5935376148d278cd1182a71374c1bdab4b1d34361a2155" + ], + "source_sha256": { + "builtin_fround": [ + "a3cffe3635ebeadf8d5935376148d278cd1182a71374c1bdab4b1d34361a2155" + ], + "eigs_float_arg": [ + "a7e89d349dba6639b4b9a2c4242dd52f48c495a3ff52c021a2a85e3d2fb8a63a" + ] + } } ] From 2ccc77fde812b88171a2002534bdacbf73529630 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 03:35:09 -0500 Subject: [PATCH 166/188] test(numbers): declare R1.6g's builtin-registration cost on ten rows The cost gate stopped on ten rows, each +0.02 to +0.7 points over its bound, on workloads that call no N9 builtin. Measured against pre-R1.6g 59d6bb70 (drivers/cost_component.py), the R1.6g component is a constant per workload family: +200K Ir for the simple loops, +412K for bench_perf, +685K for the conservative loops, so a fixed cost per global-environment creation rather than per-iteration work. A per-function cg_annotate diff places it in eager builtin registration (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild) for 77 more builtins. Each row is re-declared by ceil(delta+0.2, 0.1), with its component in the reason column; the cost gate re-runs fresh. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/cost_expect.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt index 4b9e3c0a6..7427c270a 100644 --- a/tests/phase2/cost_expect.txt +++ b/tests/phase2/cost_expect.txt @@ -1,20 +1,20 @@ bench/alloc_heavy.eigs jit 50.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +64.3% (range-int control, measured at R1.3, against +64.0%) until R5; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8199903452, R1.4 Ir=8415252793, measured main delta=+68.4121%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range and hot len int results recover part of the existing generic mixed-operand/Value API cost; banked R1.6a Ir=8428313595, current Ir=7486166749, main Ir=4996461973, main delta=+49.82935504%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers bench/alloc_heavy.eigs off 29.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8229622729, R1.4 Ir=8442823382, measured main delta=+44.6791%, bound=ceil(delta+0.2,0.1); R1.6a remeasurement of the inherited main-sync short-string layout component (4ac31e67 to 1fd4422c): controls attribute +8000006 Ir to __strlen_sse2 with unchanged hot VM/allocation counts; untouched 1fd control Ir=8457703595 versus main Ir=5835080986 (+44.945779%, already above old max44.9), same-alias candidate versus 1fd +0.00188828%; current native-tool measurement main Ir=5835080986, candidate Ir=8457872415, delta=+44.948672%; bound=ceil(delta+0.2,0.1), retaining R5 recovery of the existing generic interpreter int cost, no new reader allowance; R1.6b measured component: N3 range and hot len int results recover part of the existing generic mixed-operand/Value API cost; banked R1.6a Ir=8457872415, current Ir=7514744462, main Ir=5835072842, main delta=+28.78578666%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/conservative_observed_loop.eigs jit 26.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=80746036, current Ir=99538839, main Ir=79049516, main delta=+25.91960588%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/conservative_observed_loop.eigs off 22.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.7% (range-int control, measured at R1.3, against +1.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=95920891, current Ir=115593684, main Ir=94884432, main delta=+21.82576379%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/conservative_unobserved_loop.eigs jit 32.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.6% (range-int control, measured at R1.3, against +2.7%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=64506354, current Ir=83299237, main Ir=62814824, main delta=+32.61079423%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/conservative_unobserved_loop.eigs off 26.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +26.1% (range-int control, measured at R1.3, against +1.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=79846282, current Ir=99519057, main Ir=78869757, main delta=+26.18151847%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers +bench/conservative_observed_loop.eigs jit 27 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=80746036, current Ir=99538839, main Ir=79049516, main delta=+25.91960588%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685683 Ir (0.867 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.2 -> 27 by ceil(delta+0.2, 0.1) +bench/conservative_observed_loop.eigs off 22.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.7% (range-int control, measured at R1.3, against +1.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=95920891, current Ir=115593684, main Ir=94884432, main delta=+21.82576379%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685036 Ir (0.722 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 22.1 -> 22.7 by ceil(delta+0.2, 0.1) +bench/conservative_unobserved_loop.eigs jit 33.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.6% (range-int control, measured at R1.3, against +2.7%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=64506354, current Ir=83299237, main Ir=62814824, main delta=+32.61079423%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685660 Ir (1.092 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 32.9 -> 33.9 by ceil(delta+0.2, 0.1) +bench/conservative_unobserved_loop.eigs off 27.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +26.1% (range-int control, measured at R1.3, against +1.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=79846282, current Ir=99519057, main Ir=78869757, main delta=+26.18151847%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685769 Ir (0.869 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.4 -> 27.2 by ceil(delta+0.2, 0.1) bench/dict_ops.eigs jit 22.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +22.1% (range-int control, measured at R1.3, against +0.7%) until R5; R1.6b measured component: N3 range int production activates generic Value API/dictionary int paths, as the pre-registered range-int control predicts; banked R1.6a Ir=109524332, current Ir=132542922, main Ir=108597020, main delta=+22.05023858%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers bench/dict_ops.eigs off 21.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.4% (range-int control, measured at R1.3, against +0.7%) until R5; R1.6b measured component: N3 range int production activates generic Value API/dictionary int paths, as the pre-registered range-int control predicts; banked R1.6a Ir=113283097, current Ir=136386349, main Ir=112435644, main delta=+21.30170126%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/observed_loop.eigs jit 47.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44850891, current Ir=63643989, main Ir=43104945, main delta=+47.64892752%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers +bench/observed_loop.eigs jit 48.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44850891, current Ir=63643989, main Ir=43104945, main delta=+47.64892752%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200959 Ir (0.466 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 47.9 -> 48.2 by ceil(delta+0.2, 0.1) bench/observed_loop.eigs off 33.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=62500796, current Ir=82173713, main Ir=61524518, main delta=+33.56254656%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/scalar_loop.eigs jit 88.7 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone removes 57.8% of this excess (range-int control, measured at R1.3: +88.6% against +210.1%), R5 the rest; merge of 94657581 component (#1171): env_store_slot bumps the assign-count inside its hold, so the branch's interpreted int stores pay +424,992 Ir there against -225,073 in vm_run_ex (CAND +200,055 Ir, +0.20%) while main's JIT-compiled loop moves BASE -9,041; measured +210.10% at R1.3, +210.81% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=99738384, R1.4 Ir=99697847, measured main delta=+210.5725%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=99747054, current Ir=60503359, main Ir=32101836, main delta=+88.47320446%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/scalar_loop.eigs off 43.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone removes 66.0% of this excess (range-int control, measured at R1.3: +43.1% against +126.8%), R5 the rest; merge of 94657581 component (#1171): env_store_slot +599,992 Ir (the assign-count bump moved inside its hold) against vm_run_ex -400,073 on the branch (CAND +200,037, +0.19%), while on main the same move saves (vm_run_ex -480,053, env_store_slot +399,995: BASE -78,939, -0.17%); measured +126.81% at R1.3, +127.64% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=104109956, R1.4 Ir=104069767, measured main delta=+127.3221%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=104118664, current Ir=65469785, main Ir=45780746, main delta=+43.00724807%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/string_build.eigs jit 29.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.2% (range-int control, measured at R1.3, against +9.9%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=82669260, R1.4 Ir=83813773, measured main delta=+11.3960%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range-produced ints activate integer MOD and its non-pooled result allocation (the prior float-MOD component above is historical); banked R1.6a Ir=83852414, current Ir=97041191, main Ir=75239767, main delta=+28.97593237%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers +bench/scalar_loop.eigs jit 89.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone removes 57.8% of this excess (range-int control, measured at R1.3: +88.6% against +210.1%), R5 the rest; merge of 94657581 component (#1171): env_store_slot bumps the assign-count inside its hold, so the branch's interpreted int stores pay +424,992 Ir there against -225,073 in vm_run_ex (CAND +200,055 Ir, +0.20%) while main's JIT-compiled loop moves BASE -9,041; measured +210.10% at R1.3, +210.81% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=99738384, R1.4 Ir=99697847, measured main delta=+210.5725%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=99747054, current Ir=60503359, main Ir=32101836, main delta=+88.47320446%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200647 Ir (0.625 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 88.7 -> 89.3 by ceil(delta+0.2, 0.1) +bench/scalar_loop.eigs off 43.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone removes 66.0% of this excess (range-int control, measured at R1.3: +43.1% against +126.8%), R5 the rest; merge of 94657581 component (#1171): env_store_slot +599,992 Ir (the assign-count bump moved inside its hold) against vm_run_ex -400,073 on the branch (CAND +200,037, +0.19%), while on main the same move saves (vm_run_ex -480,053, env_store_slot +399,995: BASE -78,939, -0.17%); measured +126.81% at R1.3, +127.64% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=104109956, R1.4 Ir=104069767, measured main delta=+127.3221%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=104118664, current Ir=65469785, main Ir=45780746, main delta=+43.00724807%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200664 Ir (0.439 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 43.3 -> 43.7 by ceil(delta+0.2, 0.1) +bench/string_build.eigs jit 29.5 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.2% (range-int control, measured at R1.3, against +9.9%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=82669260, R1.4 Ir=83813773, measured main delta=+11.3960%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range-produced ints activate integer MOD and its non-pooled result allocation (the prior float-MOD component above is historical); banked R1.6a Ir=83852414, current Ir=97041191, main Ir=75239767, main delta=+28.97593237%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +199849 Ir (0.266 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 29.2 -> 29.5 by ceil(delta+0.2, 0.1) bench/string_build.eigs off 27.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +23.5% (range-int control, measured at R1.3, against +8.5%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=85095023, R1.4 Ir=86239916, measured main delta=+9.9831%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range-produced ints activate integer MOD and its non-pooled result allocation (the prior float-MOD component above is historical); banked R1.6a Ir=86278206, current Ir=99686896, main Ir=78411840, main delta=+27.13245347%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers bench/unobserved_armed_loop.eigs jit 66.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths bench/unobserved_armed_loop.eigs off 9.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +3,000,000 Ir on both trees (600,000 stores; the assign-count bump moved inside its hold), which saves 2,400,031 in the branch's vm_run_ex (CAND +600,065, +0.06%) but 4,800,031 in main's (BASE -1,798,626, -0.21%); measured +8.85% at R1.3, +9.15% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=930827459, R1.4 Ir=928427649, measured main delta=+8.7891%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM code-generation component (this workload has no bitwise ops): vm_run_ex +1799999 Ir; R5 interpreter int/slot fast paths must recover this off-tier cost; fresh2d6587ee control Ir=929028193, R1.5 Ir=930826815, measured main delta=+9.0703%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 853419139->853412688 (-0.001%), candidate Ir 930826815->928420991 (-0.258%): the candidate got cheaper; main delta=+8.7892%; bound=ceil(delta+0.2,0.1) -bench/unobserved_loop.eigs jit 47.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44857870, current Ir=63651013, main Ir=43111802, main delta=+47.64173625%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers +bench/unobserved_loop.eigs jit 48.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44857870, current Ir=63651013, main Ir=43111802, main delta=+47.64173625%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200945 Ir (0.466 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 47.9 -> 48.2 by ceil(delta+0.2, 0.1) bench/unobserved_loop.eigs off 33.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=62507730, current Ir=82180474, main Ir=61531677, main delta=+33.55799485%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers tests/bench_buf_mix.eigs jit 312.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=2997588303, R1.4 Ir=3102110794, measured main delta=+311.4903%, bound=ceil(delta+0.2,0.1); R1.6d measured component: default interp benchmark ends with buf_peak scanning 441000 cells; buffer_read_num -> buffer_read_f64 adds finite-data validation, measured peak+reader Ir +7938000 (18/cell); fresh4e77a9de control Ir=3103006291, R1.6d Ir=3110933042, net candidate increase +7926751 Ir (residual -11249 Ir in startup/argument checks); main88a1c911 Ir=753849828, main delta=+312.67277997%, bound=ceil(delta+0.2,0.1); R5 retains int VM/Value API recovery with required finite refusal preserved tests/bench_buf_mix.eigs off 98.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=3014239251, R1.4 Ir=3118762031, measured main delta=+96.9936%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 1583179368->1576132391 (-0.445%), candidate Ir 3118762031->3118770881 (+0.000%): main sped up on this bench and the merged candidate did not share it; main delta=+97.8749%; bound=ceil(delta+0.2,0.1); R1.6d measured component: default interp benchmark ends with buf_peak scanning 441000 cells; buffer_read_num -> buffer_read_f64 adds finite-data validation, measured peak+reader Ir +7938000 (18/cell); fresh4e77a9de control Ir=3119656760, R1.6d Ir=3127584374, net candidate increase +7927614 Ir (residual -10386 Ir in startup/argument checks); main88a1c911 Ir=1576130830, main delta=+98.43431233%, bound=ceil(delta+0.2,0.1); R5 retains int VM/Value API recovery with required finite refusal preserved @@ -27,4 +27,4 @@ tests/bench_idxset.eigs off 127.8 R5 design §3: interpreted int arithmetic take tests/bench_pcm_codec.eigs jit 376.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39010338030, measured main delta=+376.5029%, bound=ceil(delta+0.2,0.1) tests/bench_pcm_codec.eigs off 98.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +74,400,025 Ir against vm_run_ex -63,600,434 on the branch (CAND +10,800,129, +0.03%), while on main the same move saves (vm_run_ex -92,400,393, env_store_slot +66,000,030: BASE -26,400,939, -0.13%); measured +89.39% at R1.3, +89.70% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39192628174, measured main delta=+97.5413%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 19840219829->19771919441 (-0.344%), candidate Ir 39192628174->39195119849 (+0.006%): main sped up on this bench and the merged candidate did not share it; main delta=+98.2363%; bound=ceil(delta+0.2,0.1) tests/bench_perf.eigs jit 32.6 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.4% (range-int control, measured at R1.3, against +15.7%) until R5; R1.6b measured component: N3 range-produced ints activate generic integer arithmetic/Value API paths, as the pre-registered range-int control predicts; banked R1.6a Ir=297793217, current Ir=340827242, main Ir=257477918, main delta=+32.37144554%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -tests/bench_perf.eigs off 18.9 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +18.7% (range-int control, measured at R1.3, against +5.4%) until R5; R1.6b measured component: N3 range-produced ints activate generic integer arithmetic/Value API paths, as the pre-registered range-int control predicts; banked R1.6a Ir=309974276, current Ir=349154039, main Ir=294194185, main delta=+18.68148889%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers +tests/bench_perf.eigs off 19.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +18.7% (range-int control, measured at R1.3, against +5.4%) until R5; R1.6b measured component: N3 range-produced ints activate generic integer arithmetic/Value API paths, as the pre-registered range-int control predicts; banked R1.6a Ir=309974276, current Ir=349154039, main Ir=294194185, main delta=+18.68148889%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +412584 Ir (0.140 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 18.9 -> 19.2 by ceil(delta+0.2, 0.1) From 0f4e7ddb6ae23e477c58a91ab1d0477ef59fd093 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 04:00:22 -0500 Subject: [PATCH 167/188] phase2: move the core-TU pin for builtins_int.c; fit one cost row to both gates (#1758) R1.6g's full lane went red on two gate-maintenance items: - tools/core_ext_boundary_selftest.sh pins the clean population at 28 core TUs. R1.6g's new src/builtins_int.c makes it 29, the only core TU added since 59d6bb70, so the pin moves in the same kind of change. --selftest: PASS. - CI's bench gate (bench/check_regression.sh, the same jit rows) measured conservative_observed_loop +27.047% on the runner, against the bound of 27, which was declared from the local +26.72%. The two environments' builds differ by about 3% in base Ir, so ceil(delta+0.2, 0.1) cannot hold both: CI's delta gives 27.3, STALE locally. 27.2 is the only bound both gates accept; #1939 records the split. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/cost_expect.txt | 2 +- tools/core_ext_boundary_selftest.sh | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt index 7427c270a..9eb4905d8 100644 --- a/tests/phase2/cost_expect.txt +++ b/tests/phase2/cost_expect.txt @@ -1,6 +1,6 @@ bench/alloc_heavy.eigs jit 50.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +64.3% (range-int control, measured at R1.3, against +64.0%) until R5; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8199903452, R1.4 Ir=8415252793, measured main delta=+68.4121%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range and hot len int results recover part of the existing generic mixed-operand/Value API cost; banked R1.6a Ir=8428313595, current Ir=7486166749, main Ir=4996461973, main delta=+49.82935504%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers bench/alloc_heavy.eigs off 29.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8229622729, R1.4 Ir=8442823382, measured main delta=+44.6791%, bound=ceil(delta+0.2,0.1); R1.6a remeasurement of the inherited main-sync short-string layout component (4ac31e67 to 1fd4422c): controls attribute +8000006 Ir to __strlen_sse2 with unchanged hot VM/allocation counts; untouched 1fd control Ir=8457703595 versus main Ir=5835080986 (+44.945779%, already above old max44.9), same-alias candidate versus 1fd +0.00188828%; current native-tool measurement main Ir=5835080986, candidate Ir=8457872415, delta=+44.948672%; bound=ceil(delta+0.2,0.1), retaining R5 recovery of the existing generic interpreter int cost, no new reader allowance; R1.6b measured component: N3 range and hot len int results recover part of the existing generic mixed-operand/Value API cost; banked R1.6a Ir=8457872415, current Ir=7514744462, main Ir=5835072842, main delta=+28.78578666%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/conservative_observed_loop.eigs jit 27 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=80746036, current Ir=99538839, main Ir=79049516, main delta=+25.91960588%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685683 Ir (0.867 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.2 -> 27 by ceil(delta+0.2, 0.1) +bench/conservative_observed_loop.eigs jit 27.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=80746036, current Ir=99538839, main Ir=79049516, main delta=+25.91960588%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685683 Ir (0.867 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.2 -> 27 by ceil(delta+0.2, 0.1); CI bench gate (bench/check_regression.sh, same jit row) measured +27.047% (Ir 76,743,802 -> 97,500,699 on the runner, against a local +26.72%): re-declared 27 -> 27.2: the only bound both gates accept (CI 27.047 <= 27.2; local 26.72 within the 0.5 STALE band). The two environments differ by 0.33 pp, which ceil(delta+0.2, 0.1) cannot cover on both sides bench/conservative_observed_loop.eigs off 22.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.7% (range-int control, measured at R1.3, against +1.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=95920891, current Ir=115593684, main Ir=94884432, main delta=+21.82576379%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685036 Ir (0.722 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 22.1 -> 22.7 by ceil(delta+0.2, 0.1) bench/conservative_unobserved_loop.eigs jit 33.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.6% (range-int control, measured at R1.3, against +2.7%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=64506354, current Ir=83299237, main Ir=62814824, main delta=+32.61079423%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685660 Ir (1.092 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 32.9 -> 33.9 by ceil(delta+0.2, 0.1) bench/conservative_unobserved_loop.eigs off 27.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +26.1% (range-int control, measured at R1.3, against +1.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=79846282, current Ir=99519057, main Ir=78869757, main delta=+26.18151847%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685769 Ir (0.869 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.4 -> 27.2 by ceil(delta+0.2, 0.1) diff --git a/tools/core_ext_boundary_selftest.sh b/tools/core_ext_boundary_selftest.sh index 59a632ca5..477994dda 100755 --- a/tools/core_ext_boundary_selftest.sh +++ b/tools/core_ext_boundary_selftest.sh @@ -31,8 +31,10 @@ run_gate() { } run_gate green || { cat "$T/green.log"; echo "core-ext selftest: clean gate did not pass"; exit 1; } -grep -q 'leg A: 28 core TUs scanned' "$T/green.log" && -grep -q 'leg B: 28 core TUs compile' "$T/green.log" && +# The clean population is pinned: a new core TU moves it in the same change +# (29 since R1.6g added src/builtins_int.c). +grep -q 'leg A: 29 core TUs scanned' "$T/green.log" && +grep -q 'leg B: 29 core TUs compile' "$T/green.log" && grep -q 'OK: no core -> extension-private include edge' "$T/green.log" || { cat "$T/green.log"; echo "core-ext selftest: clean populations/verdict changed"; exit 1; } @@ -51,4 +53,4 @@ grep -q 'FAIL\[A\]: core TU src/alloc.c includes extension private header "ext_h cp "$T/alloc.c.saved" "$T/src/alloc.c" run_gate restored || { cat "$T/restored.log"; echo "core-ext selftest: restored gate did not pass"; exit 1; } -echo "PASS: core-ext boundary: 28 TUs and poisoned-header verdict preserved; parallel overlap observed; planted edge rejected; restore green" +echo "PASS: core-ext boundary: 29 TUs and poisoned-header verdict preserved; parallel overlap observed; planted edge rejected; restore green" From 21c56baebaa4746143cff9e0d18c7482213c8471 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 08:19:13 -0500 Subject: [PATCH 168/188] phase2: regenerate the inventory after sync #7 (#1758) Sync #7's merge moved src/eigs_embed.c lines (main's #1933) and brought five new eigs_value_as_num reads into src/embed_smoke.c (#1930/#1933 checks, including unattached_buffer_probe). The committed inventory still described the pre-merge source, so the inventory gate failed in phase2-check and in CI's phase2 calibration ("inventory gate on an unchanged copy passes"). Regenerated with tools/phase2_inventory.py: examined 2197 -> 2202, all classified (embed API, READ); every other change is a line move. `tools/phase2_inventory.py --check` PASSES. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-inventory.txt | 111 ++++++++++++++++--------------- 1 file changed, 58 insertions(+), 53 deletions(-) diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 85bf7df2f..16c04a083 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2197 classified=2197 unclassified=0 +examined=2202 classified=2202 unclassified=0 files=65 tokens=116 role_rules=8 derived_accessors=32 wrappers=8 # Retired (required absent): buffer_read_byte -- R1.6e: gfx_fb and ppu_render_frame use buffer_byte_at @@ -14,7 +14,7 @@ files=65 tokens=116 role_rules=8 derived_accessors=32 wrappers=8 (g) tape encode and decode 37 CASE=4 DATA=5 PARSE=7 PRODUCE=8 RAW=6 READ=2 TEST=5 (h) JSON, store and db encoders 85 CASE=4 FORMAT=3 PARSE=5 PRODUCE=22 RAW=8 READ=24 TEST=19 (i) observer numeric paths 108 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=24 READ=6 TEST=34 -(j) embed API 68 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=51 TEST=2 WRITE=3 +(j) embed API 73 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=56 TEST=2 WRITE=3 ## Per token make_int 212 @@ -27,10 +27,10 @@ num_guard 68 make_num 63 VAL_F64_RAW 57 AST_NUM 53 +eigs_value_as_num 53 VAL_I64_RAW 51 slot_is_f64 50 eigs_float_arg 49 -eigs_value_as_num 48 eigs_list_float 47 slot_from_f64 47 eigs_int_arg 34 @@ -149,8 +149,8 @@ builtins_buf.c 105 a=33 b=33 c=39 jit.c 96 d=96 eigenscript.h 72 a=7 b=50 c=14 e=1 builtins_host.c 58 a=24 b=19 c=15 +embed_smoke.c 55 j=55 ext_store.c 55 h=55 -embed_smoke.c 50 j=50 trace.c 32 g=32 jit_smoke.c 31 d=31 lint.c 29 a=29 @@ -1882,14 +1882,14 @@ eigenscript.h:2326 eigs_num_text FORMAT e eigs_embed.c:302 eigs_value_new_num make_num PRODUCE j eigs_embed.c:315 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:316 eigs_value_type VAL_INT CASE j -eigs_embed.c:340 eigs_value_as_num eigs_value_as_num READ j -eigs_embed.c:342 eigs_value_as_num VAL_I64_RAW RAW j -eigs_embed.c:342 eigs_value_as_num VAL_INT TEST j -eigs_embed.c:343 eigs_value_as_num VAL_F64_RAW RAW j -eigs_embed.c:343 eigs_value_as_num VAL_FLOAT TEST j -eigs_embed.c:424 eigs_value_buffer_get buffer_read_num READ j -eigs_embed.c:471 eigs_trace_declare_kind VAL_FLOAT DATA j -eigs_embed.c:471 eigs_trace_declare_kind VAL_INT DATA j +eigs_embed.c:360 eigs_value_as_num eigs_value_as_num READ j +eigs_embed.c:365 eigs_value_as_num VAL_I64_RAW RAW j +eigs_embed.c:365 eigs_value_as_num VAL_INT TEST j +eigs_embed.c:366 eigs_value_as_num VAL_F64_RAW RAW j +eigs_embed.c:366 eigs_value_as_num VAL_FLOAT TEST j +eigs_embed.c:437 eigs_value_buffer_get buffer_read_num READ j +eigs_embed.c:484 eigs_trace_declare_kind VAL_FLOAT DATA j +eigs_embed.c:484 eigs_trace_declare_kind VAL_INT DATA j eigs_embed.h:171 eigs_value_as_num READ j embed_concurrent.c:106 global_worker eigs_value_as_num READ j embed_concurrent.c:768 take_drain eigs_value_as_num READ j @@ -1903,50 +1903,55 @@ embed_smoke.c:199 test_worker_exit_lifecycle eigs_slot_num READ j embed_smoke.c:214 test_worker_exit_lifecycle eigs_value_as_num READ j embed_smoke.c:300 host_add eigs_value_as_num READ j embed_smoke.c:300 host_add eigs_value_as_num READ j -embed_smoke.c:363 main SLOT_F64_RAW WRITE j -embed_smoke.c:365 main SLOT_F64_RAW WRITE j -embed_smoke.c:367 main SLOT_F64_RAW RAW j -embed_smoke.c:370 main SLOT_F64_RAW RAW j -embed_smoke.c:372 main SLOT_F64_RAW RAW j -embed_smoke.c:374 main SLOT_F64_RAW RAW j -embed_smoke.c:402 main eigs_value_as_num READ j -embed_smoke.c:410 main eigs_value_as_num READ j -embed_smoke.c:420 main eigs_value_as_num READ j -embed_smoke.c:445 main eigs_value_as_num READ j -embed_smoke.c:453 main eigs_value_as_num READ j -embed_smoke.c:478 main eigs_value_as_num READ j -embed_smoke.c:504 main eigs_value_as_num READ j -embed_smoke.c:515 main eigs_value_as_num READ j -embed_smoke.c:520 main eigs_value_as_num READ j -embed_smoke.c:525 main eigs_value_as_num READ j -embed_smoke.c:591 main eigs_value_as_num READ j -embed_smoke.c:609 main eigs_value_as_num READ j -embed_smoke.c:618 main eigs_value_as_num READ j -embed_smoke.c:661 main EIGS_NUM_MAX GUARD j -embed_smoke.c:669 main eigs_value_as_num READ j -embed_smoke.c:942 main eigs_value_as_num READ j +embed_smoke.c:336 unattached_buffer_probe eigs_value_as_num READ j +embed_smoke.c:369 main SLOT_F64_RAW WRITE j +embed_smoke.c:371 main SLOT_F64_RAW WRITE j +embed_smoke.c:373 main SLOT_F64_RAW RAW j +embed_smoke.c:376 main SLOT_F64_RAW RAW j +embed_smoke.c:378 main SLOT_F64_RAW RAW j +embed_smoke.c:380 main SLOT_F64_RAW RAW j +embed_smoke.c:408 main eigs_value_as_num READ j +embed_smoke.c:416 main eigs_value_as_num READ j +embed_smoke.c:426 main eigs_value_as_num READ j +embed_smoke.c:451 main eigs_value_as_num READ j +embed_smoke.c:459 main eigs_value_as_num READ j +embed_smoke.c:484 main eigs_value_as_num READ j +embed_smoke.c:510 main eigs_value_as_num READ j +embed_smoke.c:521 main eigs_value_as_num READ j +embed_smoke.c:526 main eigs_value_as_num READ j +embed_smoke.c:534 main eigs_value_as_num READ j +embed_smoke.c:603 main eigs_value_as_num READ j +embed_smoke.c:621 main eigs_value_as_num READ j +embed_smoke.c:630 main eigs_value_as_num READ j +embed_smoke.c:673 main EIGS_NUM_MAX GUARD j +embed_smoke.c:681 main eigs_value_as_num READ j +embed_smoke.c:954 main eigs_value_as_num READ j +embed_smoke.c:997 main eigs_value_as_num READ j +embed_smoke.c:1003 main eigs_value_as_num READ j +embed_smoke.c:1007 main eigs_value_as_num READ j embed_smoke.c:1041 main eigs_value_as_num READ j -embed_smoke.c:1052 main eigs_value_as_num READ j -embed_smoke.c:1062 main SLOT_F64_RAW WRITE j -embed_smoke.c:1079 main eigs_value_as_num READ j -embed_smoke.c:1089 main eigs_value_as_num READ j -embed_smoke.c:1098 main eigs_value_as_num READ j -embed_smoke.c:1107 main eigs_value_as_num READ j -embed_smoke.c:1125 main eigs_value_as_num READ j -embed_smoke.c:1133 main eigs_value_as_num READ j -embed_smoke.c:1137 main eigs_value_as_num READ j -embed_smoke.c:1142 main eigs_value_as_num READ j -embed_smoke.c:1153 main eigs_value_as_num READ j -embed_smoke.c:1158 main eigs_value_as_num READ j +embed_smoke.c:1119 main eigs_value_as_num READ j +embed_smoke.c:1130 main eigs_value_as_num READ j +embed_smoke.c:1140 main SLOT_F64_RAW WRITE j +embed_smoke.c:1157 main eigs_value_as_num READ j embed_smoke.c:1167 main eigs_value_as_num READ j -embed_smoke.c:1186 main eigs_value_as_num READ j -embed_smoke.c:1190 main eigs_value_as_num READ j -embed_smoke.c:1199 main eigs_value_as_num READ j +embed_smoke.c:1176 main eigs_value_as_num READ j +embed_smoke.c:1185 main eigs_value_as_num READ j embed_smoke.c:1203 main eigs_value_as_num READ j -embed_smoke.c:1210 main eigs_value_as_num READ j -embed_smoke.c:1266 main eigs_value_as_num READ j -embed_smoke.c:1290 main eigs_value_as_num READ j -embed_smoke.c:1317 main eigs_value_as_num READ j +embed_smoke.c:1211 main eigs_value_as_num READ j +embed_smoke.c:1215 main eigs_value_as_num READ j +embed_smoke.c:1220 main eigs_value_as_num READ j +embed_smoke.c:1231 main eigs_value_as_num READ j +embed_smoke.c:1236 main eigs_value_as_num READ j +embed_smoke.c:1245 main eigs_value_as_num READ j +embed_smoke.c:1264 main eigs_value_as_num READ j +embed_smoke.c:1268 main eigs_value_as_num READ j +embed_smoke.c:1277 main eigs_value_as_num READ j +embed_smoke.c:1281 main eigs_value_as_num READ j +embed_smoke.c:1288 main eigs_value_as_num READ j +embed_smoke.c:1344 main eigs_value_as_num READ j +embed_smoke.c:1368 main eigs_value_as_num READ j +embed_smoke.c:1395 main eigs_value_as_num READ j ext_db.c:65 db_build_query VAL_INT TEST h ext_db.c:66 db_build_query VAL_I64_RAW RAW h ext_db.c:68 db_build_query VAL_FLOAT TEST h From 2673f819f687b1d5307cd1510d9a2430d50063b1 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 08:25:25 -0500 Subject: [PATCH 169/188] test(numbers): preregister remaining buffer boundary contracts R1.6d-D1 and R1.6z-D1. Six MAP rows red on base in off/default/osr/trace, strict 0/1; public getter C gate red on raw NaN/payload/inf bit round trips. Cold critic added iterator backedge and dynamic integer-index coverage; get_at exact diagnostic messages pinned. No frozen branch expectation amended. Release build rc=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 3 ++ tests/phase2/MAP.md | 11 +++++ tests/phase2/embed_buffer_get_raw.c | 45 +++++++++++++++++++ tests/phase2/fixtures/r16z-buffer-equal.eigs | 27 +++++++++++ tests/phase2/fixtures/r16z-vm-index.eigs | 23 ++++++++++ tests/phase2/fixtures/r16z-vm-int-index.eigs | 23 ++++++++++ tests/phase2/fixtures/r16z-vm-iter.eigs | 27 +++++++++++ tests/phase2/fixtures/r16z-vm-leaf-index.eigs | 22 +++++++++ .../phase2/fixtures/r16z-vm-local-index.eigs | 23 ++++++++++ tests/phase2/rows/N11.buffer-equal-ieee.out | 8 ++++ tests/phase2/rows/N11.buffer-equal-ieee.sh | 11 +++++ .../phase2/rows/N13.vm-buffer-index-data.out | 6 +++ tests/phase2/rows/N13.vm-buffer-index-data.sh | 12 +++++ .../rows/N13.vm-buffer-int-index-data.out | 6 +++ .../rows/N13.vm-buffer-int-index-data.sh | 12 +++++ tests/phase2/rows/N13.vm-buffer-iter-data.out | 6 +++ tests/phase2/rows/N13.vm-buffer-iter-data.sh | 12 +++++ .../rows/N13.vm-buffer-leaf-index-data.out | 6 +++ .../rows/N13.vm-buffer-leaf-index-data.sh | 12 +++++ .../rows/N13.vm-buffer-local-index-data.out | 6 +++ .../rows/N13.vm-buffer-local-index-data.sh | 12 +++++ tools/phase2_check.py | 6 +++ tools/phase2_readers.sh | 7 +++ 23 files changed, 326 insertions(+) create mode 100644 tests/phase2/embed_buffer_get_raw.c create mode 100644 tests/phase2/fixtures/r16z-buffer-equal.eigs create mode 100644 tests/phase2/fixtures/r16z-vm-index.eigs create mode 100644 tests/phase2/fixtures/r16z-vm-int-index.eigs create mode 100644 tests/phase2/fixtures/r16z-vm-iter.eigs create mode 100644 tests/phase2/fixtures/r16z-vm-leaf-index.eigs create mode 100644 tests/phase2/fixtures/r16z-vm-local-index.eigs create mode 100644 tests/phase2/rows/N11.buffer-equal-ieee.out create mode 100644 tests/phase2/rows/N11.buffer-equal-ieee.sh create mode 100644 tests/phase2/rows/N13.vm-buffer-index-data.out create mode 100644 tests/phase2/rows/N13.vm-buffer-index-data.sh create mode 100644 tests/phase2/rows/N13.vm-buffer-int-index-data.out create mode 100644 tests/phase2/rows/N13.vm-buffer-int-index-data.sh create mode 100644 tests/phase2/rows/N13.vm-buffer-iter-data.out create mode 100644 tests/phase2/rows/N13.vm-buffer-iter-data.sh create mode 100644 tests/phase2/rows/N13.vm-buffer-leaf-index-data.out create mode 100644 tests/phase2/rows/N13.vm-buffer-leaf-index-data.sh create mode 100644 tests/phase2/rows/N13.vm-buffer-local-index-data.out create mode 100644 tests/phase2/rows/N13.vm-buffer-local-index-data.sh diff --git a/Makefile b/Makefile index 13acad4f5..0868d35b5 100644 --- a/Makefile +++ b/Makefile @@ -274,6 +274,9 @@ build/phase2/gfx_audio_boundary_%: tests/phase2/gfx_audio_boundary.c src/ext_gfx $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread -ldl build/phase2/gfx_byte_boundary_%: tests/phase2/gfx_byte_boundary.c src/ext_gfx.c build/phase2/eigenscript_all.c tools/werror_flags.txt $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread -ldl +# R1.6z-D1 public getter bit-round-trip gate; compile outside timed MAP rows. +build/phase2/embed_buffer_get_raw_%: tests/phase2/embed_buffer_get_raw.c build/phase2/eigenscript_all.c tools/werror_flags.txt + $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread # Q7 lands in R1.6e; an absent source is a build failure once selected. build/phase2/q7_readers_%: tests/phase2/q7_readers.c build/phase2/eigenscript_all.c tools/werror_flags.txt $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 1f7935f39..42cc46aae 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -647,3 +647,14 @@ The `O cfg` record's v8 shape is pinned by `O3.ocfg-no-hlow` (its file lists - `O4.how-is-settledness` [R3] a binding held constant for one window; `print of (how is x)` -> the R3 settledness value at full rest (to be fixed by the R3 design) tag: an entropy-derived value + +### N11 +- `N11.buffer-equal-ieee` [R1.6z] SGD stores -inf, then self-SGD stores NaN; IEEE element comparison: distinct/same NaN false, same infinity true, infinity versus finite false, signed zeros equal; strict modes 0/1 never raise or change math flags. Also exercises list_contains and list_index_of. R1.6z-D1. +- `gate.N11.embed-buffer-get-raw` [R1.6z] `tools/phase2_readers.sh release embed_buffer_get_raw`: set/get canonical NaN, payload NaN, both infinities and negative zero by memcmp; reads SGD-program-stored NaN, with no error or flag change in strict modes 0/1. Mechanical gate, compiled outside timed rows. + +### N13 +- `N13.vm-buffer-index-data` [R1.6z] SGD-stored NaN and both infinities through index; get_at oracle R1.6d-D1: value error, finite-number message (strict NaN first diagnostic/INVALID), line 2 in every execution tier. Sixty finite calls warm the function. +- `N13.vm-buffer-local-index-data` [R1.6z] SGD-stored NaN and both infinities through local-index; get_at oracle R1.6d-D1: value error, finite-number message (strict NaN first diagnostic/INVALID), line 2 in every execution tier. Sixty finite calls warm the function. +- `N13.vm-buffer-leaf-index-data` [R1.6z] SGD-stored NaN and both infinities through leaf-index; get_at oracle R1.6d-D1: value error, finite-number message (strict NaN first diagnostic/INVALID), line 2 in every execution tier. Sixty finite calls warm the function. +- `N13.vm-buffer-iter-data` [R1.6z] SGD-stored NaN and both infinities through iter (128 cells with a backedge; nonfinite copied to final cell); get_at oracle R1.6d-D1: value error, finite-number message (strict NaN first diagnostic/INVALID), line 3 in every execution tier. Sixty finite calls warm the function. +- `N13.vm-buffer-int-index-data` [R1.6z] Dynamic integer index exercises the boxed slow INDEX_GET arm on SGD-stored NaN and both infinities; same get_at error contract at line 2, strict modes 0/1 and all execution tiers. diff --git a/tests/phase2/embed_buffer_get_raw.c b/tests/phase2/embed_buffer_get_raw.c new file mode 100644 index 000000000..66af0a780 --- /dev/null +++ b/tests/phase2/embed_buffer_get_raw.c @@ -0,0 +1,45 @@ +/* R1.6z-D1: public API raw double contract, including NaN payload bits. */ +#include "eigenscript_all.c" +static int checks, failures; +static void check(int ok, const char *label) { + ++checks; + if (!ok) { ++failures; printf("phase2-embed-buffer: FAIL %s\n", label); } +} +int main(void) { + EigsState *st = eigs_open(); + if (!st) return 1; + const uint64_t bits[] = {UINT64_C(0x7ff8000000000000), UINT64_C(0x7ff8000000000042), + UINT64_C(0x7ff0000000000000), UINT64_C(0xfff0000000000000), UINT64_C(0x8000000000000000)}; + for (int strict = 0; strict <= 1; ++strict) { + g_strict = strict; + EigsValue *b = eigs_value_new_buffer(5); + for (int i = 0; i < 5; ++i) { + double x; memcpy(&x, &bits[i], sizeof x); + eigs_value_buffer_set(b, i, x); + g_math_flags = EIGS_MATH_UNDERFLOW; + double got = eigs_value_buffer_get(b, i); + check(memcmp(&x, &got, sizeof x) == 0, "set/get bit round trip"); + check(!eigs_has_error(), "get never raises"); + check(g_math_flags == EIGS_MATH_UNDERFLOW, "get preserves flags"); + eigs_clear_error(); + } + eigs_value_release(b); + g_math_flags = 0; + EigsValue *r = eigs_eval_string("p is buf_from_list of ([1e308])\n" + "g is buf_from_list of ([1e308])\nsgd_update of [p, g, 1e308]\n" + "sgd_update of [p, p, 1.0]\np\n"); + check(r && !eigs_has_error(), "program stores a NaN through SGD"); + if (r) { + double stored = ((Value *)r)->data.buffer.data[0]; + unsigned flags = g_math_flags; + double got = eigs_value_buffer_get(r, 0); + check(isnan(stored) && memcmp(&stored, &got, sizeof got) == 0, "program NaN bits unchanged"); + check(!eigs_has_error() && flags == g_math_flags, "program getter no side effects"); + eigs_value_release(r); + } + eigs_clear_error(); + } + eigs_close(st); + printf("phase2-embed-buffer: %s checks=%d failures=%d\n", failures ? "FAIL" : "PASS", checks, failures); + return failures ? 1 : 0; +} diff --git a/tests/phase2/fixtures/r16z-buffer-equal.eigs b/tests/phase2/fixtures/r16z-buffer-equal.eigs new file mode 100644 index 000000000..57e2fd2ba --- /dev/null +++ b/tests/phase2/fixtures/r16z-buffer-equal.eigs @@ -0,0 +1,27 @@ +# SGD's raw buffer kernel stores -inf, then -inf - -inf stores NaN. +define payload(kind) as: + local p is buf_from_list of ([1e308]) + local g is buf_from_list of ([1e308]) + if kind == "inf": + g[0] is -1e308 + sgd_update of [p, g, 1e308] + if kind == "nan": + sgd_update of [p, p, 1.0] + return p +nan_a is payload of "nan" +nan_b is payload of "nan" +inf_a is payload of "inf" +inf_b is payload of "inf" +neg_inf is payload of "-inf" +finite is buf_from_list of ([1e308]) +negzero is buf_from_list of ([-1.0]) +buf_scale_range of [negzero, 0, 1, 0.0] +zero is buffer of 1 +before is math_flags of null +try: + print of [nan_a == nan_b, nan_a == nan_a, inf_a == inf_b, inf_a == finite, negzero == zero] + print of [neg_inf == neg_inf, inf_a == neg_inf, nan_a != nan_a] + print of [list_contains of [[nan_a], nan_a], list_index_of of [[nan_a], nan_a]] + print of ((math_flags of null) == before) +catch e: + print of ["unexpected-equality-raise", e.kind, e.message] diff --git a/tests/phase2/fixtures/r16z-vm-index.eigs b/tests/phase2/fixtures/r16z-vm-index.eigs new file mode 100644 index 000000000..53c4e43e7 --- /dev/null +++ b/tests/phase2/fixtures/r16z-vm-index.eigs @@ -0,0 +1,23 @@ +define read_cell(b, i) as: + local v is b[i] + return v +finite is buf_from_list of ([2.5]) +for warm in range of 60: + read_cell of [finite, 0.0] +for kind in ["nan", "inf", "-inf"]: + p is buf_from_list of ([1e308]) + g is buf_from_list of ([1e308]) + if kind == "inf": + g[0] is -1e308 + sgd_update of [p, g, 1e308] + if kind == "nan": + sgd_update of [p, p, 1.0] + try: + v is read_cell of [p, 0.0] + print of [kind, "accepted", v] + catch e: + local strict_nan is kind == "nan" and (env_get of "EIGS_STRICT") == "1" + local message_ok is e.message == "buffer_read_f64: expected a finite number" + if strict_nan: + message_ok is e.message == "arithmetic: result is not a number (NaN has no defined value)" + print of [kind, e.kind, message_ok, e.line, (math_flags of null).invalid] diff --git a/tests/phase2/fixtures/r16z-vm-int-index.eigs b/tests/phase2/fixtures/r16z-vm-int-index.eigs new file mode 100644 index 000000000..fb61c1d97 --- /dev/null +++ b/tests/phase2/fixtures/r16z-vm-int-index.eigs @@ -0,0 +1,23 @@ +define read_cell(b, i) as: + local v is b[i] + return v +finite is buf_from_list of ([2.5]) +for warm in range of 60: + read_cell of [finite, 0.0] +for kind in ["nan", "inf", "-inf"]: + p is buf_from_list of ([1e308]) + g is buf_from_list of ([1e308]) + if kind == "inf": + g[0] is -1e308 + sgd_update of [p, g, 1e308] + if kind == "nan": + sgd_update of [p, p, 1.0] + try: + v is read_cell of [p, 0] + print of [kind, "accepted", v] + catch e: + local strict_nan is kind == "nan" and (env_get of "EIGS_STRICT") == "1" + local message_ok is e.message == "buffer_read_f64: expected a finite number" + if strict_nan: + message_ok is e.message == "arithmetic: result is not a number (NaN has no defined value)" + print of [kind, e.kind, message_ok, e.line, (math_flags of null).invalid] diff --git a/tests/phase2/fixtures/r16z-vm-iter.eigs b/tests/phase2/fixtures/r16z-vm-iter.eigs new file mode 100644 index 000000000..7e83bf0cb --- /dev/null +++ b/tests/phase2/fixtures/r16z-vm-iter.eigs @@ -0,0 +1,27 @@ +define read_cell(b, i) as: + local result is 0.0 + for cell in b: + result is cell + return result +finite is buffer of 128 +for warm in range of 60: + read_cell of [finite, 0.0] +for kind in ["nan", "inf", "-inf"]: + p is buf_from_list of ([1e308]) + g is buf_from_list of ([1e308]) + if kind == "inf": + g[0] is -1e308 + sgd_update of [p, g, 1e308] + if kind == "nan": + sgd_update of [p, p, 1.0] + try: + many is buffer of 128 + buf_copy of [p, 0, many, 127, 1] + v is read_cell of [many, 0.0] + print of [kind, "accepted", v] + catch e: + local strict_nan is kind == "nan" and (env_get of "EIGS_STRICT") == "1" + local message_ok is e.message == "buffer_read_f64: expected a finite number" + if strict_nan: + message_ok is e.message == "arithmetic: result is not a number (NaN has no defined value)" + print of [kind, e.kind, message_ok, e.line, (math_flags of null).invalid] diff --git a/tests/phase2/fixtures/r16z-vm-leaf-index.eigs b/tests/phase2/fixtures/r16z-vm-leaf-index.eigs new file mode 100644 index 000000000..7c4c06048 --- /dev/null +++ b/tests/phase2/fixtures/r16z-vm-leaf-index.eigs @@ -0,0 +1,22 @@ +define read_cell(b, i) as: + return b[i] +finite is buf_from_list of ([2.5]) +for warm in range of 60: + read_cell of [finite, 0.0] +for kind in ["nan", "inf", "-inf"]: + p is buf_from_list of ([1e308]) + g is buf_from_list of ([1e308]) + if kind == "inf": + g[0] is -1e308 + sgd_update of [p, g, 1e308] + if kind == "nan": + sgd_update of [p, p, 1.0] + try: + v is read_cell of [p, 0.0] + print of [kind, "accepted", v] + catch e: + local strict_nan is kind == "nan" and (env_get of "EIGS_STRICT") == "1" + local message_ok is e.message == "buffer_read_f64: expected a finite number" + if strict_nan: + message_ok is e.message == "arithmetic: result is not a number (NaN has no defined value)" + print of [kind, e.kind, message_ok, e.line, (math_flags of null).invalid] diff --git a/tests/phase2/fixtures/r16z-vm-local-index.eigs b/tests/phase2/fixtures/r16z-vm-local-index.eigs new file mode 100644 index 000000000..618de719f --- /dev/null +++ b/tests/phase2/fixtures/r16z-vm-local-index.eigs @@ -0,0 +1,23 @@ +define read_cell(b, i) as: + local v is b[0] + return v +finite is buf_from_list of ([2.5]) +for warm in range of 60: + read_cell of [finite, 0.0] +for kind in ["nan", "inf", "-inf"]: + p is buf_from_list of ([1e308]) + g is buf_from_list of ([1e308]) + if kind == "inf": + g[0] is -1e308 + sgd_update of [p, g, 1e308] + if kind == "nan": + sgd_update of [p, p, 1.0] + try: + v is read_cell of [p, 0.0] + print of [kind, "accepted", v] + catch e: + local strict_nan is kind == "nan" and (env_get of "EIGS_STRICT") == "1" + local message_ok is e.message == "buffer_read_f64: expected a finite number" + if strict_nan: + message_ok is e.message == "arithmetic: result is not a number (NaN has no defined value)" + print of [kind, e.kind, message_ok, e.line, (math_flags of null).invalid] diff --git a/tests/phase2/rows/N11.buffer-equal-ieee.out b/tests/phase2/rows/N11.buffer-equal-ieee.out new file mode 100644 index 000000000..9147c0f8c --- /dev/null +++ b/tests/phase2/rows/N11.buffer-equal-ieee.out @@ -0,0 +1,8 @@ +[false, false, true, false, true] +[true, false, true] +[false, -1] +true +[false, false, true, false, true] +[true, false, true] +[false, -1] +true diff --git a/tests/phase2/rows/N11.buffer-equal-ieee.sh b/tests/phase2/rows/N11.buffer-equal-ieee.sh new file mode 100644 index 000000000..2bb23408b --- /dev/null +++ b/tests/phase2/rows/N11.buffer-equal-ieee.sh @@ -0,0 +1,11 @@ +# ROW: N11.buffer-equal-ieee +# ITEMS: N11 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# R1.6z-D1: sgd_update stores infinities and NaN in real program buffers. +set -eu +for strict in 0 1; do + EIGS_STRICT=$strict "$1" "$(dirname "$0")/../fixtures/r16z-buffer-equal.eigs" +done diff --git a/tests/phase2/rows/N13.vm-buffer-index-data.out b/tests/phase2/rows/N13.vm-buffer-index-data.out new file mode 100644 index 000000000..0b86f3498 --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-index-data.out @@ -0,0 +1,6 @@ +["nan", "value", true, 2, false] +["inf", "value", true, 2, false] +["-inf", "value", true, 2, false] +["nan", "value", true, 2, true] +["inf", "value", true, 2, true] +["-inf", "value", true, 2, true] diff --git a/tests/phase2/rows/N13.vm-buffer-index-data.sh b/tests/phase2/rows/N13.vm-buffer-index-data.sh new file mode 100644 index 000000000..97469d52c --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-index-data.sh @@ -0,0 +1,12 @@ +# ROW: N13.vm-buffer-index-data +# ITEMS: N13 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# R1.6d-D1: get_at oracle; 60 finite calls warm the same function first. +# Semantic tier row; native path is separately killed by the JIT-helper plant. +set -eu +for strict in 0 1; do + EIGS_STRICT=$strict "$1" "$(dirname "$0")/../fixtures/r16z-vm-index.eigs" +done diff --git a/tests/phase2/rows/N13.vm-buffer-int-index-data.out b/tests/phase2/rows/N13.vm-buffer-int-index-data.out new file mode 100644 index 000000000..0b86f3498 --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-int-index-data.out @@ -0,0 +1,6 @@ +["nan", "value", true, 2, false] +["inf", "value", true, 2, false] +["-inf", "value", true, 2, false] +["nan", "value", true, 2, true] +["inf", "value", true, 2, true] +["-inf", "value", true, 2, true] diff --git a/tests/phase2/rows/N13.vm-buffer-int-index-data.sh b/tests/phase2/rows/N13.vm-buffer-int-index-data.sh new file mode 100644 index 000000000..ef980c19c --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-int-index-data.sh @@ -0,0 +1,12 @@ +# ROW: N13.vm-buffer-int-index-data +# ITEMS: N13 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# R1.6d-D1: get_at oracle; 60 finite calls warm the same function first. +# Semantic tier row; native path is separately killed by the JIT-helper plant. +set -eu +for strict in 0 1; do + EIGS_STRICT=$strict "$1" "$(dirname "$0")/../fixtures/r16z-vm-int-index.eigs" +done diff --git a/tests/phase2/rows/N13.vm-buffer-iter-data.out b/tests/phase2/rows/N13.vm-buffer-iter-data.out new file mode 100644 index 000000000..21155cc28 --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-iter-data.out @@ -0,0 +1,6 @@ +["nan", "value", true, 3, false] +["inf", "value", true, 3, false] +["-inf", "value", true, 3, false] +["nan", "value", true, 3, true] +["inf", "value", true, 3, true] +["-inf", "value", true, 3, true] diff --git a/tests/phase2/rows/N13.vm-buffer-iter-data.sh b/tests/phase2/rows/N13.vm-buffer-iter-data.sh new file mode 100644 index 000000000..5a7b4be7e --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-iter-data.sh @@ -0,0 +1,12 @@ +# ROW: N13.vm-buffer-iter-data +# ITEMS: N13 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# R1.6d-D1: get_at oracle; 60 finite calls warm the same function first. +# Semantic tier row; native path is separately killed by the JIT-helper plant. +set -eu +for strict in 0 1; do + EIGS_STRICT=$strict "$1" "$(dirname "$0")/../fixtures/r16z-vm-iter.eigs" +done diff --git a/tests/phase2/rows/N13.vm-buffer-leaf-index-data.out b/tests/phase2/rows/N13.vm-buffer-leaf-index-data.out new file mode 100644 index 000000000..0b86f3498 --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-leaf-index-data.out @@ -0,0 +1,6 @@ +["nan", "value", true, 2, false] +["inf", "value", true, 2, false] +["-inf", "value", true, 2, false] +["nan", "value", true, 2, true] +["inf", "value", true, 2, true] +["-inf", "value", true, 2, true] diff --git a/tests/phase2/rows/N13.vm-buffer-leaf-index-data.sh b/tests/phase2/rows/N13.vm-buffer-leaf-index-data.sh new file mode 100644 index 000000000..bf715aeef --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-leaf-index-data.sh @@ -0,0 +1,12 @@ +# ROW: N13.vm-buffer-leaf-index-data +# ITEMS: N13 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# R1.6d-D1: get_at oracle; 60 finite calls warm the same function first. +# Semantic tier row; native path is separately killed by the JIT-helper plant. +set -eu +for strict in 0 1; do + EIGS_STRICT=$strict "$1" "$(dirname "$0")/../fixtures/r16z-vm-leaf-index.eigs" +done diff --git a/tests/phase2/rows/N13.vm-buffer-local-index-data.out b/tests/phase2/rows/N13.vm-buffer-local-index-data.out new file mode 100644 index 000000000..0b86f3498 --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-local-index-data.out @@ -0,0 +1,6 @@ +["nan", "value", true, 2, false] +["inf", "value", true, 2, false] +["-inf", "value", true, 2, false] +["nan", "value", true, 2, true] +["inf", "value", true, 2, true] +["-inf", "value", true, 2, true] diff --git a/tests/phase2/rows/N13.vm-buffer-local-index-data.sh b/tests/phase2/rows/N13.vm-buffer-local-index-data.sh new file mode 100644 index 000000000..9f9d2f3fc --- /dev/null +++ b/tests/phase2/rows/N13.vm-buffer-local-index-data.sh @@ -0,0 +1,12 @@ +# ROW: N13.vm-buffer-local-index-data +# ITEMS: N13 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# R1.6d-D1: get_at oracle; 60 finite calls warm the same function first. +# Semantic tier row; native path is separately killed by the JIT-helper plant. +set -eu +for strict in 0 1; do + EIGS_STRICT=$strict "$1" "$(dirname "$0")/../fixtures/r16z-vm-local-index.eigs" +done diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 1c752d37c..5bdd7c843 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -709,6 +709,8 @@ def mechanical(through, baseline, branch, out, smi_trap=None, tag=None): # R1.6f-D2: net_send's raw stored-byte fixture builds once here, # outside the MAP rows' per-tier 30 s timeout. gates.append('net-byte-boundary') + if ROUNDS.index(through) >= ROUNDS.index('R1.6z'): + gates.append('embed-buffer-get-raw') for g in gates: if g == 'int-source': res[g] = int_source(os.path.join(ROOT, 'src'), out, through) @@ -750,6 +752,10 @@ def mechanical(through, baseline, branch, out, smi_trap=None, tag=None): res[g], text = tool(['bash', 'tools/phase2_readers.sh', 'release', 'net_byte_boundary'], out, r'.*') res[g] = res[g] and len(re.findall( r'^phase2-net-boundary: PASS variant=release$', text, re.M)) == 1 + elif g == 'embed-buffer-get-raw': + res[g], text = tool(['bash', 'tools/phase2_readers.sh', 'release', 'embed_buffer_get_raw'], out, r'.*') + res[g] = res[g] and len(re.findall( + r'^phase2-embed-buffer-get: PASS variant=release$', text, re.M)) == 1 elif g == 'builtins-table': if not tag: out(' builtins-table: needs the tag binary') diff --git a/tools/phase2_readers.sh b/tools/phase2_readers.sh index 6f5d2cb55..30081569e 100755 --- a/tools/phase2_readers.sh +++ b/tools/phase2_readers.sh @@ -11,6 +11,7 @@ case "$FIXTURE" in gfx_audio_boundary) LABEL=phase2-gfx-audio ;; gfx_byte_boundary) LABEL=phase2-gfx-byte ;; net_byte_boundary) LABEL=phase2-net-boundary ;; + embed_buffer_get_raw) LABEL=phase2-embed-buffer-get ;; *) echo "phase2-readers: FAIL unknown fixture $FIXTURE"; exit 2 ;; esac [ -f "$ROOT/tests/phase2/$FIXTURE.c" ] || { echo "$LABEL: FAIL missing tests/phase2/$FIXTURE.c"; exit 1; } @@ -38,6 +39,12 @@ fi cat "$TMP/out" if [ -s "$TMP/err" ]; then cat "$TMP/err"; fail 'reader fixture wrote stderr'; fi [ "$rc" -eq 0 ] || fail "reader fixture rc=$rc" +if [ "$FIXTURE" = embed_buffer_get_raw ]; then + [ "$(grep -cE '^phase2-embed-buffer: PASS checks=36 failures=0$' "$TMP/out")" -eq 1 ] || fail 'missing unique complete getter PASS' + [ "$(wc -l < "$TMP/out" | tr -d ' ')" -eq 1 ] || fail 'unexpected getter output' + echo "$LABEL: PASS variant=$VARIANT" + exit 0 +fi if [ "$FIXTURE" = net_byte_boundary ]; then [ "$(grep -cE '^phase2-net-byte: PASS checks=72 failures=0$' "$TMP/out")" -eq 1 ] || fail 'missing unique complete net-byte-boundary PASS' [ "$(wc -l < "$TMP/out" | tr -d ' ')" -eq 1 ] || fail 'unexpected net-byte-boundary fixture output' From 3823f0d337c681d6b6e1c8c06e7a22b138c8c4e8 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 08:28:14 -0500 Subject: [PATCH 170/188] refactor(vm): retire numeric bridge at buffer data boundaries R1.6d-D1/N13: all eight VM index/iter/JIT/leaf data reads use get_at semantics. Speculative leaf refuses to raise without a callee frame. VM MAP rows green in off/default/osr/trace, strict 0/1; exact kind/message/line. Float producers/metadata retain kind; no ownership change. Release build rc=0 warnings=0. Docs and legacy indexed-read expectations move with behavior. Reviewed amendment under R1.6d-D1 point 3 / N13 and R1.6 plan rule 4: NG32 and NG35 assert a value refusal with unchanged flags. NG35 gather still copies the cell; its final [0] is the ruled scalar read. The nonfinite exact-output fixture changes its two sticky INVALID outputs from true to false because those legacy indexed reads no longer normalize NaN. Base/tip isolation receipts prove the cause; strict NaN keeps its first diagnostic and INVALID. Numeric flags 33/33; full release suite 4606/4606, failures=0, skipped=10, sections=304, rc0; embed-smoke rc0; completed strict differential rc0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF Legacy strict-math buffer-index expectations updated in this same file-group commit; strict math gate rc=0. --- README.md | 18 +++ changes/changed/1758-r16z-bridge.md | 1 + docs/BUILTINS.md | 20 +++- docs/COMPARISON.md | 26 +++- docs/SPEC.md | 28 ++++- docs/llms.txt | 25 +++- src/vm.c | 165 +++++++++++++------------- tests/test_buffer_nonfinite_read.eigs | 20 +++- tests/test_buffer_nonfinite_read.out | 10 +- tests/test_doc_examples.py | 10 +- tests/test_numeric_guard.eigs | 37 ++++-- tests/test_numeric_guard_flags.sh | 17 ++- tests/test_strict_math.sh | 20 +++- 13 files changed, 267 insertions(+), 130 deletions(-) create mode 100644 changes/changed/1758-r16z-bridge.md diff --git a/README.md b/README.md index 95ed209bd..c1cbdc43c 100644 --- a/README.md +++ b/README.md @@ -950,3 +950,21 @@ catch e: ```output value ``` + +### Stored buffer data boundary + +Buffer kernels can retain non-finite data. Scalar indexing and iteration +raise `value` when that data is read, in every strict mode (N13). + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +try: + print of p[0] +catch e: + print of e.kind +``` +```output +value +``` diff --git a/changes/changed/1758-r16z-bridge.md b/changes/changed/1758-r16z-bridge.md new file mode 100644 index 000000000..2f98e46b5 --- /dev/null +++ b/changes/changed/1758-r16z-bridge.md @@ -0,0 +1 @@ +- Buffer indexing and iteration refuse stored non-finite elements in every strict mode. Buffer equality compares stored doubles with IEEE equality, without raises or math flags; embedding buffer reads return the exact stored double, including NaN payloads, infinities and signed zero. The transitional numeric bridge and caller-less helpers are removed (#1758, R1.6z). diff --git a/docs/BUILTINS.md b/docs/BUILTINS.md index ad4733c0b..76f92ed92 100644 --- a/docs/BUILTINS.md +++ b/docs/BUILTINS.md @@ -611,7 +611,7 @@ in a buffer first converts it to float and can round it. | Name | Signature | Description | |------|-----------|-------------| -| `matmul` | `matmul of [a, b]` | Matrix multiplication. Two shaped buffers multiply on the flat data and give a buffer; a 1-D left operand gives a 1-D result. Mixed list/buffer operands give a list. An accumulation that reaches `inf - inf` is `NaN`; by default that raises a catchable `value` error naming `matmul` (#971). Kernels may retain raw non-finite values in buffer storage. Ordinary indexed reads apply the numeric guard (#1417): infinity saturates at ±`1e308`, and with strict mode off a `NaN` becomes `0` and sets `math_flags.invalid`. `sum`, `get_at`, `dot` and `write_bytes` instead refuse non-finite buffer elements in every strict mode (N13). | +| `matmul` | `matmul of [a, b]` | Matrix multiplication. Two shaped buffers multiply on the flat data and give a buffer; a 1-D left operand gives a 1-D result. Mixed list/buffer operands give a list. An accumulation that reaches `inf - inf` is `NaN`; by default that raises a catchable `value` error naming `matmul` (#971). Kernels may retain raw non-finite values in buffer storage. Indexing and iteration, like `get_at`, refuse stored NaN and infinity with `value` in every strict mode (N13). Strict NaN keeps the first-NaN diagnostic and INVALID flag; the interpreter, JIT and leaf fallback agree on the error source line. | | `matmul_at` | `matmul_at of [a, b]` | `aᵀ·b` without materialising the transpose: `a` is `(m × k)`, `b` is `(m × n)`, result `(k × n)` — the weight gradient `dW = Xᵀ·dY` of a linear layer. Buffers and nested lists; byte-identical to `matmul` of the explicitly transposed operand (same tiled kernel order). Two 1-D operands give their `(k × n)` outer product. Shape/type/size errors raise like `matmul` (#973) | | `matmul_bt` | `matmul_bt of [a, b]` | `a·bᵀ`: `a` is `(m × k)`, `b` is `(n × k)`, result `(m × n)` — the input gradient `dX = dY·Wᵀ`. A 1-D left operand is a row vector and yields a 1-D result, as for `matmul` (#973) | | `gather` | `gather of [matrix, indices, dim]` | N5 exact indices (integral floats accepted; fractions raise `value`). Selected list cells retain their numeric kind; buffer elements are floats. Gather one element per row: `out[i] = matrix[i][indices[i]]`. `matrix` may be a shaped buffer and `indices` a list or a buffer; a shaped-buffer `matrix` gives a buffer. `gather of [vec, i]` on a 1-D tensor returns element `i`. An **out-of-range index raises `index_range`** — in every form, list or buffer (#973/#1093, settled at integration: there is no element there, and `scatter_add` raises on the same index). A row that is not a row (a 1-D tensor in the per-row form) still answers `0.0` for that row | @@ -1152,3 +1152,21 @@ readers refuse non-finite buffer cells with `value` in both strict modes (N13). reader: exact integers in 0..255. Fractions and out-of-range values raise `value`; a stored NaN or infinity raises at the data boundary in both strict and lenient modes, without normalising the stored payload again. + +### Stored buffer data boundary + +Buffer kernels can retain non-finite data. Scalar indexing and iteration +raise `value` when that data is read, in every strict mode (N13). + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +try: + print of p[0] +catch e: + print of e.kind +``` +```output +value +``` diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index 80b0c60f8..b31d89e6f 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -429,10 +429,10 @@ the rest accept either, and hand back a buffer when every operand was one. before adding it to the accumulator, in ascending inner-index order, on both containers. They do not fuse the multiplication and addition. Raw non-finite results may remain in a buffer's internal work area, but every -ordinary indexed read applies EigenScript's numeric guard: infinity saturates at -±`1e308`, and a NaN raises in strict mode (or becomes `0` and sets the invalid -math flag under `EIGS_STRICT=0`). `sum`, `get_at`, `dot` and `write_bytes` -instead refuse non-finite buffer elements in every strict mode (N13). +ordinary indexed read and iteration step refuse stored NaN or infinity with +`value` in every strict mode, matching `get_at` (N13). Strict NaN retains +its first-NaN diagnostic and invalid flag. All execution tiers report the +same error kind, message and source line. Structural buffer equality and the remaining scalar reductions normalize each input before comparison or arithmetic; the reduction association contracts remain unchanged. Mixed buffer/list tensor operations and @@ -996,3 +996,21 @@ catch e: ```output value ``` + +### Stored buffer data boundary + +Buffer kernels can retain non-finite data. Scalar indexing and iteration +raise `value` when that data is read, in every strict mode (N13). + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +try: + print of p[0] +catch e: + print of e.kind +``` +```output +value +``` diff --git a/docs/SPEC.md b/docs/SPEC.md index 102c28fa1..455700750 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -384,11 +384,11 @@ consequences are contracts you can rely on: operand can hold an infinity), so any other source hits a backstop that raises as `arithmetic`. The JIT bails to the interpreter on a non-finite result, so both tiers raise from the same guard. Buffer storage may retain - a raw non-finite kernel result internally. Ordinary indexed reads apply - that guard: infinity saturates at ±`1e308`, while under `EIGS_STRICT=0` a - `NaN` becomes `0` and sets `math_flags.invalid` (strict mode raises). - `sum`, `get_at`, `dot` and `write_bytes` instead refuse non-finite buffer - elements in every strict mode (N13). + a raw non-finite kernel result internally. Indexing and iteration, like + `get_at`, refuse a stored NaN or infinity with `value` in every strict + mode (N13). Strict NaN preserves the first-NaN diagnostic and sets + `math_flags.invalid`; other non-finite data refusals leave flags alone. + The interpreter, JIT and leaf fallback agree on kind, message and line. - **JSON parse failure in `json_path`.** Under `EIGS_STRICT=0` a malformed document is walked leniently and a parse failure answers the same `""` an absent key does. Under strict `json_path` applies `json_decode`'s @@ -2900,3 +2900,21 @@ catch e: ```output value ``` + +### Stored buffer data boundary + +Buffer kernels can retain non-finite data. Scalar indexing and iteration +raise `value` when that data is read, in every strict mode (N13). + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +try: + print of p[0] +catch e: + print of e.kind +``` +```output +value +``` diff --git a/docs/llms.txt b/docs/llms.txt index 36484c71b..7062bccbd 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -244,9 +244,10 @@ sqrt(2) = 1.414213562373095 `json_path` document raise catchable errors. `EIGS_STRICT=0` is the per-run opt-out that brings the finite stand-ins back (`NaN` collapses to `0`, `sqrt of -1` is `0`, `abs of "x"` is `0`). - Non-finite tensor results receive the scalar guard when read from a buffer; - `sum`, `get_at`, `dot` and `write_bytes` instead refuse non-finite buffer - elements in every strict mode (N13). Structural buffer + Indexing and iteration refuse stored NaN and infinity with `value` in + every strict mode, matching `get_at` (N13). Strict NaN keeps its first + diagnostic and sets `math_flags.invalid`; every execution tier agrees on + the error kind, message and source line. Structural buffer equality, the other scalar reductions, mixed buffer/list materialization and numeric byte/sample/device conversions normalize their inputs and stop at the first raised read. `write_bytes` requires exact bytes in 0..255 @@ -707,3 +708,21 @@ catch e: ```output value ``` + +### Stored buffer data boundary + +Buffer kernels can retain non-finite data. Scalar indexing and iteration +raise `value` when that data is read, in every strict mode (N13). + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +try: + print of p[0] +catch e: + print of e.kind +``` +```output +value +``` diff --git a/src/vm.c b/src/vm.c index 1dbab137b..a9a816ea2 100644 --- a/src/vm.c +++ b/src/vm.c @@ -713,7 +713,7 @@ dict_set_cached_immediate(Value *dict, const char *key, uint32_t h, double num) /* Slot storage (#1665 arm D B10): a cache hit is a plain * slot store of the already-guarded immediate, whatever the * field held before (the old occupant is released). */ - return dict_value_rewrite_num(dict, ce->index, num); + return dict_value_rewrite_f64(dict, ce->index, num); } } return 0; @@ -795,7 +795,7 @@ static inline EigsSlot slot_bridge_wrap(Value *v) { static inline Value *slot_bridge_unwrap(EigsSlot s) { if (slot_is_f64(s)) { /* Materialize immediate -> fresh Value. Caller owns one ref. */ - return make_num(SLOT_F64_RAW(s)); + return make_float(SLOT_F64_RAW(s)); } if (slot_is_null(s)) { return make_null(); @@ -840,7 +840,7 @@ static inline Value *vm_slot_lift(int idx) { EigsSlot s = g_vm.stack[idx]; if (slot_is_ptr(s)) return slot_as_ptr(s); Value *v; - if (slot_is_f64(s)) v = make_num(SLOT_F64_RAW(s)); + if (slot_is_f64(s)) v = make_float(SLOT_F64_RAW(s)); else if (slot_is_null(s)) v = make_null(); else if (slot_is_bool(s)) v = make_bool(slot_as_bool(s)); /* #1758: an int is boxed on purpose, like a double (design 2.1); a @@ -991,7 +991,7 @@ static int import_collision_first_report(const char *name) { static Value *make_iter_state(Value *iterable) { Value *state = make_list(3); list_append(state, iterable); - Value *idx = make_num(0); + Value *idx = make_float(0); list_append(state, idx); val_decref(idx); /* #491: snapshot the length at loop entry (items[2]). ITER_NEXT bounds @@ -1004,7 +1004,7 @@ static Value *make_iter_state(Value *iterable) { int snap = 0; if (iterable && iterable->type == VAL_LIST) snap = iterable->data.list.count; else if (iterable && iterable->type == VAL_BUFFER) snap = iterable->data.buffer.count; - Value *slen = make_num((double)snap); + Value *slen = make_float((double)snap); list_append(state, slen); val_decref(slen); return state; @@ -1416,7 +1416,7 @@ int jit_helper_local_idx_get(int slot, int idx) { int i = idx; if (target->type == VAL_BUFFER) { if (i < target->data.buffer.count) { - vm_push_slot(slot_from_f64(buffer_read_num(target, i))); + vm_push_slot(slot_from_f64(buffer_read_f64(target, i))); } else { rt_error(EK_INDEX, g_vm.current_line, "buffer index %d out of range (length %d)", @@ -1573,7 +1573,7 @@ void jit_helper_dot_set(EigsChunk *chunk, int name_idx) { } /* Slot fast path (mirrors CASE(LOCAL_DOT_SET)): an immediate-num * write into an exclusive untracked num field mutates in place — - * no make_num, no refcount churn. Was 2 make_num + 1.5 free_value + * no make_float, no refcount churn. Was 2 make_float + 1.5 free_value * per DMG step via the vm_pop materialization below. */ EigsSlot val_s = g_vm.stack[g_vm.sp - 1]; EigsSlot tgt_s = g_vm.stack[g_vm.sp - 2]; @@ -1871,13 +1871,13 @@ int jit_helper_iter_next(void) { if ((unsigned)idx >= (unsigned)len) return 1; EigsSlot elem; if (iterable->type == VAL_BUFFER) { - elem = slot_from_f64(num_guard(buffer_read_num(iterable, idx))); + elem = slot_from_f64(num_guard(buffer_read_f64(iterable, idx))); } else { elem = slot_read_owned(list_slot(iterable, idx)); } /* In-place idx bump when the slot is an exclusive plain VAL_FLOAT * (matches the interpreter's NUM_REUSE fast path). */ - list_set_num(state, 1, (double)(idx + 1)); + list_set_f64(state, 1, (double)(idx + 1)); vm_push_slot(elem); return g_has_error ? 2 : 0; } @@ -2002,12 +2002,13 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { mini[msp++] = slot_read_value(list_slot(target, i)); /* borrow, no incref */ } else if (target->type == VAL_BUFFER) { if (!vm_index_resolve(&i, target->data.buffer.count)) return 0; - /* #1417: this speculative evaluator has no callee frame and - * skips OP_LINE. Let the generic call report a strict NaN at - * the indexed expression, before the guard can raise here. */ + /* R1.6d-D1: this speculative evaluator has no callee frame + * and skips OP_LINE. Every non-finite cell must fall back + * before a reader can raise, so the generic call diagnoses + * the indexed expression with the same kind/message/line. */ double raw = target->data.buffer.data[i]; - if (g_strict && raw != raw) return 0; - mini[msp++] = slot_from_f64(buffer_read_num(target, i)); + if (!isfinite(raw)) return 0; + mini[msp++] = slot_from_f64(buffer_read_f64(target, i)); } else { return 0; } @@ -2068,7 +2069,7 @@ static int vm_leaf_accessor_exec(EigsChunk *c, int argc) { * mutates sp net -1). */ /* Stage 5c: cached writer for the per-iteration __loop_iterations__ * update. env_set_local resolves the 19-char name (hash + table walk) - * and round-trips through make_num/val_decref on EVERY iteration of + * and round-trips through make_float/val_decref on EVERY iteration of * EVERY `loop while` — measured as the dominant cost of observed loops * once the loop body itself compiles to native code. Cache the resolved * slot per (env, binding_version); on a hit with an immediate-num slot @@ -2120,7 +2121,7 @@ static void loop_iter_store(Env *env, double n) { * cache lookup and refill below also read shared arrays/version, so * return before either path; a thread-local cache is not a slot lock. */ if (__builtin_expect(g_vm_multithreaded, 0) && env->mt_shared) { - Value *iter_val = make_num(n); + Value *iter_val = make_float(n); env_set_local(env, "__loop_iterations__", iter_val); val_decref(iter_val); return; @@ -2133,7 +2134,7 @@ static void loop_iter_store(Env *env, double n) { env->assign_counts[c->slot]++; return; } - Value *iter_val = make_num(n); + Value *iter_val = make_float(n); env_set_local(env, "__loop_iterations__", iter_val); val_decref(iter_val); int slot_idx, depth; @@ -2290,7 +2291,7 @@ void jit_helper_index_set(void) { if (target->type == VAL_LIST && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { double n = SLOT_F64_RAW(val_s); /* already guarded in a slot */ - list_rewrite_num(target, i, n); + list_rewrite_f64(target, i, n); } else { if (!_ok) rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, g_vm.current_line, "index %d out of range (list length %d)", @@ -2307,7 +2308,7 @@ void jit_helper_index_set(void) { if (target->type == VAL_LIST && val_is_number(idx)) { int i; if (!vm_value_index_is_int(idx, &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_float_arg(idx, "index")); } else if (vm_index_resolve(&i, target->data.list.count)) { val_incref(val); list_set_slot_owned(target, i, slot_from_heap(val)); @@ -2317,11 +2318,11 @@ void jit_helper_index_set(void) { } else if (target->type == VAL_BUFFER && val_is_number(idx)) { int i; if (!vm_value_index_is_int(idx, &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_float_arg(idx, "index")); } else if (!vm_index_resolve(&i, target->data.buffer.count)) { rt_error(EK_INDEX, g_vm.current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); } else if (val_is_number(val)) { - target->data.buffer.data[i] = eigs_num_arg(val, "buffer store"); + target->data.buffer.data[i] = eigs_float_arg(val, "buffer store"); } else { /* #1061 -- mirror of CASE(INDEX_SET)'s buffer arm. */ rt_error(EK_TYPE, g_vm.current_line, "cannot store %s in a buffer (buffers hold numbers)", @@ -2360,7 +2361,7 @@ int jit_helper_index_get(void) { } if (target->type == VAL_BUFFER) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { - double v = buffer_read_num(target, i); + double v = buffer_read_f64(target, i); slot_decref(tgt_s); vm_push_slot(slot_from_f64(v)); } else { @@ -2383,7 +2384,7 @@ int jit_helper_index_get(void) { if (target->type == VAL_LIST && val_is_number(idx)) { int i; if (!vm_value_index_is_int(idx, &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_float_arg(idx, "index")); } else if (vm_index_resolve(&i, target->data.list.count)) { result = list_get_owned(target, i); } else { @@ -2398,7 +2399,7 @@ int jit_helper_index_get(void) { } else if (target->type == VAL_STR && val_is_number(idx)) { int i; if (!vm_value_index_is_int(idx, &i)) { - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_float_arg(idx, "index")); } else if (vm_index_resolve(&i, (int)val_str_len(target))) { char buf[2] = { target->data.str[i], 0 }; result = make_str_len(buf, 1); @@ -2410,9 +2411,9 @@ int jit_helper_index_get(void) { } else if (target->type == VAL_BUFFER && val_is_number(idx)) { int i; if (!vm_value_index_is_int(idx, &i)) - rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); + rt_error(EK_VALUE, g_vm.current_line, "index must be an integer, got %g", eigs_float_arg(idx, "index")); else if (vm_index_resolve(&i, target->data.buffer.count)) - result = make_num(buffer_read_num(target, i)); + result = make_float(buffer_read_f64(target, i)); else rt_error(EK_INDEX, g_vm.current_line, "buffer index %d out of range (length %d)", @@ -3006,7 +3007,7 @@ static Value *vm_take_error_value(void) { Value *d = make_dict(3); dict_set_owned(d, "kind", make_str(err_kind_name((ErrKind)g_error_kind))); dict_set_owned(d, "message", make_str(g_error_raw)); - dict_set_owned(d, "line", make_num((double)g_error_line)); + dict_set_owned(d, "line", make_float((double)g_error_line)); return d; } @@ -3408,14 +3409,14 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, /* ---- Arithmetic ---- */ /* NUM_REUSE — retained for slow-path fallbacks that allocate via - * make_num then realize they could have mutated in place. The hot + * make_float then realize they could have mutated in place. The hot * arith fast path no longer needs it: immediate doubles have no * refcount and heap-num results are emitted as immediates. */ #define NUM_REUSE(v) ((v)->type == VAL_FLOAT && (v)->refcount == 1) /* Stack-top fast path: read two slots, extract doubles from either * immediate or heap VAL_FLOAT form, compute. Result is wrapped as a - * heap Value (via make_num or in-place NUM_REUSE). Immediates aren't + * heap Value (via make_float or in-place NUM_REUSE). Immediates aren't * emitted until B-3 audits every vm_peek caller for immediate-safe * refcount handling. */ #define ARITH_FAST(OP, UF) do { \ @@ -3476,9 +3477,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, double r = num_guard(VAL_F64_RAW(a) + VAL_F64_RAW(b)); if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } - vm_push(make_num(r)); + vm_push(make_float(r)); } else if (val_is_number(a) && val_is_number(b)) { - vm_push(make_num(num_guard(eigs_num_arg(a, "addition") + eigs_num_arg(b, "addition")))); + vm_push(make_float(num_guard(eigs_float_arg(a, "addition") + eigs_float_arg(b, "addition")))); } else if (a->type == VAL_STR && b->type == VAL_STR) { int la = val_str_len(a), lb = val_str_len(b); /* #292's byte budget charged only the size-controlled builtins; @@ -3534,17 +3535,17 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, g_math_flags |= EIGS_MATH_UNDERFLOW; \ if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } \ if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } \ - vm_push(make_num(r)); \ + vm_push(make_float(r)); \ } else if (val_is_number(a) && val_is_number(b)) { \ - double ad = eigs_num_arg(a, OPNAME), bd = eigs_num_arg(b, OPNAME); \ + double ad = eigs_float_arg(a, OPNAME), bd = eigs_float_arg(b, OPNAME); \ double r = num_guard(ad OP bd); \ if ((UF) && r == 0.0 && ad != 0.0 && bd != 0.0) \ g_math_flags |= EIGS_MATH_UNDERFLOW; \ - vm_push(make_num(r)); \ + vm_push(make_float(r)); \ } else { \ rt_error(EK_TYPE, current_line, "cannot apply '%s' to %s and %s", \ OPNAME, val_type_name(a->type), val_type_name(b->type)); \ - vm_push(make_num(0)); \ + vm_push(make_float(0)); \ } \ val_decref(a); val_decref(b); \ DISPATCH(); \ @@ -3563,23 +3564,23 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, CASE(DIV): { Value *b = vm_pop(); Value *a = vm_pop(); if (val_is_number(a) && val_is_number(b)) { - if (eigs_num_arg(b, "division") == 0.0) { + if (eigs_float_arg(b, "division") == 0.0) { rt_error(EK_VALUE, current_line, "division by zero"); - vm_push(make_num(0)); + vm_push(make_float(0)); } else { - double r = num_guard(eigs_num_arg(a, "division") / eigs_num_arg(b, "division")); + double r = num_guard(eigs_float_arg(a, "division") / eigs_float_arg(b, "division")); /* divisor already known nonzero (the raise above), so a zero * quotient from a nonzero dividend is underflow. */ - if (r == 0.0 && eigs_num_arg(a, "division") != 0.0) + if (r == 0.0 && eigs_float_arg(a, "division") != 0.0) g_math_flags |= EIGS_MATH_UNDERFLOW; if (NUM_REUSE(a)) { VAL_F64_RAW(a) = r; vm_push(a); val_decref(b); DISPATCH(); } if (NUM_REUSE(b)) { VAL_F64_RAW(b) = r; vm_push(b); val_decref(a); DISPATCH(); } - vm_push(make_num(r)); + vm_push(make_float(r)); } } else { rt_error(EK_TYPE, current_line, "cannot apply '/' to %s and %s", val_type_name(a->type), val_type_name(b->type)); - vm_push(make_num(0)); + vm_push(make_float(0)); } val_decref(a); val_decref(b); DISPATCH(); @@ -3604,17 +3605,17 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, vm_push(make_int(q)); } } else { - double divisor = eigs_num_arg(b, "floor division"); + double divisor = eigs_float_arg(b, "floor division"); /* #1758 comment 6294926822: exactly DIV's error through R1.4. * N11 changes this float arm with DIV/MOD to IEEE floor(x/0). */ if (divisor == 0.0) { rt_error(EK_VALUE, current_line, "division by zero"); - vm_push(make_num(0)); + vm_push(make_float(0)); } else { /* #1882: Python float_divmod's quotient, not floor(a/b). * Derive it from fmod so decimal boundaries and an * underflowed opposite-sign ratio agree with floor %. */ - double dividend = eigs_num_arg(a, "floor division"); + double dividend = eigs_float_arg(a, "floor division"); double rem = fmod(dividend, divisor); double div = (dividend - rem) / divisor; if (rem != 0.0 && ((rem < 0.0) != (divisor < 0.0))) @@ -3626,7 +3627,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } else { floordiv = signbit(dividend / divisor) ? -0.0 : 0.0; } - vm_push(make_num(num_guard(floordiv))); + vm_push(make_float(num_guard(floordiv))); } } } else { @@ -3656,18 +3657,18 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, vm_push(make_int(rem)); } } else { - double divisor = eigs_num_arg(b, "modulo"); + double divisor = eigs_float_arg(b, "modulo"); if (divisor == 0.0) { rt_error(EK_VALUE, current_line, "modulo by zero"); - vm_push(make_num(0)); + vm_push(make_float(0)); } else { - vm_push(make_num(num_guard(vm_floor_mod(eigs_num_arg(a, "modulo"), divisor)))); + vm_push(make_float(num_guard(vm_floor_mod(eigs_float_arg(a, "modulo"), divisor)))); } } } else { rt_error(EK_TYPE, current_line, "cannot apply '%%' to %s and %s", val_type_name(a->type), val_type_name(b->type)); - vm_push(make_num(0)); + vm_push(make_float(0)); } val_decref(a); val_decref(b); DISPATCH(); @@ -4528,7 +4529,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } /* Pop args + fn from stack (slot-direct; immediates never - * round-trip through make_num + free_value). #1171: the + * round-trip through make_float + free_value). #1171: the * callee's reference is released only AFTER callframe_init has * taken the frame's chunk reference. The stack can hold the * function's LAST reference: a rebind of its name (another @@ -4648,7 +4649,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } CASE(RETURN): { - /* Slot-native: avoid make_num/free_value round-trip when a callee + /* Slot-native: avoid make_float/free_value round-trip when a callee * returns an immediate. Carry the result slot across the frame * switch directly. */ EigsSlot result_s; @@ -4785,7 +4786,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } if (target->type == VAL_BUFFER) { if (_ok && vm_index_resolve(&i, target->data.buffer.count)) { - double v = buffer_read_num(target, i); + double v = buffer_read_f64(target, i); slot_decref(tgt_s); vm_push_slot(slot_from_f64(v)); } else { @@ -4830,7 +4831,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } if (target->type == VAL_LIST && slot_is_f64(val_s)) { if (_ok && vm_index_resolve(&i, target->data.list.count)) { - list_set_num(target, i, SLOT_F64_RAW(val_s)); + list_set_f64(target, i, SLOT_F64_RAW(val_s)); } else { if (!_ok) rt_error(EK_VALUE, current_line, "index must be an integer, got %g", SLOT_F64_RAW(idx_s)); else rt_error(EK_INDEX, current_line, "index %d out of range (list length %d)", @@ -4847,7 +4848,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (target->type == VAL_LIST && val_is_number(idx)) { int i; if (!vm_value_index_is_int(idx, &i)) { - rt_error(EK_VALUE, current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); + rt_error(EK_VALUE, current_line, "index must be an integer, got %g", eigs_float_arg(idx, "index")); } else if (vm_index_resolve(&i, target->data.list.count)) { val_incref(val); list_set_slot_owned(target, i, slot_from_heap(val)); @@ -4857,11 +4858,11 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, } else if (target->type == VAL_BUFFER && val_is_number(idx)) { int i; if (!vm_value_index_is_int(idx, &i)) { - rt_error(EK_VALUE, current_line, "index must be an integer, got %g", eigs_num_arg(idx, "index")); + rt_error(EK_VALUE, current_line, "index must be an integer, got %g", eigs_float_arg(idx, "index")); } else if (!vm_index_resolve(&i, target->data.buffer.count)) { rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); } else if (val_is_number(val)) { - target->data.buffer.data[i] = eigs_num_arg(val, "buffer store"); + target->data.buffer.data[i] = eigs_float_arg(val, "buffer store"); } else { /* #1061: the last fail-soft numeric context. A non-number * store was silently DROPPED (the old element stayed), so @@ -5006,9 +5007,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, if (target) { int i = (int)idx; if (target->type == VAL_BUFFER) { - /* DMG hot path: mem[addr] — emit immediate, skip make_num. */ + /* DMG hot path: mem[addr] — emit immediate, skip make_float. */ if (i < target->data.buffer.count) { - vm_push_slot(slot_from_f64(buffer_read_num(target, i))); + vm_push_slot(slot_from_f64(buffer_read_f64(target, i))); } else { rt_error(EK_INDEX, current_line, "buffer index %d out of range (length %d)", i, target->data.buffer.count); @@ -5187,12 +5188,12 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, ip += exit_offset; } else { /* Update index — mutate in place when the existing slot is - * an exclusive plain VAL_FLOAT (avoids per-iter make_num/free). */ - list_set_num(state, 1, (double)(idx + 1)); + * an exclusive plain VAL_FLOAT (avoids per-iter make_float/free). */ + list_set_f64(state, 1, (double)(idx + 1)); if (iterable->type == VAL_BUFFER) { - /* Push number immediate directly — skip make_num + immediate- + /* Push number immediate directly — skip make_float + immediate- * promote round-trip through vm_push. */ - vm_push_slot(slot_from_f64(buffer_read_num(iterable, idx))); + vm_push_slot(slot_from_f64(buffer_read_f64(iterable, idx))); } else { EigsSlot elem = slot_read_owned(list_slot(iterable, idx)); vm_push_slot(elem); @@ -5531,9 +5532,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, list_append_owned(list, make_str( vm_slot_value_opaque(e, (int)slot) ? "opaque" : observer_slot_report(&q))); - list_append_owned(list, make_num(q.entropy)); - list_append_owned(list, make_num(s->dH)); - list_append_owned(list, make_num(s->prev_dH)); + list_append_owned(list, make_float(q.entropy)); + list_append_owned(list, make_float(s->dH)); + list_append_owned(list, make_float(s->prev_dH)); vm_push(list); } else { vm_push(builtin_observe(NULL)); @@ -5567,9 +5568,9 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, list_append_owned(list, make_str( vm_slot_value_opaque(oe, oidx) ? "opaque" /* #708 */ : observer_slot_report(&q))); - list_append_owned(list, make_num(q.entropy)); - list_append_owned(list, make_num(s->dH)); - list_append_owned(list, make_num(s->prev_dH)); + list_append_owned(list, make_float(q.entropy)); + list_append_owned(list, make_float(s->dH)); + list_append_owned(list, make_float(s->prev_dH)); vm_push(list); } else { vm_push(builtin_observe(NULL)); @@ -5634,14 +5635,14 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, switch (kind) { case 0: /* what */ if (v && v->type == VAL_INT) { val_incref(v); result = v; } - else if (v && v->type == VAL_FLOAT) { result = make_num(VAL_F64_RAW(v)); } + else if (v && v->type == VAL_FLOAT) { result = make_float(VAL_F64_RAW(v)); } /* #1637: a bool is its own value -- it fell to the else arm and * answered 0, so `what is (5 > 3)` read as false. */ else if (v && v->type == VAL_BOOL) { result = make_bool(v->data.boolean); } - else if (v && v->type == VAL_STR) { result = make_num(val_str_len(v)); } - else if (v && v->type == VAL_LIST) { result = make_num(v->data.list.count); } - else if (v && v->type == VAL_BUFFER) { result = make_num(v->data.buffer.count); } - else { result = make_num(0); } + else if (v && v->type == VAL_STR) { result = make_float(val_str_len(v)); } + else if (v && v->type == VAL_LIST) { result = make_float(v->data.list.count); } + else if (v && v->type == VAL_BUFFER) { result = make_float(v->data.buffer.count); } + else { result = make_float(0); } break; case 1: /* who — returns descriptive type name */ if (v) result = make_str( @@ -5659,10 +5660,10 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * slot trajectory (observer state is binding-keyed). where/why/how on a * bound ident go through INTERROGATE_NAMED; the bare value form reports * the no-observation defaults. */ - case 2: /* when */ result = make_num(0); break; - case 3: /* where */ result = make_num(0); break; - case 4: /* why */ result = make_num(0); break; - case 5: /* how */ result = make_num(1.0); break; + case 2: /* when */ result = make_float(0); break; + case 3: /* where */ result = make_float(0); break; + case 4: /* why */ result = make_float(0); break; + case 5: /* how */ result = make_float(1.0); break; } val_decref(v); vm_push(result); @@ -5682,7 +5683,7 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, result = make_str(name); break; case 2: /* when — return assignment count */ - result = make_num(env_get_assign_count(frame->env, name, h)); + result = make_float(env_get_assign_count(frame->env, name, h)); break; case 6: { /* prev — value just before the most recent assignment */ EigsSlot prev_slot; @@ -5708,14 +5709,14 @@ static Value *vm_run_ex(EigsChunk *chunk, Env *env, Task *resume, * in-place mutation is visible. dH (why/how) is the * assignment-recorded trajectory and stays as stored. */ double h_now; - result = make_num(observer_entropy_now(oe, oidx, &h_now) + result = make_float(observer_entropy_now(oe, oidx, &h_now) ? h_now : s->entropy); } - else if (kind == 4) result = make_num(s->dH); - else result = make_num(observer_settledness(s->dH)); + else if (kind == 4) result = make_float(s->dH); + else result = make_float(observer_settledness(s->dH)); } else { /* #262 Step E: unobserved binding — no trajectory. */ - result = make_num(kind == 5 ? 1.0 : 0.0); + result = make_float(kind == 5 ? 1.0 : 0.0); } break; } diff --git a/tests/test_buffer_nonfinite_read.eigs b/tests/test_buffer_nonfinite_read.eigs index 78d220988..6d764d777 100644 --- a/tests/test_buffer_nonfinite_read.eigs +++ b/tests/test_buffer_nonfinite_read.eigs @@ -46,7 +46,10 @@ try: print of (get_at of [infs, 0]) catch e: print of e.kind -print of (gather of [infs, [0, 0]])[0] +try: + print of (gather of [infs, [0, 0]])[0] +catch e: + print of e.kind left is buffer of [1, 2] left[0] is 1e200 @@ -55,7 +58,10 @@ right is buffer of [2, 1] right[0] is 1e200 right[1] is 0 - 1e200 nans is matmul of [left, right] -print of nans[0] +try: + print of nans[0] +catch e: + print of e.kind # N13 / R1.6d: final data reader refuses the raw nonfinite payload. try: print of (buf_get of [nans, 0]) @@ -65,11 +71,14 @@ try: print of (get_at of [nans, 0]) catch e: print of e.kind -print of (gather of [nans, [0]])[0] +try: + print of (gather of [nans, [0]])[0] +catch e: + print of e.kind +# R1.6d-D1 point 3 / N13: lenient scalar refusals leave INVALID clear. print of (math_flags of null).invalid -# Buffer indices are scalar reads as well. A NaN index must collapse to zero -# before it is converted to an integer; casting the raw value is undefined C. +# Buffer indices require finite exact data before any integer conversion. source is buffer of 1 source[0] is 7 source_matrix is reshape of [source, 1, 1] @@ -84,4 +93,5 @@ try: catch e: print of e.kind print of target[0] +# R1.6d-D1 point 3 / N13: lenient scalar refusals leave INVALID clear. print of (math_flags of null).invalid diff --git a/tests/test_buffer_nonfinite_read.out b/tests/test_buffer_nonfinite_read.out index e7a64e5e0..39564245a 100644 --- a/tests/test_buffer_nonfinite_read.out +++ b/tests/test_buffer_nonfinite_read.out @@ -5,13 +5,13 @@ value value value value -1e+308 -0 value value -0 -true +value +value +value +false value value 0 -true +false diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py index fabd89bac..685917ab7 100644 --- a/tests/test_doc_examples.py +++ b/tests/test_doc_examples.py @@ -324,17 +324,17 @@ def is_asan_build(): # --------------------------------------------------------------------------- POPULATION = { # file fences paired fragment nocheck value-comments - "README.md": (15, 11, 4, 0, 0), # R1.6g: +1 paired Rust-derived N9 example - "docs/llms.txt": (17, 14, 2, 1, 0), # R1.6g: +1 paired Rust-derived N9 example - "docs/SPEC.md": (95, 91, 1, 3, 0), # R1.6g: +1 paired Rust-derived N9 example - "docs/COMPARISON.md": (27, 26, 1, 0, 0), # R1.6g: +1 paired Rust-derived N9 example + "README.md": (16, 12, 4, 0, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/llms.txt": (18, 15, 2, 1, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/SPEC.md": (96, 92, 1, 3, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/COMPARISON.md": (28, 27, 1, 0, 0), # R1.6g: +1 paired Rust-derived N9 example "docs/CONCURRENCY.md": ( 8, 8, 0, 0, 0), # #1736: +1 paired (detached task catches its own error) "docs/STDLIB.md": ( 15, 7, 8, 0, 0), "docs/SYNTAX.md": ( 35, 15, 20, 0, 1), "docs/PREDICATES.md": ( 13, 2, 10, 1, 4), "docs/DIAGNOSTICS.md": ( 4, 1, 3, 0, 0), "docs/OBSERVER.md": ( 2, 0, 2, 0, 0), - "docs/BUILTINS.md": ( 1, 1, 0, 0, 0), + "docs/BUILTINS.md": (2, 2, 0, 0, 0), "docs/LANGUAGE_CONTRACT.md": ( 1, 0, 1, 0, 0), } diff --git a/tests/test_numeric_guard.eigs b/tests/test_numeric_guard.eigs index 3897951a3..866c2df6a 100644 --- a/tests/test_numeric_guard.eigs +++ b/tests/test_numeric_guard.eigs @@ -101,8 +101,8 @@ assert of [unobserved_inf == CAP, "NG19 unobserved reassignment literal caps"] # #1417: tensor kernels may hold an intermediate IEEE infinity in their -# unboxed result buffer. Every language-level read must expose the numeric -# ceiling, independent of which opcode consumes the scalar. +# unboxed result buffer. Every language-level read must use the finite +# data boundary, independent of which opcode consumes the scalar. raw_inf_input is buffer of 4 raw_inf_input[0] is 1e300 raw_inf_input[1] is 1e300 @@ -110,17 +110,28 @@ raw_inf_input[2] is 1e300 raw_inf_input[3] is 1e300 raw_inf_matrix is reshape of [raw_inf_input, 2, 2] raw_inf_product is matmul of [raw_inf_matrix, raw_inf_matrix] -assert of [not (raw_inf_product[0] > CAP), "NG31 comparison reads a clamped buffer infinity"] -assert of [(raw_inf_product[0] / raw_inf_product[1]) == 1, "NG31 division reads clamped buffer infinities"] -assert of [(raw_inf_product[0] % 3) == 2, "NG31 modulo reads a clamped buffer infinity"] -assert of [not (raw_inf_product[0] * 0.5 > CAP), "NG31 multiplication reads a clamped buffer infinity"] -assert of [not (raw_inf_product[0] + 0 > CAP), "NG31 addition reads a clamped buffer infinity"] -raw_inf_scalar is raw_inf_product[0] -assert of [raw_inf_scalar == CAP, "NG31 index read into a scalar is clamped"] +define ng_read_cmp(b) as: + return b[0] > CAP +define ng_read_div(b) as: + return b[0] / b[1] +define ng_read_mod(b) as: + return b[0] % 3 +define ng_read_mul(b) as: + return b[0] * 0.5 > CAP +define ng_read_add(b) as: + return b[0] + 0 > CAP +define ng_read_zero(b) as: + return b[0] +ng_final_refuses of [ng_read_cmp, raw_inf_product, "NG31 N13 indexed comparison refuses infinity"] +ng_final_refuses of [ng_read_div, raw_inf_product, "NG31 N13 indexed division refuses infinity"] +ng_final_refuses of [ng_read_mod, raw_inf_product, "NG31 N13 indexed modulo refuses infinity"] +ng_final_refuses of [ng_read_mul, raw_inf_product, "NG31 N13 indexed multiply refuses infinity"] +ng_final_refuses of [ng_read_add, raw_inf_product, "NG31 N13 indexed addition refuses infinity"] +ng_final_refuses of [ng_read_zero, raw_inf_product, "NG31 N13 index refuses infinity"] ng_final_refuses of [buf_get, [raw_inf_product, 0], "NG31 N13 buf_get refuses infinity"] -# A NaN uses the same read boundary as infinity. In non-strict mode every -# accessor returns numeric 0 and sets invalid; none may leak the NaN-box null +# A NaN uses the same refusing data boundary as infinity. Every +# accessor refuses nonfinite data; none may leak the NaN-box null # tag merely because it bypasses make_num. nan_left is buffer of [1, 2] nan_left[0] is 1e200 @@ -129,7 +140,7 @@ nan_right is buffer of [2, 1] nan_right[0] is 1e200 nan_right[1] is 0 - 1e200 raw_nan_product is matmul of [nan_left, nan_right] -assert of [raw_nan_product[0] == 0, "NG32 indexed NaN read collapses to zero"] +ng_final_refuses of [ng_read_zero, raw_nan_product, "NG32 N13 indexed NaN refuses"] ng_final_refuses of [buf_get, [raw_nan_product, 0], "NG33 N13 buf_get refuses NaN"] # N13 / R1.6c: get_at now uses the final finite-only buffer reader. ng_get_at_refused is false @@ -139,7 +150,7 @@ catch e: ng_get_at_refused is e.kind == "value" assert of [ng_get_at_refused, "NG34 N13 get_at refuses non-finite payload"] nan_gathered is gather of [raw_nan_product, [0]] -assert of [nan_gathered[0] == 0, "NG35 gather NaN read collapses to zero"] +ng_final_refuses of [ng_read_zero, nan_gathered, "NG35 N13 gathered NaN refuses on read"] # #1417: structural comparisons and scalar reductions read normalized inputs. pair_left is buffer of [1, 1] diff --git a/tests/test_numeric_guard_flags.sh b/tests/test_numeric_guard_flags.sh index 7e50d598d..f0108383c 100755 --- a/tests/test_numeric_guard_flags.sh +++ b/tests/test_numeric_guard_flags.sh @@ -61,9 +61,22 @@ right is buffer of [2, 1] right[0] is 1e200 right[1] is 0 - 1e200 raw is matmul of [left, right]' +# R1.6d-D1 point 3 / N13: indexed data reads refuse lenient NaN. +# NG35's gather copies the raw cell; the following [0] is the scalar read. for spec in \ 'NG32 index|x is raw[0]' \ - 'NG35 gather|x is (gather of [raw, [0]])[0]' \ + 'NG35 gathered index|x is (gather of [raw, [0]])[0]'; do + name=${spec%%|*}; op=${spec#*|} + run "$name N13 refusal" "$nan_setup +before is math_flags of null +caught is false +try: + $op +catch e: + caught is e.kind == \"value\" +assert of [caught and ((math_flags of null) == before), \"R1.6d-D1 indexed NaN refuses without flag writes\"]" +done +for spec in \ 'NG38 equality|x is raw == raw' \ 'NG39 distinct equality|zero is buffer of 1; x is raw == zero'; do name=${spec%%|*}; op=${spec#*|}; op=$(printf '%s' "$op" | sed 's/; */\n/g') @@ -110,7 +123,7 @@ catch e: assert of [caught, \"N13 sum refuses non-finite payload instead of substituting zero\"]" # NG56 needs 8 stored bytes since #1926 refuses a short input. Keep the NaN # in buffer storage so the decoder's own read performs the refusal: an index read -# first (raw[0]) would set it before f64_from_bytes ever ran. +# first (raw[0]) would refuse before f64_from_bytes ever ran (N13). run "NG56 f64_from_bytes N13 refusal" 'left is buffer of [8, 2] for i in range of 16: left[i] is 1e200 diff --git a/tests/test_strict_math.sh b/tests/test_strict_math.sh index 36c35ea26..f12060bbb 100755 --- a/tests/test_strict_math.sh +++ b/tests/test_strict_math.sh @@ -242,9 +242,9 @@ run "SM49a opt-out matmul(inf-inf) LIST path still collapses to 0 + invalid" 0 0 'local r is matmul of [[[1e200, 1e200]], [[1e200], [0 - 1e200]]] print of f"{r} {(math_flags of null).invalid}"' # #1417 applies the same scalar-read rule to buffer and list results. The -# kernel may retain a raw NaN internally, but exposing it collapses it to 0 and -# sets invalid just as make_num does on the boxed path. -run "SM49b opt-out matmul(inf-inf) BUFFER read collapses to 0 + invalid" 0 0 "0 true" \ +# kernel may retain a raw NaN internally; indexed data reads refuse it in +# every strict mode (R1.6d-D1/N13), without a lenient INVALID flag write. +run "SM49b opt-out matmul(inf-inf) BUFFER read refuses" 0 1 "buffer_read_f64: expected a finite number" \ 'local m1 is buffer of [1, 2] m1[0] is 1e200 m1[1] is 1e200 @@ -255,7 +255,7 @@ local r is matmul of [m1, m2] print of f"{r[0]} {(math_flags of null).invalid}"' # #1131: canonicalization must visit every NaN and preserve intervening # finite results. On ARM the kernel's invalid-operation NaNs are positive. -run "SM49c opt-out matmul buffer guards each NaN and preserves finite neighbor" 0 0 "0 2e+200 0 true" \ +run "SM49c opt-out matmul buffer refuses each NaN and preserves finite neighbor" 0 0 "value 2e+200 value false" \ 'local a is buffer of [1, 2] a[0] is 1e200 a[1] is 1e200 @@ -267,7 +267,17 @@ b[3] is 0 - 1e200 b[4] is 1 b[5] is 0 - 1e200 local r is matmul of [a, b] -print of f"{r[0]} {r[1]} {r[2]} {(math_flags of null).invalid}"' +local first is "accepted" +local last is "accepted" +try: + first is r[0] +catch e: + first is e.kind +try: + last is r[2] +catch e: + last is e.kind +print of f"{first} {r[1]} {last} {(math_flags of null).invalid}"' run "SM50 strict pow(-8, 0.5) raises, named" 1 1 "pow: result is not a number" 'print of (pow of [0 - 8, 0.5])' run "SM51 strict elementwise pow raises" 1 1 "pow: result is not a number" 'print of (pow of [[0 - 8, 4], 0.5])' run "SM52 strict num(\"nan\") raises, named" 1 1 "num: expected complete numeric-literal text" 'print of (num of "nan")' From d671fa699d324548887fbfd71ac1f1065d45014b Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 08:33:18 -0500 Subject: [PATCH 171/188] refactor(runtime): use final numeric readers and IEEE buffer equality R1.6z-D1: raw stored-double element equality, NaN unequal to itself, signed zeros equal, no errors or math flags. Runtime/compiler/task/tape float producers retain kinds. Six MAP rows green across four tiers, strict 0/1; exact diagnostic contract. Release build rc=0 warnings=0; executed docs updated with behavior and ruling/prior-art reasoning. Reviewed amendment under R1.6z-D1 point 1 / N11 and R1.6 plan rule 4: NG38/NG39 assert false for NaN buffer equality and unchanged math flags, replacing the legacy INVALID-write expectations in this same behavior commit. Numeric flags 33/33; full release suite 4606/4606, failures=0, skipped=10, sections=304, rc0; embed-smoke rc0; completed strict differential rc0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- README.md | 21 ++++++++++++++ docs/BUILTINS.md | 21 ++++++++++++++ docs/COMPARISON.md | 27 +++++++++++++++-- docs/SPEC.md | 21 ++++++++++++++ docs/design/phase2-numbers.md | 33 +++++++++++++++++++-- docs/llms.txt | 23 ++++++++++++++- src/compiler.c | 2 +- src/eigenscript.c | 48 +++++++++++++++---------------- src/eigenscript.h | 2 +- src/task.c | 10 +++---- src/trace.c | 2 +- tests/test_doc_examples.py | 10 +++---- tests/test_numeric_guard.eigs | 12 ++++---- tests/test_numeric_guard_flags.sh | 6 ++-- 14 files changed, 187 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index c1cbdc43c..f372153ed 100644 --- a/README.md +++ b/README.md @@ -968,3 +968,24 @@ catch e: ```output value ``` + +### Buffer equality + +Buffers compare their stored doubles with IEEE equality: NaN differs from +everything, even itself; infinities compare by sign; signed zeros are equal. +Equality never raises or changes math flags, including under strict mode. + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +print of (p == p) +print of (p == g) +sgd_update of [p, p, 1.0] +print of (p == p) +``` +```output +true +false +false +``` diff --git a/docs/BUILTINS.md b/docs/BUILTINS.md index 76f92ed92..f27e17ab9 100644 --- a/docs/BUILTINS.md +++ b/docs/BUILTINS.md @@ -1170,3 +1170,24 @@ catch e: ```output value ``` + +### Buffer equality + +Buffers compare their stored doubles with IEEE equality: NaN differs from +everything, even itself; infinities compare by sign; signed zeros are equal. +Equality never raises or changes math flags, including under strict mode. + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +print of (p == p) +print of (p == g) +sgd_update of [p, p, 1.0] +print of (p == p) +``` +```output +true +false +false +``` diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index b31d89e6f..d99f4f693 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -433,8 +433,10 @@ ordinary indexed read and iteration step refuse stored NaN or infinity with `value` in every strict mode, matching `get_at` (N13). Strict NaN retains its first-NaN diagnostic and invalid flag. All execution tiers report the same error kind, message and source line. -Structural buffer equality and the remaining scalar reductions normalize each -input before comparison or arithmetic; the reduction +Structural buffer equality compares stored doubles with IEEE equality, without +raises or math flags; NaN differs from everything, including itself, infinities +compare by sign, and signed zeros are equal. The remaining scalar reductions +retain their declared data boundaries; the reduction association contracts remain unchanged. Mixed buffer/list tensor operations and numeric byte/sample/device conversions also normalize reads and stop on the first error. `write_bytes` requires exact bytes in 0..255 (N5/Q1); other byte @@ -1014,3 +1016,24 @@ catch e: ```output value ``` + +### Buffer equality + +Buffers compare their stored doubles with IEEE equality: NaN differs from +everything, even itself; infinities compare by sign; signed zeros are equal. +Equality never raises or changes math flags, including under strict mode. + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +print of (p == p) +print of (p == g) +sgd_update of [p, p, 1.0] +print of (p == p) +``` +```output +true +false +false +``` diff --git a/docs/SPEC.md b/docs/SPEC.md index 455700750..20e0f7d25 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -2918,3 +2918,24 @@ catch e: ```output value ``` + +### Buffer equality + +Buffers compare their stored doubles with IEEE equality: NaN differs from +everything, even itself; infinities compare by sign; signed zeros are equal. +Equality never raises or changes math flags, including under strict mode. + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +print of (p == p) +print of (p == g) +sgd_update of [p, p, 1.0] +print of (p == p) +``` +```output +true +false +false +``` diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 55566efad..b9589e502 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -898,6 +898,35 @@ the builtin table's `q7` column, §6, names each builtin's classes): measurement's scale): round, and raise `value` naming the builtin when the result does not fit what the C call can honour (`eigs_magnitude_arg`). +### 2.6a Stored non-finite buffers (R1.6z-D1) + +Buffer equality compares the stored doubles element by element with C `==` +and requires equal counts. NaN equals nothing, including itself; +inf equals +only +inf, -inf only -inf, and -0.0 equals +0.0. Equality is total: it never +raises and never writes math flags, in either strict mode. Buffers stay out +of the identity shortcut (#1417). This applies N2/N11 scalar equality to +unboxed elements and avoids fabricated finite answers (Principles §2). + +Measured prior art in the ruling: Python `array.array('d')` and `memoryview` +compare a NaN-containing buffer unequal to itself, matching NumPy +`array_equal` with its default `equal_nan=False`. Python list identity +shortcuts are deliberately rejected. Refusal would make equality partial; +bit comparison would incorrectly distinguish signed zeros. + +The public C getter `eigs_value_buffer_get` returns the stored double exactly, +including NaN payloads, infinities and negative zero. It never normalizes, +raises for a valid element, or writes math flags. It mirrors the setter's +bit-preserving store and Lua `lua_tonumberx`/CPython `PyFloat_AsDouble`, +which also hand C the raw double. Clamping fabricates a value; a new status +channel would change the ABI for a property C can test with `isfinite`. +Wrong-type and out-of-range reports remain the separately decided API contract. +The getter migration and public API docs land in the embed file group. + +VM indexing and iteration use the finite data boundary, matching `get_at` +(R1.6d-D1): lenient NaN and every infinity raise `value`; strict NaN keeps +its first diagnostic and INVALID flag. Speculative leaf evaluation bails +before raising, preserving the callee's error kind, message and source line. + ### 2.7 Every meaning change coincides with a token change Round 0's order changed meanings with no token change: R1.1 widened @@ -974,7 +1003,7 @@ catches a miss: with one float box on both sides today (EQ compares two floats in its fast path, and container comparisons pass fresh element views; read, not probed, since no NaN exists yet), so R2.2 excludes floats from the - shortcut as #1417 excluded buffers, and the C slot test calls it with + shortcut as #1417 excluded buffers (see §2.6a, R1.6z-D1), and the C slot test calls it with one NaN box on both sides; - C casts of a double to an integer type (undefined on NaN or inf): every builtin argument goes through a §2.6 reader, which refuses a non-finite @@ -2244,7 +2273,7 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: `log of 0` is -inf, `x/0` is ±inf, `0/0` and float `x%0` are NaN. Q8: `sort`/`sort_by` order floats by IEEE `totalOrder` (NaN after +inf), and `min`/`max` propagate NaN. `values_equal_impl`'s identity shortcut - excludes floats. + excludes floats, extending the stored-buffer rule in §2.6a (R1.6z-D1). 3. **R2.3, N13 refusal inside the writers:** the JSON encoder, the store encoder (delete the pre-walk `store_nonfinite_scalar`), the byte encoders and the int conversion. This removes the class #1746 chased for diff --git a/docs/llms.txt b/docs/llms.txt index 7062bccbd..6555d6a4b 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -248,7 +248,7 @@ sqrt(2) = 1.414213562373095 every strict mode, matching `get_at` (N13). Strict NaN keeps its first diagnostic and sets `math_flags.invalid`; every execution tier agrees on the error kind, message and source line. Structural buffer - equality, the other scalar reductions, mixed buffer/list materialization + The other scalar reductions, mixed buffer/list materialization and numeric byte/sample/device conversions normalize their inputs and stop at the first raised read. `write_bytes` requires exact bytes in 0..255 (N5/Q1); other byte converters retain truncation and wrapping at this stage; @@ -726,3 +726,24 @@ catch e: ```output value ``` + +### Buffer equality + +Buffers compare their stored doubles with IEEE equality: NaN differs from +everything, even itself; infinities compare by sign; signed zeros are equal. +Equality never raises or changes math flags, including under strict mode. + +```eigenscript +p is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [p, g, 1e308] +print of (p == p) +print of (p == g) +sgd_update of [p, p, 1.0] +print of (p == p) +``` +```output +true +false +false +``` diff --git a/src/compiler.c b/src/compiler.c index c318aa685..2c8a493a6 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -580,7 +580,7 @@ static int add_string_constant(Compiler *c, const char *str) { } static int add_num_constant(Compiler *c, double num) { - Value *v = make_num(num); + Value *v = make_float(num); int idx = chunk_add_constant(c->chunk, v); val_decref(v); return check_const_index(idx); diff --git a/src/eigenscript.c b/src/eigenscript.c index 93aa3715b..787afca5f 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -1450,24 +1450,24 @@ Value *observer_slot_trajectory(const ObserverSlot *s) { /* windows read newest-first (offset 0 = most recent); emit oldest-first * so the lists read chronologically, like a history. */ for (int i = vcnt - 1; i >= 0; i--) { - list_append_owned(rel, make_num(observer_slot_v_get(s, (size_t)i))); - list_append_owned(raw, make_num(observer_slot_vr_get(s, (size_t)i))); + list_append_owned(rel, make_float(observer_slot_v_get(s, (size_t)i))); + list_append_owned(raw, make_float(observer_slot_vr_get(s, (size_t)i))); } for (int i = dcnt - 1; i >= 0; i--) - list_append_owned(dh, make_num(observer_slot_window_get(s, (size_t)i))); + list_append_owned(dh, make_float(observer_slot_window_get(s, (size_t)i))); dict_set_owned(out, "rel", rel); dict_set_owned(out, "raw", raw); dict_set_owned(out, "dh", dh); - dict_set_owned(out, "entropy", make_num(s ? s->entropy : 0.0)); - dict_set_owned(out, "dH", make_num(s ? s->dH : 0.0)); - dict_set_owned(out, "last_entropy", make_num(s ? s->last_entropy : 0.0)); - dict_set_owned(out, "last_value", make_num((s && s->v_used) ? s->last_value : 0.0)); + dict_set_owned(out, "entropy", make_float(s ? s->entropy : 0.0)); + dict_set_owned(out, "dH", make_float(s ? s->dH : 0.0)); + dict_set_owned(out, "last_entropy", make_float(s ? s->last_entropy : 0.0)); + dict_set_owned(out, "last_value", make_float((s && s->v_used) ? s->last_value : 0.0)); dict_set_owned(out, "observed", make_bool(s && s->used != 0)); /* #1637 */ dict_set_owned(out, "numeric", make_bool(s && s->v_used != 0)); /* #1044: the depth this slot classifies over travels with the snapshot, * so `classify of (trajectory of x)` agrees with `report of x` for a * binding carrying a per-binding override. */ - dict_set_owned(out, "window", make_num((double)observer_slot_window(s))); + dict_set_owned(out, "window", make_float((double)observer_slot_window(s))); return out; } @@ -1500,7 +1500,7 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { Value *w = dict_get_view_local(dict, "window", &w_view); if (w) { /* #1758: a number of either kind, read through the bridge */ - double wd = val_is_number(w) ? eigs_num_arg(w, __func__) : 0.0; + double wd = val_is_number(w) ? eigs_float_arg(w, __func__) : 0.0; if (!val_is_number(w) || wd < OBSERVER_WINDOW_MIN || wd > OBSERVER_WINDOW_MAX || wd != (int)wd) return 0; @@ -1524,8 +1524,8 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { memset(out, 0, sizeof *out); return 0; } - out->v_window[out->v_window_count] = eigs_slot_num(a, __func__); - out->vr_window[out->v_window_count] = eigs_slot_num(b, __func__); + out->v_window[out->v_window_count] = eigs_slot_float(a, __func__); + out->vr_window[out->v_window_count] = eigs_slot_float(b, __func__); out->v_window_count++; } out->v_window_head = (uint8_t)(out->v_window_count % N); @@ -1540,7 +1540,7 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { memset(out, 0, sizeof *out); return 0; } - out->dh_window[out->dh_window_count++] = eigs_slot_num(a, __func__); + out->dh_window[out->dh_window_count++] = eigs_slot_float(a, __func__); } out->dh_window_head = (uint8_t)(out->dh_window_count % N); /* #1637: the scalar fields are numbers and the two flags are bools, as @@ -1558,7 +1558,7 @@ int observer_slot_from_trajectory(ObserverSlot *out, Value *dict) { memset(out, 0, sizeof *out); return 0; } - *dsts[k] = eigs_num_arg(v, __func__); /* #1758: an int converts (the bridge) */ + *dsts[k] = eigs_float_arg(v, __func__); /* #1758: an int converts (the bridge) */ } EIGS_VIEW(fo_view); EIGS_VIEW(fn_view); Value *fo = dict_get_view_local(dict, "observed", &fo_view); @@ -1663,7 +1663,7 @@ void free_value(Value *v) { env_intern_release_value(v); if (v->type == VAL_FLOAT) { /* the freelist recycles float boxes; an int box is freed */ #ifndef EIGS_POOL_OFF_NUM - /* Route freed NUMs to freelist for reuse by make_num */ + /* Route freed NUMs to freelist for reuse by make_float */ if (g_num_freelist_count < NUM_FREELIST_CAP) { memcpy(EIGS_NUM_LINK(v), &g_num_freelist, sizeof(Value *)); g_num_freelist = v; @@ -1765,7 +1765,7 @@ static inline Value *make_float_pooled(double n) { eigs_num_park_unpoison(v); memset(v, 0, sizeof(Value)); } else -#endif /* EIGS_POOL_OFF_NUM (#1665): never satisfy a make_num from the freelist — +#endif /* EIGS_POOL_OFF_NUM (#1665): never satisfy a make_float from the freelist — * every heap NUM is a fresh xcalloc. */ { v = xcalloc(1, sizeof(Value)); @@ -1812,7 +1812,7 @@ void recycle_intermediate(Value *v) { #endif } -/* Unpooled make_num: never touches the per-thread NUM freelist, so it is +/* Unpooled make_float: never touches the per-thread NUM freelist, so it is * safe without a current VM thread (C-level fixtures, tests/test_intern_owners.c). */ Value* make_float_permanent(double n) { n = num_guard(n); @@ -2366,7 +2366,7 @@ EigsSlot slot_from_value(Value *v) { } /* slot_to_value: produces a Value* the caller owns a ref to. - * - immediate double -> make_num + * - immediate double -> make_float * - immediate null -> g_null_singleton * - immediate bool -> the true/false singleton (#1637) * - heap/tracked pointer -> incref and return @@ -2377,7 +2377,7 @@ EigsSlot slot_from_value(Value *v) { * as null, silently). */ Value* slot_to_value(EigsSlot s) { - if (slot_is_f64(s)) return make_num(SLOT_F64_RAW(s)); + if (slot_is_f64(s)) return make_float(SLOT_F64_RAW(s)); if (slot_is_null(s)) return &g_null_singleton; if (slot_is_bool(s)) return make_bool(slot_as_bool(s)); if (slot_is_heap(s)) { @@ -2883,7 +2883,7 @@ static EigsSlot module_ns_project(Value *d, Env *e, const char *key, uint32_t h, * release, so no destructor runs under the hold. (#1758: an * int takes the general path below; slot_to_value boxes it and * the dict store re-canonicalizes it.) */ - dict_value_rewrite_num(d, di, SLOT_F64_RAW(s)); + dict_value_rewrite_f64(d, di, SLOT_F64_RAW(s)); env_shared_unlock(e); *found = 1; return dict_value_slot(d, di); @@ -3131,7 +3131,7 @@ static Value *chan_clone_rec(Value *v, int depth) { if (depth > CHAN_CLONE_MAX_DEPTH && v->type != VAL_FLOAT && v->type != VAL_INT && v->type != VAL_NULL && v->type != VAL_BOOL && v->type != VAL_STR) { val_incref(v); return v; } switch (v->type) { - case VAL_FLOAT: return make_num(VAL_F64_RAW(v)); + case VAL_FLOAT: return make_float(VAL_F64_RAW(v)); case VAL_INT: return make_int(VAL_I64_RAW(v)); case VAL_NULL: return make_null(); case VAL_BOOL: return make_bool(v->data.boolean); @@ -3409,11 +3409,9 @@ static int values_equal_impl(Value *a, Value *b, int depth, const char *op) { case VAL_BUFFER: { if (a->data.buffer.count != b->data.buffer.count) return 0; for (int i = 0; i < a->data.buffer.count; i++) { - double av = buffer_read_num(a, i); - if (g_has_error) return 0; - double bv = buffer_read_num(b, i); - if (g_has_error) return 0; - if (av != bv) return 0; + /* R1.6z-D1: total IEEE equality on stored doubles. No + * scalar boundary, normalization, error or math-flag write. */ + if (!(a->data.buffer.data[i] == b->data.buffer.data[i])) return 0; } return 1; } diff --git a/src/eigenscript.h b/src/eigenscript.h index 979e20a82..170af7433 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -460,7 +460,7 @@ struct Value { ValType type; union { /* #1637 round 4: renamed so no unchecked read compiles. A Value's - * number is read through the checking accessors (eigs_num_arg, + * number is read through the checking accessors (eigs_float_arg, * eigs_list_num, eigs_opt_num), which raise on a bool or any other * non-number, or through VAL_F64_RAW where the type is already * proven -- and every VAL_F64_RAW use sits in a function on the diff --git a/src/task.c b/src/task.c index 6f5c2433d..999c653d7 100644 --- a/src/task.c +++ b/src/task.c @@ -311,9 +311,9 @@ Value *task_sched_trace_read(void) { for (int i = 0; i < s->trace_count; i++) { const SchedTraceEntry *e = &s->trace[i]; Value *d = make_dict(4); - dict_set_owned(d, "seq", make_num((double)i)); - dict_set_owned(d, "tick", make_num(e->tick)); - dict_set_owned(d, "task", make_num(e->task)); + dict_set_owned(d, "seq", make_float((double)i)); + dict_set_owned(d, "tick", make_float(e->tick)); + dict_set_owned(d, "task", make_float(e->task)); dict_set_owned(d, "cause", make_str(e->cause < SCAUSE__COUNT ? sched_cause_name[e->cause] : "?")); list_append_owned(out, d); @@ -581,7 +581,7 @@ int task_do_kill(int tid) { Value *ev = make_dict(3); dict_set_owned(ev, "kind", make_str(err_kind_name(EK_INTERRUPT))); dict_set_owned(ev, "message", make_str("task was killed")); - dict_set_owned(ev, "line", make_num(0)); + dict_set_owned(ev, "line", make_float(0)); t->error_value = ev; } for (int i = 1; i < HANDLE_TABLE_SIZE; i++) { @@ -686,7 +686,7 @@ static void task_error_summary(Value *ev, char *out, size_t cap) { if (msg && msg->type == VAL_STR) { Value *line = dict_get_view(ev, "line", &lv); /* The checking accessor (#1637): the type is proven, so it cannot raise. */ - double ln = (line && val_is_number(line)) ? eigs_num_arg(line, __func__) : 0; + double ln = (line && val_is_number(line)) ? eigs_float_arg(line, __func__) : 0; if (ln > 0) snprintf(out, cap, "line %.0f: %s", ln, msg->data.str); else diff --git a/src/trace.c b/src/trace.c index 554bc88b1..459ba18be 100644 --- a/src/trace.c +++ b/src/trace.c @@ -2461,7 +2461,7 @@ static Value *parse_value_p(const char **p) { * tape tokens are scheduled in docs/design/phase2-numbers.md §8, R2.5. */ if (end == *p || !at_token_boundary(*end) || !isfinite(d)) return NULL; *p = end; - return make_num(d); + return make_float(d); } static Value *parse_value(const char *s) { diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py index 685917ab7..374ecb7e5 100644 --- a/tests/test_doc_examples.py +++ b/tests/test_doc_examples.py @@ -324,17 +324,17 @@ def is_asan_build(): # --------------------------------------------------------------------------- POPULATION = { # file fences paired fragment nocheck value-comments - "README.md": (16, 12, 4, 0, 0), # R1.6g: +1 paired Rust-derived N9 example - "docs/llms.txt": (18, 15, 2, 1, 0), # R1.6g: +1 paired Rust-derived N9 example - "docs/SPEC.md": (96, 92, 1, 3, 0), # R1.6g: +1 paired Rust-derived N9 example - "docs/COMPARISON.md": (28, 27, 1, 0, 0), # R1.6g: +1 paired Rust-derived N9 example + "README.md": (17, 13, 4, 0, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/llms.txt": (19, 16, 2, 1, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/SPEC.md": (97, 93, 1, 3, 0), # R1.6g: +1 paired Rust-derived N9 example + "docs/COMPARISON.md": (29, 28, 1, 0, 0), # R1.6g: +1 paired Rust-derived N9 example "docs/CONCURRENCY.md": ( 8, 8, 0, 0, 0), # #1736: +1 paired (detached task catches its own error) "docs/STDLIB.md": ( 15, 7, 8, 0, 0), "docs/SYNTAX.md": ( 35, 15, 20, 0, 1), "docs/PREDICATES.md": ( 13, 2, 10, 1, 4), "docs/DIAGNOSTICS.md": ( 4, 1, 3, 0, 0), "docs/OBSERVER.md": ( 2, 0, 2, 0, 0), - "docs/BUILTINS.md": (2, 2, 0, 0, 0), + "docs/BUILTINS.md": (3, 3, 0, 0, 0), "docs/LANGUAGE_CONTRACT.md": ( 1, 0, 1, 0, 0), } diff --git a/tests/test_numeric_guard.eigs b/tests/test_numeric_guard.eigs index 866c2df6a..f898fbbfa 100644 --- a/tests/test_numeric_guard.eigs +++ b/tests/test_numeric_guard.eigs @@ -152,7 +152,7 @@ assert of [ng_get_at_refused, "NG34 N13 get_at refuses non-finite payload"] nan_gathered is gather of [raw_nan_product, [0]] ng_final_refuses of [ng_read_zero, nan_gathered, "NG35 N13 gathered NaN refuses on read"] -# #1417: structural comparisons and scalar reductions read normalized inputs. +# R1.6z-D1: structural comparisons use stored IEEE doubles; reductions use their declared data readers. pair_left is buffer of [1, 1] pair_left[0] is 1e200 pair_right is buffer of [1, 2] @@ -162,9 +162,9 @@ raw_pair is matmul of [pair_left, pair_right] finite_pair is buffer of 2 finite_pair[0] is CAP finite_pair[1] is 0 - CAP -assert of [raw_pair == finite_pair, "NG36 structural equality normalizes infinities"] -assert of [(list_contains of [[raw_pair], finite_pair]), "NG36 list_contains shares normalized equality"] -assert of [(list_index_of of [[raw_pair], finite_pair]) == 0, "NG36 list_index_of shares normalized equality"] +assert of [raw_pair != finite_pair, "NG36 IEEE equality distinguishes infinity from finite"] +assert of [not (list_contains of [[raw_pair], finite_pair]), "NG36 list_contains shares IEEE equality"] +assert of [(list_index_of of [[raw_pair], finite_pair]) == -1, "NG36 list_index_of shares IEEE equality"] # N13 / R1.6b: sum now crosses the final float-reader boundary, which # refuses non-finite buffer payloads in both strict modes. Other reductions # keep their earlier normalization policy until their own reader migration. @@ -177,9 +177,9 @@ define ng_sum_refuses_nonfinite(tensor_input, label) as: assert of [refused, label] ng_sum_refuses_nonfinite of [raw_pair, "NG37 N13 sum refuses non-finite elements before cancellation"] ng_final_refuses of [mean, raw_pair, "NG37 N13 mean refuses non-finite input"] -assert of [raw_nan_product == raw_nan_product, "NG38 same-buffer equality normalizes NaN"] +assert of [raw_nan_product != raw_nan_product, "NG38 IEEE NaN buffer differs from itself"] zero_one is buffer of 1 -assert of [raw_nan_product == zero_one, "NG39 distinct-buffer equality normalizes NaN"] +assert of [raw_nan_product != zero_one, "NG39 IEEE NaN differs from zero"] zero_pair is buffer of 2 # N13 / R1.6c: dot also refuses instead of substituting finite operands. ng_dot_refused is false diff --git a/tests/test_numeric_guard_flags.sh b/tests/test_numeric_guard_flags.sh index f0108383c..6ac5b912f 100755 --- a/tests/test_numeric_guard_flags.sh +++ b/tests/test_numeric_guard_flags.sh @@ -76,13 +76,15 @@ catch e: caught is e.kind == \"value\" assert of [caught and ((math_flags of null) == before), \"R1.6d-D1 indexed NaN refuses without flag writes\"]" done +# R1.6z-D1 point 1 / N11: IEEE equality never writes arithmetic flags. for spec in \ 'NG38 equality|x is raw == raw' \ 'NG39 distinct equality|zero is buffer of 1; x is raw == zero'; do name=${spec%%|*}; op=${spec#*|}; op=$(printf '%s' "$op" | sed 's/; */\n/g') - run "$name invalid" "$nan_setup + run "$name N11 IEEE flags unchanged" "$nan_setup +before is math_flags of null $op -assert of [(math_flags of null).invalid, \"NaN read sets invalid\"]" +assert of [not x and ((math_flags of null) == before), \"R1.6z-D1 IEEE NaN equality is false without flag writes\"]" done # N13 / R1.6d: these raw NaN reads refuse in lenient mode. for spec in \ From b948b7e85c5326b4377826b8dc87d62f898d6f44 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 08:36:43 -0500 Subject: [PATCH 172/188] refactor(containers): retire bridge uses from boxing and facades Three float boxes use the exact same make_float pool/guard. slot_view reads its already-proven float through slot_f64_value, preserving raw payload behavior for direct-C facades. No ownership or numeric-kind change. Bridge definitions remain solely for later fixture/final deletion groups. Release build rc=0 warnings=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- src/container.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/container.h b/src/container.h index c3f3c19d1..bdc684f04 100644 --- a/src/container.h +++ b/src/container.h @@ -192,8 +192,9 @@ static inline Value *slot_view(EigsSlot s, EigsView *view) { if (slot_type(s) != VAL_FLOAT) return eigs_slot_ref(s); } view->v.type = VAL_FLOAT; - VAL_F64_RAW(&view->v) = slot_is_f64(s) ? SLOT_F64_RAW(s) - : eigs_num_arg(slot_as_ptr(s), "slot_view"); + /* The branch above proves float storage; retain raw facade semantics + * even for a direct-C nonfinite box, without a flag write or raise. */ + (void)slot_f64_value(s, &VAL_F64_RAW(&view->v)); view->v.refcount = EIGS_VIEW_RC; return &view->v; } @@ -320,7 +321,7 @@ static inline Value *list_get_owned(const Value *list, int i) { static inline Value *list_get_return(const Value *list, int i) { EigsSlot s = list_slot(list, i); if (slot_is_smi(s)) return slot_to_value(s); - return slot_is_f64(s) ? make_num(SLOT_F64_RAW(s)) : eigs_slot_ref(s); + return slot_is_f64(s) ? make_float(SLOT_F64_RAW(s)) : eigs_slot_ref(s); } static inline Value *dict_value_get_owned(const Value *dict, int i) { return slot_to_value(dict_value_slot(dict, i)); @@ -329,7 +330,7 @@ __attribute__((unused)) static inline Value *dict_value_get_return(const Value *dict, int i) { EigsSlot s = dict_value_slot(dict, i); if (slot_is_smi(s)) return slot_to_value(s); - return slot_is_f64(s) ? make_num(SLOT_F64_RAW(s)) : eigs_slot_ref(s); + return slot_is_f64(s) ? make_float(SLOT_F64_RAW(s)) : eigs_slot_ref(s); } /* Keyed reads (eigenscript.c). The slot is borrowed from the dict (for a @@ -359,7 +360,7 @@ static inline void dict_value_set_owned(Value *dict, int i, Value *v) { * append borrows it and therefore increfs. Every double path applies * num_guard. */ static inline Value *eigs_slot_box(EigsSlot s) { - if (slot_is_f64(s)) return make_num(num_guard(SLOT_F64_RAW(s))); + if (slot_is_f64(s)) return make_float(num_guard(SLOT_F64_RAW(s))); if (slot_is_smi(s)) return slot_to_value(s); /* #1758: kind-preserving */ Value *v = eigs_slot_ref(s); val_incref(v); return v; } From a99b6dd6a7002ed6a80db34a4b7fbea28112ef58 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 08:38:30 -0500 Subject: [PATCH 173/188] fix(embed): return stored buffer doubles bit for bit R1.6z-D1: getter preserves canonical/payload NaN, infinities and negative zero; valid reads never raise or change flags. Wrong-type/OOB behavior unchanged. Public header and embedding guide document contract. C getter gate checks=36 failures=0; release build rc=0 warnings=0. Reviewed amendment under R1.6 plan rule 4, R1.6z-D1 point 2 / N11: the complete C/embed getter sweep found one legacy pin at embed_smoke.c:673 (stored INFINITY == EIGS_NUM_MAX). Replace it with memcmp against the stored double, no pending error, and unchanged seeded math flags. No other old NaN/inf getter pin found. Acceptance: release build 1/1 rc0; embed-smoke 1/1 rc0; embed-smoke-asan 1/1 rc0 with detect_leaks=1; old-assertion plant 1/1 killed at rc2, exactly one FAIL, then source restored. Original C getter gate 36/36 unchanged. No frozen expectation or runtime change. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/EMBEDDING.md | 12 ++++++++++++ src/eigs_embed.c | 5 +++-- src/eigs_embed.h | 3 +++ src/embed_smoke.c | 41 +++++++++++++++++++++++++++++++++-------- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/docs/EMBEDDING.md b/docs/EMBEDDING.md index 5dfe753f9..2eeb2807a 100644 --- a/docs/EMBEDDING.md +++ b/docs/EMBEDDING.md @@ -697,3 +697,15 @@ CHANGELOG entry. The opaque types (`EigsState`, `EigsThread`, `EigsValue`) intentionally hide their layout: those structs change between releases and the only safe way to touch them is through the documented accessors. + +### Stored non-finite buffer data + +`eigs_value_buffer_get` returns a valid element's stored double exactly, +including NaN payloads, infinities and negative zero. A set/get round trip +preserves bits; the getter neither normalizes nor writes math flags and never +raises for non-finite data. The setter already stores doubles unchanged. C +callers can use `isfinite()` when their application needs finite values. +Wrong-type and out-of-range reports and their sentinels keep the API contract +above. Script indexing and iteration instead enforce the finite data boundary. +This follows Lua's `lua_tonumberx` and CPython's `PyFloat_AsDouble` C boundary +(R1.6z-D1; design §2.6a). diff --git a/src/eigs_embed.c b/src/eigs_embed.c index e4643d26a..43d71983f 100644 --- a/src/eigs_embed.c +++ b/src/eigs_embed.c @@ -299,7 +299,7 @@ EigsValue *eigs_get_global(const char *name) { /* ---- Values ------------------------------------------------------- */ -EigsValue *eigs_value_new_num(double n) { return make_num(n); } +EigsValue *eigs_value_new_num(double n) { return make_float(n); } EigsValue *eigs_value_new_string(const char *s) { return make_str(s ? s : ""); } EigsValue *eigs_value_new_null(void) { return make_null(); } EigsValue *eigs_value_new_bool(int b) { return make_bool(b != 0); } @@ -434,7 +434,8 @@ double eigs_value_buffer_get(EigsValue *v, int i) { i, v->data.buffer.count); return 0.0; } - return buffer_read_num(v, i); + /* R1.6z-D1: the public C API exposes stored data, bit for bit. */ + return v->data.buffer.data[i]; } void eigs_value_buffer_set(EigsValue *v, int i, double x) { diff --git a/src/eigs_embed.h b/src/eigs_embed.h index 4af139c80..649da79cf 100644 --- a/src/eigs_embed.h +++ b/src/eigs_embed.h @@ -196,6 +196,9 @@ EigsValue *eigs_value_new_buffer(int count); /* zeroed, 1-D (unshaped) */ * unchanged; inspect/clear the error through the error API above. A thread * with no attached state has no error channel and gets the sentinel alone. */ int eigs_value_buffer_len(EigsValue *v); /* wrong type: 0 + error */ +/* Valid reads return the stored double exactly: NaN payloads, infinities and + * signed zero included. No normalization, math-flag write or raise. This + * mirrors the setter's raw double store; C callers can test isfinite(). */ double eigs_value_buffer_get(EigsValue *v, int i); /* OOB: 0.0 + error */ void eigs_value_buffer_set(EigsValue *v, int i, double x); /* OOB: no-op + error */ diff --git a/src/embed_smoke.c b/src/embed_smoke.c index 3bcf1c99e..fa2903b07 100644 --- a/src/embed_smoke.c +++ b/src/embed_smoke.c @@ -195,8 +195,8 @@ static void test_worker_exit_lifecycle(void) { CHECK(handle && handle->type == VAL_DICT, "exit fixture owns join handle"); if (handle && handle->type == VAL_DICT) { int found_id = 0, found_gen = 0; - f.handle_id = (int)eigs_slot_num(dict_get_slot(handle, "_handle_id", &found_id), "embed_smoke"); - f.handle_gen = (uint32_t)eigs_slot_num(dict_get_slot(handle, "_handle_gen", &found_gen), "embed_smoke"); + f.handle_id = (int)eigs_slot_float(dict_get_slot(handle, "_handle_id", &found_id), "embed_smoke"); + f.handle_gen = (uint32_t)eigs_slot_float(dict_get_slot(handle, "_handle_gen", &found_gen), "embed_smoke"); CHECK(found_id && found_gen, "join handle carries its id and generation"); pthread_t requester; int made = pthread_create(&requester, NULL, exit_after_join_claim, &f) == 0; @@ -669,9 +669,21 @@ int main(void) { CHECK(eigs_has_error() && strcmp(eigs_last_error_kind(), "index_range") == 0, "negative buffer set leaves index_range"); eigs_clear_error(); - eigs_value_buffer_set(buf, 2, INFINITY); - CHECK(eigs_value_buffer_get(buf, 2) == EIGS_NUM_MAX, - "buffer non-finite get is clamped"); + /* R1.6z-D1 point 2 / N11: the C getter preserves stored bits and + * leaves both the pending-error channel and math flags alone. */ + { + double stored = INFINITY; + unsigned saved_flags = g_math_flags; + eigs_value_buffer_set(buf, 2, stored); + g_math_flags = EIGS_MATH_UNDERFLOW; + double read_back = eigs_value_buffer_get(buf, 2); + CHECK(memcmp(&read_back, &stored, sizeof stored) == 0, + "R1.6z-D1 buffer non-finite get preserves stored bits"); + CHECK(!eigs_has_error(), "R1.6z-D1 buffer non-finite get never raises"); + CHECK(g_math_flags == EIGS_MATH_UNDERFLOW, + "R1.6z-D1 buffer non-finite get preserves math flags"); + g_math_flags = saved_flags; + } /* Host buffer visible to script — SAME object, no copy at the * boundary: the script's buf_set is visible back in C. */ @@ -735,10 +747,23 @@ int main(void) { strcmp(eigs_value_as_string(r), "int") == 0, "#1417 recursive failure prefix has a boxed int result"); eigs_value_release(r); + /* R1.6z-D1: equality never crosses the scalar data boundary. */ + for (int mode = 0; mode <= 1; ++mode) { + eigs_state_set_strict(st, mode); + g_math_flags = 0; + r = eigs_eval_string("[nf_raw == nf_raw, nf_raw == nf_finite, " + "list_contains of [[nf_raw, nf_later], nf_finite], " + "list_index_of of [[nf_raw, nf_later], nf_finite]]"); + CHECK(r && !eigs_has_error() && r->type == VAL_LIST && + r->data.list.count == 4 && + slot_is_bool(list_slot(r, 0)) && !slot_as_bool(list_slot(r, 0)), + "R1.6z-D1 NaN buffer equality is false without a raise"); + CHECK(g_math_flags == 0, "R1.6z-D1 equality leaves math flags alone"); + eigs_value_release(r); + eigs_clear_error(); + } + eigs_state_set_strict(st, 1); const char *nf_reads[] = { - "nf_raw == nf_raw", "nf_raw == nf_finite", - "list_contains of [[nf_raw, nf_later], nf_finite]", - "list_index_of of [[nf_raw, nf_later], nf_finite]", "sum of nf_raw", "mean of nf_raw", "norm of nf_raw", "sum of ([nf_raw, nf_later])", "sum of nf_shaped", From 60e2f623a6a52f22a9e5426ec9e5ca6c86bfd253 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 08:39:01 -0500 Subject: [PATCH 174/188] test(numbers): migrate C fixtures off the numeric bridge Explicit double producers/readers retain float kind; make_float_permanent preserves no-state fixtures. Retire the three old bridge classifier entries (their raw-NaN behavior is intentionally not reinterpreted as a finite data-reader expectation). Final typed readers keep their independent matrix. Release build and container slot C test rc=0. Final deletion follows in its own commit. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/slot_layer.c | 44 +------------------------ tests/strict_shape_descriptor.c | 4 +-- tests/test_container_slots.c | 48 ++++++++++++++-------------- tests/test_db_params.c | 2 +- tests/test_embed_observer.c | 16 +++++----- tests/test_error_line_fallback.c | 10 +++--- tests/test_gc_traversal.c | 4 +-- tests/test_intern_owners.c | 12 +++---- tests/test_loop_counter_sequential.c | 2 +- tests/test_native_fn.c | 6 ++-- tests/test_pool_poison.c | 8 ++--- tests/test_sandbox_intern_lifetime.c | 2 +- tests/test_sandbox_work_budget.c | 10 +++--- tests/test_trace_context.c | 6 ++-- tests/test_trace_correspondence.c | 4 +-- 15 files changed, 68 insertions(+), 110 deletions(-) diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index e49552c96..d3279736c 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -111,12 +111,6 @@ static int aborts_naming(void (*fn)(EigsSlot), EigsSlot s, const char *who, cons /* ---- Part A: RETURN checks (0 = ok) ------------------------------------ */ -static int r_eigs_slot_elem_num(int64_t v) { return eigs_slot_elem_num(smi(v), "slot_layer") != (double)v; } -static int r_eigs_slot_num(int64_t v) { return eigs_slot_num(smi(v), "slot_layer") != (double)v; } -static int r_eigs_slot_opt_num(int64_t v) { - double d = -7.25; - return eigs_slot_opt_num(smi(v), &d, "slot_layer") != 1 || d != (double)v; -} static int r_eigs_slot_store_borrow(int64_t v) { return eigs_slot_store_borrow(smi(v)).u != smi(v).u; } static int r_eigs_slot_store_owned(int64_t v) { return eigs_slot_store_owned(smi(v)).u != smi(v).u; } static int r_ent_child_slot(int64_t v) { @@ -234,9 +228,6 @@ static const Entry ENTRIES[] = { {"vm.c:vm_number_compare", r_vm_number_compare, 0, 0, "exact numeric comparison"}, {"vm.c:vm_iter_index", r_vm_iter_index, 0, 0, "checked C int metadata"}, {"vm.c:vm_iter_limit", r_vm_iter_limit, 0, 0, "bounded snapshot"}, - {"container.h:eigs_slot_elem_num", r_eigs_slot_elem_num, 0, 0, "bridge: the int's double"}, - {"container.h:eigs_slot_num", r_eigs_slot_num, 0, 0, "bridge: the int's double"}, - {"container.h:eigs_slot_opt_num", r_eigs_slot_opt_num, 0, 0, "bridge: present, the int's double"}, {"container.h:eigs_slot_store_borrow", r_eigs_slot_store_borrow, 0, 0, "canonical storage: unchanged"}, {"container.h:eigs_slot_store_owned", r_eigs_slot_store_owned, 0, 0, "canonical storage: unchanged"}, {"eigenscript.c:ent_child_slot", r_ent_child_slot, 0, 0, "the entropy of its double"}, @@ -335,10 +326,6 @@ static int is_heap_kind(EigsSlot s) { return s.u == KB[K_HEAP]; } /* Cells: call one entry and render its result. Each runs in a forked child. */ #define CELL(name) static void c_##name(EigsSlot s, char *b, size_t n) -CELL(elem_num) { r_d(b, n, eigs_slot_elem_num(s, "matrix")); } -CELL(num) { r_d(b, n, eigs_slot_num(s, "matrix")); } -CELL(opt_num) { double d = -7.25; int r = eigs_slot_opt_num(s, &d, "matrix"); - snprintf(b, n, "o:%d d:%016llx", r, (unsigned long long)u64_of(d)); } CELL(store_borrow) { EigsSlot r = eigs_slot_store_borrow(s); snprintf(b, n, "b:%016llx", (unsigned long long)r.u); if (is_heap_kind(r)) slot_decref(r); } CELL(store_owned) { if (is_heap_kind(s)) slot_incref(s); @@ -388,32 +375,6 @@ CELL(obs_value) { r_v(b, n, obs_slot_value(s)); } #define ABORT(who) snprintf(b, n, "A:%s", who) static void e_d(char *b, size_t n, double d, int raise) { r_d(b, n, d); if (raise) strncat(b, " raise", n - strlen(b) - 1); } static void e_bool(char *b, size_t n, int k) { snprintf(b, n, "v:%s", k == K_TRUE ? "true" : "false"); } -EXP(elem_num) { - switch (kclass(k)) { - case C_F64: e_d(b, n, KD(k), 0); break; - case C_NULL: case C_HEAP: e_d(b, n, 0.0, 0); break; /* non-strict element read */ - case C_BOOL: e_d(b, n, 0.0, 1); break; /* a bool raises (#1637) */ - case C_SMI: e_d(b, n, 5.0, 0); break; - default: ABORT("eigs_slot_ref"); - } -} -EXP(num) { - switch (kclass(k)) { - case C_F64: e_d(b, n, KD(k), 0); break; - case C_SMI: e_d(b, n, 5.0, 0); break; - case C_NULL: case C_BOOL: case C_HEAP: e_d(b, n, 0.0, 1); break; /* required: raises */ - default: ABORT("eigs_slot_ref"); - } -} -EXP(opt_num) { - switch (kclass(k)) { - case C_F64: snprintf(b, n, "o:1 d:%016llx", (unsigned long long)KB[k]); break; - case C_SMI: snprintf(b, n, "o:1 d:%016llx", (unsigned long long)u64_of(5.0)); break; - case C_NULL: snprintf(b, n, "o:0 d:%016llx", (unsigned long long)u64_of(-7.25)); break; - case C_BOOL: case C_HEAP: snprintf(b, n, "o:0 d:%016llx raise", (unsigned long long)u64_of(-7.25)); break; - default: ABORT("eigs_slot_ref"); - } -} EXP(store_slot) { /* both normalisers: a double is guarded (NaN -> 0), the rest kept */ snprintf(b, n, "b:%016llx", (unsigned long long)(k == K_NAN ? 0 : KB[k])); } @@ -600,9 +561,6 @@ static const MatrixEntry MATRIX[] = { {"vm.c:vm_number_compare", c_vm_number_compare, e_vm_number_compare}, {"vm.c:vm_iter_index", c_vm_iter_index, e_vm_iter_index}, {"vm.c:vm_iter_limit", c_vm_iter_limit, e_vm_iter_limit}, - {"container.h:eigs_slot_elem_num", c_elem_num, e_elem_num}, - {"container.h:eigs_slot_num", c_num, e_num}, - {"container.h:eigs_slot_opt_num", c_opt_num, e_opt_num}, {"container.h:eigs_slot_store_borrow", c_store_borrow, e_store_slot}, {"container.h:eigs_slot_store_owned", c_store_owned, e_store_slot}, {"eigenscript.c:ent_child_slot", c_ent_child, e_ent_child}, @@ -920,7 +878,7 @@ static int part_e(void) { int main(void) { EigsState *st = eigs_open(); if (!st) { printf("slot-layer-test: FAIL eigs_open\n"); return 1; } - /* Part B reads the canonical NaN back through make_num, whose guard + /* Part B reads the canonical NaN back through make_float, whose guard * raises under strict mode; the test pins the soft read instead. */ eigs_state_set_strict(st, 0); g_str = make_str("x"); diff --git a/tests/strict_shape_descriptor.c b/tests/strict_shape_descriptor.c index 29ed5eb36..367b3076e 100644 --- a/tests/strict_shape_descriptor.c +++ b/tests/strict_shape_descriptor.c @@ -31,10 +31,10 @@ int main(void) { Value *code = make_list(chunk->code_len); Value *constants = make_list(chunk->const_count); for (int i = 0; i < chunk->code_len; i++) - list_append_owned(code, make_num(chunk->code[i])); + list_append_owned(code, make_float(chunk->code[i])); /* list_append takes its own reference before chunk_free releases its copy. */ list_append(constants, chunk->constants[0]); - list_append_owned(descriptor, make_num(EIGS_BYTECODE_ABI)); + list_append_owned(descriptor, make_float(EIGS_BYTECODE_ABI)); list_append_owned(descriptor, code); list_append_owned(descriptor, constants); json = eigs_json_encode(descriptor); diff --git a/tests/test_container_slots.c b/tests/test_container_slots.c index 215941196..5d727c8c8 100644 --- a/tests/test_container_slots.c +++ b/tests/test_container_slots.c @@ -11,8 +11,8 @@ static int failed; #define CHECK(x) do { if (!(x)) { fprintf(stderr, "FAIL:%d: %s\n", __LINE__, #x); failed = 1; } } while (0) static int num_cmp(const void *a, const void *b) { - double da = eigs_slot_num(*(const EigsSlot *)a, __func__); - double db = eigs_slot_num(*(const EigsSlot *)b, __func__); + double da = eigs_slot_float(*(const EigsSlot *)a, __func__); + double db = eigs_slot_float(*(const EigsSlot *)b, __func__); return (da > db) - (da < db); } @@ -24,14 +24,14 @@ int main(int argc, char **argv) { * must abort in the real builtin-return compensation path. */ static EigsView escaped; Value *arg = make_list(1); - list_append_num(arg, 1.0); + list_append_f64(arg, 1.0); vm_borrow_compensate(arg, slot_view(slot_from_f64(1665.0), &escaped), 1, NULL, NULL); return 99; } Value *list = make_list(8); Value *nested = make_list(1); Value *str = make_str("slot"); - list_append_num(list, 3.0); + list_append_f64(list, 3.0); list_append_slot(list, eigs_container_slot(str)); list_append_slot(list, eigs_container_slot(nested)); list_append_slot(list, eigs_container_slot(make_null())); @@ -48,28 +48,28 @@ int main(int argc, char **argv) { CHECK(slot_type(list_slot(list, 0)) == VAL_FLOAT); CHECK(list_elem_type(list, 1) == VAL_STR); CHECK(list_get_ref(list, 0) == NULL && list_get_ref(list, 1) != NULL); - CHECK(eigs_slot_num(list_slot(list, 0), "test") == 3.0); - CHECK(eigs_slot_elem_num(list_slot(list, 0), "test") == 3.0); + CHECK(eigs_slot_float(list_slot(list, 0), "test") == 3.0); + CHECK(eigs_slot_elem_float(list_slot(list, 0), "test") == 3.0); double opt = 7.0; - CHECK(!eigs_slot_opt_num(list_slot(list, 3), &opt, "test") && opt == 7.0); - CHECK(eigs_slot_opt_num(list_slot(list, 0), &opt, "test") && opt == 3.0); + CHECK(!eigs_slot_opt_float(list_slot(list, 3), &opt, "test") && opt == 7.0); + CHECK(eigs_slot_opt_float(list_slot(list, 0), &opt, "test") && opt == 3.0); { EIGS_VIEW(a); EIGS_VIEW(b); Value *av = list_get_view(list, 0, &a); - list_append_num(list, 9.0); + list_append_f64(list, 9.0); Value *bv = list_get_view(list, 5, &b); - CHECK(av != bv && eigs_num_arg(av, "test") == 3.0 && eigs_num_arg(bv, "test") == 9.0); + CHECK(av != bv && eigs_float_arg(av, "test") == 3.0 && eigs_float_arg(bv, "test") == 9.0); CHECK(list_get_view(list, 1, &a) == list_get_ref(list, 1)); } Value *owned = list_get_owned(list, 0); Value *returned = list_get_return(list, 0); CHECK(owned != returned && owned->type == VAL_FLOAT && VAL_F64_RAW(owned) == 3.0); val_decref(owned); val_decref(returned); - list_set_num(list, 0, 4.0); + list_set_f64(list, 0, 4.0); list_set_slot_owned(list, 1, slot_from_heap(make_str("owned"))); - CHECK(eigs_slot_num(list_slot(list, 0), "test") == 4.0); + CHECK(eigs_slot_float(list_slot(list, 0), "test") == 4.0); /* A boxed number or a singleton stored through a heap slot is re-encoded. */ - list_set_slot_owned(list, 2, slot_from_heap(make_num(5.0))); + list_set_slot_owned(list, 2, slot_from_heap(make_float(5.0))); CHECK(slot_is_f64(list_values_storage(list)[2])); list_set_owned(list, 3, make_bool(0)); CHECK(list_values_storage(list)[3].u == SLOT_FALSE_BITS); @@ -77,26 +77,26 @@ int main(int argc, char **argv) { { int strict = g_strict; g_strict = 0; - list_set_num(list, 4, -__builtin_nan("")); + list_set_f64(list, 4, -__builtin_nan("")); g_strict = strict; CHECK(slot_is_f64(list_values_storage(list)[4])); } EigsSlot taken = list_take_slot(list, 0); - CHECK(eigs_slot_num(taken, "test") == 4.0); + CHECK(eigs_slot_float(taken, "test") == 4.0); slot_decref(taken); list_move(list, 0, 0, 1); Value *sort = make_list(3); - list_append_num(sort, 2); list_append_num(sort, 1); list_append_num(sort, 3); + list_append_f64(sort, 2); list_append_f64(sort, 1); list_append_f64(sort, 3); list_sort(sort, num_cmp); - CHECK(eigs_slot_num(list_slot(sort, 0), "test") == 1.0); + CHECK(eigs_slot_float(list_slot(sort, 0), "test") == 1.0); /* Zero bits are 0.0: a calloc'd slot array reads as numbers. */ Value *zeros = make_list(4); CHECK(slot_is_f64(list_values_storage(zeros)[0]) && zeros->data.list.count == 0); Value *dict = make_dict(4); - dict_set_owned(dict, "n", make_num(2)); + dict_set_owned(dict, "n", make_float(2)); dict_set_owned(dict, "s", make_str("dict")); dict_set_owned(dict, "l", make_list(1)); dict_set_owned(dict, "z", make_null()); @@ -105,8 +105,8 @@ int main(int argc, char **argv) { int si = env_hash_find_dict(dict, "s", env_hash_name("s")); CHECK(dict_value_type(dict, ni) == VAL_FLOAT && dict_value_get_ref(dict, ni) == NULL); CHECK(slot_is_f64(dict_values_storage(dict)[ni])); - CHECK(eigs_slot_num(dict_value_slot(dict, ni), "test") == 2.0); - { EIGS_VIEW(v); CHECK(eigs_num_arg(dict_value_get_view(dict, ni, &v), "test") == 2.0); } + CHECK(eigs_slot_float(dict_value_slot(dict, ni), "test") == 2.0); + { EIGS_VIEW(v); CHECK(eigs_float_arg(dict_value_get_view(dict, ni, &v), "test") == 2.0); } { EIGS_VIEW(v); Value *zv = dict_get_view(dict, "z", &v); CHECK(zv && zv->type == VAL_NULL && dict_get_view(dict, "missing", &v) == NULL); } { int found = 0; EigsSlot zs = dict_get_slot(dict, "z", &found); @@ -115,13 +115,13 @@ int main(int argc, char **argv) { owned = dict_value_get_owned(dict, ni); returned = dict_value_get_return(dict, ni); CHECK(owned != returned && VAL_F64_RAW(owned) == 2.0); val_decref(owned); val_decref(returned); - dict_value_set_num(dict, ni, 8.0); + dict_value_set_f64(dict, ni, 8.0); dict_value_set_slot_owned(dict, si, slot_from_heap(make_str("changed"))); - CHECK(eigs_slot_num(dict_value_slot(dict, ni), "test") == 8.0); + CHECK(eigs_slot_float(dict_value_slot(dict, ni), "test") == 8.0); taken = dict_value_take_slot(dict, ni); - CHECK(eigs_slot_num(taken, "test") == 8.0 && slot_is_null(dict_value_slot(dict, ni))); + CHECK(eigs_slot_float(taken, "test") == 8.0 && slot_is_null(dict_value_slot(dict, ni))); slot_decref(taken); - dict_value_set_owned(dict, ni, make_num(8.0)); + dict_value_set_owned(dict, ni, make_float(8.0)); val_decref(zeros); val_decref(dict); val_decref(sort); val_decref(list); eigs_close(state); diff --git a/tests/test_db_params.c b/tests/test_db_params.c index 301f7ebe8..ca8c4e377 100644 --- a/tests/test_db_params.c +++ b/tests/test_db_params.c @@ -20,7 +20,7 @@ int main(void) { Value *arg = make_list(5); list_append_owned(arg, make_str("update t set a = $1, b = $2, c = $3, d = $4")); list_append(arg, make_bool(1)); - list_append_owned(arg, make_num(3)); + list_append_owned(arg, make_float(3)); list_append_owned(arg, make_str("s")); list_append(arg, make_bool(0)); const char *sql = NULL; const char *params[DB_MAX_PARAMS]; diff --git a/tests/test_embed_observer.c b/tests/test_embed_observer.c index d706510b8..f56eb7ac7 100644 --- a/tests/test_embed_observer.c +++ b/tests/test_embed_observer.c @@ -34,11 +34,11 @@ static void raw_host(void) { return; } Env *env = env_new(NULL); - env_set_local_owned(env, "raw_x", make_num(100)); + env_set_local_owned(env, "raw_x", make_float(100)); double x = 100; for (int i = 0; i < 12; i++) { x *= 0.5; - env_set_local_owned(env, "raw_x", make_num(x)); + env_set_local_owned(env, "raw_x", make_float(x)); observer_slot_update_num(env, 0, x); } int answer = observer_predicate_at(env, 0, 2 /* improving */, 1); @@ -53,12 +53,12 @@ static void direct(void) { EigsState *st = eigs_open(); if (!st) { check(0, "open direct state"); return; } Env *env = g_global_env; - env_set_local_owned(env, "native_x", make_num(100)); + env_set_local_owned(env, "native_x", make_float(100)); int idx = env->count - 1; double x = 100; for (int i = 0; i < 12; i++) { x *= 0.5; - env_set_local_owned(env, "native_x", make_num(x)); + env_set_local_owned(env, "native_x", make_float(x)); observer_slot_update_num(env, idx, x); } int answer = observer_predicate_at(env, idx, 2 /* improving opcode operand */, 1); @@ -70,7 +70,7 @@ static void direct(void) { x = 100; for (int i = 0; i < 12; i++) { x *= 0.5; - emit(c, OP_CONST, (uint16_t)constant(c, make_num(x))); + emit(c, OP_CONST, (uint16_t)constant(c, make_float(x))); emit(c, OP_SET_NAME, (uint16_t)name); emit(c, OP_OBSERVE_NAME_POST, (uint16_t)name); chunk_emit(c, OP_POP, 1); @@ -203,16 +203,16 @@ static void gap(const char *source, const char *name) { static EigsValue *host_reader(EigsValue *arg) { (void)arg; Env *env = env_new(NULL); - env_set_local_owned(env, "x", make_num(100)); + env_set_local_owned(env, "x", make_float(100)); double x = 100; for (int i = 0; i < 12; i++) { x *= 0.5; - env_set_local_owned(env, "x", make_num(x)); + env_set_local_owned(env, "x", make_float(x)); observer_slot_update_num(env, 0, x); } int answer = observer_predicate_at(env, 0, 2 /* improving */, 1); env_decref(env); - return make_num(answer); + return make_float(answer); } /* Execute the documented explicit-host-arm recipe. No compiled predicate * may rescue the read-free unit: interrogate its slot directly from C. */ diff --git a/tests/test_error_line_fallback.c b/tests/test_error_line_fallback.c index 8e4059890..51800afb5 100644 --- a/tests/test_error_line_fallback.c +++ b/tests/test_error_line_fallback.c @@ -120,8 +120,8 @@ int main(void) { if (!ekey) return 1; Value *good = make_list(6001), *bad = make_list(6001); for (int i = 0; i < 6001; i++) { - list_append_owned(good, make_num(6001 - i)); - list_append_owned(bad, make_num(i < 6000 ? 6001 - i : -1)); + list_append_owned(good, make_float(6001 - i)); + list_append_owned(bad, make_float(i < 6000 ? 6001 - i : -1)); } Value *args_good = make_list(2), *args_bad = make_list(2); list_append(args_good, good); list_append(args_good, ekey); @@ -180,12 +180,12 @@ int main(void) { * NUM_ZERO 2, DIV 7, RETURN 40 (src/vm.h enum order). */ static const int HALT77[] = {68, 77, 0, 0, 0, 3, 2, 7, 40}; Value *code = make_list(9), *desc = make_list(3), *sb_args = make_list(2); - for (int i = 0; i < 9; i++) list_append_owned(code, make_num(HALT77[i])); - list_append_owned(desc, make_num(1)); + for (int i = 0; i < 9; i++) list_append_owned(code, make_float(HALT77[i])); + list_append_owned(desc, make_float(1)); list_append_owned(desc, code); list_append_owned(desc, make_list(0)); list_append_owned(sb_args, desc); - list_append_owned(sb_args, make_num(100)); + list_append_owned(sb_args, make_float(100)); g_has_error = 0; g_trace_current_line = 100; r = builtin_sandbox_run(sb_args); diff --git a/tests/test_gc_traversal.c b/tests/test_gc_traversal.c index 77488ac5a..c380d5c4d 100644 --- a/tests/test_gc_traversal.c +++ b/tests/test_gc_traversal.c @@ -62,7 +62,7 @@ static void collect(int nodes,int garbage,int values,int envs,int chunks) { static void duplicate_and_leaf(void) { Value *leaf=make_list_heap(64), *root=make_list_heap(2); - for (int i=0;i<64;++i) list_append_owned(leaf,make_num(i)); + for (int i=0;i<64;++i) list_append_owned(leaf,make_float(i)); list_append(root,leaf); list_append(root,leaf); duplicate_child=leaf; val_decref(leaf); gc_note_possible_root(root); @@ -73,7 +73,7 @@ static void duplicate_and_leaf(void) { collect(4,2,4,0,0); CHECK(traversal_skips>before,"numeric-leaf mark traversal skipped"); CHECK(list_slot(root,0).u==list_slot(root,1).u,"live duplicate aliases retained"); - CHECK(eigs_slot_num(list_slot(slot_as_ptr(list_slot(root,0)),63),"gc_traversal")==63,"live leaf contents retained"); + CHECK(eigs_slot_float(list_slot(slot_as_ptr(list_slot(root,0)),63),"gc_traversal")==63,"live leaf contents retained"); duplicate_child=NULL; val_decref(root); gc_collect_cycles(); ++cases; diff --git a/tests/test_intern_owners.c b/tests/test_intern_owners.c index cd1301bca..61d892681 100644 --- a/tests/test_intern_owners.c +++ b/tests/test_intern_owners.c @@ -47,11 +47,11 @@ int main(void) { if (!a) { fputs("SETUP FAIL: state A\n", stderr); return 2; } EnvInternTable *old = eigs_current->intern_tbl; env_intern_table_ref(old); /* test owner, retained through normal close */ - env_set_local_owned(a->global_env, "owner_fixture_root", make_num_permanent(3)); + env_set_local_owned(a->global_env, "owner_fixture_root", make_float_permanent(3)); CHECK("state root retains originating table", owns(a->global_env->intern_refs, old) == 1); CHECK("builtin layer retains originating table", owns(a->builtin_env->intern_refs, old) == 1); int before = refs(old); - env_set_local_owned(a->global_env, "owner_fixture_second", make_num_permanent(4)); + env_set_local_owned(a->global_env, "owner_fixture_second", make_float_permanent(4)); CHECK("same Env deduplicates table owner", refs(old) == before); char *old_name = env_intern_name("owner_fixture_old_chunk"); @@ -61,15 +61,15 @@ int main(void) { Value *fn = make_fn("owner_fixture_fn", params, 1, a->global_env); CHECK("function params acquire separate owner", fn->data.fn.param_intern_tbl == old && refs(old) == before + 2); Value *ordinary = make_dict(1); - dict_set_owned(ordinary, "owner_fixture_dict", make_num_permanent(5)); + dict_set_owned(ordinary, "owner_fixture_dict", make_float_permanent(5)); CHECK("ordinary dict retains its exact table", owns(ordinary->data.dict.intern_refs, old) == 1 && refs(old) == before + 3); (void)env_intern_name("owner_fixture_scope_zero"); uint32_t previous = g_sandbox_intern_scope; uint32_t scope = env_intern_scope_begin(); Value *zero = make_dict(1), *private = make_dict(1); - dict_set_owned(zero, "owner_fixture_scope_zero", make_num_permanent(6)); - dict_set_owned(private, "owner_fixture_private_key", make_num_permanent(7)); + dict_set_owned(zero, "owner_fixture_scope_zero", make_float_permanent(6)); + dict_set_owned(private, "owner_fixture_private_key", make_float_permanent(7)); CHECK("scope-zero reuse has exact table owner", owns(zero->data.dict.intern_refs, old) == 1); CHECK("promoted private key has live Value owner", private_names(a, private) == 1); CHECK("private copy does not retain whole table", private->data.dict.intern_refs == NULL); @@ -129,7 +129,7 @@ int main(void) { if (!b) { fputs("SETUP FAIL: state B\n", stderr); return 2; } EnvInternTable *other = eigs_current->intern_tbl; env_intern_table_ref(other); - env_set_local_owned(b->global_env, "owner_fixture_other_state", make_num_permanent(8)); + env_set_local_owned(b->global_env, "owner_fixture_other_state", make_float_permanent(8)); CHECK("state B owns its own table", owns(b->global_env->intern_refs, other) == 1); CHECK("state B does not own state A table", owns(b->global_env->intern_refs, old) == 0); CHECK("state A does not own state B table", owns(a->global_env->intern_refs, other) == 0); diff --git a/tests/test_loop_counter_sequential.c b/tests/test_loop_counter_sequential.c index 301b16177..9de334231 100644 --- a/tests/test_loop_counter_sequential.c +++ b/tests/test_loop_counter_sequential.c @@ -65,7 +65,7 @@ static void grow_env(Env *env, const char *label) { for (int i = 0; i <= before; ++i) { char name[64]; snprintf(name, sizeof(name), "sequential_growth_%d", i); - Value *value = make_num(i); + Value *value = make_float(i); env_set_local(env, name, value); val_decref(value); } diff --git a/tests/test_native_fn.c b/tests/test_native_fn.c index e83872f03..87af4e7b4 100644 --- a/tests/test_native_fn.c +++ b/tests/test_native_fn.c @@ -15,10 +15,10 @@ static void check(int ok, const char *what) { if (!ok) fail = 1; } static Value *probe_add1(Value *a) { - double d = (a && val_is_number(a)) ? eigs_num_arg(a, __func__) : 0.0; - return make_num(d + 1); + double d = (a && val_is_number(a)) ? eigs_float_arg(a, __func__) : 0.0; + return make_float(d + 1); } -static Value *probe_plain(Value *a) { (void)a; return make_num(0); } +static Value *probe_plain(Value *a) { (void)a; return make_float(0); } static char *eval_str(const char *src) { Value *v = eigs_eval_string(src); diff --git a/tests/test_pool_poison.c b/tests/test_pool_poison.c index 00ca7f291..f16413c6f 100644 --- a/tests/test_pool_poison.c +++ b/tests/test_pool_poison.c @@ -50,7 +50,7 @@ static int run_program(void) { } static int plant_num(void) { - Value *v = make_num(42.5); + Value *v = make_float(42.5); val_decref(v); /* refcount 0 -> parked on the freelist */ if (g_num_freelist != v) { puts("NOT-ARMED num: value not parked"); return 3; } printf("ARMED num: parked NUM %p, reading %p\n", (void *)v, @@ -107,10 +107,10 @@ static int plant_envfield(void) { static int control(void) { int bad = 0; - /* NUM pop: make_num hands the parked Value back, readable again. */ - Value *v = make_num(1.5); + /* NUM pop: make_float hands the parked Value back, readable again. */ + Value *v = make_float(1.5); val_decref(v); - Value *again = make_num(2.5); + Value *again = make_float(2.5); if (again != v) { puts("NOT-ARMED control: freelist did not reuse"); return 3; } if (VAL_F64_RAW(again) != 2.5 || again->refcount != 1) bad = 1; printf("control num reuse: %s\n", bad ? "WRONG" : "ok"); diff --git a/tests/test_sandbox_intern_lifetime.c b/tests/test_sandbox_intern_lifetime.c index 283b1c987..0269d4cea 100644 --- a/tests/test_sandbox_intern_lifetime.c +++ b/tests/test_sandbox_intern_lifetime.c @@ -14,7 +14,7 @@ extern Value *builtin_sandbox_run(Value *arg); extern size_t env_intern_debug_count(const char *prefix); static void append_num(Value *list, double n) { - list_append_owned(list, make_num(n)); + list_append_owned(list, make_float(n)); } static size_t intern_count(void) { diff --git a/tests/test_sandbox_work_budget.c b/tests/test_sandbox_work_budget.c index 7ebe90b76..10fb84728 100644 --- a/tests/test_sandbox_work_budget.c +++ b/tests/test_sandbox_work_budget.c @@ -25,10 +25,10 @@ static Value *ordinary_descriptor(void) { Value *code = make_list(chunk->code_len); Value *constants = make_list(1); for (int i = 0; i < chunk->code_len; i++) - list_append_owned(code, make_num(chunk->code[i])); + list_append_owned(code, make_float(chunk->code[i])); list_append(constants, chunk->constants[0]); descriptor = make_list(3); - list_append_owned(descriptor, make_num(EIGS_BYTECODE_ABI)); + list_append_owned(descriptor, make_float(EIGS_BYTECODE_ABI)); list_append_owned(descriptor, code); list_append_owned(descriptor, constants); } @@ -55,9 +55,9 @@ int main(void) { for (int run = 0; run < 2; run++) { Value *args = make_list(4); list_append(args, descriptor); - list_append_owned(args, make_num(100)); - list_append_owned(args, make_num(1048576)); - list_append_owned(args, make_num(10000)); + list_append_owned(args, make_float(100)); + list_append_owned(args, make_float(1048576)); + list_append_owned(args, make_float(10000)); Value *out = builtin_sandbox_run(args); EigsView ok_view, result_view; Value *ok = out ? dict_get_view(out, "ok", &ok_view) : NULL; diff --git a/tests/test_trace_context.c b/tests/test_trace_context.c index 04816e6ad..f5fb79f12 100644 --- a/tests/test_trace_context.c +++ b/tests/test_trace_context.c @@ -103,7 +103,7 @@ static Value *continuing_worker(Value *arg) { pthread_mutex_unlock(&mu); Value *v = NULL; if (!trace_replay_take("sample", &v)) { - v = make_num(7 + i + live_bias); + v = make_float(7 + i + live_bias); trace_nondet_value("sample", v); live_calls++; } @@ -115,7 +115,7 @@ static Value *continuing_worker(Value *arg) { pthread_cond_broadcast(&cv); pthread_mutex_unlock(&mu); } - return make_num(observed[0]*10 + observed[1]); + return make_float(observed[0]*10 + observed[1]); } static Value *start_worker(void) { phase = completed = worker_error = 0; @@ -245,7 +245,7 @@ int main(void) { eigs_set_trace_sink(sink, NULL); Value *numbers[] = {make_int(3), make_int(INT64_C(9007199254740993)), make_int(INT64_MIN), make_int(INT64_MAX), - make_num(3.0), make_num(-0.0)}; + make_float(3.0), make_float(-0.0)}; for (size_t i = 0; i < sizeof numbers / sizeof numbers[0]; i++) { trace_nondet_value("sample", numbers[i]); val_decref(numbers[i]); diff --git a/tests/test_trace_correspondence.c b/tests/test_trace_correspondence.c index 74c0a5f92..2006758f5 100644 --- a/tests/test_trace_correspondence.c +++ b/tests/test_trace_correspondence.c @@ -50,7 +50,7 @@ static Value *sensor(Value *arg) { pthread_mutex_unlock(&mu); Value *value = NULL; if (!trace_replay_take("ordinary_sensor", &value)) { - value = make_num(id + live_bias); + value = make_float(id + live_bias); trace_nondet_value("ordinary_sensor", value); /* deliberately before LINE */ pthread_mutex_lock(&mu); live_calls++; @@ -73,7 +73,7 @@ typedef struct { static Value *spawn_sensor(int id) { Value *args = make_list(2); Value *fn = make_builtin(sensor); - Value *number = make_num(id); + Value *number = make_float(id); list_append(args, fn); list_append(args, number); val_decref(fn); From 5a9ec1d620bd8fbda002809681b239b5b1eb4c7b Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 09:06:18 -0500 Subject: [PATCH 175/188] refactor(numbers): delete the bridge, meter and caller-less helpers All 21 transitional tokens absent without aliases. Production and C-fixture meter measured zero before final removal (actual compiler diagnostics archived). Delete obsolete definitions, seven already-dead marked helpers and the matrix formatter whose last callers were removed in group6. Retired vocabulary is required absent. Remove five obsolete classifier dispositions; review embed smoke bool-slot classifier. Normal build warnings=0; num-read and slot-layer green; six MAP rows green in four tiers, strict 0/1. Declare R1.6z landed. Frozen branch files unchanged. Reviewed legacy store pin: old clamped-index assertion is red on candidate, then updated under the pre-registered N13/R1.6d-D1 boundary; raw non-finite store round trip uses N11 IEEE buffer equality. Focused store gate green in interpreter/JIT-enabled and strict 0/1 (four runs). No frozen expectation change. Preserve the legacy store assertion tally with assert_eq: Tests=184 Pass=184 Fail=0 in all four interpreter/JIT-enabled strict-mode runs. Reviewed gate-pin amendment (brief lesson 6): builtin_exec_capture and builtin_tensor_load differ only by retired constructor spelling inside comments. Executable C and whole-argument helper closures are unchanged. Repin exactly those two exempt body/source hashes and record the reason. Each repinned check was independently planted red once (rc1, exactly its named source/helper error), then restored byte-for-byte; shape contract 268 candidates / 139 guarded / 129 exempt / 0 errors. Full release suite 4606/4606, failures=0, skipped=10, sections=304, rc0; completed strict differential rc0. No gate logic, runtime, frozen row or D2 change. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- .claude/rules/c-runtime-memory.md | 2 +- Makefile | 6 - docs/ARCHITECTURE.md | 2 +- docs/SPEC.md | 2 +- docs/design/phase2-inventory.txt | 1548 ++++++++++++++--------------- docs/design/phase2-numbers.md | 6 +- docs/llms.txt | 2 +- src/builtins_host.c | 2 +- src/builtins_tensor.c | 4 +- src/container.h | 97 -- src/eigenscript.c | 37 +- src/eigenscript.h | 75 +- src/ext_gfx.c | 8 +- src/jit.c | 12 - tests/phase2/builtins_landed.txt | 1 + tests/phase2/slot_layer.c | 1 - tests/test_db.eigs | 2 +- tests/test_http_rss_growth.sh | 2 +- tests/test_numeric_guard.eigs | 2 +- tests/test_store.eigs | 16 +- tests/test_strict_math.sh | 4 +- tools/num_read_allowlist.txt | 13 +- tools/num_read_check.sh | 2 +- tools/phase2_check.py | 14 +- tools/phase2_inventory.py | 12 +- tools/strict_shape_contracts.json | 12 +- 26 files changed, 813 insertions(+), 1071 deletions(-) diff --git a/.claude/rules/c-runtime-memory.md b/.claude/rules/c-runtime-memory.md index 51f27824d..2cb9ba0d9 100644 --- a/.claude/rules/c-runtime-memory.md +++ b/.claude/rules/c-runtime-memory.md @@ -92,7 +92,7 @@ iteration, or a collector that quietly stops working). record, `store_put` refused to re-insert it, and the caller was told 1). - **`eigs_json_encode` borrows its argument and `eigs_json_parse_value` returns - an owned ref.** `eigs_json_encode(make_num(x))` leaks the `make_num`; a parsed + an owned ref.** `eigs_json_encode(make_float(x))` leaks the `make_float`; a parsed Value must be decref'd on *every* path including early returns, and the value read out of it before the decref. Three of the five call sites in `ext_http.c` had this wrong (#731) — if you touch one, re-audit the rest. diff --git a/Makefile b/Makefile index 0868d35b5..e2beb2045 100644 --- a/Makefile +++ b/Makefile @@ -12,12 +12,6 @@ endif # build error instead of an ignorable warning. CFLAGS := -Wall -Wextra -Werror=implicit-function-declaration $(WERROR_FLAGS) -O2 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE -# #1758 R1.6: an opt-in progress meter, never part of ordinary CI warnings. -# Flags do not invalidate existing objects; use make -B for a meter census. -ifeq ($(EIGS_PHASE2_METER),1) -override CFLAGS += -DEIGS_PHASE2_METER -endif - # RELRO/BIND_NOW are ELF concepts; macOS's ld64 rejects -z, and PIE is # already the default there. Without this split every Makefile link target # (notably `make lsp`) fails on macOS even though build.sh works. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e3f3ae785..75eb05d35 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -203,7 +203,7 @@ EigenScript uses reference counting plus numeric and environment freelists. refcount reaches zero, `free_value` tears down the value and its children. **Numeric freelist.** Freed `VAL_FLOAT` values are placed in a per-thread -freelist (up to 4096 entries) and reused by `make_num`, avoiding +freelist (up to 4096 entries) and reused by `make_float`, avoiding malloc/free churn in arithmetic-heavy loops. `VAL_INT` boxes are freed directly; immediate floats and SMIs need no heap reference count. diff --git a/docs/SPEC.md b/docs/SPEC.md index 20e0f7d25..5c194bfe8 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -365,7 +365,7 @@ consequences are contracts you can rely on: and `num` still *coerces* (`num of ([1, 2])` is `0` — that is its documented contract, not a guard). The distinction is not derivable from the code: `task_alive` has two - `return make_num(0)` lines four apart, one a type guard and one the + `return make_float(0)` lines four apart, one a type guard and one the documented answer. `tools/strict_differential.sh` checks the distinction that can be executed: a guard probe must raise in strict mode, the default (with the variable unset or set to `1`), and a pinned documented answer must not. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 16c04a083..c043a2d23 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,54 +1,71 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2202 classified=2202 unclassified=0 -files=65 tokens=116 role_rules=8 derived_accessors=32 wrappers=8 +examined=2121 classified=2121 unclassified=0 +files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 +# Retired (required absent): buf_num_arg -- R1.6z: bridge deleted; every caller migrated # Retired (required absent): buffer_read_byte -- R1.6e: gfx_fb and ppu_render_frame use buffer_byte_at +# Retired (required absent): buffer_read_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): dict_value_get_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): dict_value_rewrite_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): dict_value_set_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_elem_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_list_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_num_arg -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_num_arg_slow -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_opt_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_slot_elem_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_slot_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): eigs_slot_opt_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): finite_num_to_byte -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): list_append_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): list_get_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): list_rewrite_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): list_set_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): make_num -- R1.6z: bridge deleted; every caller migrated +# Retired (required absent): make_num_permanent -- R1.6z: bridge deleted; every caller migrated ## Per category -(a) type tests 511 CASE=61 DATA=4 TEST=443 YIELD=3 -(b) payload reads 632 RAW=136 READ=496 -(c) producers 558 GUARD=79 PARSE=3 PRODUCE=448 TAGSET=9 WRITE=19 -(d) JIT emitters and guards 127 EMIT=89 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 +(a) type tests 494 CASE=61 DATA=4 TEST=426 YIELD=3 +(b) payload reads 593 RAW=123 READ=470 +(c) producers 538 GUARD=75 PARSE=3 PRODUCE=433 TAGSET=9 WRITE=18 +(d) JIT emitters and guards 125 EMIT=87 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 18 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=5 -(f) equality, ordering and hashing 53 CASE=2 PRODUCE=4 RAW=15 READ=9 TEST=23 +(f) equality, ordering and hashing 51 CASE=2 PRODUCE=4 RAW=15 READ=7 TEST=23 (g) tape encode and decode 37 CASE=4 DATA=5 PARSE=7 PRODUCE=8 RAW=6 READ=2 TEST=5 (h) JSON, store and db encoders 85 CASE=4 FORMAT=3 PARSE=5 PRODUCE=22 RAW=8 READ=24 TEST=19 (i) observer numeric paths 108 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=24 READ=6 TEST=34 -(j) embed API 73 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=56 TEST=2 WRITE=3 +(j) embed API 72 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=55 TEST=2 WRITE=3 ## Per token make_int 212 -val_is_number 183 -VAL_INT 157 -VAL_FLOAT 154 -make_float 139 -SLOT_F64_RAW 84 -num_guard 68 -make_num 63 -VAL_F64_RAW 57 +make_float 200 +val_is_number 180 +VAL_INT 156 +VAL_FLOAT 152 +SLOT_F64_RAW 78 +eigs_float_arg 73 +num_guard 64 +VAL_F64_RAW 55 AST_NUM 53 eigs_value_as_num 53 -VAL_I64_RAW 51 -slot_is_f64 50 -eigs_float_arg 49 +VAL_I64_RAW 50 eigs_list_float 47 -slot_from_f64 47 +slot_from_f64 44 +slot_is_f64 44 eigs_int_arg 34 eigs_int_arg_range 34 -slot_is_smi 33 -eigs_num_arg 29 +slot_is_smi 28 +eigs_slot_float 27 +buffer_read_f64 26 number 26 eigs_number_arg 23 -eigs_slot_float 22 -slot_f64_value 22 +slot_f64_value 23 +list_set_f64 22 eigs_list_int_range 21 -slot_smi_val 20 -list_set_f64 19 -buffer_read_f64 18 strtod 16 +slot_smi_val 15 eigs_list_int 13 slot_from_int 13 -buffer_read_num 12 slot_int_value 12 eigs_magnitude_arg 11 NUM_REUSE 10 @@ -60,10 +77,8 @@ EIGS_NUM_MAX 8 eigs_byte_arg 8 eigs_bounded_arg 7 eigs_num_text 7 -eigs_slot_num 7 eigs_list_bounded 6 eigs_list_magnitude 6 -eigs_num_arg_slow 6 eigs_opt_int_range 6 eigs_slot_int 6 eigs_slot_int_range 6 @@ -72,10 +87,9 @@ buffer_index_at 5 eigs_slot_magnitude 5 VAL_F64_OFFSET 4 buf_float_arg 4 -dict_value_rewrite_num 4 +dict_value_rewrite_f64 4 eigs_elem_byte 4 eigs_opt_magnitude 4 -list_set_num 4 eigs_elem_bounded 3 eigs_elem_float 3 eigs_elem_int 3 @@ -90,31 +104,21 @@ eigs_opt_number 3 eigs_slot_byte 3 eigs_slot_elem_byte 3 eigs_slot_elem_number 3 -list_rewrite_num 3 -make_float_permanent 3 -dict_value_rewrite_f64 2 +list_rewrite_f64 3 dict_value_rewrite_int 2 -eigs_elem_num 2 eigs_list_byte 2 -eigs_list_num 2 eigs_list_number 2 -eigs_opt_num 2 eigs_slot_bounded 2 -eigs_slot_elem_num 2 eigs_slot_opt_int_range 2 -eigs_slot_opt_num 2 f64_ 2 -list_rewrite_f64 2 list_rewrite_int 2 -make_num_permanent 2 +make_float_permanent 2 atof 1 d_ 1 dict_value_get_f64 1 dict_value_get_int 1 -dict_value_get_num 1 dict_value_set_f64 1 dict_value_set_int 1 -dict_value_set_num 1 eigs_slot_elem_bounded 1 eigs_slot_elem_float 1 eigs_slot_elem_int 1 @@ -126,28 +130,45 @@ eigs_slot_opt_byte 1 eigs_slot_opt_int 1 eigs_slot_opt_magnitude 1 eigs_slot_opt_number 1 -finite_num_to_byte 1 i64_ 1 list_append_f64 1 list_append_int 1 -list_append_num 1 list_get_f64 1 list_get_int 1 -list_get_num 1 list_set_int 1 +buf_num_arg 0 buffer_read_byte 0 +buffer_read_num 0 +dict_value_get_num 0 +dict_value_rewrite_num 0 +dict_value_set_num 0 +eigs_elem_num 0 +eigs_list_num 0 +eigs_num_arg 0 +eigs_num_arg_slow 0 +eigs_opt_num 0 +eigs_slot_elem_num 0 +eigs_slot_num 0 +eigs_slot_opt_num 0 +finite_num_to_byte 0 +list_append_num 0 +list_get_num 0 +list_rewrite_num 0 +list_set_num 0 +make_num 0 +make_num_permanent 0 data.number (AST) 3 ## Per file (category counts) builtins.c 321 a=84 b=73 c=115 e=4 f=13 h=22 i=10 vm.c 314 a=72 b=101 c=77 e=2 f=10 i=52 ext_gfx.c 260 a=100 b=73 c=87 -eigenscript.c 205 a=25 b=84 c=28 e=7 f=18 i=43 builtins_tensor.c 198 a=53 b=56 c=89 -container.h 171 a=39 b=81 c=51 +eigenscript.c 189 a=23 b=75 c=25 e=7 f=16 i=43 +container.h 122 a=25 b=60 c=37 builtins_buf.c 105 a=33 b=33 c=39 -jit.c 96 d=96 -eigenscript.h 72 a=7 b=50 c=14 e=1 +jit.c 94 d=94 +eigenscript.h 59 a=6 b=41 c=11 e=1 builtins_host.c 58 a=24 b=19 c=15 embed_smoke.c 55 j=55 ext_store.c 55 h=55 @@ -161,8 +182,8 @@ chunk.c 20 a=4 e=4 f=12 model_infer.c 18 a=2 b=7 c=9 ext_http.c 14 a=3 b=4 c=7 builtins_int.c 11 b=4 c=7 -eigs_embed.c 11 j=11 lexer.c 11 b=10 c=1 +eigs_embed.c 10 j=10 model_train.c 8 a=2 b=4 c=1 i=1 ext_db.c 7 h=7 embed_concurrent.c 6 j=6 @@ -260,25 +281,20 @@ leaf_exec OP_NUM_ONE OP_NUM_ONE leaf_exec OP_NUM_ZERO OP_NUM_ZERO ## Slot classifiers (R1.1 worklist) -D1=66 D2=19 D3=26 T=68 dispositions=111 missing=0 stale=0 +D1=61 D2=19 D3=27 T=68 dispositions=107 missing=0 stale=0 D1 container.h:dict_value_get_f64 guarded slot_f64_value=1 D1 container.h:dict_value_get_int smi-arm slot_int_value=1 -D1 container.h:dict_value_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:dict_value_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:dict_value_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:eigs_slot_box smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 -D1 container.h:eigs_slot_elem_num smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 -D1 container.h:eigs_slot_num smi-arm eigs_slot_ref=1 slot_as_ptr=2 slot_is_f64=1 slot_is_heap=1 slot_is_smi=1 slot_smi_val=1 -D1 container.h:eigs_slot_opt_num smi-arm eigs_slot_ref=1 slot_as_ptr=3 slot_is_f64=1 slot_is_heap=2 slot_is_null=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:eigs_slot_store_borrow guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 D1 container.h:eigs_slot_store_owned guarded slot_as_ptr=1 slot_is_f64=1 slot_is_heap=1 D1 container.h:list_get_f64 guarded slot_f64_value=1 D1 container.h:list_get_int smi-arm slot_int_value=1 -D1 container.h:list_get_num smi-arm slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 container.h:list_get_ref smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:list_get_return smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 D1 container.h:slot_type smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_heap=1 slot_is_null=1 slot_is_smi=1 slot_type=1 -D1 container.h:slot_view smi-arm eigs_slot_ref=1 slot_as_ptr=1 slot_is_f64=2 slot_is_smi=1 slot_smi_val=1 slot_type=1 +D1 container.h:slot_view smi-arm eigs_slot_ref=1 slot_f64_value=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 slot_type=1 D1 eigenscript.c:ent_child_slot smi-arm eigs_slot_ref=1 slot_is_f64=1 slot_is_smi=1 slot_smi_val=1 D1 eigenscript.c:module_ns_project guarded slot_is_f64=2 D1 eigenscript.c:observer_entropy_now smi-arm slot_as_ptr=1 slot_is_bool=1 slot_is_f64=1 slot_is_ptr=1 slot_is_smi=1 slot_smi_val=1 @@ -349,6 +365,7 @@ D2 vm.c:vm_slot_value_opaque guarded slot_as_ptr=1 slo D3 container.h:eigs_container_slot not-a-classifier SLOT_SMI_MAX=1 SLOT_SMI_MIN=1 D3 container.h:eigs_slot_adopt guarded slot_is_heap=1 D3 eigenscript.c:slot_from_value not-a-classifier SLOT_SMI_MAX=1 SLOT_SMI_MIN=1 +D3 embed_smoke.c:main guarded slot_is_bool=1 D3 jit.c:jit_compile_to_thunk/OP_EQ not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 D3 jit.c:jit_compile_to_thunk/OP_NEG not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 D3 jit.c:jit_compile_to_thunk/OP_NULL not-a-classifier SLOT_FALSE_BITS=1 SLOT_TRUE_BITS=1 @@ -1403,7 +1420,7 @@ chunk.c:433 chunk_disassemble VAL_INT TEST e chunk.c:434 chunk_disassemble VAL_I64_RAW RAW e chunk.c:800 chunk_verify_impl VAL_INT TEST a chunk.c:1107 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a -compiler.c:583 add_num_constant make_num PRODUCE c +compiler.c:583 add_num_constant make_float PRODUCE c compiler.c:590 add_int_constant make_int PRODUCE c compiler.c:599 literal_index_u16 data.number RAW b compiler.c:599 literal_index_u16 number RAW b @@ -1446,160 +1463,111 @@ container.h:59 eigs_slot_store_borrow SLOT_F64_RAW RAW b container.h:59 eigs_slot_store_borrow num_guard GUARD c container.h:59 eigs_slot_store_borrow slot_from_f64 PRODUCE c container.h:59 eigs_slot_store_borrow slot_is_f64 TEST a -container.h:87 dict_value_rewrite_num dict_value_rewrite_num PRODUCE c -container.h:89 dict_value_rewrite_num slot_from_f64 PRODUCE c -container.h:94 list_rewrite_num list_rewrite_num PRODUCE c -container.h:96 list_rewrite_num slot_from_f64 PRODUCE c -container.h:105 slot_type VAL_FLOAT YIELD a -container.h:105 slot_type slot_is_f64 TEST a -container.h:109 slot_type VAL_INT YIELD a -container.h:109 slot_type slot_is_smi TEST a -container.h:135 list_get_ref slot_is_f64 TEST a -container.h:135 list_get_ref slot_is_smi TEST a -container.h:139 dict_value_get_ref slot_is_f64 TEST a -container.h:139 dict_value_get_ref slot_is_smi TEST a -container.h:150 eigs_slot_num eigs_slot_num READ b -container.h:151 eigs_slot_num SLOT_F64_RAW RAW b -container.h:151 eigs_slot_num slot_is_f64 TEST a -container.h:152 eigs_slot_num slot_is_smi TEST a -container.h:152 eigs_slot_num slot_smi_val RAW b -container.h:153 eigs_slot_num val_is_number TEST a -container.h:154 eigs_slot_num eigs_num_arg READ b -container.h:155 eigs_slot_num eigs_num_arg_slow READ b -container.h:158 eigs_slot_elem_num eigs_slot_elem_num READ b -container.h:159 eigs_slot_elem_num SLOT_F64_RAW RAW b -container.h:159 eigs_slot_elem_num slot_is_f64 TEST a -container.h:160 eigs_slot_elem_num slot_is_smi TEST a -container.h:160 eigs_slot_elem_num slot_smi_val RAW b -container.h:162 eigs_slot_elem_num eigs_num_arg READ b -container.h:162 eigs_slot_elem_num val_is_number TEST a -container.h:163 eigs_slot_elem_num eigs_num_arg_slow READ b -container.h:167 eigs_slot_opt_num eigs_slot_opt_num READ b -container.h:169 eigs_slot_opt_num SLOT_F64_RAW RAW b -container.h:169 eigs_slot_opt_num slot_is_f64 TEST a -container.h:170 eigs_slot_opt_num slot_is_smi TEST a -container.h:170 eigs_slot_opt_num slot_smi_val RAW b -container.h:171 eigs_slot_opt_num val_is_number TEST a -container.h:172 eigs_slot_opt_num eigs_num_arg READ b -container.h:174 eigs_slot_opt_num eigs_num_arg_slow READ b -container.h:184 slot_view slot_is_f64 TEST a -container.h:185 slot_view slot_is_smi TEST a -container.h:186 slot_view VAL_INT TAGSET c -container.h:187 slot_view VAL_I64_RAW WRITE c -container.h:187 slot_view slot_smi_val RAW b -container.h:192 slot_view VAL_FLOAT TEST a -container.h:194 slot_view VAL_FLOAT TAGSET c -container.h:195 slot_view SLOT_F64_RAW RAW b -container.h:195 slot_view VAL_F64_RAW WRITE c -container.h:195 slot_view slot_is_f64 TEST a -container.h:196 slot_view eigs_num_arg READ b -container.h:209 eigs_view_check VAL_FLOAT TEST a -container.h:209 eigs_view_check VAL_INT TEST a -container.h:228 eigs_slot_number eigs_slot_number READ b -container.h:229 eigs_slot_number eigs_number_arg READ b -container.h:232 eigs_slot_elem_number eigs_slot_elem_number READ b -container.h:233 eigs_slot_elem_number eigs_elem_number READ b -container.h:236 eigs_slot_opt_number eigs_slot_opt_number READ b -container.h:237 eigs_slot_opt_number eigs_opt_number READ b -container.h:240 eigs_slot_float eigs_slot_float READ b -container.h:241 eigs_slot_float eigs_float_arg READ b -container.h:244 eigs_slot_elem_float eigs_slot_elem_float READ b -container.h:245 eigs_slot_elem_float eigs_elem_float READ b -container.h:248 eigs_slot_opt_float eigs_slot_opt_float READ b -container.h:249 eigs_slot_opt_float eigs_opt_float READ b -container.h:252 eigs_slot_int eigs_slot_int READ b -container.h:253 eigs_slot_int eigs_int_arg READ b -container.h:256 eigs_slot_elem_int eigs_slot_elem_int READ b -container.h:257 eigs_slot_elem_int eigs_elem_int READ b -container.h:260 eigs_slot_opt_int eigs_slot_opt_int READ b -container.h:261 eigs_slot_opt_int eigs_opt_int READ b -container.h:264 eigs_slot_byte eigs_slot_byte READ b -container.h:265 eigs_slot_byte eigs_byte_arg READ b -container.h:268 eigs_slot_elem_byte eigs_slot_elem_byte READ b -container.h:269 eigs_slot_elem_byte eigs_elem_byte READ b -container.h:272 eigs_slot_opt_byte eigs_slot_opt_byte READ b -container.h:273 eigs_slot_opt_byte eigs_opt_byte READ b -container.h:276 eigs_slot_int_range eigs_slot_int_range READ b -container.h:277 eigs_slot_int_range eigs_int_arg_range READ b -container.h:280 eigs_slot_elem_int_range eigs_slot_elem_int_range READ b -container.h:281 eigs_slot_elem_int_range eigs_elem_int_range READ b -container.h:284 eigs_slot_opt_int_range eigs_slot_opt_int_range READ b -container.h:285 eigs_slot_opt_int_range eigs_opt_int_range READ b -container.h:288 eigs_slot_bounded eigs_slot_bounded READ b -container.h:289 eigs_slot_bounded eigs_bounded_arg READ b -container.h:292 eigs_slot_elem_bounded eigs_slot_elem_bounded READ b -container.h:293 eigs_slot_elem_bounded eigs_elem_bounded READ b -container.h:296 eigs_slot_opt_bounded eigs_slot_opt_bounded READ b -container.h:297 eigs_slot_opt_bounded eigs_opt_bounded READ b -container.h:300 eigs_slot_magnitude eigs_slot_magnitude READ b -container.h:301 eigs_slot_magnitude eigs_magnitude_arg READ b -container.h:304 eigs_slot_elem_magnitude eigs_slot_elem_magnitude READ b -container.h:305 eigs_slot_elem_magnitude eigs_elem_magnitude READ b -container.h:308 eigs_slot_opt_magnitude eigs_slot_opt_magnitude READ b -container.h:309 eigs_slot_opt_magnitude eigs_opt_magnitude READ b -container.h:322 list_get_return slot_is_smi TEST a -container.h:323 list_get_return SLOT_F64_RAW RAW b -container.h:323 list_get_return make_num PRODUCE c -container.h:323 list_get_return slot_is_f64 TEST a -container.h:331 dict_value_get_return slot_is_smi TEST a -container.h:332 dict_value_get_return SLOT_F64_RAW RAW b -container.h:332 dict_value_get_return make_num PRODUCE c -container.h:332 dict_value_get_return slot_is_f64 TEST a -container.h:362 eigs_slot_box SLOT_F64_RAW RAW b -container.h:362 eigs_slot_box make_num PRODUCE c -container.h:362 eigs_slot_box num_guard GUARD c -container.h:362 eigs_slot_box slot_is_f64 TEST a -container.h:363 eigs_slot_box slot_is_smi TEST a -container.h:386 list_set_num list_set_num PRODUCE c -container.h:387 list_set_num list_rewrite_num PRODUCE c -container.h:387 list_set_num num_guard GUARD c -container.h:391 list_append_num list_append_num PRODUCE c -container.h:392 list_append_num num_guard GUARD c -container.h:394 list_append_num slot_from_f64 PRODUCE c -container.h:398 dict_value_set_num dict_value_set_num PRODUCE c -container.h:399 dict_value_set_num dict_value_rewrite_num PRODUCE c -container.h:399 dict_value_set_num num_guard GUARD c -container.h:405 list_rewrite_f64 list_rewrite_f64 PRODUCE c -container.h:407 list_rewrite_f64 slot_from_f64 PRODUCE c -container.h:411 list_set_f64 list_set_f64 PRODUCE c -container.h:412 list_set_f64 list_rewrite_f64 PRODUCE c -container.h:412 list_set_f64 num_guard GUARD c -container.h:415 list_get_f64 list_get_f64 READ b -container.h:416 list_get_f64 slot_f64_value READ b -container.h:419 dict_value_rewrite_f64 dict_value_rewrite_f64 PRODUCE c -container.h:421 dict_value_rewrite_f64 slot_from_f64 PRODUCE c -container.h:425 dict_value_set_f64 dict_value_set_f64 PRODUCE c -container.h:426 dict_value_set_f64 dict_value_rewrite_f64 PRODUCE c -container.h:426 dict_value_set_f64 num_guard GUARD c -container.h:429 dict_value_get_f64 dict_value_get_f64 READ b -container.h:430 dict_value_get_f64 slot_f64_value READ b -container.h:433 list_append_f64 list_append_f64 PRODUCE c -container.h:434 list_append_f64 num_guard GUARD c -container.h:436 list_append_f64 slot_from_f64 PRODUCE c -container.h:439 list_rewrite_int list_rewrite_int PRODUCE c -container.h:441 list_rewrite_int slot_from_int PRODUCE c -container.h:445 list_set_int list_set_int PRODUCE c -container.h:446 list_set_int list_rewrite_int PRODUCE c -container.h:449 list_get_int list_get_int READ b -container.h:450 list_get_int slot_int_value READ b -container.h:453 dict_value_rewrite_int dict_value_rewrite_int PRODUCE c -container.h:455 dict_value_rewrite_int slot_from_int PRODUCE c -container.h:459 dict_value_set_int dict_value_set_int PRODUCE c -container.h:460 dict_value_set_int dict_value_rewrite_int PRODUCE c -container.h:463 dict_value_get_int dict_value_get_int READ b -container.h:464 dict_value_get_int slot_int_value READ b -container.h:467 list_append_int list_append_int PRODUCE c -container.h:470 list_append_int slot_from_int PRODUCE c -container.h:502 list_get_num list_get_num READ b -container.h:504 list_get_num slot_is_smi TEST a -container.h:504 list_get_num slot_smi_val RAW b -container.h:505 list_get_num slot_is_f64 TEST a -container.h:506 list_get_num SLOT_F64_RAW RAW b -container.h:511 dict_value_get_num dict_value_get_num READ b -container.h:513 dict_value_get_num slot_is_smi TEST a -container.h:513 dict_value_get_num slot_smi_val RAW b -container.h:514 dict_value_get_num slot_is_f64 TEST a -container.h:515 dict_value_get_num SLOT_F64_RAW RAW b +container.h:86 slot_type VAL_FLOAT YIELD a +container.h:86 slot_type slot_is_f64 TEST a +container.h:90 slot_type VAL_INT YIELD a +container.h:90 slot_type slot_is_smi TEST a +container.h:116 list_get_ref slot_is_f64 TEST a +container.h:116 list_get_ref slot_is_smi TEST a +container.h:120 dict_value_get_ref slot_is_f64 TEST a +container.h:120 dict_value_get_ref slot_is_smi TEST a +container.h:129 slot_view slot_is_f64 TEST a +container.h:130 slot_view slot_is_smi TEST a +container.h:131 slot_view VAL_INT TAGSET c +container.h:132 slot_view VAL_I64_RAW WRITE c +container.h:132 slot_view slot_smi_val RAW b +container.h:137 slot_view VAL_FLOAT TEST a +container.h:139 slot_view VAL_FLOAT TAGSET c +container.h:142 slot_view VAL_F64_RAW RAW b +container.h:142 slot_view slot_f64_value READ b +container.h:155 eigs_view_check VAL_FLOAT TEST a +container.h:155 eigs_view_check VAL_INT TEST a +container.h:174 eigs_slot_number eigs_slot_number READ b +container.h:175 eigs_slot_number eigs_number_arg READ b +container.h:178 eigs_slot_elem_number eigs_slot_elem_number READ b +container.h:179 eigs_slot_elem_number eigs_elem_number READ b +container.h:182 eigs_slot_opt_number eigs_slot_opt_number READ b +container.h:183 eigs_slot_opt_number eigs_opt_number READ b +container.h:186 eigs_slot_float eigs_slot_float READ b +container.h:187 eigs_slot_float eigs_float_arg READ b +container.h:190 eigs_slot_elem_float eigs_slot_elem_float READ b +container.h:191 eigs_slot_elem_float eigs_elem_float READ b +container.h:194 eigs_slot_opt_float eigs_slot_opt_float READ b +container.h:195 eigs_slot_opt_float eigs_opt_float READ b +container.h:198 eigs_slot_int eigs_slot_int READ b +container.h:199 eigs_slot_int eigs_int_arg READ b +container.h:202 eigs_slot_elem_int eigs_slot_elem_int READ b +container.h:203 eigs_slot_elem_int eigs_elem_int READ b +container.h:206 eigs_slot_opt_int eigs_slot_opt_int READ b +container.h:207 eigs_slot_opt_int eigs_opt_int READ b +container.h:210 eigs_slot_byte eigs_slot_byte READ b +container.h:211 eigs_slot_byte eigs_byte_arg READ b +container.h:214 eigs_slot_elem_byte eigs_slot_elem_byte READ b +container.h:215 eigs_slot_elem_byte eigs_elem_byte READ b +container.h:218 eigs_slot_opt_byte eigs_slot_opt_byte READ b +container.h:219 eigs_slot_opt_byte eigs_opt_byte READ b +container.h:222 eigs_slot_int_range eigs_slot_int_range READ b +container.h:223 eigs_slot_int_range eigs_int_arg_range READ b +container.h:226 eigs_slot_elem_int_range eigs_slot_elem_int_range READ b +container.h:227 eigs_slot_elem_int_range eigs_elem_int_range READ b +container.h:230 eigs_slot_opt_int_range eigs_slot_opt_int_range READ b +container.h:231 eigs_slot_opt_int_range eigs_opt_int_range READ b +container.h:234 eigs_slot_bounded eigs_slot_bounded READ b +container.h:235 eigs_slot_bounded eigs_bounded_arg READ b +container.h:238 eigs_slot_elem_bounded eigs_slot_elem_bounded READ b +container.h:239 eigs_slot_elem_bounded eigs_elem_bounded READ b +container.h:242 eigs_slot_opt_bounded eigs_slot_opt_bounded READ b +container.h:243 eigs_slot_opt_bounded eigs_opt_bounded READ b +container.h:246 eigs_slot_magnitude eigs_slot_magnitude READ b +container.h:247 eigs_slot_magnitude eigs_magnitude_arg READ b +container.h:250 eigs_slot_elem_magnitude eigs_slot_elem_magnitude READ b +container.h:251 eigs_slot_elem_magnitude eigs_elem_magnitude READ b +container.h:254 eigs_slot_opt_magnitude eigs_slot_opt_magnitude READ b +container.h:255 eigs_slot_opt_magnitude eigs_opt_magnitude READ b +container.h:268 list_get_return slot_is_smi TEST a +container.h:269 list_get_return SLOT_F64_RAW RAW b +container.h:269 list_get_return make_float PRODUCE c +container.h:269 list_get_return slot_is_f64 TEST a +container.h:277 dict_value_get_return slot_is_smi TEST a +container.h:278 dict_value_get_return SLOT_F64_RAW RAW b +container.h:278 dict_value_get_return make_float PRODUCE c +container.h:278 dict_value_get_return slot_is_f64 TEST a +container.h:308 eigs_slot_box SLOT_F64_RAW RAW b +container.h:308 eigs_slot_box make_float PRODUCE c +container.h:308 eigs_slot_box num_guard GUARD c +container.h:308 eigs_slot_box slot_is_f64 TEST a +container.h:309 eigs_slot_box slot_is_smi TEST a +container.h:334 list_rewrite_f64 list_rewrite_f64 PRODUCE c +container.h:336 list_rewrite_f64 slot_from_f64 PRODUCE c +container.h:340 list_set_f64 list_set_f64 PRODUCE c +container.h:341 list_set_f64 list_rewrite_f64 PRODUCE c +container.h:341 list_set_f64 num_guard GUARD c +container.h:344 list_get_f64 list_get_f64 READ b +container.h:345 list_get_f64 slot_f64_value READ b +container.h:348 dict_value_rewrite_f64 dict_value_rewrite_f64 PRODUCE c +container.h:350 dict_value_rewrite_f64 slot_from_f64 PRODUCE c +container.h:354 dict_value_set_f64 dict_value_set_f64 PRODUCE c +container.h:355 dict_value_set_f64 dict_value_rewrite_f64 PRODUCE c +container.h:355 dict_value_set_f64 num_guard GUARD c +container.h:358 dict_value_get_f64 dict_value_get_f64 READ b +container.h:359 dict_value_get_f64 slot_f64_value READ b +container.h:362 list_append_f64 list_append_f64 PRODUCE c +container.h:363 list_append_f64 num_guard GUARD c +container.h:365 list_append_f64 slot_from_f64 PRODUCE c +container.h:368 list_rewrite_int list_rewrite_int PRODUCE c +container.h:370 list_rewrite_int slot_from_int PRODUCE c +container.h:374 list_set_int list_set_int PRODUCE c +container.h:375 list_set_int list_rewrite_int PRODUCE c +container.h:378 list_get_int list_get_int READ b +container.h:379 list_get_int slot_int_value READ b +container.h:382 dict_value_rewrite_int dict_value_rewrite_int PRODUCE c +container.h:384 dict_value_rewrite_int slot_from_int PRODUCE c +container.h:388 dict_value_set_int dict_value_set_int PRODUCE c +container.h:389 dict_value_set_int dict_value_rewrite_int PRODUCE c +container.h:392 dict_value_get_int dict_value_get_int READ b +container.h:393 dict_value_get_int slot_int_value READ b +container.h:396 list_append_int list_append_int PRODUCE c +container.h:399 list_append_int slot_from_int PRODUCE c eigenlsp.c:501 walk_ast_symbols AST_NUM CASE a eigenlsp.c:637 collect_references AST_NUM CASE a eigenscript.c:311 val_type_name VAL_FLOAT CASE a @@ -1625,261 +1593,232 @@ eigenscript.c:1403 observer_entropy_now slot_is_f64 TEST i eigenscript.c:1405 observer_entropy_now SLOT_F64_RAW RAW i eigenscript.c:1406 observer_entropy_now slot_is_smi TEST i eigenscript.c:1408 observer_entropy_now slot_smi_val RAW i -eigenscript.c:1453 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1454 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1457 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1461 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1462 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1463 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1464 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1470 observer_slot_trajectory make_num PRODUCE i -eigenscript.c:1503 observer_slot_from_trajectory eigs_num_arg READ i +eigenscript.c:1453 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1454 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1457 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1461 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1462 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1463 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1464 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1470 observer_slot_trajectory make_float PRODUCE i +eigenscript.c:1503 observer_slot_from_trajectory eigs_float_arg READ i eigenscript.c:1503 observer_slot_from_trajectory val_is_number TEST i eigenscript.c:1504 observer_slot_from_trajectory val_is_number TEST i eigenscript.c:1522 observer_slot_from_trajectory VAL_FLOAT TEST i eigenscript.c:1522 observer_slot_from_trajectory VAL_FLOAT TEST i eigenscript.c:1522 observer_slot_from_trajectory VAL_INT TEST i eigenscript.c:1522 observer_slot_from_trajectory VAL_INT TEST i -eigenscript.c:1527 observer_slot_from_trajectory eigs_slot_num READ i -eigenscript.c:1528 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1527 observer_slot_from_trajectory eigs_slot_float READ i +eigenscript.c:1528 observer_slot_from_trajectory eigs_slot_float READ i eigenscript.c:1538 observer_slot_from_trajectory VAL_FLOAT TEST i eigenscript.c:1538 observer_slot_from_trajectory VAL_INT TEST i -eigenscript.c:1543 observer_slot_from_trajectory eigs_slot_num READ i +eigenscript.c:1543 observer_slot_from_trajectory eigs_slot_float READ i eigenscript.c:1556 observer_slot_from_trajectory val_is_number TEST i -eigenscript.c:1561 observer_slot_from_trajectory eigs_num_arg READ i +eigenscript.c:1561 observer_slot_from_trajectory eigs_float_arg READ i eigenscript.c:1664 free_value VAL_FLOAT TEST a eigenscript.c:1745 free_value VAL_FLOAT CASE a eigenscript.c:1746 free_value VAL_INT CASE a eigenscript.c:1757 make_float_pooled num_guard GUARD c eigenscript.c:1773 make_float_pooled VAL_FLOAT TAGSET c eigenscript.c:1774 make_float_pooled VAL_F64_RAW WRITE c -eigenscript.c:1781 make_float make_float PRODUCE c -eigenscript.c:1782 make_num make_num PRODUCE c -eigenscript.c:1786 make_int make_int PRODUCE c -eigenscript.c:1788 make_int VAL_INT TAGSET c -eigenscript.c:1789 make_int VAL_I64_RAW WRITE c -eigenscript.c:1795 recycle_intermediate VAL_FLOAT TEST a -eigenscript.c:1817 make_float_permanent make_float_permanent PRODUCE c -eigenscript.c:1818 make_float_permanent num_guard GUARD c -eigenscript.c:1820 make_float_permanent VAL_FLOAT TAGSET c -eigenscript.c:1821 make_float_permanent VAL_F64_RAW WRITE c -eigenscript.c:1826 make_num_permanent make_float_permanent PRODUCE c -eigenscript.c:1826 make_num_permanent make_num_permanent PRODUCE c -eigenscript.c:1852 eigs_num_arg_slow eigs_num_arg_slow READ b -eigenscript.c:1853 eigs_num_arg_slow VAL_F64_RAW RAW b -eigenscript.c:1853 eigs_num_arg_slow VAL_FLOAT TEST a -eigenscript.c:1857 eigs_num_arg_slow VAL_I64_RAW RAW b -eigenscript.c:1857 eigs_num_arg_slow VAL_INT TEST a -eigenscript.c:1864 eigs_list_num eigs_list_num READ b -eigenscript.c:1871 eigs_list_num eigs_slot_num READ b -eigenscript.c:1874 eigs_elem_num eigs_elem_num READ b -eigenscript.c:1875 eigs_elem_num eigs_slot_elem_num READ b -eigenscript.c:1878 eigs_opt_num eigs_opt_num READ b -eigenscript.c:1879 eigs_opt_num eigs_slot_opt_num READ b -eigenscript.c:1885 eigs_number_read VAL_INT TEST a -eigenscript.c:1886 eigs_number_read VAL_I64_RAW RAW b -eigenscript.c:1888 eigs_number_read VAL_FLOAT TEST a -eigenscript.c:1889 eigs_number_read VAL_F64_RAW RAW b -eigenscript.c:1897 eigs_number_arg eigs_number_arg READ b -eigenscript.c:1908 eigs_float_arg eigs_float_arg READ b -eigenscript.c:1909 eigs_float_arg eigs_number_arg READ b -eigenscript.c:1913 eigs_int_arg eigs_int_arg READ b -eigenscript.c:1918 eigs_int_arg num_to_i64_exact READ b -eigenscript.c:1924 eigs_int_arg_range READ b -eigenscript.c:1926 eigs_int_arg_range eigs_int_arg READ b -eigenscript.c:1937 eigs_byte_arg eigs_byte_arg READ b -eigenscript.c:1939 eigs_byte_arg eigs_int_arg_range READ b -eigenscript.c:2073 eigs_geom_shape READ b -eigenscript.c:2080 eigs_geom_shape eigs_list_float READ b -eigenscript.c:2120 eigs_bounded_arg eigs_bounded_arg READ b -eigenscript.c:2121 eigs_bounded_arg eigs_float_arg READ b -eigenscript.c:2137 eigs_magnitude_arg READ b -eigenscript.c:2139 eigs_magnitude_arg eigs_number_arg READ b -eigenscript.c:2143 eigs_magnitude_arg num_to_i64_exact READ b -eigenscript.c:2167 eigs_reader_elem_default val_is_number TEST a -eigenscript.c:2170 eigs_list_number eigs_list_number READ b -eigenscript.c:2173 eigs_list_number eigs_number_arg READ b -eigenscript.c:2175 eigs_elem_number eigs_elem_number READ b -eigenscript.c:2176 eigs_elem_number eigs_number_arg READ b -eigenscript.c:2178 eigs_opt_number eigs_opt_number READ b -eigenscript.c:2180 eigs_opt_number eigs_number_arg READ b -eigenscript.c:2185 eigs_list_float eigs_list_float READ b -eigenscript.c:2188 eigs_list_float eigs_float_arg READ b -eigenscript.c:2190 eigs_elem_float eigs_elem_float READ b -eigenscript.c:2191 eigs_elem_float eigs_float_arg READ b -eigenscript.c:2193 eigs_opt_float eigs_opt_float READ b -eigenscript.c:2195 eigs_opt_float eigs_float_arg READ b -eigenscript.c:2200 eigs_list_int eigs_list_int READ b -eigenscript.c:2203 eigs_list_int eigs_int_arg READ b -eigenscript.c:2205 eigs_elem_int eigs_elem_int READ b -eigenscript.c:2206 eigs_elem_int eigs_int_arg READ b -eigenscript.c:2208 eigs_opt_int eigs_opt_int READ b -eigenscript.c:2210 eigs_opt_int eigs_int_arg READ b -eigenscript.c:2215 eigs_list_byte eigs_list_byte READ b -eigenscript.c:2218 eigs_list_byte eigs_byte_arg READ b -eigenscript.c:2220 eigs_elem_byte eigs_elem_byte READ b -eigenscript.c:2221 eigs_elem_byte eigs_byte_arg READ b -eigenscript.c:2223 eigs_opt_byte eigs_opt_byte READ b -eigenscript.c:2225 eigs_opt_byte eigs_byte_arg READ b -eigenscript.c:2230 eigs_list_int_range eigs_list_int_range READ b -eigenscript.c:2233 eigs_list_int_range eigs_int_arg_range READ b -eigenscript.c:2235 eigs_elem_int_range eigs_elem_int_range READ b -eigenscript.c:2236 eigs_elem_int_range VAL_INT TAGSET c -eigenscript.c:2237 eigs_elem_int_range eigs_int_arg_range READ b -eigenscript.c:2239 eigs_opt_int_range eigs_opt_int_range READ b -eigenscript.c:2241 eigs_opt_int_range eigs_int_arg_range READ b -eigenscript.c:2244 eigs_list_bounded eigs_list_bounded READ b -eigenscript.c:2247 eigs_list_bounded eigs_bounded_arg READ b -eigenscript.c:2249 eigs_elem_bounded eigs_elem_bounded READ b -eigenscript.c:2250 eigs_elem_bounded VAL_INT TAGSET c -eigenscript.c:2251 eigs_elem_bounded eigs_bounded_arg READ b -eigenscript.c:2253 eigs_opt_bounded eigs_opt_bounded READ b -eigenscript.c:2255 eigs_opt_bounded eigs_bounded_arg READ b -eigenscript.c:2258 eigs_list_magnitude eigs_list_magnitude READ b -eigenscript.c:2261 eigs_list_magnitude eigs_magnitude_arg READ b -eigenscript.c:2263 eigs_elem_magnitude eigs_elem_magnitude READ b -eigenscript.c:2264 eigs_elem_magnitude VAL_INT TAGSET c -eigenscript.c:2265 eigs_elem_magnitude eigs_magnitude_arg READ b -eigenscript.c:2267 eigs_opt_magnitude eigs_opt_magnitude READ b -eigenscript.c:2269 eigs_opt_magnitude eigs_magnitude_arg READ b -eigenscript.c:2274 buffer_read_f64 buffer_read_f64 READ b -eigenscript.c:2280 buffer_read_f64 num_guard GUARD c -eigenscript.c:2286 buffer_read_f64 num_guard GUARD c -eigenscript.c:2288 buffer_index_at buffer_index_at READ b -eigenscript.c:2296 buffer_index_at buffer_read_f64 READ b -eigenscript.c:2298 buffer_index_at VAL_FLOAT TAGSET c -eigenscript.c:2299 buffer_index_at VAL_F64_RAW WRITE c -eigenscript.c:2300 buffer_index_at eigs_int_arg READ b -eigenscript.c:2304 buffer_byte_at buffer_byte_at READ b -eigenscript.c:2306 buffer_byte_at buffer_index_at READ b -eigenscript.c:2346 slot_from_value VAL_FLOAT TEST a -eigenscript.c:2350 slot_from_value VAL_F64_RAW RAW b -eigenscript.c:2352 slot_from_value slot_from_f64 PRODUCE c -eigenscript.c:2356 slot_from_value VAL_INT TEST a -eigenscript.c:2357 slot_from_value VAL_I64_RAW RAW b -eigenscript.c:2360 slot_from_value slot_from_int PRODUCE c -eigenscript.c:2380 slot_to_value SLOT_F64_RAW RAW b -eigenscript.c:2380 slot_to_value make_num PRODUCE c -eigenscript.c:2380 slot_to_value slot_is_f64 TEST a -eigenscript.c:2388 slot_to_value make_int PRODUCE c -eigenscript.c:2388 slot_to_value slot_is_smi TEST a -eigenscript.c:2388 slot_to_value slot_smi_val RAW b -eigenscript.c:2881 module_ns_project slot_is_f64 TEST a -eigenscript.c:2881 module_ns_project slot_is_f64 TEST a -eigenscript.c:2886 module_ns_project SLOT_F64_RAW RAW b -eigenscript.c:2886 module_ns_project dict_value_rewrite_num PRODUCE c -eigenscript.c:3131 chan_clone_rec VAL_FLOAT TEST a -eigenscript.c:3131 chan_clone_rec VAL_INT TEST a -eigenscript.c:3134 chan_clone_rec VAL_F64_RAW RAW b -eigenscript.c:3134 chan_clone_rec VAL_FLOAT CASE a -eigenscript.c:3134 chan_clone_rec make_num PRODUCE c -eigenscript.c:3135 chan_clone_rec VAL_I64_RAW RAW b -eigenscript.c:3135 chan_clone_rec VAL_INT CASE a -eigenscript.c:3135 chan_clone_rec make_int PRODUCE c -eigenscript.c:3322 is_truthy VAL_F64_RAW RAW b -eigenscript.c:3322 is_truthy VAL_FLOAT CASE a -eigenscript.c:3323 is_truthy VAL_I64_RAW RAW b -eigenscript.c:3323 is_truthy VAL_INT CASE a -eigenscript.c:3362 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:3362 values_equal_impl VAL_INT TEST f -eigenscript.c:3363 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3363 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3364 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:3364 values_equal_impl VAL_INT TEST f -eigenscript.c:3365 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3365 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3366 values_equal_impl val_is_number TEST f -eigenscript.c:3367 values_equal_impl val_is_number TEST f -eigenscript.c:3381 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3381 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3381 values_equal_impl VAL_FLOAT CASE f -eigenscript.c:3382 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3382 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3382 values_equal_impl VAL_INT CASE f -eigenscript.c:3412 values_equal_impl buffer_read_num READ f -eigenscript.c:3414 values_equal_impl buffer_read_num READ f -eigenscript.c:3454 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3469 eigs_num_text strtod PARSE e -eigenscript.c:3479 value_to_string VAL_FLOAT CASE e -eigenscript.c:3480 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3480 value_to_string eigs_num_text FORMAT e -eigenscript.c:3483 value_to_string VAL_INT CASE e -eigenscript.c:3484 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4785 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4786 gc_value_is_node VAL_INT CASE a +eigenscript.c:1780 make_float make_float PRODUCE c +eigenscript.c:1784 make_int make_int PRODUCE c +eigenscript.c:1786 make_int VAL_INT TAGSET c +eigenscript.c:1787 make_int VAL_I64_RAW WRITE c +eigenscript.c:1793 recycle_intermediate VAL_FLOAT TEST a +eigenscript.c:1815 make_float_permanent make_float_permanent PRODUCE c +eigenscript.c:1816 make_float_permanent num_guard GUARD c +eigenscript.c:1818 make_float_permanent VAL_FLOAT TAGSET c +eigenscript.c:1819 make_float_permanent VAL_F64_RAW WRITE c +eigenscript.c:1852 eigs_number_read VAL_INT TEST a +eigenscript.c:1853 eigs_number_read VAL_I64_RAW RAW b +eigenscript.c:1855 eigs_number_read VAL_FLOAT TEST a +eigenscript.c:1856 eigs_number_read VAL_F64_RAW RAW b +eigenscript.c:1864 eigs_number_arg eigs_number_arg READ b +eigenscript.c:1875 eigs_float_arg eigs_float_arg READ b +eigenscript.c:1876 eigs_float_arg eigs_number_arg READ b +eigenscript.c:1880 eigs_int_arg eigs_int_arg READ b +eigenscript.c:1885 eigs_int_arg num_to_i64_exact READ b +eigenscript.c:1891 eigs_int_arg_range READ b +eigenscript.c:1893 eigs_int_arg_range eigs_int_arg READ b +eigenscript.c:1904 eigs_byte_arg eigs_byte_arg READ b +eigenscript.c:1906 eigs_byte_arg eigs_int_arg_range READ b +eigenscript.c:2040 eigs_geom_shape READ b +eigenscript.c:2047 eigs_geom_shape eigs_list_float READ b +eigenscript.c:2087 eigs_bounded_arg eigs_bounded_arg READ b +eigenscript.c:2088 eigs_bounded_arg eigs_float_arg READ b +eigenscript.c:2104 eigs_magnitude_arg READ b +eigenscript.c:2106 eigs_magnitude_arg eigs_number_arg READ b +eigenscript.c:2110 eigs_magnitude_arg num_to_i64_exact READ b +eigenscript.c:2134 eigs_reader_elem_default val_is_number TEST a +eigenscript.c:2137 eigs_list_number eigs_list_number READ b +eigenscript.c:2140 eigs_list_number eigs_number_arg READ b +eigenscript.c:2142 eigs_elem_number eigs_elem_number READ b +eigenscript.c:2143 eigs_elem_number eigs_number_arg READ b +eigenscript.c:2145 eigs_opt_number eigs_opt_number READ b +eigenscript.c:2147 eigs_opt_number eigs_number_arg READ b +eigenscript.c:2152 eigs_list_float eigs_list_float READ b +eigenscript.c:2155 eigs_list_float eigs_float_arg READ b +eigenscript.c:2157 eigs_elem_float eigs_elem_float READ b +eigenscript.c:2158 eigs_elem_float eigs_float_arg READ b +eigenscript.c:2160 eigs_opt_float eigs_opt_float READ b +eigenscript.c:2162 eigs_opt_float eigs_float_arg READ b +eigenscript.c:2167 eigs_list_int eigs_list_int READ b +eigenscript.c:2170 eigs_list_int eigs_int_arg READ b +eigenscript.c:2172 eigs_elem_int eigs_elem_int READ b +eigenscript.c:2173 eigs_elem_int eigs_int_arg READ b +eigenscript.c:2175 eigs_opt_int eigs_opt_int READ b +eigenscript.c:2177 eigs_opt_int eigs_int_arg READ b +eigenscript.c:2182 eigs_list_byte eigs_list_byte READ b +eigenscript.c:2185 eigs_list_byte eigs_byte_arg READ b +eigenscript.c:2187 eigs_elem_byte eigs_elem_byte READ b +eigenscript.c:2188 eigs_elem_byte eigs_byte_arg READ b +eigenscript.c:2190 eigs_opt_byte eigs_opt_byte READ b +eigenscript.c:2192 eigs_opt_byte eigs_byte_arg READ b +eigenscript.c:2197 eigs_list_int_range eigs_list_int_range READ b +eigenscript.c:2200 eigs_list_int_range eigs_int_arg_range READ b +eigenscript.c:2202 eigs_elem_int_range eigs_elem_int_range READ b +eigenscript.c:2203 eigs_elem_int_range VAL_INT TAGSET c +eigenscript.c:2204 eigs_elem_int_range eigs_int_arg_range READ b +eigenscript.c:2206 eigs_opt_int_range eigs_opt_int_range READ b +eigenscript.c:2208 eigs_opt_int_range eigs_int_arg_range READ b +eigenscript.c:2211 eigs_list_bounded eigs_list_bounded READ b +eigenscript.c:2214 eigs_list_bounded eigs_bounded_arg READ b +eigenscript.c:2216 eigs_elem_bounded eigs_elem_bounded READ b +eigenscript.c:2217 eigs_elem_bounded VAL_INT TAGSET c +eigenscript.c:2218 eigs_elem_bounded eigs_bounded_arg READ b +eigenscript.c:2220 eigs_opt_bounded eigs_opt_bounded READ b +eigenscript.c:2222 eigs_opt_bounded eigs_bounded_arg READ b +eigenscript.c:2225 eigs_list_magnitude eigs_list_magnitude READ b +eigenscript.c:2228 eigs_list_magnitude eigs_magnitude_arg READ b +eigenscript.c:2230 eigs_elem_magnitude eigs_elem_magnitude READ b +eigenscript.c:2231 eigs_elem_magnitude VAL_INT TAGSET c +eigenscript.c:2232 eigs_elem_magnitude eigs_magnitude_arg READ b +eigenscript.c:2234 eigs_opt_magnitude eigs_opt_magnitude READ b +eigenscript.c:2236 eigs_opt_magnitude eigs_magnitude_arg READ b +eigenscript.c:2241 buffer_read_f64 buffer_read_f64 READ b +eigenscript.c:2247 buffer_read_f64 num_guard GUARD c +eigenscript.c:2253 buffer_read_f64 num_guard GUARD c +eigenscript.c:2255 buffer_index_at buffer_index_at READ b +eigenscript.c:2263 buffer_index_at buffer_read_f64 READ b +eigenscript.c:2265 buffer_index_at VAL_FLOAT TAGSET c +eigenscript.c:2266 buffer_index_at VAL_F64_RAW WRITE c +eigenscript.c:2267 buffer_index_at eigs_int_arg READ b +eigenscript.c:2271 buffer_byte_at buffer_byte_at READ b +eigenscript.c:2273 buffer_byte_at buffer_index_at READ b +eigenscript.c:2313 slot_from_value VAL_FLOAT TEST a +eigenscript.c:2317 slot_from_value VAL_F64_RAW RAW b +eigenscript.c:2319 slot_from_value slot_from_f64 PRODUCE c +eigenscript.c:2323 slot_from_value VAL_INT TEST a +eigenscript.c:2324 slot_from_value VAL_I64_RAW RAW b +eigenscript.c:2327 slot_from_value slot_from_int PRODUCE c +eigenscript.c:2347 slot_to_value SLOT_F64_RAW RAW b +eigenscript.c:2347 slot_to_value make_float PRODUCE c +eigenscript.c:2347 slot_to_value slot_is_f64 TEST a +eigenscript.c:2355 slot_to_value make_int PRODUCE c +eigenscript.c:2355 slot_to_value slot_is_smi TEST a +eigenscript.c:2355 slot_to_value slot_smi_val RAW b +eigenscript.c:2848 module_ns_project slot_is_f64 TEST a +eigenscript.c:2848 module_ns_project slot_is_f64 TEST a +eigenscript.c:2853 module_ns_project SLOT_F64_RAW RAW b +eigenscript.c:2853 module_ns_project dict_value_rewrite_f64 PRODUCE c +eigenscript.c:3098 chan_clone_rec VAL_FLOAT TEST a +eigenscript.c:3098 chan_clone_rec VAL_INT TEST a +eigenscript.c:3101 chan_clone_rec VAL_F64_RAW RAW b +eigenscript.c:3101 chan_clone_rec VAL_FLOAT CASE a +eigenscript.c:3101 chan_clone_rec make_float PRODUCE c +eigenscript.c:3102 chan_clone_rec VAL_I64_RAW RAW b +eigenscript.c:3102 chan_clone_rec VAL_INT CASE a +eigenscript.c:3102 chan_clone_rec make_int PRODUCE c +eigenscript.c:3289 is_truthy VAL_F64_RAW RAW b +eigenscript.c:3289 is_truthy VAL_FLOAT CASE a +eigenscript.c:3290 is_truthy VAL_I64_RAW RAW b +eigenscript.c:3290 is_truthy VAL_INT CASE a +eigenscript.c:3329 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:3329 values_equal_impl VAL_INT TEST f +eigenscript.c:3330 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3330 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3331 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:3331 values_equal_impl VAL_INT TEST f +eigenscript.c:3332 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3332 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3333 values_equal_impl val_is_number TEST f +eigenscript.c:3334 values_equal_impl val_is_number TEST f +eigenscript.c:3348 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3348 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3348 values_equal_impl VAL_FLOAT CASE f +eigenscript.c:3349 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3349 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3349 values_equal_impl VAL_INT CASE f +eigenscript.c:3419 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:3434 eigs_num_text strtod PARSE e +eigenscript.c:3444 value_to_string VAL_FLOAT CASE e +eigenscript.c:3445 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3445 value_to_string eigs_num_text FORMAT e +eigenscript.c:3448 value_to_string VAL_INT CASE e +eigenscript.c:3449 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4750 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4751 gc_value_is_node VAL_INT CASE a eigenscript.h:196 number RAW b eigenscript.h:214 AST_NUM DATA a eigenscript.h:240 number RAW b -eigenscript.h:290 VAL_FLOAT DATA a -eigenscript.h:299 VAL_INT DATA a -eigenscript.h:307 #define val_is_number VAL_FLOAT TEST a -eigenscript.h:307 #define val_is_number VAL_INT TEST a -eigenscript.h:307 #define val_is_number val_is_number TEST a -eigenscript.h:328 #define VAL_F64_RAW VAL_F64_RAW RAW b -eigenscript.h:328 #define VAL_F64_RAW f64_ RAW b -eigenscript.h:329 #define VAL_I64_RAW VAL_I64_RAW RAW b -eigenscript.h:329 #define VAL_I64_RAW i64_ RAW b -eigenscript.h:330 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b -eigenscript.h:330 #define VAL_F64_OFFSET f64_ RAW b -eigenscript.h:1407 eigs_num_arg_slow READ b -eigenscript.h:1409 eigs_num_arg eigs_num_arg READ b -eigenscript.h:1410 eigs_num_arg VAL_F64_RAW RAW b -eigenscript.h:1410 eigs_num_arg VAL_FLOAT TEST a -eigenscript.h:1411 eigs_num_arg eigs_num_arg_slow READ b -eigenscript.h:1413 eigs_list_num READ b -eigenscript.h:1418 eigs_elem_num READ b -eigenscript.h:1419 eigs_opt_num READ b -eigenscript.h:1426 eigs_number_arg READ b -eigenscript.h:1427 eigs_list_number READ b -eigenscript.h:1428 eigs_elem_number READ b -eigenscript.h:1429 eigs_opt_number READ b -eigenscript.h:1430 eigs_float_arg READ b -eigenscript.h:1431 eigs_list_float READ b -eigenscript.h:1432 eigs_elem_float READ b -eigenscript.h:1433 eigs_opt_float READ b -eigenscript.h:1434 eigs_int_arg READ b -eigenscript.h:1435 eigs_list_int READ b -eigenscript.h:1436 eigs_elem_int READ b -eigenscript.h:1437 eigs_opt_int READ b -eigenscript.h:1438 eigs_byte_arg READ b -eigenscript.h:1439 eigs_list_byte READ b -eigenscript.h:1440 eigs_elem_byte READ b -eigenscript.h:1441 eigs_opt_byte READ b -eigenscript.h:1442 eigs_int_arg_range READ b -eigenscript.h:1443 eigs_list_int_range READ b -eigenscript.h:1444 eigs_elem_int_range READ b -eigenscript.h:1445 eigs_opt_int_range READ b -eigenscript.h:1455 eigs_geom_shape READ b -eigenscript.h:1457 eigs_bounded_arg READ b -eigenscript.h:1458 eigs_list_bounded READ b -eigenscript.h:1459 eigs_elem_bounded READ b -eigenscript.h:1460 eigs_opt_bounded READ b -eigenscript.h:1461 eigs_magnitude_arg READ b -eigenscript.h:1462 eigs_list_magnitude READ b -eigenscript.h:1463 eigs_elem_magnitude READ b -eigenscript.h:1464 eigs_opt_magnitude READ b -eigenscript.h:1836 make_num PRODUCE c -eigenscript.h:1837 make_float PRODUCE c -eigenscript.h:1838 make_float_permanent PRODUCE c -eigenscript.h:1839 make_int PRODUCE c -eigenscript.h:1849 make_num_permanent PRODUCE c -eigenscript.h:1901 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c -eigenscript.h:1943 num_guard num_guard GUARD c -eigenscript.h:1951 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1951 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1952 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1952 num_guard EIGS_NUM_MAX GUARD c -eigenscript.h:1962 buffer_read_num buffer_read_num READ b -eigenscript.h:1963 buffer_read_num num_guard GUARD c -eigenscript.h:1972 finite_num_to_byte finite_num_to_byte READ b -eigenscript.h:1981 num_to_i64_exact num_to_i64_exact READ b -eigenscript.h:2000 buffer_read_f64 READ b -eigenscript.h:2001 buffer_byte_at READ b -eigenscript.h:2002 buffer_index_at READ b -eigenscript.h:2014 num_guard_named num_guard_named GUARD c -eigenscript.h:2020 num_guard_named num_guard GUARD c -eigenscript.h:2326 eigs_num_text FORMAT e -eigs_embed.c:302 eigs_value_new_num make_num PRODUCE j +eigenscript.h:281 VAL_FLOAT DATA a +eigenscript.h:290 VAL_INT DATA a +eigenscript.h:298 #define val_is_number VAL_FLOAT TEST a +eigenscript.h:298 #define val_is_number VAL_INT TEST a +eigenscript.h:298 #define val_is_number val_is_number TEST a +eigenscript.h:319 #define VAL_F64_RAW VAL_F64_RAW RAW b +eigenscript.h:319 #define VAL_F64_RAW f64_ RAW b +eigenscript.h:320 #define VAL_I64_RAW VAL_I64_RAW RAW b +eigenscript.h:320 #define VAL_I64_RAW i64_ RAW b +eigenscript.h:321 #define VAL_F64_OFFSET VAL_F64_OFFSET RAW b +eigenscript.h:321 #define VAL_F64_OFFSET f64_ RAW b +eigenscript.h:1395 eigs_number_arg READ b +eigenscript.h:1396 eigs_list_number READ b +eigenscript.h:1397 eigs_elem_number READ b +eigenscript.h:1398 eigs_opt_number READ b +eigenscript.h:1399 eigs_float_arg READ b +eigenscript.h:1400 eigs_list_float READ b +eigenscript.h:1401 eigs_elem_float READ b +eigenscript.h:1402 eigs_opt_float READ b +eigenscript.h:1403 eigs_int_arg READ b +eigenscript.h:1404 eigs_list_int READ b +eigenscript.h:1405 eigs_elem_int READ b +eigenscript.h:1406 eigs_opt_int READ b +eigenscript.h:1407 eigs_byte_arg READ b +eigenscript.h:1408 eigs_list_byte READ b +eigenscript.h:1409 eigs_elem_byte READ b +eigenscript.h:1410 eigs_opt_byte READ b +eigenscript.h:1411 eigs_int_arg_range READ b +eigenscript.h:1412 eigs_list_int_range READ b +eigenscript.h:1413 eigs_elem_int_range READ b +eigenscript.h:1414 eigs_opt_int_range READ b +eigenscript.h:1424 eigs_geom_shape READ b +eigenscript.h:1426 eigs_bounded_arg READ b +eigenscript.h:1427 eigs_list_bounded READ b +eigenscript.h:1428 eigs_elem_bounded READ b +eigenscript.h:1429 eigs_opt_bounded READ b +eigenscript.h:1430 eigs_magnitude_arg READ b +eigenscript.h:1431 eigs_list_magnitude READ b +eigenscript.h:1432 eigs_elem_magnitude READ b +eigenscript.h:1433 eigs_opt_magnitude READ b +eigenscript.h:1805 make_float PRODUCE c +eigenscript.h:1806 make_float_permanent PRODUCE c +eigenscript.h:1807 make_int PRODUCE c +eigenscript.h:1868 #define EIGS_NUM_MAX EIGS_NUM_MAX GUARD c +eigenscript.h:1910 num_guard num_guard GUARD c +eigenscript.h:1918 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1918 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1919 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1919 num_guard EIGS_NUM_MAX GUARD c +eigenscript.h:1928 num_to_i64_exact num_to_i64_exact READ b +eigenscript.h:1947 buffer_read_f64 READ b +eigenscript.h:1948 buffer_byte_at READ b +eigenscript.h:1949 buffer_index_at READ b +eigenscript.h:1961 num_guard_named num_guard_named GUARD c +eigenscript.h:1967 num_guard_named num_guard GUARD c +eigenscript.h:2273 eigs_num_text FORMAT e +eigs_embed.c:302 eigs_value_new_num make_float PRODUCE j eigs_embed.c:315 eigs_value_type VAL_FLOAT CASE j eigs_embed.c:316 eigs_value_type VAL_INT CASE j eigs_embed.c:360 eigs_value_as_num eigs_value_as_num READ j @@ -1887,9 +1826,8 @@ eigs_embed.c:365 eigs_value_as_num VAL_I64_RAW RAW j eigs_embed.c:365 eigs_value_as_num VAL_INT TEST j eigs_embed.c:366 eigs_value_as_num VAL_F64_RAW RAW j eigs_embed.c:366 eigs_value_as_num VAL_FLOAT TEST j -eigs_embed.c:437 eigs_value_buffer_get buffer_read_num READ j -eigs_embed.c:484 eigs_trace_declare_kind VAL_FLOAT DATA j -eigs_embed.c:484 eigs_trace_declare_kind VAL_INT DATA j +eigs_embed.c:485 eigs_trace_declare_kind VAL_FLOAT DATA j +eigs_embed.c:485 eigs_trace_declare_kind VAL_INT DATA j eigs_embed.h:171 eigs_value_as_num READ j embed_concurrent.c:106 global_worker eigs_value_as_num READ j embed_concurrent.c:768 take_drain eigs_value_as_num READ j @@ -1898,8 +1836,8 @@ embed_concurrent.c:1763 fu_worker eigs_value_as_num READ j embed_concurrent.c:1830 test_register_while_workers_read eigs_value_as_num READ j embed_concurrent.c:1834 test_register_while_workers_read eigs_value_as_num READ j embed_smoke.c:190 test_worker_exit_lifecycle eigs_value_as_num READ j -embed_smoke.c:198 test_worker_exit_lifecycle eigs_slot_num READ j -embed_smoke.c:199 test_worker_exit_lifecycle eigs_slot_num READ j +embed_smoke.c:198 test_worker_exit_lifecycle eigs_slot_float READ j +embed_smoke.c:199 test_worker_exit_lifecycle eigs_slot_float READ j embed_smoke.c:214 test_worker_exit_lifecycle eigs_value_as_num READ j embed_smoke.c:300 host_add eigs_value_as_num READ j embed_smoke.c:300 host_add eigs_value_as_num READ j @@ -1925,33 +1863,33 @@ embed_smoke.c:621 main eigs_value_as_num READ j embed_smoke.c:630 main eigs_value_as_num READ j embed_smoke.c:673 main EIGS_NUM_MAX GUARD j embed_smoke.c:681 main eigs_value_as_num READ j -embed_smoke.c:954 main eigs_value_as_num READ j -embed_smoke.c:997 main eigs_value_as_num READ j -embed_smoke.c:1003 main eigs_value_as_num READ j -embed_smoke.c:1007 main eigs_value_as_num READ j -embed_smoke.c:1041 main eigs_value_as_num READ j -embed_smoke.c:1119 main eigs_value_as_num READ j -embed_smoke.c:1130 main eigs_value_as_num READ j -embed_smoke.c:1140 main SLOT_F64_RAW WRITE j -embed_smoke.c:1157 main eigs_value_as_num READ j -embed_smoke.c:1167 main eigs_value_as_num READ j -embed_smoke.c:1176 main eigs_value_as_num READ j -embed_smoke.c:1185 main eigs_value_as_num READ j -embed_smoke.c:1203 main eigs_value_as_num READ j -embed_smoke.c:1211 main eigs_value_as_num READ j -embed_smoke.c:1215 main eigs_value_as_num READ j -embed_smoke.c:1220 main eigs_value_as_num READ j -embed_smoke.c:1231 main eigs_value_as_num READ j -embed_smoke.c:1236 main eigs_value_as_num READ j -embed_smoke.c:1245 main eigs_value_as_num READ j -embed_smoke.c:1264 main eigs_value_as_num READ j -embed_smoke.c:1268 main eigs_value_as_num READ j +embed_smoke.c:967 main eigs_value_as_num READ j +embed_smoke.c:1010 main eigs_value_as_num READ j +embed_smoke.c:1016 main eigs_value_as_num READ j +embed_smoke.c:1020 main eigs_value_as_num READ j +embed_smoke.c:1054 main eigs_value_as_num READ j +embed_smoke.c:1132 main eigs_value_as_num READ j +embed_smoke.c:1143 main eigs_value_as_num READ j +embed_smoke.c:1153 main SLOT_F64_RAW WRITE j +embed_smoke.c:1170 main eigs_value_as_num READ j +embed_smoke.c:1180 main eigs_value_as_num READ j +embed_smoke.c:1189 main eigs_value_as_num READ j +embed_smoke.c:1198 main eigs_value_as_num READ j +embed_smoke.c:1216 main eigs_value_as_num READ j +embed_smoke.c:1224 main eigs_value_as_num READ j +embed_smoke.c:1228 main eigs_value_as_num READ j +embed_smoke.c:1233 main eigs_value_as_num READ j +embed_smoke.c:1244 main eigs_value_as_num READ j +embed_smoke.c:1249 main eigs_value_as_num READ j +embed_smoke.c:1258 main eigs_value_as_num READ j embed_smoke.c:1277 main eigs_value_as_num READ j embed_smoke.c:1281 main eigs_value_as_num READ j -embed_smoke.c:1288 main eigs_value_as_num READ j -embed_smoke.c:1344 main eigs_value_as_num READ j -embed_smoke.c:1368 main eigs_value_as_num READ j -embed_smoke.c:1395 main eigs_value_as_num READ j +embed_smoke.c:1290 main eigs_value_as_num READ j +embed_smoke.c:1294 main eigs_value_as_num READ j +embed_smoke.c:1301 main eigs_value_as_num READ j +embed_smoke.c:1357 main eigs_value_as_num READ j +embed_smoke.c:1381 main eigs_value_as_num READ j +embed_smoke.c:1408 main eigs_value_as_num READ j ext_db.c:65 db_build_query VAL_INT TEST h ext_db.c:66 db_build_query VAL_I64_RAW RAW h ext_db.c:68 db_build_query VAL_FLOAT TEST h @@ -2335,77 +2273,75 @@ jit.c:1633 emit_overflow_check_rax EMIT d jit.c:1636 emit_overflow_check_rax emit_btr_63_rdx EMIT d jit.c:1697 emit_cvttsd2si_xmm0_r8d emit_cvttsd2si_xmm0_r8d EMIT d jit.c:1702 emit_cvtsi2sd_r8d_xmm1 emit_cvtsi2sd_r8d_xmm1 EMIT d -jit.c:1709 emit_cvttsd2si_xmm0_edx emit_cvttsd2si_xmm0_edx EMIT d -jit.c:1714 emit_cvtsi2sd_edx_xmm0 emit_cvtsi2sd_edx_xmm0 EMIT d -jit.c:1907 emit_jump_unless_bool_rax TAG-IMM 0xFFF9 EMIT d -jit.c:2025 emit_conditional_decref_rsi_hook TAG-IMM 0xFFFB EMIT d -jit.c:2171 emit_dict_cache_probe TAG-IMM 0xFFFB EMIT d -jit.c:2336 emit_load_numeric_operand EMIT d -jit.c:2341 emit_load_numeric_operand TAG-IMM 0xFFF8 EMIT d -jit.c:2346 emit_load_numeric_operand TAG-IMM 0xFFFB EMIT d -jit.c:2349 emit_load_numeric_operand TAG-IMM 0xFFFD EMIT d -jit.c:2356 emit_load_numeric_operand VAL_FLOAT EMIT d -jit.c:2360 emit_load_numeric_operand VAL_F64_OFFSET RAW d -jit.c:2361 emit_load_numeric_operand VAL_F64_OFFSET RAW d -jit.c:2390 emit_decref_binop_operands TAG-IMM 0xFFFB EMIT d -jit.c:2418 emit_commit_binop TAG-IMM 0xFFFB EMIT d -jit.c:2626 jit_compile_to_thunk max_normal_bits EMIT d -jit.c:2627 jit_compile_to_thunk EIGS_NUM_MAX GUARD d -jit.c:2627 jit_compile_to_thunk max_normal_bits EMIT d -jit.c:2794 jit_compile_to_thunk/OP_NULL TAG-IMM 0xFFF8 EMIT d -jit.c:2815 jit_compile_to_thunk/OP_CONST VAL_FLOAT TEST d -jit.c:2818 jit_compile_to_thunk/OP_CONST VAL_F64_RAW RAW d -jit.c:2821 jit_compile_to_thunk/OP_CONST TAG-IMM 0xFFFB EMIT d -jit.c:3017 jit_compile_to_thunk/OP_SET_NAME TAG-IMM 0xFFFB EMIT d -jit.c:3138 jit_compile_to_thunk/OP_LOCAL_DOT_GET emit_immediate_num_check_rax EMIT d -jit.c:3264 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rax EMIT d -jit.c:3267 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rdx EMIT d -jit.c:3445 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFF8 EMIT d -jit.c:3450 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFB EMIT d -jit.c:3452 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFD EMIT d -jit.c:3458 jit_compile_to_thunk/OP_SET_LOCAL VAL_FLOAT EMIT d -jit.c:3464 jit_compile_to_thunk/OP_SET_LOCAL VAL_F64_OFFSET RAW d -jit.c:3523 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d -jit.c:3527 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d -jit.c:3537 jit_compile_to_thunk/OP_MOD emit_btr_63_rsi EMIT d -jit.c:3551 jit_compile_to_thunk/OP_MOD fmod EMIT d -jit.c:3557 jit_compile_to_thunk/OP_MOD emit_overflow_check_rax EMIT d -jit.c:3557 jit_compile_to_thunk/OP_MOD max_normal_bits EMIT d -jit.c:3605 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d -jit.c:3609 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d -jit.c:3617 jit_compile_to_thunk/OP_ADD emit_addsd_xmm0_xmm1 EMIT d -jit.c:3618 jit_compile_to_thunk/OP_ADD emit_subsd_xmm0_xmm1 EMIT d -jit.c:3619 jit_compile_to_thunk/OP_ADD emit_mulsd_xmm0_xmm1 EMIT d -jit.c:3620 jit_compile_to_thunk/OP_ADD emit_divsd_xmm0_xmm1 EMIT d -jit.c:3627 jit_compile_to_thunk/OP_ADD emit_overflow_check_rax EMIT d -jit.c:3627 jit_compile_to_thunk/OP_ADD max_normal_bits EMIT d -jit.c:3666 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d -jit.c:3670 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d -jit.c:3683 jit_compile_to_thunk/OP_EQ emit_ucomisd_xmm0_xmm1 EMIT d -jit.c:3723 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rax EMIT d -jit.c:3725 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rdx EMIT d -jit.c:3731 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm0_rax EMIT d -jit.c:3732 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rax_xmm2 EMIT d -jit.c:3733 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm0_xmm2 EMIT d -jit.c:3736 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm1_rdx EMIT d -jit.c:3737 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm2 EMIT d -jit.c:3738 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm1_xmm2 EMIT d -jit.c:3758 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm0 EMIT d -jit.c:3788 jit_compile_to_thunk/OP_NOT emit_immediate_num_check_rax EMIT d -jit.c:3801 jit_compile_to_thunk/OP_NEG emit_btr_63_rax EMIT d -jit.c:3816 jit_compile_to_thunk/OP_NEG emit_cvttsd2si_xmm0_rax EMIT d -jit.c:3817 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm2 EMIT d -jit.c:3818 jit_compile_to_thunk/OP_NEG emit_ucomisd_xmm0_xmm2 EMIT d -jit.c:3822 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm0 EMIT d -jit.c:3941 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_immediate_num_check_rax EMIT d -jit.c:3944 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_btr_63_rax EMIT d -jit.c:4081 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rdx EMIT d -jit.c:4086 jit_compile_to_thunk/OP_INDEX_SET TAG-IMM 0xFFFB EMIT d -jit.c:4100 jit_compile_to_thunk/OP_INDEX_SET emit_cvttsd2si_xmm0_r8d EMIT d -jit.c:4101 jit_compile_to_thunk/OP_INDEX_SET emit_cvtsi2sd_r8d_xmm1 EMIT d -jit.c:4102 jit_compile_to_thunk/OP_INDEX_SET emit_ucomisd_xmm0_xmm1 EMIT d -jit.c:4110 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rax EMIT d -jit.c:4368 jit_compile_to_thunk/OP_POP VAL_FLOAT TEST d +jit.c:1895 emit_jump_unless_bool_rax TAG-IMM 0xFFF9 EMIT d +jit.c:2013 emit_conditional_decref_rsi_hook TAG-IMM 0xFFFB EMIT d +jit.c:2159 emit_dict_cache_probe TAG-IMM 0xFFFB EMIT d +jit.c:2324 emit_load_numeric_operand EMIT d +jit.c:2329 emit_load_numeric_operand TAG-IMM 0xFFF8 EMIT d +jit.c:2334 emit_load_numeric_operand TAG-IMM 0xFFFB EMIT d +jit.c:2337 emit_load_numeric_operand TAG-IMM 0xFFFD EMIT d +jit.c:2344 emit_load_numeric_operand VAL_FLOAT EMIT d +jit.c:2348 emit_load_numeric_operand VAL_F64_OFFSET RAW d +jit.c:2349 emit_load_numeric_operand VAL_F64_OFFSET RAW d +jit.c:2378 emit_decref_binop_operands TAG-IMM 0xFFFB EMIT d +jit.c:2406 emit_commit_binop TAG-IMM 0xFFFB EMIT d +jit.c:2614 jit_compile_to_thunk max_normal_bits EMIT d +jit.c:2615 jit_compile_to_thunk EIGS_NUM_MAX GUARD d +jit.c:2615 jit_compile_to_thunk max_normal_bits EMIT d +jit.c:2782 jit_compile_to_thunk/OP_NULL TAG-IMM 0xFFF8 EMIT d +jit.c:2803 jit_compile_to_thunk/OP_CONST VAL_FLOAT TEST d +jit.c:2806 jit_compile_to_thunk/OP_CONST VAL_F64_RAW RAW d +jit.c:2809 jit_compile_to_thunk/OP_CONST TAG-IMM 0xFFFB EMIT d +jit.c:3005 jit_compile_to_thunk/OP_SET_NAME TAG-IMM 0xFFFB EMIT d +jit.c:3126 jit_compile_to_thunk/OP_LOCAL_DOT_GET emit_immediate_num_check_rax EMIT d +jit.c:3252 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rax EMIT d +jit.c:3255 jit_compile_to_thunk/OP_LOCAL_DOT_SET emit_immediate_num_check_rdx EMIT d +jit.c:3433 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFF8 EMIT d +jit.c:3438 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFB EMIT d +jit.c:3440 jit_compile_to_thunk/OP_SET_LOCAL TAG-IMM 0xFFFD EMIT d +jit.c:3446 jit_compile_to_thunk/OP_SET_LOCAL VAL_FLOAT EMIT d +jit.c:3452 jit_compile_to_thunk/OP_SET_LOCAL VAL_F64_OFFSET RAW d +jit.c:3511 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d +jit.c:3515 jit_compile_to_thunk/OP_MOD emit_load_numeric_operand EMIT d +jit.c:3525 jit_compile_to_thunk/OP_MOD emit_btr_63_rsi EMIT d +jit.c:3539 jit_compile_to_thunk/OP_MOD fmod EMIT d +jit.c:3545 jit_compile_to_thunk/OP_MOD emit_overflow_check_rax EMIT d +jit.c:3545 jit_compile_to_thunk/OP_MOD max_normal_bits EMIT d +jit.c:3593 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d +jit.c:3597 jit_compile_to_thunk/OP_ADD emit_load_numeric_operand EMIT d +jit.c:3605 jit_compile_to_thunk/OP_ADD emit_addsd_xmm0_xmm1 EMIT d +jit.c:3606 jit_compile_to_thunk/OP_ADD emit_subsd_xmm0_xmm1 EMIT d +jit.c:3607 jit_compile_to_thunk/OP_ADD emit_mulsd_xmm0_xmm1 EMIT d +jit.c:3608 jit_compile_to_thunk/OP_ADD emit_divsd_xmm0_xmm1 EMIT d +jit.c:3615 jit_compile_to_thunk/OP_ADD emit_overflow_check_rax EMIT d +jit.c:3615 jit_compile_to_thunk/OP_ADD max_normal_bits EMIT d +jit.c:3654 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d +jit.c:3658 jit_compile_to_thunk/OP_EQ emit_load_numeric_operand EMIT d +jit.c:3671 jit_compile_to_thunk/OP_EQ emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:3711 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rax EMIT d +jit.c:3713 jit_compile_to_thunk/OP_BAND emit_immediate_num_check_rdx EMIT d +jit.c:3719 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm0_rax EMIT d +jit.c:3720 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:3721 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:3724 jit_compile_to_thunk/OP_BAND emit_cvttsd2si_xmm1_rdx EMIT d +jit.c:3725 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm2 EMIT d +jit.c:3726 jit_compile_to_thunk/OP_BAND emit_ucomisd_xmm1_xmm2 EMIT d +jit.c:3746 jit_compile_to_thunk/OP_BAND emit_cvtsi2sd_rdx_xmm0 EMIT d +jit.c:3776 jit_compile_to_thunk/OP_NOT emit_immediate_num_check_rax EMIT d +jit.c:3789 jit_compile_to_thunk/OP_NEG emit_btr_63_rax EMIT d +jit.c:3804 jit_compile_to_thunk/OP_NEG emit_cvttsd2si_xmm0_rax EMIT d +jit.c:3805 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm2 EMIT d +jit.c:3806 jit_compile_to_thunk/OP_NEG emit_ucomisd_xmm0_xmm2 EMIT d +jit.c:3810 jit_compile_to_thunk/OP_NEG emit_cvtsi2sd_rax_xmm0 EMIT d +jit.c:3929 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_immediate_num_check_rax EMIT d +jit.c:3932 jit_compile_to_thunk/OP_JUMP_IF_FALSE emit_btr_63_rax EMIT d +jit.c:4069 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rdx EMIT d +jit.c:4074 jit_compile_to_thunk/OP_INDEX_SET TAG-IMM 0xFFFB EMIT d +jit.c:4088 jit_compile_to_thunk/OP_INDEX_SET emit_cvttsd2si_xmm0_r8d EMIT d +jit.c:4089 jit_compile_to_thunk/OP_INDEX_SET emit_cvtsi2sd_r8d_xmm1 EMIT d +jit.c:4090 jit_compile_to_thunk/OP_INDEX_SET emit_ucomisd_xmm0_xmm1 EMIT d +jit.c:4098 jit_compile_to_thunk/OP_INDEX_SET emit_immediate_num_check_rax EMIT d +jit.c:4356 jit_compile_to_thunk/OP_POP VAL_FLOAT TEST d jit_smoke.c:103 jit_helper_local_idx_get slot_from_f64 PRODUCE d jit_smoke.c:138 jit_helper_iter_next SLOT_F64_RAW RAW d jit_smoke.c:142 jit_helper_iter_next slot_from_f64 PRODUCE d @@ -2517,11 +2453,11 @@ tape_read.c:387 tape_parse strtod PARSE g tape_read.c:388 tape_parse strtod PARSE g tape_read.c:389 tape_parse strtod PARSE g tape_read.c:391 tape_parse strtod PARSE g -task.c:314 task_sched_trace_read make_num PRODUCE c -task.c:315 task_sched_trace_read make_num PRODUCE c -task.c:316 task_sched_trace_read make_num PRODUCE c -task.c:584 task_do_kill make_num PRODUCE c -task.c:689 task_error_summary eigs_num_arg READ b +task.c:314 task_sched_trace_read make_float PRODUCE c +task.c:315 task_sched_trace_read make_float PRODUCE c +task.c:316 task_sched_trace_read make_float PRODUCE c +task.c:584 task_do_kill make_float PRODUCE c +task.c:689 task_error_summary eigs_float_arg READ b task.c:689 task_error_summary val_is_number TEST a trace.c:742 trace_query_at slot_from_f64 PRODUCE g trace.c:757 trace_query_at slot_from_f64 PRODUCE g @@ -2535,7 +2471,7 @@ trace.c:2036 kinds_text VAL_FLOAT DATA g trace.c:2345 parse_value_p strtod PARSE g trace.c:2451 parse_value_p make_int PRODUCE g trace.c:2454 parse_value_p strtod PARSE g -trace.c:2464 parse_value_p make_num PRODUCE g +trace.c:2464 parse_value_p make_float PRODUCE g trace.c:2758 trace_source_record make_int PRODUCE g trace.c:2767 trace_source_record make_int PRODUCE g trace.c:2791 trace_source_replay VAL_FLOAT TEST g @@ -2591,13 +2527,13 @@ vm.c:224 obs_dump_scope slot_is_f64 TEST i vm.c:225 obs_dump_scope SLOT_F64_RAW RAW i vm.c:226 obs_dump_scope slot_is_smi TEST i vm.c:227 obs_dump_scope slot_smi_val RAW i -vm.c:716 dict_set_cached_immediate dict_value_rewrite_num PRODUCE c +vm.c:716 dict_set_cached_immediate dict_value_rewrite_f64 PRODUCE c vm.c:796 slot_bridge_unwrap slot_is_f64 TEST a vm.c:798 slot_bridge_unwrap SLOT_F64_RAW RAW b -vm.c:798 slot_bridge_unwrap make_num PRODUCE c +vm.c:798 slot_bridge_unwrap make_float PRODUCE c vm.c:807 slot_bridge_unwrap slot_is_smi TEST a vm.c:843 vm_slot_lift SLOT_F64_RAW RAW b -vm.c:843 vm_slot_lift make_num PRODUCE c +vm.c:843 vm_slot_lift make_float PRODUCE c vm.c:843 vm_slot_lift slot_is_f64 TEST a vm.c:848 vm_slot_lift slot_is_smi TEST a vm.c:880 slot_truthy SLOT_F64_RAW RAW b @@ -2615,13 +2551,13 @@ vm.c:920 vm_number_compare slot_f64_value READ b vm.c:932 vm_iter_index slot_f64_value READ b vm.c:938 vm_iter_index slot_int_value READ b vm.c:946 vm_iter_limit slot_int_value READ b -vm.c:994 make_iter_state make_num PRODUCE c -vm.c:1007 make_iter_state make_num PRODUCE c +vm.c:994 make_iter_state make_float PRODUCE c +vm.c:1007 make_iter_state make_float PRODUCE c vm.c:1229 vm_store_local_slot slot_is_f64 TEST a vm.c:1233 vm_store_local_slot VAL_FLOAT TEST a vm.c:1235 vm_store_local_slot SLOT_F64_RAW RAW b vm.c:1235 vm_store_local_slot VAL_F64_RAW WRITE c -vm.c:1419 jit_helper_local_idx_get buffer_read_num READ b +vm.c:1419 jit_helper_local_idx_get buffer_read_f64 READ b vm.c:1419 jit_helper_local_idx_get slot_from_f64 PRODUCE c vm.c:1580 jit_helper_dot_set slot_is_f64 TEST a vm.c:1583 jit_helper_dot_set SLOT_F64_RAW RAW b @@ -2634,261 +2570,261 @@ vm.c:1709 obs_slot_num slot_is_smi TEST i vm.c:1709 obs_slot_num slot_smi_val RAW i vm.c:1710 obs_slot_num VAL_INT TEST i vm.c:1711 obs_slot_num VAL_I64_RAW RAW i -vm.c:1874 jit_helper_iter_next buffer_read_num READ b +vm.c:1874 jit_helper_iter_next buffer_read_f64 READ b vm.c:1874 jit_helper_iter_next num_guard GUARD c vm.c:1874 jit_helper_iter_next slot_from_f64 PRODUCE c -vm.c:1880 jit_helper_iter_next list_set_num PRODUCE c +vm.c:1880 jit_helper_iter_next list_set_f64 PRODUCE c vm.c:1950 vm_leaf_accessor_exec/OP_CONST VAL_F64_RAW RAW b vm.c:1950 vm_leaf_accessor_exec/OP_CONST slot_from_f64 PRODUCE c vm.c:1954 vm_leaf_accessor_exec/OP_NUM_ZERO slot_from_f64 PRODUCE c vm.c:1957 vm_leaf_accessor_exec/OP_NUM_ONE slot_from_f64 PRODUCE c vm.c:1996 vm_leaf_accessor_exec/OP_INDEX_GET slot_f64_value READ b -vm.c:2010 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_num READ b -vm.c:2010 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c -vm.c:2021 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2011 vm_leaf_accessor_exec/OP_INDEX_GET buffer_read_f64 READ b +vm.c:2011 vm_leaf_accessor_exec/OP_INDEX_GET slot_from_f64 PRODUCE c vm.c:2022 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b -vm.c:2040 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c -vm.c:2040 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c -vm.c:2123 loop_iter_store make_num PRODUCE c -vm.c:2130 loop_iter_store slot_is_f64 TEST a -vm.c:2131 loop_iter_store SLOT_F64_RAW WRITE c -vm.c:2136 loop_iter_store make_num PRODUCE c -vm.c:2251 vm_value_index_is_int VAL_INT TEST a -vm.c:2252 vm_value_index_is_int VAL_I64_RAW RAW b -vm.c:2257 vm_value_index_is_int VAL_F64_RAW RAW b -vm.c:2270 jit_helper_index_set slot_is_f64 TEST a -vm.c:2275 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2276 jit_helper_index_set slot_is_f64 TEST a -vm.c:2278 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2280 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2290 jit_helper_index_set slot_is_f64 TEST a -vm.c:2292 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2293 jit_helper_index_set list_rewrite_num PRODUCE c -vm.c:2295 jit_helper_index_set SLOT_F64_RAW RAW b -vm.c:2307 jit_helper_index_set val_is_number TEST a -vm.c:2310 jit_helper_index_set eigs_num_arg READ b -vm.c:2317 jit_helper_index_set val_is_number TEST a -vm.c:2320 jit_helper_index_set eigs_num_arg READ b -vm.c:2323 jit_helper_index_set val_is_number TEST a -vm.c:2324 jit_helper_index_set eigs_num_arg READ b -vm.c:2343 jit_helper_index_get slot_is_f64 TEST a -vm.c:2345 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2352 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2363 jit_helper_index_get buffer_read_num READ b -vm.c:2365 jit_helper_index_get slot_from_f64 PRODUCE c -vm.c:2367 jit_helper_index_get SLOT_F64_RAW RAW b -vm.c:2383 jit_helper_index_get val_is_number TEST a -vm.c:2386 jit_helper_index_get eigs_num_arg READ b -vm.c:2398 jit_helper_index_get val_is_number TEST a -vm.c:2401 jit_helper_index_get eigs_num_arg READ b -vm.c:2410 jit_helper_index_get val_is_number TEST a -vm.c:2413 jit_helper_index_get eigs_num_arg READ b -vm.c:2415 jit_helper_index_get buffer_read_num READ b -vm.c:2415 jit_helper_index_get make_num PRODUCE c -vm.c:3009 vm_take_error_value make_num PRODUCE c -vm.c:3113 slot_type_name slot_is_f64 TEST e -vm.c:3114 slot_type_name slot_is_smi TEST e -vm.c:3357 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a -vm.c:3358 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b -vm.c:3358 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c -vm.c:3367 vm_run_ex/CASE(INT_ZERO) slot_from_int PRODUCE c -vm.c:3371 vm_run_ex/CASE(INT_ONE) slot_from_int PRODUCE c -vm.c:3377 vm_run_ex/CASE(INT_CONST) VAL_I64_RAW RAW b -vm.c:3378 vm_run_ex/CASE(INT_CONST) slot_from_int PRODUCE c -vm.c:3389 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c -vm.c:3394 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c -vm.c:3414 #define NUM_REUSE NUM_REUSE TEST a -vm.c:3414 #define NUM_REUSE VAL_FLOAT TEST a -vm.c:3425 #define ARITH_FAST slot_f64_value READ b -vm.c:3425 #define ARITH_FAST slot_f64_value READ b -vm.c:3426 #define ARITH_FAST num_guard GUARD c -vm.c:3431 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3432 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3440 #define ARITH_FAST NUM_REUSE TEST a -vm.c:3441 #define ARITH_FAST VAL_F64_RAW WRITE c -vm.c:3449 #define ARITH_FAST slot_from_f64 PRODUCE c -vm.c:3461 #define INT_ARITH slot_int_value READ b -vm.c:3461 #define INT_ARITH slot_int_value READ b -vm.c:3475 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3475 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a -vm.c:3476 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3476 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b -vm.c:3476 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3477 vm_run_ex/CASE(ADD) NUM_REUSE TEST a -vm.c:3477 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:2023 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_f64_value READ b +vm.c:2041 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL num_guard GUARD c +vm.c:2041 vm_leaf_accessor_exec/OP_ADD|OP_SUB|OP_MUL slot_from_f64 PRODUCE c +vm.c:2124 loop_iter_store make_float PRODUCE c +vm.c:2131 loop_iter_store slot_is_f64 TEST a +vm.c:2132 loop_iter_store SLOT_F64_RAW WRITE c +vm.c:2137 loop_iter_store make_float PRODUCE c +vm.c:2252 vm_value_index_is_int VAL_INT TEST a +vm.c:2253 vm_value_index_is_int VAL_I64_RAW RAW b +vm.c:2258 vm_value_index_is_int VAL_F64_RAW RAW b +vm.c:2271 jit_helper_index_set slot_is_f64 TEST a +vm.c:2276 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2277 jit_helper_index_set slot_is_f64 TEST a +vm.c:2279 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2281 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2291 jit_helper_index_set slot_is_f64 TEST a +vm.c:2293 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2294 jit_helper_index_set list_rewrite_f64 PRODUCE c +vm.c:2296 jit_helper_index_set SLOT_F64_RAW RAW b +vm.c:2308 jit_helper_index_set val_is_number TEST a +vm.c:2311 jit_helper_index_set eigs_float_arg READ b +vm.c:2318 jit_helper_index_set val_is_number TEST a +vm.c:2321 jit_helper_index_set eigs_float_arg READ b +vm.c:2324 jit_helper_index_set val_is_number TEST a +vm.c:2325 jit_helper_index_set eigs_float_arg READ b +vm.c:2344 jit_helper_index_get slot_is_f64 TEST a +vm.c:2346 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2353 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2364 jit_helper_index_get buffer_read_f64 READ b +vm.c:2366 jit_helper_index_get slot_from_f64 PRODUCE c +vm.c:2368 jit_helper_index_get SLOT_F64_RAW RAW b +vm.c:2384 jit_helper_index_get val_is_number TEST a +vm.c:2387 jit_helper_index_get eigs_float_arg READ b +vm.c:2399 jit_helper_index_get val_is_number TEST a +vm.c:2402 jit_helper_index_get eigs_float_arg READ b +vm.c:2411 jit_helper_index_get val_is_number TEST a +vm.c:2414 jit_helper_index_get eigs_float_arg READ b +vm.c:2416 jit_helper_index_get buffer_read_f64 READ b +vm.c:2416 jit_helper_index_get make_float PRODUCE c +vm.c:3010 vm_take_error_value make_float PRODUCE c +vm.c:3114 slot_type_name slot_is_f64 TEST e +vm.c:3115 slot_type_name slot_is_smi TEST e +vm.c:3358 vm_run_ex/CASE(CONST) VAL_FLOAT TEST a +vm.c:3359 vm_run_ex/CASE(CONST) VAL_F64_RAW RAW b +vm.c:3359 vm_run_ex/CASE(CONST) slot_from_f64 PRODUCE c +vm.c:3368 vm_run_ex/CASE(INT_ZERO) slot_from_int PRODUCE c +vm.c:3372 vm_run_ex/CASE(INT_ONE) slot_from_int PRODUCE c +vm.c:3378 vm_run_ex/CASE(INT_CONST) VAL_I64_RAW RAW b +vm.c:3379 vm_run_ex/CASE(INT_CONST) slot_from_int PRODUCE c +vm.c:3390 vm_run_ex/CASE(NUM_ZERO) slot_from_f64 PRODUCE c +vm.c:3395 vm_run_ex/CASE(NUM_ONE) slot_from_f64 PRODUCE c +vm.c:3415 #define NUM_REUSE NUM_REUSE TEST a +vm.c:3415 #define NUM_REUSE VAL_FLOAT TEST a +vm.c:3426 #define ARITH_FAST slot_f64_value READ b +vm.c:3426 #define ARITH_FAST slot_f64_value READ b +vm.c:3427 #define ARITH_FAST num_guard GUARD c +vm.c:3432 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3433 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3441 #define ARITH_FAST NUM_REUSE TEST a +vm.c:3442 #define ARITH_FAST VAL_F64_RAW WRITE c +vm.c:3450 #define ARITH_FAST slot_from_f64 PRODUCE c +vm.c:3462 #define INT_ARITH slot_int_value READ b +vm.c:3462 #define INT_ARITH slot_int_value READ b +vm.c:3476 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3476 vm_run_ex/CASE(ADD) VAL_FLOAT TEST a +vm.c:3477 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3477 vm_run_ex/CASE(ADD) VAL_F64_RAW RAW b +vm.c:3477 vm_run_ex/CASE(ADD) num_guard GUARD c vm.c:3478 vm_run_ex/CASE(ADD) NUM_REUSE TEST a vm.c:3478 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c -vm.c:3479 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3480 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3480 vm_run_ex/CASE(ADD) val_is_number TEST a -vm.c:3481 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3481 vm_run_ex/CASE(ADD) eigs_num_arg READ b -vm.c:3481 vm_run_ex/CASE(ADD) make_num PRODUCE c -vm.c:3481 vm_run_ex/CASE(ADD) num_guard GUARD c -vm.c:3531 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3531 #define NUM_BINOP VAL_FLOAT TEST a -vm.c:3532 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3532 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3532 #define NUM_BINOP num_guard GUARD c +vm.c:3479 vm_run_ex/CASE(ADD) NUM_REUSE TEST a +vm.c:3479 vm_run_ex/CASE(ADD) VAL_F64_RAW WRITE c +vm.c:3480 vm_run_ex/CASE(ADD) make_float PRODUCE c +vm.c:3481 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3481 vm_run_ex/CASE(ADD) val_is_number TEST a +vm.c:3482 vm_run_ex/CASE(ADD) eigs_float_arg READ b +vm.c:3482 vm_run_ex/CASE(ADD) eigs_float_arg READ b +vm.c:3482 vm_run_ex/CASE(ADD) make_float PRODUCE c +vm.c:3482 vm_run_ex/CASE(ADD) num_guard GUARD c +vm.c:3532 #define NUM_BINOP VAL_FLOAT TEST a +vm.c:3532 #define NUM_BINOP VAL_FLOAT TEST a vm.c:3533 #define NUM_BINOP VAL_F64_RAW RAW b vm.c:3533 #define NUM_BINOP VAL_F64_RAW RAW b -vm.c:3535 #define NUM_BINOP NUM_REUSE TEST a -vm.c:3535 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3533 #define NUM_BINOP num_guard GUARD c +vm.c:3534 #define NUM_BINOP VAL_F64_RAW RAW b +vm.c:3534 #define NUM_BINOP VAL_F64_RAW RAW b vm.c:3536 #define NUM_BINOP NUM_REUSE TEST a vm.c:3536 #define NUM_BINOP VAL_F64_RAW WRITE c -vm.c:3537 #define NUM_BINOP make_num PRODUCE c -vm.c:3538 #define NUM_BINOP val_is_number TEST a -vm.c:3538 #define NUM_BINOP val_is_number TEST a -vm.c:3539 #define NUM_BINOP eigs_num_arg READ b -vm.c:3539 #define NUM_BINOP eigs_num_arg READ b -vm.c:3540 #define NUM_BINOP num_guard GUARD c -vm.c:3543 #define NUM_BINOP make_num PRODUCE c -vm.c:3547 #define NUM_BINOP make_num PRODUCE c -vm.c:3565 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3565 vm_run_ex/CASE(DIV) val_is_number TEST a -vm.c:3566 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3568 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3570 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3570 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3570 vm_run_ex/CASE(DIV) num_guard GUARD c -vm.c:3573 vm_run_ex/CASE(DIV) eigs_num_arg READ b -vm.c:3575 vm_run_ex/CASE(DIV) NUM_REUSE TEST a -vm.c:3575 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3537 #define NUM_BINOP NUM_REUSE TEST a +vm.c:3537 #define NUM_BINOP VAL_F64_RAW WRITE c +vm.c:3538 #define NUM_BINOP make_float PRODUCE c +vm.c:3539 #define NUM_BINOP val_is_number TEST a +vm.c:3539 #define NUM_BINOP val_is_number TEST a +vm.c:3540 #define NUM_BINOP eigs_float_arg READ b +vm.c:3540 #define NUM_BINOP eigs_float_arg READ b +vm.c:3541 #define NUM_BINOP num_guard GUARD c +vm.c:3544 #define NUM_BINOP make_float PRODUCE c +vm.c:3548 #define NUM_BINOP make_float PRODUCE c +vm.c:3566 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3566 vm_run_ex/CASE(DIV) val_is_number TEST a +vm.c:3567 vm_run_ex/CASE(DIV) eigs_float_arg READ b +vm.c:3569 vm_run_ex/CASE(DIV) make_float PRODUCE c +vm.c:3571 vm_run_ex/CASE(DIV) eigs_float_arg READ b +vm.c:3571 vm_run_ex/CASE(DIV) eigs_float_arg READ b +vm.c:3571 vm_run_ex/CASE(DIV) num_guard GUARD c +vm.c:3574 vm_run_ex/CASE(DIV) eigs_float_arg READ b vm.c:3576 vm_run_ex/CASE(DIV) NUM_REUSE TEST a vm.c:3576 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c -vm.c:3577 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3582 vm_run_ex/CASE(DIV) make_num PRODUCE c -vm.c:3590 vm_run_ex/CASE(IDIV) val_is_number TEST a -vm.c:3590 vm_run_ex/CASE(IDIV) val_is_number TEST a -vm.c:3591 vm_run_ex/CASE(IDIV) VAL_INT TEST a -vm.c:3591 vm_run_ex/CASE(IDIV) VAL_INT TEST a -vm.c:3592 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b -vm.c:3592 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b -vm.c:3595 vm_run_ex/CASE(IDIV) make_int PRODUCE c -vm.c:3598 vm_run_ex/CASE(IDIV) make_int PRODUCE c -vm.c:3604 vm_run_ex/CASE(IDIV) make_int PRODUCE c -vm.c:3607 vm_run_ex/CASE(IDIV) eigs_num_arg READ b -vm.c:3612 vm_run_ex/CASE(IDIV) make_num PRODUCE c -vm.c:3617 vm_run_ex/CASE(IDIV) eigs_num_arg READ b -vm.c:3629 vm_run_ex/CASE(IDIV) make_num PRODUCE c -vm.c:3629 vm_run_ex/CASE(IDIV) num_guard GUARD c -vm.c:3635 vm_run_ex/CASE(IDIV) make_int PRODUCE c -vm.c:3645 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3645 vm_run_ex/CASE(MOD) val_is_number TEST a -vm.c:3646 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3646 vm_run_ex/CASE(MOD) VAL_INT TEST a -vm.c:3647 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b -vm.c:3647 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b -vm.c:3650 vm_run_ex/CASE(MOD) make_int PRODUCE c -vm.c:3656 vm_run_ex/CASE(MOD) make_int PRODUCE c -vm.c:3659 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3662 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3664 vm_run_ex/CASE(MOD) eigs_num_arg READ b -vm.c:3664 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3664 vm_run_ex/CASE(MOD) num_guard GUARD c -vm.c:3670 vm_run_ex/CASE(MOD) make_num PRODUCE c -vm.c:3686 #define INT_BINOP_R slot_from_int PRODUCE c -vm.c:3692 #define INT_BINOP_R slot_f64_value READ b -vm.c:3712 vm_run_ex/CASE(NEG) slot_f64_value READ b -vm.c:3715 vm_run_ex/CASE(NEG) NUM_REUSE TEST a -vm.c:3715 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c -vm.c:3718 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3722 vm_run_ex/CASE(NEG) slot_int_value READ b -vm.c:3727 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c -vm.c:3732 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c -vm.c:3749 vm_run_ex/CASE(BNOT) slot_from_int PRODUCE c -vm.c:3754 vm_run_ex/CASE(BNOT) slot_f64_value READ b -vm.c:3767 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3767 vm_run_ex/CASE(EQ) slot_is_smi TEST f -vm.c:3773 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3773 vm_run_ex/CASE(EQ) slot_f64_value READ f -vm.c:3793 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3793 vm_run_ex/CASE(NE) slot_is_smi TEST f -vm.c:3799 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3799 vm_run_ex/CASE(NE) slot_f64_value READ f -vm.c:3821 #define NUM_CMP slot_f64_value READ f -vm.c:3821 #define NUM_CMP slot_f64_value READ f -vm.c:4769 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a -vm.c:4771 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4778 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4788 vm_run_ex/CASE(INDEX_GET) buffer_read_num READ b -vm.c:4790 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c -vm.c:4792 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b -vm.c:4814 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4816 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4817 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4819 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4821 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4831 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a -vm.c:4833 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4833 vm_run_ex/CASE(INDEX_SET) list_set_num PRODUCE c -vm.c:4835 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b -vm.c:4847 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4850 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4857 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4860 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4863 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a -vm.c:4864 vm_run_ex/CASE(INDEX_SET) eigs_num_arg READ b -vm.c:4920 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a -vm.c:4923 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b -vm.c:4984 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a -vm.c:4985 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5011 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_num READ b -vm.c:5011 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c -vm.c:5117 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a -vm.c:5118 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b -vm.c:5191 vm_run_ex/CASE(ITER_NEXT) list_set_num PRODUCE c -vm.c:5195 vm_run_ex/CASE(ITER_NEXT) buffer_read_num READ b -vm.c:5195 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c -vm.c:5534 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5535 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5536 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_num PRODUCE i -vm.c:5570 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5571 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5572 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_num PRODUCE i -vm.c:5636 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i -vm.c:5637 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i -vm.c:5637 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i -vm.c:5637 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5641 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5642 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5643 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5644 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5648 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i -vm.c:5662 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5663 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5664 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5665 vm_run_ex/CASE(INTERROGATE) make_num PRODUCE i -vm.c:5685 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5711 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5714 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5715 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5718 vm_run_ex/CASE(INTERROGATE_NAMED) make_num PRODUCE i -vm.c:5734 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i -vm.c:5742 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i -vm.c:5745 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i -vm.c:5750 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i -vm.c:5770 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i -vm.c:5771 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i -vm.c:5772 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i -vm.c:5773 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i -vm.c:5903 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a -vm.c:5903 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a -vm.c:5920 #define READ_SLICE_BOUND slot_is_f64 TEST a -vm.c:5921 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5923 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b -vm.c:5930 #define READ_SLICE_BOUND VAL_INT TEST a -vm.c:5934 #define READ_SLICE_BOUND VAL_I64_RAW RAW b -vm.c:5937 #define READ_SLICE_BOUND VAL_FLOAT TEST a -vm.c:5938 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5941 #define READ_SLICE_BOUND VAL_F64_RAW RAW b -vm.c:5952 #define READ_SLICE_BOUND slot_is_smi TEST a -vm.c:5955 #define READ_SLICE_BOUND slot_smi_val RAW b -vm.c:6645 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a -vm.c:6646 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b -vm.c:6647 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a -vm.c:6650 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b -vm.c:6660 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a -vm.c:6661 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b -vm.c:6663 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a -vm.c:6667 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b +vm.c:3577 vm_run_ex/CASE(DIV) NUM_REUSE TEST a +vm.c:3577 vm_run_ex/CASE(DIV) VAL_F64_RAW WRITE c +vm.c:3578 vm_run_ex/CASE(DIV) make_float PRODUCE c +vm.c:3583 vm_run_ex/CASE(DIV) make_float PRODUCE c +vm.c:3591 vm_run_ex/CASE(IDIV) val_is_number TEST a +vm.c:3591 vm_run_ex/CASE(IDIV) val_is_number TEST a +vm.c:3592 vm_run_ex/CASE(IDIV) VAL_INT TEST a +vm.c:3592 vm_run_ex/CASE(IDIV) VAL_INT TEST a +vm.c:3593 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b +vm.c:3593 vm_run_ex/CASE(IDIV) VAL_I64_RAW RAW b +vm.c:3596 vm_run_ex/CASE(IDIV) make_int PRODUCE c +vm.c:3599 vm_run_ex/CASE(IDIV) make_int PRODUCE c +vm.c:3605 vm_run_ex/CASE(IDIV) make_int PRODUCE c +vm.c:3608 vm_run_ex/CASE(IDIV) eigs_float_arg READ b +vm.c:3613 vm_run_ex/CASE(IDIV) make_float PRODUCE c +vm.c:3618 vm_run_ex/CASE(IDIV) eigs_float_arg READ b +vm.c:3630 vm_run_ex/CASE(IDIV) make_float PRODUCE c +vm.c:3630 vm_run_ex/CASE(IDIV) num_guard GUARD c +vm.c:3636 vm_run_ex/CASE(IDIV) make_int PRODUCE c +vm.c:3646 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3646 vm_run_ex/CASE(MOD) val_is_number TEST a +vm.c:3647 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3647 vm_run_ex/CASE(MOD) VAL_INT TEST a +vm.c:3648 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b +vm.c:3648 vm_run_ex/CASE(MOD) VAL_I64_RAW RAW b +vm.c:3651 vm_run_ex/CASE(MOD) make_int PRODUCE c +vm.c:3657 vm_run_ex/CASE(MOD) make_int PRODUCE c +vm.c:3660 vm_run_ex/CASE(MOD) eigs_float_arg READ b +vm.c:3663 vm_run_ex/CASE(MOD) make_float PRODUCE c +vm.c:3665 vm_run_ex/CASE(MOD) eigs_float_arg READ b +vm.c:3665 vm_run_ex/CASE(MOD) make_float PRODUCE c +vm.c:3665 vm_run_ex/CASE(MOD) num_guard GUARD c +vm.c:3671 vm_run_ex/CASE(MOD) make_float PRODUCE c +vm.c:3687 #define INT_BINOP_R slot_from_int PRODUCE c +vm.c:3693 #define INT_BINOP_R slot_f64_value READ b +vm.c:3713 vm_run_ex/CASE(NEG) slot_f64_value READ b +vm.c:3716 vm_run_ex/CASE(NEG) NUM_REUSE TEST a +vm.c:3716 vm_run_ex/CASE(NEG) VAL_F64_RAW WRITE c +vm.c:3719 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3723 vm_run_ex/CASE(NEG) slot_int_value READ b +vm.c:3728 vm_run_ex/CASE(NEG) slot_from_int PRODUCE c +vm.c:3733 vm_run_ex/CASE(NEG) slot_from_f64 PRODUCE c +vm.c:3750 vm_run_ex/CASE(BNOT) slot_from_int PRODUCE c +vm.c:3755 vm_run_ex/CASE(BNOT) slot_f64_value READ b +vm.c:3768 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3768 vm_run_ex/CASE(EQ) slot_is_smi TEST f +vm.c:3774 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3774 vm_run_ex/CASE(EQ) slot_f64_value READ f +vm.c:3794 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3794 vm_run_ex/CASE(NE) slot_is_smi TEST f +vm.c:3800 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3800 vm_run_ex/CASE(NE) slot_f64_value READ f +vm.c:3822 #define NUM_CMP slot_f64_value READ f +vm.c:3822 #define NUM_CMP slot_f64_value READ f +vm.c:4770 vm_run_ex/CASE(INDEX_GET) slot_is_f64 TEST a +vm.c:4772 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4779 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4789 vm_run_ex/CASE(INDEX_GET) buffer_read_f64 READ b +vm.c:4791 vm_run_ex/CASE(INDEX_GET) slot_from_f64 PRODUCE c +vm.c:4793 vm_run_ex/CASE(INDEX_GET) SLOT_F64_RAW RAW b +vm.c:4815 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4817 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4818 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4820 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4822 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4832 vm_run_ex/CASE(INDEX_SET) slot_is_f64 TEST a +vm.c:4834 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4834 vm_run_ex/CASE(INDEX_SET) list_set_f64 PRODUCE c +vm.c:4836 vm_run_ex/CASE(INDEX_SET) SLOT_F64_RAW RAW b +vm.c:4848 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4851 vm_run_ex/CASE(INDEX_SET) eigs_float_arg READ b +vm.c:4858 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4861 vm_run_ex/CASE(INDEX_SET) eigs_float_arg READ b +vm.c:4864 vm_run_ex/CASE(INDEX_SET) val_is_number TEST a +vm.c:4865 vm_run_ex/CASE(INDEX_SET) eigs_float_arg READ b +vm.c:4921 vm_run_ex/CASE(DOT_SET) slot_is_f64 TEST a +vm.c:4924 vm_run_ex/CASE(DOT_SET) SLOT_F64_RAW RAW b +vm.c:4985 vm_run_ex/CASE(LOCAL_DOT_SET) slot_is_f64 TEST a +vm.c:4986 vm_run_ex/CASE(LOCAL_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5012 vm_run_ex/CASE(LOCAL_IDX_GET) buffer_read_f64 READ b +vm.c:5012 vm_run_ex/CASE(LOCAL_IDX_GET) slot_from_f64 PRODUCE c +vm.c:5118 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) slot_is_f64 TEST a +vm.c:5119 vm_run_ex/CASE(LOCAL_IDX_DOT_SET) SLOT_F64_RAW RAW b +vm.c:5192 vm_run_ex/CASE(ITER_NEXT) list_set_f64 PRODUCE c +vm.c:5196 vm_run_ex/CASE(ITER_NEXT) buffer_read_f64 READ b +vm.c:5196 vm_run_ex/CASE(ITER_NEXT) slot_from_f64 PRODUCE c +vm.c:5535 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_float PRODUCE i +vm.c:5536 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_float PRODUCE i +vm.c:5537 vm_run_ex/CASE(OBSERVE_VALUE_SLOT) make_float PRODUCE i +vm.c:5571 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_float PRODUCE i +vm.c:5572 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_float PRODUCE i +vm.c:5573 vm_run_ex/CASE(OBSERVE_VALUE_NAME) make_float PRODUCE i +vm.c:5637 vm_run_ex/CASE(INTERROGATE) VAL_INT TEST i +vm.c:5638 vm_run_ex/CASE(INTERROGATE) VAL_F64_RAW RAW i +vm.c:5638 vm_run_ex/CASE(INTERROGATE) VAL_FLOAT TEST i +vm.c:5638 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5642 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5643 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5644 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5645 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5649 vm_run_ex/CASE(INTERROGATE) val_is_number TEST i +vm.c:5663 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5664 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5665 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5666 vm_run_ex/CASE(INTERROGATE) make_float PRODUCE i +vm.c:5686 vm_run_ex/CASE(INTERROGATE_NAMED) make_float PRODUCE i +vm.c:5712 vm_run_ex/CASE(INTERROGATE_NAMED) make_float PRODUCE i +vm.c:5715 vm_run_ex/CASE(INTERROGATE_NAMED) make_float PRODUCE i +vm.c:5716 vm_run_ex/CASE(INTERROGATE_NAMED) make_float PRODUCE i +vm.c:5719 vm_run_ex/CASE(INTERROGATE_NAMED) make_float PRODUCE i +vm.c:5735 vm_run_ex/CASE(INTERROGATE_NAMED_AT) val_is_number TEST i +vm.c:5743 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_INT TEST i +vm.c:5746 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_I64_RAW RAW i +vm.c:5751 vm_run_ex/CASE(INTERROGATE_NAMED_AT) VAL_F64_RAW RAW i +vm.c:5771 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) val_is_number TEST i +vm.c:5772 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_INT TEST i +vm.c:5773 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_I64_RAW RAW i +vm.c:5774 vm_run_ex/CASE(INTERROGATE_NAMED_WHEN) VAL_F64_RAW RAW i +vm.c:5904 vm_run_ex/CASE(SLICE_GET) VAL_FLOAT CASE a +vm.c:5904 vm_run_ex/CASE(SLICE_GET) VAL_INT CASE a +vm.c:5921 #define READ_SLICE_BOUND slot_is_f64 TEST a +vm.c:5922 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5924 #define READ_SLICE_BOUND SLOT_F64_RAW RAW b +vm.c:5931 #define READ_SLICE_BOUND VAL_INT TEST a +vm.c:5935 #define READ_SLICE_BOUND VAL_I64_RAW RAW b +vm.c:5938 #define READ_SLICE_BOUND VAL_FLOAT TEST a +vm.c:5939 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5942 #define READ_SLICE_BOUND VAL_F64_RAW RAW b +vm.c:5953 #define READ_SLICE_BOUND slot_is_smi TEST a +vm.c:5956 #define READ_SLICE_BOUND slot_smi_val RAW b +vm.c:6646 vm_run_ex/CASE(DISPATCH) slot_is_f64 TEST a +vm.c:6647 vm_run_ex/CASE(DISPATCH) SLOT_F64_RAW RAW b +vm.c:6648 vm_run_ex/CASE(DISPATCH) slot_is_smi TEST a +vm.c:6651 vm_run_ex/CASE(DISPATCH) slot_smi_val RAW b +vm.c:6661 vm_run_ex/CASE(DISPATCH) VAL_FLOAT TEST a +vm.c:6662 vm_run_ex/CASE(DISPATCH) VAL_F64_RAW RAW b +vm.c:6664 vm_run_ex/CASE(DISPATCH) VAL_INT TEST a +vm.c:6668 vm_run_ex/CASE(DISPATCH) VAL_I64_RAW RAW b diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index b9589e502..089fad7e0 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -695,21 +695,16 @@ result).** | `builtins_host.c:ls_entry_cmp` | guarded | sorts the string entries `ls` built itself (D2) | | `container.h:dict_value_get_f64` | guarded | final float-storage reader: an SMI returns 0 without writing the output; no allocation or ownership transfer (D1) | | `container.h:dict_value_get_int` | smi-arm | final int-storage reader: exact SMI or boxed int payload; no allocation or ownership transfer (D1) | -| `container.h:dict_value_get_num` | smi-arm | bridge reader (2.7): an int element converts to its double, exactly (|SMI| < 2^47), until R1.6 deletes the bridge (D1) | | `container.h:dict_value_get_ref` | smi-arm | NULL for an SMI or a double (container.h:137); since R1.3 a boxed int (\|i\| >= 2^47) is a heap slot and comes back as its non-NULL `VAL_INT` Value, so the caller types the element before reading it (D1) | | `container.h:dict_value_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value`, the one SMI boxer (unwired until R1.3) (D1) | | `container.h:eigs_container_slot` | not-a-classifier | the canonicalizing Value-to-slot writer (R1.2): it reads a Value, not a slot, and writes the bits; a `VAL_INT` box becomes an SMI inside [-2^47, 2^47) and stays a heap slot outside it (2.1) (D3) | | `container.h:eigs_slot_adopt` | guarded | decides ownership from what `eigs_container_slot` returned (compile-forced); a small int comes back as an SMI and its box is released (D3) | | `container.h:eigs_slot_box` | smi-arm | an SMI is boxed as an owned int through `slot_to_value`; floats retain `make_num` (R1.3) (D1) | -| `container.h:eigs_slot_elem_num` | smi-arm | bridge reader: an int converts to its double (D1) | -| `container.h:eigs_slot_num` | smi-arm | bridge reader: an int converts to its double (D1) | -| `container.h:eigs_slot_opt_num` | smi-arm | bridge reader: an int converts to its double and answers present (D1) | | `container.h:eigs_slot_ref` | refuse | an immediate double or an SMI was dereferenced as a pointer; every caller tests for a number first. R1.1 aborts on any slot that is not a pointer, null or bool, so a caller missed later fails loudly (D2) | | `container.h:eigs_slot_store_borrow` | guarded | an SMI is canonical storage and comes back as it is, with no reference to take (D1) | | `container.h:eigs_slot_store_owned` | guarded | an SMI is canonical storage and comes back as it is, with no reference to release (D1) | | `container.h:list_get_f64` | guarded | final float-storage reader: an SMI returns 0 without writing the output; no allocation or ownership transfer (D1) | | `container.h:list_get_int` | smi-arm | final int-storage reader: exact SMI or boxed int payload; no allocation or ownership transfer (D1) | -| `container.h:list_get_num` | smi-arm | bridge reader: an int element converts to its double (D1) | | `container.h:list_get_ref` | smi-arm | NULL for an SMI or a double (container.h:133); since R1.3 a boxed int (\|i\| >= 2^47) is a heap slot and comes back as its non-NULL `VAL_INT` Value (D1) | | `container.h:list_get_return` | smi-arm | an int element returns a fresh int Value through `slot_to_value` (unwired until R1.3) (D1) | | `container.h:slot_type` | smi-arm | an SMI's type is `VAL_INT` (R1.2); any other unknown tag refuses instead of being read as a pointer (D1) | @@ -727,6 +722,7 @@ result).** | `jit.c:jit_compile_to_thunk/OP_EQ` | not-a-classifier | writes the bool result bits (D3) | | `jit.c:jit_compile_to_thunk/OP_NEG` | not-a-classifier | the NOT arm writes bool result bits (D3) | | `jit.c:jit_compile_to_thunk/OP_NULL` | not-a-classifier | the constant arm writes null and bool bits (D3) | +| `embed_smoke.c:main` | guarded | C smoke fixture checks a known result-list slot with slot_is_bool before reading its bool payload (R1.6z-D1) | | `jit_smoke.c:run_bool_cases` | not-a-classifier | test harness: expected bool bits (D3) | | `jit_smoke.c:run_index_bail_cases` | guarded | test harness: an exact null test of a result (D3) | | `trace.c:trace_source_replay` | guarded | source-size metadata requires `VAL_INT` before the exact int reader; a rejected float is read only for main's unchanged diagnostic (sync #5, #1885) (D1) | diff --git a/docs/llms.txt b/docs/llms.txt index 6555d6a4b..5f10a79c1 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -247,7 +247,7 @@ sqrt(2) = 1.414213562373095 Indexing and iteration refuse stored NaN and infinity with `value` in every strict mode, matching `get_at` (N13). Strict NaN keeps its first diagnostic and sets `math_flags.invalid`; every execution tier agrees on - the error kind, message and source line. Structural buffer + the error kind, message and source line. The other scalar reductions, mixed buffer/list materialization and numeric byte/sample/device conversions normalize their inputs and stop at the first raised read. `write_bytes` requires exact bytes in 0..255 diff --git a/src/builtins_host.c b/src/builtins_host.c index 33445e53f..98ea38f80 100644 --- a/src/builtins_host.c +++ b/src/builtins_host.c @@ -1626,7 +1626,7 @@ static Value* exec_capture_result(int code, const char *text) { Value* builtin_exec_capture(Value *arg) { /* fs:CHANNEL replay refuses the exec; the refusal belongs to the replay * layer and [-1, ""] is exec_capture's documented "did not run". */ - /* #1008: these launder through a HELPER, so no `return make_num(-1)` + /* #1008: these launder through a HELPER, so no `return make_float(-1)` * appears and the classifier's matcher — which enumerates literal soft * returns — cannot see them at all. ARG_GUARD's soft argument is * evaluated only on the non-strict path, so the helper call is fine diff --git a/src/builtins_tensor.c b/src/builtins_tensor.c index fb0d711b0..57a2d2d0e 100644 --- a/src/builtins_tensor.c +++ b/src/builtins_tensor.c @@ -886,7 +886,7 @@ Value* builtin_tensor_matmul(Value *arg) { double *out = xcalloc((size_t)ar * bc, sizeof(double)); ne_matmul_buf(af, ar, ac, bf, bc, out); /* #971: same NaN collapse as the buffer path, so the strict raise names - * matmul instead of the bare num_guard backstop inside make_num. */ + * matmul instead of the bare num_guard backstop inside make_float. */ for (int64_t i = 0; i < (int64_t)ar * bc; i++) { if (out[i] != out[i]) out[i] = num_guard_named(out[i], "matmul"); if (g_has_error) { free(af); free(bf); free(out); return make_null(); } @@ -2566,7 +2566,7 @@ Value* builtin_tensor_load(Value *arg) { free(data); fclose(f); tensor_load_record_verdict(0, 0); return make_null(); } /* #971: the file is untrusted bytes, so a NaN pattern is reachable - * here. flat_to_tensor_* would collapse it through make_num anyway + * here. flat_to_tensor_* would collapse it through make_float anyway * (same 0 + EIGS_MATH_INVALID); guarding first lets the strict raise * name tensor_load. */ for (int i = 0; i < total; i++) { diff --git a/src/container.h b/src/container.h index bdc684f04..5cf46b184 100644 --- a/src/container.h +++ b/src/container.h @@ -79,25 +79,6 @@ static inline EigsSlot dict_value_slot(const Value *dict, int i) { return dict->data.dict.vals[i]; } -/* Store an immediate number the caller has already normalised (a VM stack - * slot is guarded at its producer), skipping the redundant num_guard on the - * assignment hot path. A plain slot store: the previous occupant is - * released after the store, so a destructor it runs sees the new value. */ -EIGS_R16_DEPRECATED("#1758 R1.6: replace dict_value_rewrite_num by its decided numeric reader or producer") -static inline int dict_value_rewrite_num(const Value *dict, int i, double d) { - EigsSlot old = dict->data.dict.vals[i]; - dict->data.dict.vals[i] = slot_from_f64(d); - slot_decref(old); - return 1; -} -EIGS_R16_DEPRECATED("#1758 R1.6: replace list_rewrite_num by its decided numeric reader or producer") -static inline int list_rewrite_num(const Value *list, int i, double d) { - EigsSlot old = list->data.list.items[i]; - list->data.list.items[i] = slot_from_f64(d); - slot_decref(old); - return 1; -} - /* Return the logical type of a borrowed slot without allocating. #1758: an * SMI's type is VAL_INT; any reserved tag refuses instead of being read * as a pointer. */ @@ -139,42 +120,6 @@ static inline Value *dict_value_get_ref(const Value *dict, int i) { return (slot_is_f64(s) || slot_is_smi(s)) ? NULL : eigs_slot_ref(s); } -/* Numeric readers have the same strict/bool behavior as the Value readers: - * required raises for every non-number, element raises for bool or in strict - * mode, and optional treats null as absent. The heap-VAL_FLOAT arms serve a - * slot that did not come from container storage (a VM-internal box). - * #1758: these are the bridge (design 2.7) -- until R1.6 deletes them a - * number read is a double, so an int (an SMI) converts, exactly: |SMI| < - * 2^47. */ -EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_slot_num by its decided numeric reader or producer") -static inline double eigs_slot_num(EigsSlot s, const char *who) { - if (slot_is_f64(s)) return SLOT_F64_RAW(s); - if (slot_is_smi(s)) return (double)slot_smi_val(s); - if (slot_is_heap(s) && val_is_number(slot_as_ptr(s))) - return eigs_num_arg(slot_as_ptr(s), who); /* #1758: an int box converts (the bridge) */ - return eigs_num_arg_slow(eigs_slot_ref(s), who); -} -EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_slot_elem_num by its decided numeric reader or producer") -static inline double eigs_slot_elem_num(EigsSlot s, const char *who) { - if (slot_is_f64(s)) return SLOT_F64_RAW(s); - if (slot_is_smi(s)) return (double)slot_smi_val(s); - Value *v = eigs_slot_ref(s); - if (v && val_is_number(v)) return eigs_num_arg(v, who); - if (g_strict || (v && v->type == VAL_BOOL)) return eigs_num_arg_slow(v, who); - return 0.0; -} -EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_slot_opt_num by its decided numeric reader or producer") -static inline int eigs_slot_opt_num(EigsSlot s, double *out, const char *who) { - if (slot_is_null(s) || (slot_is_heap(s) && slot_as_ptr(s)->type == VAL_NULL)) return 0; - if (slot_is_f64(s)) { *out = SLOT_F64_RAW(s); return 1; } - if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } - if (slot_is_heap(s) && val_is_number(slot_as_ptr(s))) { - *out = eigs_num_arg(slot_as_ptr(s), who); return 1; - } - (void)eigs_num_arg_slow(eigs_slot_ref(s), who); - return 0; -} - /* A numeric view is a caller-owned, allocation-free Value facade. Reference * slots return their real pointer. The cleanup guard catches retaining or * decrefing a numeric facade: its sentinel refcount must be unchanged. @@ -382,23 +327,6 @@ static inline void list_append_slot(Value *list, EigsSlot s) { if (!list_reserve_one(list)) return; list->data.list.items[list->data.list.count++] = eigs_slot_store_borrow(s); } -EIGS_R16_DEPRECATED("#1758 R1.6: replace list_set_num by its decided numeric reader or producer") -static inline __attribute__((always_inline)) void -list_set_num(Value *list, int i, double d) { - list_rewrite_num(list, i, num_guard(d)); -} -__attribute__((unused)) -EIGS_R16_DEPRECATED("#1758 R1.6: replace list_append_num by its decided numeric reader or producer") -static inline void list_append_num(Value *list, double d) { - d = num_guard(d); - if (!list_reserve_one(list)) return; - list->data.list.items[list->data.list.count++] = slot_from_f64(d); -} -__attribute__((unused)) -EIGS_R16_DEPRECATED("#1758 R1.6: replace dict_value_set_num by its decided numeric reader or producer") -static inline void dict_value_set_num(Value *dict, int i, double d) { - dict_value_rewrite_num(dict, i, num_guard(d)); -} /* Typed container writers own exactly one stored reference. _rewrite_f64 * receives an already-normalised double, matching the existing fast store. * An int outside the SMI range owns the box slot_from_int creates. */ @@ -496,31 +424,6 @@ static inline void list_sort(Value *list, int (*cmp)(const void *, const void *) qsort(list->data.list.items, (size_t)list->data.list.count, sizeof(EigsSlot), cmp); } -/* #1758: bridge readers (design 2.7): an int element converts to its double - * until R1.6 deletes them. */ -__attribute__((unused)) -EIGS_R16_DEPRECATED("#1758 R1.6: replace list_get_num by its decided numeric reader or producer") -static inline int list_get_num(const Value *list, int i, double *out) { - EigsSlot s = list_slot(list, i); - if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } - if (!slot_is_f64(s)) return 0; - *out = SLOT_F64_RAW(s); - return 1; -} -__attribute__((unused)) -EIGS_R16_DEPRECATED("#1758 R1.6: replace dict_value_get_num by its decided numeric reader or producer") -static inline int dict_value_get_num(const Value *dict, int i, double *out) { - EigsSlot s = dict_value_slot(dict, i); - if (slot_is_smi(s)) { *out = (double)slot_smi_val(s); return 1; } - if (!slot_is_f64(s)) return 0; - *out = SLOT_F64_RAW(s); - return 1; -} -__attribute__((unused)) -static inline int list_iter_count(const Value *list) { return list->data.list.count; } -__attribute__((unused)) -static inline int dict_value_iter_count(const Value *dict) { return dict->data.dict.count; } - /* Raw storage is confined to bulk allocation/movement/destruction code. */ __attribute__((unused)) static inline EigsSlot *list_values_storage(Value *list) { return list->data.list.items; } diff --git a/src/eigenscript.c b/src/eigenscript.c index 787afca5f..e23f68556 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -1776,10 +1776,8 @@ static inline Value *make_float_pooled(double n) { return v; } -/* Both names share the exact pooling and normalisation path while the - * bridge exists. R1.6a migrates no caller. */ +/* Float construction retains the existing pooling and normalization path. */ Value *make_float(double n) { return make_float_pooled(n); } -Value *make_num(double n) { return make_float_pooled(n); } /* #1758 R1.3: large int slots and Value API boundaries own ordinary heap * Values. Int boxes never enter the float freelist and own no GC edges. */ @@ -1823,7 +1821,6 @@ Value* make_float_permanent(double n) { return v; } -Value *make_num_permanent(double n) { return make_float_permanent(n); } /* Forward decl of the VAL_NULL singleton — defined below near make_null. */ static Value g_null_singleton; @@ -1849,36 +1846,6 @@ static const char *num_who(const char *who) { return strncmp(who, "builtin_", 8) == 0 ? who + 8 : who; } -double eigs_num_arg_slow(const Value *v, const char *who) { - if (v && v->type == VAL_FLOAT) return VAL_F64_RAW(v); - /* #1758 R1.2, the bridge (design 2.7): until R1.6 a number a builtin - * reads is a double, so an int converts (rounding beyond 2^53), as every - * number already is one on the tag. */ - if (v && v->type == VAL_INT) return (double)VAL_I64_RAW(v); - if (!g_has_error) - rt_error(EK_TYPE, 0, "%s: expected a number, got %s", num_who(who), - v ? val_type_name(v->type) : "nothing"); - return 0.0; -} - -double eigs_list_num(const Value *list, int i, const char *who) { - if (!list || list->type != VAL_LIST || i < 0 || i >= list->data.list.count) { - if (!g_has_error) - rt_error(EK_TYPE, 0, "%s: expected a number as argument %d, got nothing", - num_who(who), i); - return 0.0; - } - return eigs_slot_num(list_slot(list, i), who); -} - -double eigs_elem_num(const Value *v, const char *who) { - return eigs_slot_elem_num(eigs_container_slot((Value *)v), who); -} - -int eigs_opt_num(const Value *v, double *out, const char *who) { - return eigs_slot_opt_num(eigs_container_slot((Value *)v), out, who); -} - /* The final readers never own their argument. Keep the payload/type * predicate here so all forms share it, including every refusal path. */ static int eigs_number_read(const Value *v, EigsNum *out, const char *who) { @@ -3352,7 +3319,7 @@ int is_truthy(Value *v) { * mixed-type pair stays unequal. */ static int values_equal_impl(Value *a, Value *b, int depth, const char *op) { /* #1417: a buffer compared with itself still exposes its elements. Do - * not bypass normalization (or a strict NaN raise) through identity. */ + * not make a NaN-holding buffer equal to itself through identity. */ if (a == b && (!a || a->type != VAL_BUFFER)) return 1; if (!a || !b) return 0; if (a->type != b->type) { diff --git a/src/eigenscript.h b/src/eigenscript.h index 170af7433..b0a397970 100644 --- a/src/eigenscript.h +++ b/src/eigenscript.h @@ -14,7 +14,7 @@ * defines both; the default build (none defined) is the pooled baseline. The * call sites below test the per-layer macros only — never EIGS_POOL_OFF * directly — so this is the single point of truth for the union. - * EIGS_POOL_OFF_NUM — Value NUM freelist (free_value/make_num/recycle_intermediate) + * EIGS_POOL_OFF_NUM — Value NUM freelist (free_value/make_float/recycle_intermediate) * EIGS_POOL_OFF_CALLENV — call-env recycling (vm_park_call_env/vm_take_call_env) */ #ifdef EIGS_POOL_OFF # ifndef EIGS_POOL_OFF_NUM @@ -275,15 +275,6 @@ struct ASTNode { /* ---- Value types ---- */ -/* #1758 R1.6: the bridge survives until R1.6z. Only an explicit meter - * build deprecates it; ordinary builds keep their zero-warning contract. */ -#if defined(EIGS_PHASE2_METER) && (defined(__GNUC__) || defined(__clang__)) -#define EIGS_R16_DEPRECATED(msg) __attribute__((deprecated(msg))) -#else -#define EIGS_R16_DEPRECATED(msg) -#endif - - typedef enum { /* #1758 R1.2a: a double. A number Value is a VAL_FLOAT or a * VAL_INT; `type of` says "num" for both (decision (B)). */ @@ -322,8 +313,8 @@ static inline int eigs_cmp_int_float(int64_t i, double f) { /* #1637 round 4: the ONE raw way into a Value's number (an lvalue: also the * write). Only for a Value whose type is proven (VAL_FLOAT for the double, * VAL_INT for the int64), in a function listed in tools/num_read_allowlist.txt - * with its use count. Everything else uses eigs_num_arg / eigs_list_num / - * eigs_opt_num. VAL_F64_OFFSET is the double member for JIT-emitted loads and + * with its use count. Everything else uses eigs_float_arg / eigs_list_float / + * eigs_opt_float. VAL_F64_OFFSET is the double member for JIT-emitted loads and * stores (#1758 R1.2). */ #define VAL_F64_RAW(v) ((v)->data.f64_) #define VAL_I64_RAW(v) ((v)->data.i64_) @@ -461,7 +452,7 @@ struct Value { union { /* #1637 round 4: renamed so no unchecked read compiles. A Value's * number is read through the checking accessors (eigs_float_arg, - * eigs_list_num, eigs_opt_num), which raise on a bool or any other + * eigs_list_float, eigs_opt_float), which raise on a bool or any other * non-number, or through VAL_F64_RAW where the type is already * proven -- and every VAL_F64_RAW use sits in a function on the * reviewed list tools/num_read_allowlist.txt, pinned by count @@ -541,10 +532,10 @@ _Static_assert(sizeof(((Value *)0)->data.strv) <= sizeof(((Value *)0)->data.fn), * compiler instruments for ASan; every other build expands these to nothing, * so release objects are byte-identical. * - * Parked NUM (free_value / recycle_intermediate -> make_num): the whole Value + * Parked NUM (free_value / recycle_intermediate -> make_float): the whole Value * is poisoned EXCEPT the link word, the sizeof(Value *) bytes the freelist * threads its next pointer through (EIGS_NUM_LINK). Only the pool's own push, - * pop (make_num) and drain (eigs_thread_drain_caches) touch those bytes. In + * pop (make_float) and drain (eigs_thread_drain_caches) touch those bytes. In * every other build the link overlays the number itself (offset * offsetof(Value, data)), which would leave a stale NUMBER read -- the * commonest stale read of a recycled NUM -- undetectable; so under ASan the @@ -1392,31 +1383,9 @@ extern __thread EigsThread *eigs_current; * and false in every argument slot of every builtin must raise unless the * slot is on its reviewed any-value list. */ int eigs_arg_has_bool(const Value *arg); -/* #1637: THE checked number reads. C code turning a Value into a double goes - * through one of these (tools/num_read_check.sh enforces it: a raw - * `->data.f64_` read needs a VAL_FLOAT test in the same function, or a reviewed - * allowlist entry). A bool -- or any other non-number -- raises a type error - * naming `who` (a `builtin_` prefix is dropped) and reads as 0.0; the caller - * checks g_has_error before acting on the value. - * eigs_num_arg(v, who) v must be a number - * eigs_list_num(l, i, who) element i of the argument list must exist and - * be a number - * eigs_opt_num(v, &d, who) optional: absent/null -> 0 (use the default); - * a number -> 1 with *d set; anything else raises - * and returns 0 */ -double eigs_num_arg_slow(const Value *v, const char *who) EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_num_arg_slow by its decided numeric reader or producer"); -EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_num_arg by its decided numeric reader or producer") -static inline double eigs_num_arg(const Value *v, const char *who) { - if (__builtin_expect(v && v->type == VAL_FLOAT, 1)) return VAL_F64_RAW(v); - return eigs_num_arg_slow(v, who); /* #1758: an int converts there */ -} -double eigs_list_num(const Value *list, int i, const char *who) EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_list_num by its decided numeric reader or producer"); -/* #1637 round 4: an ELEMENT a builtin reads as a number (a tensor cell, a - * byte). A bool raises in every strict mode; any other non-number raises - * under EIGS_STRICT and reads as the documented 0.0 under EIGS_STRICT=0. - * The caller checks g_has_error. */ -double eigs_elem_num(const Value *v, const char *who) EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_elem_num by its decided numeric reader or producer"); -int eigs_opt_num(const Value *v, double *out, const char *who) EIGS_R16_DEPRECATED("#1758 R1.6: replace eigs_opt_num by its decided numeric reader or producer"); +/* #1637/#1758: required, element and optional checked readers are split + * by numeric contract below. Raw payload macros require a reviewed kind + * proof in tools/num_read_allowlist.txt. Callers stop on g_has_error. */ /* #1758 R1.6a: final numeric readers. All inputs are BORROWED, including * on a raise: no reader allocates, retains, or releases its argument. Every * floating input must be finite. Required/list reads reject non-numbers; @@ -1549,7 +1518,7 @@ void eigs_bool_gate_exempt(BuiltinFn fn); /* a host function: never gated */ * simple early return. The raise still returns, so the caller stops before * consuming the coerced value. * - * These sites have no `return make_num(0)` to enumerate. A probe that + * These sites have no `return make_float(0)` to enumerate. A probe that * stays silent under strict is what tools/strict_differential.sh catches. */ /* PLACEMENT IS LOAD-BEARING: this RETURNS, so it must sit BEFORE anything the * function has allocated and still owns, or the raise abandons it. Put the @@ -1833,7 +1802,6 @@ void strbuf_free(strbuf *b); /* ---- Value constructors ---- */ -Value* make_num(double n) EIGS_R16_DEPRECATED("#1758 R1.6: replace make_num by its decided numeric reader or producer"); Value* make_float(double n); Value* make_float_permanent(double n); Value* make_int(int64_t n); /* owned, unpooled int box; slots canonicalize small ints */ @@ -1846,7 +1814,6 @@ Value* make_null(void); /* #1637: the immortal true/false singletons (refcount no-ops, like null). */ Value* make_bool(int b); Value* make_list(int capacity); -Value* make_num_permanent(double n) EIGS_R16_DEPRECATED("#1758 R1.6: replace make_num_permanent by its decided numeric reader or producer"); /* unpooled make_num; needs no VM thread */ Value* make_list_heap(int capacity); Value* make_text_builder(void); Value* make_fn(const char *name, char **params, int param_count, Env *closure); @@ -1953,26 +1920,6 @@ static inline double num_guard(double x) { return x; } -/* #1417: VAL_BUFFER storage is an unboxed numerical work area, so kernels - * can transiently leave an IEEE NaN or infinity in it. The language's - * finite-number invariant applies when an element crosses the buffer/scalar - * boundary: every scalar read goes through this helper. Keeping the guard at - * that boundary also lets bulk kernels retain their unboxed representation. */ -EIGS_R16_DEPRECATED("#1758 R1.6: replace buffer_read_num by its decided numeric reader or producer") -static inline double buffer_read_num(const Value *buffer, int64_t index) { - return num_guard(buffer->data.buffer.data[index]); -} - -/* Numeric byte consumers truncate and wrap modulo 256. Reduce in double - * first: even a normalized finite number can be outside the C int range. - * The caller must normalize the input and stop on a raised read first. */ -EIGS_R16_DEPRECATED("#1758 R1.6: replace finite_num_to_byte by its decided numeric reader or producer") -/* ext_net.c remains a caller until R1.6f/z; minimal amalgamations omit it. */ -__attribute__((unused)) -static inline unsigned char finite_num_to_byte(double x) { - return (unsigned char)((int)fmod(x, 256.0) & 0xFF); -} - /* #1740: a bitwise operand converts to int64 only if it is an EXACT integer * in [-2^63, 2^63) -- Lua 5.4's rule (manual 3.4.3). Returns 0 for a * fractional or out-of-range number; the caller raises `value`. Range test @@ -2171,7 +2118,7 @@ Value* env_get_hashed(Env *env, const char *name, uint32_t h); Value* env_get_local_hashed(Env *env, const char *name, uint32_t h); void env_set_local_hashed(Env *env, const char *name, uint32_t h, Value *val); /* Slot-flavored fast paths: take/produce EigsSlot directly so immediates - * never round-trip through make_num + val_decref. Reference-count + * never round-trip through make_float + val_decref. Reference-count * semantics match the Value* variants: env *borrows* the input slot and * incref's internally, *_get returns a slot the caller must slot_decref. */ /* #868/#908: how many assignments this binding has seen, for the `when ` diff --git a/src/ext_gfx.c b/src/ext_gfx.c index 720361474..b830463f7 100644 --- a/src/ext_gfx.c +++ b/src/ext_gfx.c @@ -393,7 +393,7 @@ static const char* scancode_name(int sc) { /* ---- Builtins ---- */ -/* #1007: the drawing surface reads RUNS of list elements as `eigs_num_arg(&(), __func__)` +/* #1007: the drawing surface reads RUNS of list elements as `eigs_float_arg(&(), __func__)` * with no type check. `Value`'s union overlaps `double num` with * `char *str`, so an unchecked read reinterprets a pointer as a double * and then `(int)`-casts it — the read itself is the defect, which is why @@ -451,7 +451,7 @@ Value* builtin_gfx_open(Value *arg) { * same value. */ ARG_GUARD(!arg || arg->type != VAL_LIST || arg->data.list.count < 3, "gfx_open", "[number width, number height, title]", make_bool(0)); - /* #1007: width and height were read as `eigs_num_arg(&(), __func__)` with no type check + /* #1007: width and height were read as `eigs_float_arg(&(), __func__)` with no type check * while the title on the very next line WAS checked. Value's union * overlaps `double num` with `char *str`, so gfx_open of ["800","600",t] * reinterpreted a pointer as a double and int-cast it — in practice a @@ -1028,7 +1028,7 @@ Value* builtin_gfx_text(Value *arg) { * before #1007, so its wrong-typed scale is a COERCION and keeps * measuring at scale 1 (STRICT_REQUIRE there, byte-identical off the * flag). This one did not: - * int scale = (count >= 7) ? (int)eigs_num_arg(items[6], __func__) : 1; + * int scale = (count >= 7) ? (int)eigs_float_arg(items[6], __func__) : 1; * reads the union unchecked, so a string scale drew the glyph from a * reinterpreted `char *` — a subnormal that truncates to 0 and is then * clamped to 1, which is why it LOOKED like scale 1 while being a pun. @@ -1366,7 +1366,7 @@ Value* builtin_audio_open(Value *arg) { && !(arg->type == VAL_LIST && arg->data.list.count >= 2), "audio_open", "[number freq, number channels] or null"); if (arg && arg->type == VAL_LIST && arg->data.list.count >= 2) { - /* The same unchecked `eigs_num_arg(&(), __func__)` type-pun as gfx_open. That it is an + /* The same unchecked `eigs_float_arg(&(), __func__)` type-pun as gfx_open. That it is an * oversight rather than a convention is settled 180 lines down: * audio_stream_open guards this identical pair with `(type == VAL_FLOAT || type == VAL_INT)` * before reading it. */ diff --git a/src/jit.c b/src/jit.c index 9af7e0c65..10d5bd482 100644 --- a/src/jit.c +++ b/src/jit.c @@ -1702,18 +1702,6 @@ static uint8_t *emit_cvttsd2si_xmm0_r8d(uint8_t *w) { static uint8_t *emit_cvtsi2sd_r8d_xmm1(uint8_t *w) { *w++ = 0xF2; *w++ = 0x41; *w++ = 0x0F; *w++ = 0x2A; *w++ = 0xC8; return w; } -/* cvttsd2si %xmm0, %edx (4 bytes) — 32-bit, mirrors `(int)val_s.d`. - * No longer used by OP_INDEX_SET (buffer stores keep the raw double now) - * but kept for future int-conversion fast paths. */ -__attribute__((unused)) -static uint8_t *emit_cvttsd2si_xmm0_edx(uint8_t *w) { - *w++ = 0xF2; *w++ = 0x0F; *w++ = 0x2C; *w++ = 0xD0; return w; -} -/* cvtsi2sd %edx, %xmm0 (4 bytes) — 32-bit source. */ -__attribute__((unused)) -static uint8_t *emit_cvtsi2sd_edx_xmm0(uint8_t *w) { - *w++ = 0xF2; *w++ = 0x0F; *w++ = 0x2A; *w++ = 0xC2; return w; -} /* jp rel32 (6 bytes): 0F 8A — jump if PF=1 (unordered ucomisd). */ static uint8_t *emit_jp_rel32(uint8_t *w, uint8_t **patch) { *w++ = 0x0F; *w++ = 0x8A; *patch = w; diff --git a/tests/phase2/builtins_landed.txt b/tests/phase2/builtins_landed.txt index 2f6c05e7f..ff5d05100 100644 --- a/tests/phase2/builtins_landed.txt +++ b/tests/phase2/builtins_landed.txt @@ -6,3 +6,4 @@ R1.6d R1.6e R1.6f R1.6g +R1.6z diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index d3279736c..3c2033492 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -373,7 +373,6 @@ CELL(obs_value) { r_v(b, n, obs_slot_value(s)); } * `A:` an abort naming the reader; ` raise` a type error raised. */ #define EXP(name) static void e_##name(int k, char *b, size_t n) #define ABORT(who) snprintf(b, n, "A:%s", who) -static void e_d(char *b, size_t n, double d, int raise) { r_d(b, n, d); if (raise) strncat(b, " raise", n - strlen(b) - 1); } static void e_bool(char *b, size_t n, int k) { snprintf(b, n, "v:%s", k == K_TRUE ? "true" : "false"); } EXP(store_slot) { /* both normalisers: a double is guarded (NaN -> 0), the rest kept */ snprintf(b, n, "b:%016llx", (unsigned long long)(k == K_NAN ? 0 : KB[k])); diff --git a/tests/test_db.eigs b/tests/test_db.eigs index 2a0bb0627..7457703f1 100644 --- a/tests/test_db.eigs +++ b/tests/test_db.eigs @@ -205,7 +205,7 @@ if live: assert of [(type of (db_query_value of "SELECT null::int")) == "none", "DB24 db_query_value returns null for SQL NULL"] assert of [(type of (db_query_value of "SELECT ''")) == "str", "DB24 db_query_value keeps '' a str"] assert of [(db_query_value of "SELECT 7::float8") == 7, "DB24 db_query_value types floats"] - # NaN would become 0 through make_num's num_guard — a silently wrong + # NaN would become 0 through make_float's num_guard — a silently wrong # number — so it comes back as text on both paths. assert of [(db_query_value of "SELECT 'NaN'::float8") == "NaN", "DB24 NaN stays text, not 0"] nan_row is (json_decode of (db_query_json of "SELECT 'NaN'::float8 AS x"))[0] diff --git a/tests/test_http_rss_growth.sh b/tests/test_http_rss_growth.sh index 7f844ba2f..5bbe02af8 100755 --- a/tests/test_http_rss_growth.sh +++ b/tests/test_http_rss_growth.sh @@ -38,7 +38,7 @@ # # RSS1 shared_incr: the counter path the builtin exists for. Leaked two # Values per call (a parsed JSON Value on both the success and the -# type-mismatch path, plus the make_num handed to eigs_json_encode). +# type-mismatch path, plus the make_float handed to eigs_json_encode). # RSS2 http_route_authed with a shared-store auth source: leaked the parsed # `require_auth` Value on every authenticated request. Same class, found # while auditing the other eigs_json_parse_value call sites for #731. diff --git a/tests/test_numeric_guard.eigs b/tests/test_numeric_guard.eigs index f898fbbfa..a9058888b 100644 --- a/tests/test_numeric_guard.eigs +++ b/tests/test_numeric_guard.eigs @@ -132,7 +132,7 @@ ng_final_refuses of [buf_get, [raw_inf_product, 0], "NG31 N13 buf_get refuses in # A NaN uses the same refusing data boundary as infinity. Every # accessor refuses nonfinite data; none may leak the NaN-box null -# tag merely because it bypasses make_num. +# tag merely because it bypasses make_float. nan_left is buffer of [1, 2] nan_left[0] is 1e200 nan_left[1] is 1e200 diff --git a/tests/test_store.eigs b/tests/test_store.eigs index d4c956326..25f34cb21 100644 --- a/tests/test_store.eigs +++ b/tests/test_store.eigs @@ -1,8 +1,9 @@ load_file of "lib/test.eigs" # Clean up any leftover test database -if file_exists of "/tmp/test_eigenstore.db": - remove_file of "/tmp/test_eigenstore.db" +for stale_path in ["/tmp/eigs1006_fp_a", "/tmp/eigs1006_fp_b", "/tmp/eigs1006_fp_c", "/tmp/eigs1006_update.db", "/tmp/eigs1758_r16b_boxed_store.db", "/tmp/eigs816_bounds.db", "/tmp/eigs_store_badmagic.db", "/tmp/eigs_store_badver.db", "/tmp/eigs_store_short.db", "/tmp/test_eigenstore.db"]: + if file_exists of stale_path: + remove_file of stale_path # Open creates file db is store_open of "/tmp/test_eigenstore.db" @@ -136,11 +137,18 @@ nb[2] is 1e300 nb[3] is 1e300 nm is reshape of [nb, 2, 2] np is matmul of [nm, nm] -assert_eq of [np[0], 1e308, "matmul overflow is clamped at the scalar read boundary"] +# R1.6d-D1/R1.6z: scalar indexing refuses raw infinity; the stored +# payload still round-trips, which IEEE buffer equality can observe directly. +nonfinite_index_refused is false +try: + np[0] +catch e: + nonfinite_index_refused is e.kind == "value" and e.message == "buffer_read_f64: expected a finite number" +assert_eq of [nonfinite_index_refused, true, "matmul overflow is refused at the scalar read boundary"] nk is store_put of [db2, "blobs", {"n": np}] ni is store_get of [db2, "blobs", nk] assert_eq of [type of ni.n, "buffer", "non-finite buffer still decodes as a buffer"] -assert_eq of [ni.n[0], np[0], "non-finite buffer element round-trips"] +assert_eq of [ni.n, np, "non-finite buffer elements round-trip by IEEE comparison"] # An empty buffer stays an empty buffer, not a null and not an empty list. eb is buffer of 0 diff --git a/tests/test_strict_math.sh b/tests/test_strict_math.sh index f12060bbb..08fc8b4c8 100755 --- a/tests/test_strict_math.sh +++ b/tests/test_strict_math.sh @@ -147,7 +147,7 @@ run "SM17 strict leaves valid args alone" 1 0 "1" 'prin # The exclusions matter as much as the conversions: these 0s are DOCUMENTED # RETURN VALUES, not fail-soft guards, so strict must NOT make them raise. -# A sed over `return make_num(0)` would have broken both. +# A sed over `return make_float(0)` would have broken both. run "SM18 strict: try_parse(bad) still answers false" 1 0 "false" 'print of (try_parse of "!!!")' run "SM19 strict: unknown task id still not alive" 1 0 "false" 'print of (task_alive of 99999)' @@ -174,7 +174,7 @@ run "SM27 strict write_bytes type raises" 1 1 "write_bytes: expected" 'print # str_replace COERCES rather than returning a stand-in — a non-string element # silently became "" and the search ran over an empty string. It has no -# `return make_num(0)` to convert, so it is invisible to the classifier and +# `return make_float(0)` to convert, so it is invisible to the classifier and # needed STRICT_REQUIRE (raise under strict, no-op otherwise). Found by the # differential, not by the classifier: SM29 is why both harnesses exist. run "SM28 opt-out str_replace(num,..) unchanged" 0 0 "[]" \ diff --git a/tools/num_read_allowlist.txt b/tools/num_read_allowlist.txt index c6bd35ef9..489d06252 100644 --- a/tools/num_read_allowlist.txt +++ b/tools/num_read_allowlist.txt @@ -3,8 +3,8 @@ # SLOT_F64_RAW / VAL_F64_OFFSET tokens per function and fails when a count # differs (a new raw read, however it is spelled across lines, changes the # count), when a function with raw tokens is missing here, or a row is stale. -# Ordinary builtin argument reads use eigs_num_arg / eigs_list_num / -# eigs_opt_num / eigs_elem_num, which raise on a bool. The explicitly reviewed +# Ordinary builtin argument reads use eigs_float_arg / eigs_list_float / +# eigs_opt_float / eigs_elem_float, which raise on a bool. The explicitly reviewed # exceptions below preserve a numeric kind or exact int text (JSON and sorting), # box a typed dispatch argument, or write a typed sentinel (matmul). # A double bridge would lose int digits in the exact readers; each raw payload @@ -12,16 +12,11 @@ # token counts and reasons; they do not exempt ordinary argument coercion. builtins_tensor.c|builtin_tensor_matmul|1|writes the NaN-boxed null sentinel into a result buffer cell (EIGS_STRICT=0 path); a write, no Value is read builtins.c|eigs_json_encode_value|1|JSON encoder: case VAL_INT writes the int's exact digits (#1758 R1.2a) -container.h|dict_value_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) container.h|dict_value_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 container.h|eigs_container_slot|2|Value-to-slot encoder reads a box only after type == VAL_FLOAT (then num_guards it) or type == VAL_INT (an SMI in range, design 2.1) container.h|eigs_slot_store_borrow|1|storage normaliser re-guards an immediate only after slot_is_f64 (#1665 arm D B10) container.h|eigs_slot_store_owned|1|storage normaliser re-guards an immediate only after slot_is_f64 (#1665 arm D B10) container.h|eigs_slot_box|1|borrowed slot write boxes a double only after slot_is_f64 -container.h|eigs_slot_elem_num|1|element numeric accessor reads only after slot_is_f64 -container.h|eigs_slot_num|1|required numeric accessor reads only after slot_is_f64 -container.h|eigs_slot_opt_num|1|optional numeric accessor reads only after slot_is_f64 -container.h|list_get_num|1|accessor numeric fast path: reads the slot only behind its own slot_is_f64 test (#1665 arm D) container.h|list_get_return|1|builtin-return read boxes an immediate only after slot_is_f64 chunk.c|chunk_disassemble|2|debug disassembly prints a constant behind its own type == VAL_FLOAT test chunk.c|const_equal|4|constant-pool dedup compares two constants after testing both are VAL_FLOAT @@ -29,7 +24,6 @@ chunk.c|const_hash_value|2|constant-pool hash of a constant inside its type == V eigenscript.c|chan_clone_rec|2|channel deep-copy, switch cases VAL_FLOAT and VAL_INT preserve the payload and numeric kind eigenscript.c|compute_entropy_impl|2|observer entropy, switch case VAL_FLOAT, and case VAL_INT (an int's entropy is its double's, design 7) eigenscript.c|ent_child_slot|1|observer entropy reads an immediate only after slot_is_f64 -eigenscript.c|eigs_num_arg_slow|2|checked reader slow path: reads only after type == VAL_FLOAT, or VAL_INT (the bridge converts an int, design 2.7) eigenscript.c|is_truthy|2|truthiness, switch case VAL_FLOAT and case VAL_INT (a bool has its own case) eigenscript.c|make_float_pooled|1|shared float constructors: writes the number of a Value it just typed VAL_FLOAT eigenscript.c|make_float_permanent|1|unpooled float constructor: writes the number of a Value it just typed VAL_FLOAT @@ -44,7 +38,6 @@ eigenscript.c|value_to_string|2|printing, switch case VAL_FLOAT and case VAL_INT eigenscript.h|#define VAL_F64_OFFSET|1|the raw double member offset definition (JIT; #1758 R1.2a: was VAL_NUM_OFFSET) eigenscript.h|#define VAL_F64_RAW|1|the raw double read definition (#1758 R1.2a: was VAL_NUM_RAW) eigenscript.h|#define VAL_I64_RAW|1|the raw int64 read definition (#1758 R1.2a) -eigenscript.h|eigs_num_arg|1|inline fast path of the checking accessor: reads only after type == VAL_FLOAT eigs_embed.c|eigs_value_as_num|2|embedding API: reads only after type == VAL_FLOAT; a bool answers NaN and other non-numbers 0.0 (docs/EMBEDDING.md) embed_smoke.c|main|7|C test program: builds and inspects slots it constructed as numbers ext_store.c|store_json_encode|2|store record encoder: case VAL_INT writes exact digits; case VAL_FLOAT preserves the historical payload including non-finite data until N13 (R2.3) @@ -86,7 +79,7 @@ builtins.c|builtin_json_path|1|VAL_INT scalar text is exact digits before releas builtins.c|builtin_sort_by|1|numeric key kind retained for exact mixed sorting (#1758 N2) builtins.c|sort_cmp_num|6|validated numeric slots viewed through slot_view; int comparisons are exact (#1758 N2) value_slot.h|slot_int_value|1|boxed VAL_INT payload after its type test (#1758 R1.2i) -container.h|slot_view|3|typed float or int facade, preserving exact payload and kind (#1758 R1.2i) +container.h|slot_view|2|typed float or int facade, preserving exact payload and kind (#1758 R1.2i) ext_db.c|db_build_query|1|VAL_INT parameters encode as exact digits after the kind test (#1758 R1.2) vm.c|vm_value_index_is_int|2|Guarded exact VAL_INT-to-C-index conversion; the other numeric kind keeps the float integrality test (#1758 R1.2) eigenscript.c|make_int|1|int constructor initializes the exact signed payload diff --git a/tools/num_read_check.sh b/tools/num_read_check.sh index 61ccc4546..0a37196d6 100644 --- a/tools/num_read_check.sh +++ b/tools/num_read_check.sh @@ -7,7 +7,7 @@ # compiles. #1758 R1.2z removed the deprecated numeric aliases; the scanner # also catches their reintroduction before compilation. Code reaches a number in # exactly two ways: -# - the checking accessors eigs_num_arg / eigs_list_num / eigs_opt_num, +# - the checking accessors eigs_float_arg / eigs_list_float / eigs_opt_float, # which raise a type error on a bool or any other non-number; # - the raw macros VAL_F64_RAW(v) / VAL_I64_RAW(v) / SLOT_F64_RAW(s) (and # VAL_F64_OFFSET for JIT-emitted loads), for a value whose type is diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 5bdd7c843..3603ddb97 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -1131,9 +1131,9 @@ def stray(rd): args.planted_leaf_scan = build_plant('leaf-scan', out) args.planted_leaf_mul = build_plant('leaf-mul', out) args.planted_random_int = build_plant('random-int', out) - args.planted_value_eq = build_plant('value-eq-raw', out) + args.planted_value_eq = build_plant('value-eq-identity', out) for label, b, files, want in ( - ('plant C (buffer equality reads raw elements), release build', args.planted_value_eq, + ('plant C (buffer NaN identity shortcut), release build', args.planted_value_eq, ['tests/test_numeric_guard.eigs', 'tests/test_bool.eigs'], ('DIFF', 'same')),): if not b: out('CAL %-58s NOT RUN (no binary; --build-plants builds it)' % label) @@ -1190,10 +1190,10 @@ def stray(rd): # R1.6b/N3 preserves the int result; the fault remains the shifted range. 'random-int': ('src/builtins.c', 'make_int(lo_i + (eigs_random_long() % (int64_t)span))', 'make_int(lo_i + 1 + (eigs_random_long() % (int64_t)span))', 'build'), - # the second R1.1 critic's plant C: equality of two buffers reads raw - # elements (no read normalisation); the suite's [42c] goes red on it - 'value-eq-raw': ('src/eigenscript.c', ' case VAL_BUFFER: {\n if (a->data.buffer.count != b->data.buffer.count) return 0;\n for (int i = 0; i < a->data.buffer.count; i++) {\n double av = buffer_read_num(a, i);\n if (g_has_error) return 0;\n double bv = buffer_read_num(b, i);\n', - ' case VAL_BUFFER: {\n if (a->data.buffer.count != b->data.buffer.count) return 0;\n for (int i = 0; i < a->data.buffer.count; i++) {\n double av = a->data.buffer.data[i]; /* CRITIC PLANT C: raw element, no read normalisation */\n if (g_has_error) return 0;\n double bv = b->data.buffer.data[i];\n', 'build'), + # R1.6z-D1: identity would make a NaN-holding buffer equal to itself. + 'value-eq-identity': ('src/eigenscript.c', + ' if (a == b && (!a || a->type != VAL_BUFFER)) return 1;', + ' if (a == b) return 1; /* PLANT: bypass IEEE buffer elements */', 'build'), } _PLANT_DIR = [] @@ -1354,7 +1354,7 @@ def main(): ap.add_argument('--planted-leaf-scan', help='calibration: a build whose leaf scanner returns early') ap.add_argument('--planted-leaf-mul', help='calibration: a build whose leaf MUL computes a*b+1') ap.add_argument('--planted-random-int', help='calibration: a build whose random_int answers lo+1..hi+1') - ap.add_argument('--planted-value-eq', help='calibration: a build whose buffer equality reads raw elements (C)') + ap.add_argument('--planted-value-eq', help='calibration: a build whose buffer equality bypasses NaN elements (C)') ap.add_argument('--build-plants', action='store_true', help='calibration: build the four active planted binaries from HEAD') args = ap.parse_args() diff --git a/tools/phase2_inventory.py b/tools/phase2_inventory.py index 644b92bca..faa45035a 100755 --- a/tools/phase2_inventory.py +++ b/tools/phase2_inventory.py @@ -87,6 +87,7 @@ 'num_to_i64_exact': 'READ', 'finite_num_to_byte': 'READ', 'buffer_read_byte': 'READ', # a buffer element as a byte (Q1: N5, no wrap) + 'buf_num_arg': 'READ', # R1.6z: required absent (bridge deleted) 'buf_float_arg': 'READ', # R1.6d: decided float-only gain/value wrapper 'eigs_value_as_num': 'READ', # embed API accessor 'number': 'RAW', # lexer/AST EigsNum payload (#1758 R1.3) @@ -135,6 +136,16 @@ 'buffer_read_byte': 'R1.6e: gfx_fb and ppu_render_frame use buffer_byte_at', } +# R1.6z deletes the bridge. Retaining its vocabulary as REQUIRED ABSENT +# keeps a reintroduction visible while permitting the measured zero count. +for retired in ('eigs_num_arg', 'eigs_num_arg_slow', 'eigs_list_num', 'eigs_elem_num', + 'eigs_opt_num', 'eigs_slot_num', 'eigs_slot_elem_num', 'eigs_slot_opt_num', + 'buf_num_arg', 'make_num', 'make_num_permanent', 'list_set_num', + 'list_append_num', 'list_rewrite_num', 'dict_value_set_num', + 'dict_value_rewrite_num', 'list_get_num', 'dict_value_get_num', + 'finite_num_to_byte', 'buffer_read_byte', 'buffer_read_num'): + RETIRED_VOCAB.setdefault(retired, 'R1.6z: bridge deleted; every caller migrated') + # JIT-only vocabulary (jit.c, jit.h, jit_smoke.c): the emitted guards test # raw tag bits and never name a VOCAB token, so a token scan alone sees almost # none of them. These are the tag-range immediates and the emitters that @@ -176,7 +187,6 @@ # changes with them. (Derived check: a new such function must be added to # VOCAB or here, with a reason.) WRAPPERS = { - 'eigs_value_buffer_get': 'embed buffer data reader: the buffer_read_num boundary inside it is already a site', 'compute_entropy_impl': 'observer: returns an entropy, not the number; its payload read is the site', 'ent_child_slot': 'observer: returns a child entropy, not the number; its payload read is the site', 'observer_entropy_now': 'observer: writes an entropy, not the number; its payload read is the site', diff --git a/tools/strict_shape_contracts.json b/tools/strict_shape_contracts.json index 05378eefe..ff840e09b 100644 --- a/tools/strict_shape_contracts.json +++ b/tools/strict_shape_contracts.json @@ -787,17 +787,17 @@ "category": "variadic", "minimum": null, "maximum": null, - "reason": "Whole string list is argv; exactly [argv-list, timeout] is alternate form. Rejecting all >2 breaks valid commands. Reviewed R1.6c (#1758): numeric readers changed; outer argument shape is unchanged.", + "reason": "Whole string list is argv; exactly [argv-list, timeout] is alternate form. Rejecting all >2 breaks valid commands. Reviewed R1.6c (#1758): numeric readers changed; outer argument shape is unchanged. R1.6z reviewed repin: only the retired constructor spelling in a comment changes (make_num to make_float); executable C and the whole-argument helper closure are unchanged.", "public_names": [ "exec_capture" ], "disposition": "exempt", "body_sha256": [ - "5e9886f655fbb21594fe3fe2413307e8256cb9e7259196dbf2dbb128e14c51c8" + "24b7703f8cc21699dea02c0d35addda751e9ec9280d12626b1d0531169740a99" ], "source_sha256": { "builtin_exec_capture": [ - "5e9886f655fbb21594fe3fe2413307e8256cb9e7259196dbf2dbb128e14c51c8" + "24b7703f8cc21699dea02c0d35addda751e9ec9280d12626b1d0531169740a99" ], "eigs_list_float": [ "7742c72ce566aaacdfbf62a4a65569897bbbae97493aff0c5d3017606422503a" @@ -2364,17 +2364,17 @@ "category": "output_only", "minimum": null, "maximum": null, - "reason": "Input is scalar string; list operations concern output or replay result, not input tuple.", + "reason": "Input is scalar string; list operations concern output or replay result, not input tuple. R1.6z reviewed repin: only the retired constructor spelling in a comment changes (make_num to make_float); executable C and the whole-argument helper closure are unchanged.", "public_names": [ "tensor_load" ], "disposition": "exempt", "body_sha256": [ - "5d8bb4327209a39a7771eb85a7f2073f20ce2fff22d6114cd1b42ef6797ccea8" + "aaba6fe5cd7938dc4a7129b2ee176e64aec6d8e6e3edd0314bd8b1ebffeca1b8" ], "source_sha256": { "builtin_tensor_load": [ - "5d8bb4327209a39a7771eb85a7f2073f20ce2fff22d6114cd1b42ef6797ccea8" + "aaba6fe5cd7938dc4a7129b2ee176e64aec6d8e6e3edd0314bd8b1ebffeca1b8" ] } }, From 7d8b91ca0940802b5fcb7bc384176d559b7061c7 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 10:20:28 -0500 Subject: [PATCH 176/188] test(numbers): preregister structural container self-equality R1.6z-D2 (#1758 comment 6385903088). Raw SGD NaN through list/dict/nested/cyclic self-comparison and membership; finite cycle and 40-level shared DAG controls. Strict 0/1. Before fix: RED 4/4 tiers (off/default/OSR/trace), each program exits 0 with wrong answers; existing d8a9d2c2 runtime unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- tests/phase2/MAP.md | 1 + .../fixtures/r16z-container-self-equal.eigs | 29 +++++++++++++++++++ .../rows/N11.container-self-equal-ieee.out | 10 +++++++ .../rows/N11.container-self-equal-ieee.sh | 12 ++++++++ 4 files changed, 52 insertions(+) create mode 100644 tests/phase2/fixtures/r16z-container-self-equal.eigs create mode 100644 tests/phase2/rows/N11.container-self-equal-ieee.out create mode 100644 tests/phase2/rows/N11.container-self-equal-ieee.sh diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 42cc46aae..ca26ed45b 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -650,6 +650,7 @@ The `O cfg` record's v8 shape is pinned by `O3.ocfg-no-hlow` (its file lists ### N11 - `N11.buffer-equal-ieee` [R1.6z] SGD stores -inf, then self-SGD stores NaN; IEEE element comparison: distinct/same NaN false, same infinity true, infinity versus finite false, signed zeros equal; strict modes 0/1 never raise or change math flags. Also exercises list_contains and list_index_of. R1.6z-D1. +- `N11.container-self-equal-ieee` [R1.6z] Raw SGD stores -inf, then self-SGD stores NaN (`fixtures/r16z-container-self-equal.eigs`). Self-comparison of a list, dict, nested list and cyclic list reaching that buffer is false; a finite-buffer list and finite cycle are true. Membership/index search for the NaN-buffer list fail. Strict modes 0/1 never raise or change math flags. A finite shared DAG built as `[x, x]` 40 times compares true within the 30-second row timeout. R1.6z-D2; pre-registered red on d8a9d2c2 before the fix. - `gate.N11.embed-buffer-get-raw` [R1.6z] `tools/phase2_readers.sh release embed_buffer_get_raw`: set/get canonical NaN, payload NaN, both infinities and negative zero by memcmp; reads SGD-program-stored NaN, with no error or flag change in strict modes 0/1. Mechanical gate, compiled outside timed rows. ### N13 diff --git a/tests/phase2/fixtures/r16z-container-self-equal.eigs b/tests/phase2/fixtures/r16z-container-self-equal.eigs new file mode 100644 index 000000000..526643e9a --- /dev/null +++ b/tests/phase2/fixtures/r16z-container-self-equal.eigs @@ -0,0 +1,29 @@ +# R1.6z-D2 cost witness: only 41 distinct lists/buffers, not 2^40 paths. +unobserved: + x is buffer of 1 + for i in range of 40: + x is [x, x] + print of (x == x) + +# SGD's raw buffer kernel stores -inf; self-SGD then stores NaN. +a is buf_from_list of ([1e308]) +g is buf_from_list of ([1e308]) +sgd_update of [a, g, 1e308] +sgd_update of [a, a, 1.0] +l is [a] +d is {"x": a} +nested is [[a]] +finite is [buffer of 1] +cycle is [] +append of [cycle, cycle] +append of [cycle, a] +finite_cycle is [] +append of [finite_cycle, finite_cycle] +before is math_flags of null +try: + print of [l == l, d == d, nested == nested, finite == finite] + print of [cycle == cycle, finite_cycle == finite_cycle, l != l, d != d] + print of [list_contains of [[l], l], list_index_of of [[l], l]] + print of ((math_flags of null) == before) +catch e: + print of ["unexpected-equality-raise", e.kind, e.message] diff --git a/tests/phase2/rows/N11.container-self-equal-ieee.out b/tests/phase2/rows/N11.container-self-equal-ieee.out new file mode 100644 index 000000000..2a8511cf8 --- /dev/null +++ b/tests/phase2/rows/N11.container-self-equal-ieee.out @@ -0,0 +1,10 @@ +true +[false, false, false, true] +[false, true, true, true] +[false, -1] +true +true +[false, false, false, true] +[false, true, true, true] +[false, -1] +true diff --git a/tests/phase2/rows/N11.container-self-equal-ieee.sh b/tests/phase2/rows/N11.container-self-equal-ieee.sh new file mode 100644 index 000000000..0fe51c001 --- /dev/null +++ b/tests/phase2/rows/N11.container-self-equal-ieee.sh @@ -0,0 +1,12 @@ +# ROW: N11.container-self-equal-ieee +# ITEMS: N11 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# R1.6z-D2: raw SGD stores NaN; self-comparison follows it through containers. +# The 40-level shared DAG is the cost witness; the row timeout is 30 seconds. +set -eu +for strict in 0 1; do + EIGS_STRICT=$strict "$1" "$(dirname "$0")/../fixtures/r16z-container-self-equal.eigs" +done From db349464b0f8ed1db0aa29ef14315fd45fe63156 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sat, 24 Oct 2026 10:22:09 -0500 Subject: [PATCH 177/188] fix(runtime): scan container identity for non-reflexive elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R1.6z-D2 (#1758 comment 6385903088), No silent wrong answers. Iterative borrowed-pointer walk with a visited hash set; buffers visited once, cycles terminate. Distinct-container pairwise traversal/depth cap unchanged; R2.2 extension documented. D2 MAP green 4/4 tiers, strict 0/1, finite 40-level shared DAG, nested/cyclic NaN, membership and flags. make: 0 warnings. Deleted-token comment removed. Reviewed amendment: refresh the generated numeric inventory after line shifts; move the existing buffer-identity calibration match to the new block (the original identity plant proves it red). Independent critic found stale normalization prose in README/SPEC; reconcile it with D1/D2 and indexing/iteration. Runtime and preregistered fixture unchanged. Reviewed gate-population amendment: the whole final Phase 2 check exposed a MAP reference written as a command span rather than a path. Name the existing getter C fixture and reader script explicitly; preserve the command arguments separately. The real getter passed 36/36 checks; all program tiers, token/inventory and other C gates were green. This changes no expectation, runtime or test executable. Full train receipts are invalidated and rerun. Mechanical continuation amendment: regenerate the numeric inventory after the reviewed embed getter pin removes EIGS_NUM_MAX and shifts its later source anchors. No inventory-generator, runtime or D2 fixture change. Reviewed continuation 4 cost amendment, original brief lesson10 / #1939: all 11 OVER rows profiled against make-built main dde78c5c and pre-R1.6z 2ba66cc8 in three serial arms. Raw per-function Ir accounts for final numeric readers, finite buffer-data boundaries and VM code-generation changes; constructor alias removal is accounted separately. Tighten all 11 STALE rows; recover_round remains R5. Independent critic reviewed raw profiles, formulas, CI exception and scope. Cost stage: workloads=15 rows=30 over_declared_max=0 stale_declarations=0 PASS, rc0; CI bench gate rc0, 9/9 declarations applied. All 22 changed rows are within 3% of allowed Ir; local margins and prior CI inference are recorded in declarations and evidence. No executable, frozen expectation or other source changes. bench/conservative_observed_loop.eigs jit: max 27.2->26.5, local delta=26.09493323%, margin=0.40506677pp. R1.6z measured against pre-round2ba66cc8: old Ir=100175815, tip Ir=99685893, net -489922 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -9999 Ir (vm_run_ex -9999 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +99 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +107 Ir; every function delta preserved) bench/conservative_observed_loop.eigs off: max 22.7->22.1, local delta=21.85575982%, margin=0.24424018pp. R1.6z measured against pre-round2ba66cc8: old Ir=116230547, tip Ir=115630461, net -600086 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -119999 Ir (vm_run_ex -119999 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual -65 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions -57 Ir; every function delta preserved) bench/conservative_unobserved_loop.eigs jit: max 33.9->33.1, local delta=32.83859521%, margin=0.26140479pp. R1.6z measured against pre-round2ba66cc8: old Ir=83937756, tip Ir=83452788, net -484968 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -4998 Ir (vm_run_ex -4998 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +52 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +60 Ir; every function delta preserved) bench/conservative_unobserved_loop.eigs off: max 27.2->26.5, local delta=26.29338019%, margin=0.20661981pp. R1.6z measured against pre-round2ba66cc8: old Ir=100157519, tip Ir=99617487, net -540032 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -59998 Ir (vm_run_ex -59998 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual -12 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions -4 Ir; every function delta preserved) bench/observed_loop.eigs jit: max 48.2->47.1, local delta=46.85956630%, margin=0.24043370pp. R1.6z measured against pre-round2ba66cc8: old Ir=63796565, tip Ir=63311655, net -484910 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -5001 Ir (vm_run_ex -5001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +113 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +121 Ir; every function delta preserved) bench/observed_loop.eigs off: max 33.8->33.2, local delta=32.91914844%, margin=0.28085156pp. R1.6z measured against pre-round2ba66cc8: old Ir=82326014, tip Ir=81785998, net -540016 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -60001 Ir (vm_run_ex -60001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +7 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +15 Ir; every function delta preserved) bench/scalar_loop.eigs jit: max 89.3->88.1, local delta=87.89544429%, margin=0.20455571pp. R1.6z measured against pre-round2ba66cc8: old Ir=60675645, tip Ir=60315786, net -359859 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -40001 Ir (vm_run_ex -40001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -320022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +164 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +172 Ir; every function delta preserved) bench/scalar_loop.eigs off: max 43.7->43, local delta=42.70394338%, margin=0.29605662pp. R1.6z measured against pre-round2ba66cc8: old Ir=65641792, tip Ir=65281914, net -359878 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -40001 Ir (vm_run_ex -40001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -320022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +145 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +153 Ir; every function delta preserved) bench/unobserved_armed_loop.eigs off: max 9.0->9.4, local delta=9.10122491%, margin=0.29877509pp. R1.6z measured against pre-round2ba66cc8: old Ir=929245584, tip Ir=930445331, net +1199747 Ir; shared VM dispatch/helper code-generation effect of bridge retirement +1200001 Ir (vm_run_ex +1200001 Ir); other-function residual -254 Ir (other runtime functions -13 Ir; external string/number-formatting/startup functions -241 Ir; every function delta preserved) bench/unobserved_loop.eigs jit: max 48.2->47.1, local delta=46.85050059%, margin=0.24949941pp. R1.6z measured against pre-round2ba66cc8: old Ir=63804716, tip Ir=63319820, net -484896 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -5001 Ir (vm_run_ex -5001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +127 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +135 Ir; every function delta preserved) bench/unobserved_loop.eigs off: max 33.8->33.2, local delta=32.91480511%, margin=0.28519489pp. R1.6z measured against pre-round2ba66cc8: old Ir=82334123, tip Ir=81794226, net -539897 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -60001 Ir (vm_run_ex -60001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +126 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +134 Ir; every function delta preserved) tests/bench_buf_mix.eigs jit: max 312.9->321.8, local delta=321.59468680%, margin=0.20531320pp. R1.6z measured against pre-round2ba66cc8: old Ir=3111202023, tip Ir=3178233059, net +67031036 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +48951663 Ir (eigs_float_arg +18524210 Ir, eigs_number_arg +38810652 Ir, eigs_num_arg_slow -8383199 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +15876000 Ir (buffer_read_f64 +21168000 Ir, jit_helper_index_get -5292000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +2203008 Ir (vm_run_ex +2203008 Ir); constructor alias retirement -2 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +362 Ir (other runtime functions -27 Ir; external string/number-formatting/startup functions +389 Ir; every function delta preserved) tests/bench_buf_mix.eigs off: max 98.7->103, local delta=102.70259655%, margin=0.29740345pp. R1.6z measured against pre-round2ba66cc8: old Ir=3127852086, tip Ir=3194883016, net +67030930 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +48951663 Ir (eigs_float_arg +18524210 Ir, eigs_number_arg +38810652 Ir, eigs_num_arg_slow -8383199 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +15876000 Ir (buffer_read_f64 +21168000 Ir, jit_helper_index_get -5292000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +2203008 Ir (vm_run_ex +2203008 Ir); constructor alias retirement -2 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +256 Ir (other runtime functions -27 Ir; external string/number-formatting/startup functions +283 Ir; every function delta preserved) tests/bench_buf_resample.eigs jit: max 202.1->207.4, local delta=207.17516274%, margin=0.22483726pp. R1.6z measured against pre-round2ba66cc8: old Ir=14578356573, tip Ir=14840872110, net +262515537 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +207811659 Ir (eigs_float_arg +126290530 Ir, eigs_number_arg +216479136 Ir, eigs_num_arg_slow -134958007 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +43200018 Ir (buffer_read_f64 +57600024 Ir, jit_helper_index_get -14400006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +11503643 Ir (vm_run_ex +11503643 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +212 Ir (other runtime functions -26 Ir; external string/number-formatting/startup functions +238 Ir; every function delta preserved) tests/bench_buf_resample.eigs off: max 70.7->73.7, local delta=73.49685726%, margin=0.20314274pp. R1.6z measured against pre-round2ba66cc8: old Ir=14621999324, tip Ir=14884514976, net +262515652 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +207811659 Ir (eigs_float_arg +126290530 Ir, eigs_number_arg +216479136 Ir, eigs_num_arg_slow -134958007 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +43200018 Ir (buffer_read_f64 +57600024 Ir, jit_helper_index_get -14400006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +11503643 Ir (vm_run_ex +11503643 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +327 Ir (other runtime functions -26 Ir; external string/number-formatting/startup functions +353 Ir; every function delta preserved) tests/bench_dmg_shape.eigs jit: max 230.1->231.1, local delta=230.89514065%, margin=0.20485935pp. R1.6z measured against pre-round2ba66cc8: old Ir=4215433176, tip Ir=4229812330, net +14379154 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +196608 Ir (eigs_float_arg +655360 Ir, eigs_number_arg +786432 Ir, eigs_num_arg_slow -1245184 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +9000000 Ir (buffer_read_f64 +12000000 Ir, jit_helper_index_get -3000000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +5187517 Ir (vm_run_ex +5187517 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -4967 Ir (other runtime functions -103 Ir; external string/number-formatting/startup functions -4864 Ir; every function delta preserved) tests/bench_dmg_shape.eigs off: max 76.7->77.3, local delta=77.01532116%, margin=0.28467884pp. R1.6z measured against pre-round2ba66cc8: old Ir=4197227719, tip Ir=4211611742, net +14384023 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +196608 Ir (eigs_float_arg +655360 Ir, eigs_number_arg +786432 Ir, eigs_num_arg_slow -1245184 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +9000000 Ir (buffer_read_f64 +12000000 Ir, jit_helper_index_get -3000000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +5187517 Ir (vm_run_ex +5187517 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -98 Ir (other runtime functions -59 Ir; external string/number-formatting/startup functions -39 Ir; every function delta preserved) tests/bench_idxset.eigs jit: max 457.5->459.2, local delta=458.93432994%, margin=0.26567006pp. R1.6z measured against pre-round2ba66cc8: old Ir=534010570, tip Ir=535405691, net +1395121 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +300000 Ir (eigs_float_arg +1000000 Ir, eigs_number_arg +1200000 Ir, eigs_num_arg_slow -1900000 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +18 Ir (buffer_read_f64 +24 Ir, jit_helper_index_get -6 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +1100000 Ir (vm_run_ex +1100000 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -4893 Ir (other runtime functions -55 Ir; external string/number-formatting/startup functions -4838 Ir; every function delta preserved) tests/bench_idxset.eigs off: max 127.8->128.5, local delta=128.26360227%, margin=0.23639773pp. R1.6z measured against pre-round2ba66cc8: old Ir=534004479, tip Ir=535404391, net +1399912 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +300000 Ir (eigs_float_arg +1000000 Ir, eigs_number_arg +1200000 Ir, eigs_num_arg_slow -1900000 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +18 Ir (buffer_read_f64 +24 Ir, jit_helper_index_get -6 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +1100000 Ir (vm_run_ex +1100000 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -102 Ir (other runtime functions -13 Ir; external string/number-formatting/startup functions -89 Ir; every function delta preserved) tests/bench_pcm_codec.eigs jit: max 376.8->383.8, local delta=383.52384573%, margin=0.27615427pp. R1.6z measured against pre-round2ba66cc8: old Ir=39023891158, tip Ir=39585491642, net +561600484 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +468002880 Ir (eigs_float_arg +280809600 Ir, eigs_number_arg +483611520 Ir, eigs_num_arg_slow -296418240 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +86400018 Ir (buffer_read_f64 +115200024 Ir, jit_helper_index_get -28800006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +7197108 Ir (vm_run_ex +7197108 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +473 Ir (other runtime functions -39 Ir; external string/number-formatting/startup functions +512 Ir; every function delta preserved) tests/bench_pcm_codec.eigs off: max 98.5->101.4, local delta=101.13250999%, margin=0.26749001pp. R1.6z measured against pre-round2ba66cc8: old Ir=39206179064, tip Ir=39767779547, net +561600483 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +468002880 Ir (eigs_float_arg +280809600 Ir, eigs_number_arg +483611520 Ir, eigs_num_arg_slow -296418240 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +86400018 Ir (buffer_read_f64 +115200024 Ir, jit_helper_index_get -28800006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +7197108 Ir (vm_run_ex +7197108 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +472 Ir (other runtime functions -39 Ir; external string/number-formatting/startup functions +511 Ir; every function delta preserved) tests/bench_perf.eigs off: max 19.2->18.8, local delta=18.55142783%, margin=0.24857217pp. R1.6z measured against pre-round2ba66cc8: old Ir=349488837, tip Ir=348433201, net -1055636 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -220005 Ir (vm_run_ex -220005 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -816088 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); constructor alias retirement -20 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -19523 Ir (other runtime functions -213 Ir; external string/number-formatting/startup functions -19310 Ir; every function delta preserved) Final acceptance counts: precheck: selftests: enrolment 46/46; product-triggered rows 9 (bound <= 60s each); 7 self-tests selected; selftests: 7 passed, 0 failed; total 1180.26s; precheck: 19 passed, 0 failed, 0 skipped in 1237s phase2-builtins-all-profiles: phase2-builtins: PASS rows=310 landed=R1.6b,R1.6c,R1.6d,R1.6e,R1.6f,R1.6g,R1.6z migrated=310 unchanged=0 phase2-check: phase2-check: PASS phase2-ci: phase2-lib-diff: N4 source_functions=28 exported_functions=19 calls=4631 both_ok=2500 changed_functions=11; phase2-lib-diff: listed_functions=13 undeclared=0 stale=0 PASS; phase2-builtins: PASS rows=310 landed=R1.6b,R1.6c,R1.6d,R1.6e,R1.6f,R1.6g,R1.6z migrated=310 unchanged=0; phase2-ci: PASS (through=R1.6z) lib-diff: phase2-lib-diff: range=[-3, 110] modules=78 importable=66 functions=889 via_reexport=95 no_params=24 calls=281423 examined=281423 unexamined=0 both_ok=124575 both_raise=156668 improved=0; phase2-lib-diff: N4 source_functions=28 exported_functions=19 calls=4631 both_ok=2500 changed_functions=11; phase2-lib-diff: listed_functions=13 undeclared=0 stale=0 PASS full-release-make-test: RESULTS: 4606/4606 passed, 0 failed, 10 skipped extensions-suite: RESULTS: 4849/4849 passed, 0 failed, 5 skipped corpus-adjudication: Corpus adjudicated: 10 differences traced to R1.6z behavior/registration; sole expected runaway timeout; no other crash/timeout. replay-diff: replay_diff: OK (267 programs record+replay; 27 at the documented boundary; 0 nondeterministic; 1 ledgered) jit-diff: jit_diff: OBS examined=772 denied=13; jit_diff: OK (267 programs x {jit, osr} vs the interpreter; suite-env completed=16; OBS examined=772 denied=13; 32 arms adjudicated; 2 ledgered) cost-measure: phase2-cost: workloads=15 rows=30 over_declared_max=0 stale_declarations=0 PASS D2: red 4/4 tiers on d8a9d2c2; green 4/4 tiers on release and ASan, strict 0/1. Three D2 plants killed (identity rc1, missing visited set rc124 at 30s, top-level-only rc1). Shared DAG true in 0.0072–0.0117 seconds. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- README.md | 7 +- changes/changed/1758-r16z-bridge.md | 1 + docs/SPEC.md | 9 ++- docs/design/phase2-inventory.txt | 113 ++++++++++++++-------------- docs/design/phase2-numbers.md | 27 ++++++- src/eigenscript.c | 87 ++++++++++++++++++++- tests/phase2/MAP.md | 2 +- tests/phase2/cost_expect.txt | 44 +++++------ tests/phase2/gfx_byte_boundary.c | 2 +- tools/phase2_check.py | 4 +- 10 files changed, 201 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index f372153ed..106bb2006 100644 --- a/README.md +++ b/README.md @@ -442,10 +442,11 @@ out-of-domain call (`sqrt of -1`), a `NaN` result or a wrong-typed builtin argument (`abs of "x"`) raises a catchable error. Run with `EIGS_STRICT=0` to get the finite stand-ins instead: `NaN` becomes `0`, `sqrt of -1` is `0`, and `asin`/`acos` clamp their inputs. Buffer consumers apply the same normalization, -except `sum`, `get_at`, `dot` and `write_bytes`, which refuse non-finite +except `sum`, `get_at`, indexing, iteration, `dot` and `write_bytes`, which refuse non-finite buffer elements in every strict mode (N13). -Structural buffer equality and the other scalar reductions normalize each -input by this rule too, as do mixed buffer/list materialization +Structural buffer equality compares stored doubles directly with IEEE equality; +list/dict self-equality follows that rule through nested and cyclic containers. +The other scalar reductions normalize each input, as do mixed buffer/list materialization and the remaining numeric byte or sample conversions. `write_bytes` instead requires exact bytes in 0..255 (N5/Q1). A raised read stops subsequent work. `type_mismatch` error by default; `EIGS_STRICT=0` retains numeric-zero diff --git a/changes/changed/1758-r16z-bridge.md b/changes/changed/1758-r16z-bridge.md index 2f98e46b5..e074a8e0d 100644 --- a/changes/changed/1758-r16z-bridge.md +++ b/changes/changed/1758-r16z-bridge.md @@ -1 +1,2 @@ - Buffer indexing and iteration refuse stored non-finite elements in every strict mode. Buffer equality compares stored doubles with IEEE equality, without raises or math flags; embedding buffer reads return the exact stored double, including NaN payloads, infinities and signed zero. The transitional numeric bridge and caller-less helpers are removed (#1758, R1.6z). +- Container self-equality follows IEEE buffer equality through nested and cyclic lists/dicts, with a visited scan that keeps shared structures linear (R1.6z-D2). diff --git a/docs/SPEC.md b/docs/SPEC.md index 5c194bfe8..ff8b81156 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -2653,12 +2653,13 @@ A buffer can carry a 2-D shape, making it a flat-backed matrix. `buffer of [buf, rows, cols]` shapes an existing flat buffer (the element count must match). `shape of buf` returns `[rows, cols]` for a shaped buffer, or `[count]` when unshaped. Indexing stays flat (`buf[r*cols + c]`). -At the buffer/scalar boundary, `sum`, `get_at`, `dot` and `write_bytes` refuse +At the buffer/scalar boundary, `sum`, `get_at`, indexing, iteration, `dot` and `write_bytes` refuse non-finite elements in every strict mode (N13). Other consumers use the numeric guard: infinity saturates at ±`1e308`, while a `NaN` raises in strict mode or becomes `0` and sets -`math_flags.invalid` under `EIGS_STRICT=0`. Structural buffer equality and -the other scalar reductions normalize each input before comparison or -arithmetic. A strict read that raises inside a function retains that +`math_flags.invalid` under `EIGS_STRICT=0`. Structural buffer equality compares +stored doubles directly with IEEE equality; list/dict self-equality follows +that rule through nested and cyclic containers. The other scalar reductions +normalize each input before arithmetic. A strict read that raises inside a function retains that function's source location and call frame. Buffer-to-list tensor materialization and numeric byte/sample/device conversions apply the same read rule, stopping at the first raised read. `write_bytes` requires exact bytes in 0..255 (N5/Q1); diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index c043a2d23..89d726a55 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2121 classified=2121 unclassified=0 +examined=2120 classified=2120 unclassified=0 files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 # Retired (required absent): buf_num_arg -- R1.6z: bridge deleted; every caller migrated @@ -34,7 +34,7 @@ files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 (g) tape encode and decode 37 CASE=4 DATA=5 PARSE=7 PRODUCE=8 RAW=6 READ=2 TEST=5 (h) JSON, store and db encoders 85 CASE=4 FORMAT=3 PARSE=5 PRODUCE=22 RAW=8 READ=24 TEST=19 (i) observer numeric paths 108 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=24 READ=6 TEST=34 -(j) embed API 72 CASE=2 DATA=2 GUARD=1 PRODUCE=1 RAW=6 READ=55 TEST=2 WRITE=3 +(j) embed API 71 CASE=2 DATA=2 PRODUCE=1 RAW=6 READ=55 TEST=2 WRITE=3 ## Per token make_int 212 @@ -73,8 +73,8 @@ buffer_byte_at 10 eigs_geom_shape 10 eigs_slot_opt_float 9 num_to_i64_exact 9 -EIGS_NUM_MAX 8 eigs_byte_arg 8 +EIGS_NUM_MAX 7 eigs_bounded_arg 7 eigs_num_text 7 eigs_list_bounded 6 @@ -170,8 +170,8 @@ builtins_buf.c 105 a=33 b=33 c=39 jit.c 94 d=94 eigenscript.h 59 a=6 b=41 c=11 e=1 builtins_host.c 58 a=24 b=19 c=15 -embed_smoke.c 55 j=55 ext_store.c 55 h=55 +embed_smoke.c 54 j=54 trace.c 32 g=32 jit_smoke.c 31 d=31 lint.c 29 a=29 @@ -1734,31 +1734,31 @@ eigenscript.c:3289 is_truthy VAL_F64_RAW RAW b eigenscript.c:3289 is_truthy VAL_FLOAT CASE a eigenscript.c:3290 is_truthy VAL_I64_RAW RAW b eigenscript.c:3290 is_truthy VAL_INT CASE a -eigenscript.c:3329 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:3329 values_equal_impl VAL_INT TEST f -eigenscript.c:3330 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3330 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3331 values_equal_impl VAL_FLOAT TEST f -eigenscript.c:3331 values_equal_impl VAL_INT TEST f -eigenscript.c:3332 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3332 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3333 values_equal_impl val_is_number TEST f -eigenscript.c:3334 values_equal_impl val_is_number TEST f -eigenscript.c:3348 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3348 values_equal_impl VAL_F64_RAW RAW f -eigenscript.c:3348 values_equal_impl VAL_FLOAT CASE f -eigenscript.c:3349 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3349 values_equal_impl VAL_I64_RAW RAW f -eigenscript.c:3349 values_equal_impl VAL_INT CASE f -eigenscript.c:3419 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3434 eigs_num_text strtod PARSE e -eigenscript.c:3444 value_to_string VAL_FLOAT CASE e -eigenscript.c:3445 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3445 value_to_string eigs_num_text FORMAT e -eigenscript.c:3448 value_to_string VAL_INT CASE e -eigenscript.c:3449 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4750 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4751 gc_value_is_node VAL_INT CASE a +eigenscript.c:3410 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:3410 values_equal_impl VAL_INT TEST f +eigenscript.c:3411 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3411 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3412 values_equal_impl VAL_FLOAT TEST f +eigenscript.c:3412 values_equal_impl VAL_INT TEST f +eigenscript.c:3413 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3413 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3414 values_equal_impl val_is_number TEST f +eigenscript.c:3415 values_equal_impl val_is_number TEST f +eigenscript.c:3429 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3429 values_equal_impl VAL_F64_RAW RAW f +eigenscript.c:3429 values_equal_impl VAL_FLOAT CASE f +eigenscript.c:3430 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3430 values_equal_impl VAL_I64_RAW RAW f +eigenscript.c:3430 values_equal_impl VAL_INT CASE f +eigenscript.c:3500 eigs_num_text eigs_num_text FORMAT e +eigenscript.c:3515 eigs_num_text strtod PARSE e +eigenscript.c:3525 value_to_string VAL_FLOAT CASE e +eigenscript.c:3526 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3526 value_to_string eigs_num_text FORMAT e +eigenscript.c:3529 value_to_string VAL_INT CASE e +eigenscript.c:3530 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4831 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4832 gc_value_is_node VAL_INT CASE a eigenscript.h:196 number RAW b eigenscript.h:214 AST_NUM DATA a eigenscript.h:240 number RAW b @@ -1861,35 +1861,34 @@ embed_smoke.c:534 main eigs_value_as_num READ j embed_smoke.c:603 main eigs_value_as_num READ j embed_smoke.c:621 main eigs_value_as_num READ j embed_smoke.c:630 main eigs_value_as_num READ j -embed_smoke.c:673 main EIGS_NUM_MAX GUARD j -embed_smoke.c:681 main eigs_value_as_num READ j -embed_smoke.c:967 main eigs_value_as_num READ j -embed_smoke.c:1010 main eigs_value_as_num READ j -embed_smoke.c:1016 main eigs_value_as_num READ j -embed_smoke.c:1020 main eigs_value_as_num READ j -embed_smoke.c:1054 main eigs_value_as_num READ j -embed_smoke.c:1132 main eigs_value_as_num READ j -embed_smoke.c:1143 main eigs_value_as_num READ j -embed_smoke.c:1153 main SLOT_F64_RAW WRITE j -embed_smoke.c:1170 main eigs_value_as_num READ j -embed_smoke.c:1180 main eigs_value_as_num READ j -embed_smoke.c:1189 main eigs_value_as_num READ j -embed_smoke.c:1198 main eigs_value_as_num READ j -embed_smoke.c:1216 main eigs_value_as_num READ j -embed_smoke.c:1224 main eigs_value_as_num READ j +embed_smoke.c:693 main eigs_value_as_num READ j +embed_smoke.c:979 main eigs_value_as_num READ j +embed_smoke.c:1022 main eigs_value_as_num READ j +embed_smoke.c:1028 main eigs_value_as_num READ j +embed_smoke.c:1032 main eigs_value_as_num READ j +embed_smoke.c:1066 main eigs_value_as_num READ j +embed_smoke.c:1144 main eigs_value_as_num READ j +embed_smoke.c:1155 main eigs_value_as_num READ j +embed_smoke.c:1165 main SLOT_F64_RAW WRITE j +embed_smoke.c:1182 main eigs_value_as_num READ j +embed_smoke.c:1192 main eigs_value_as_num READ j +embed_smoke.c:1201 main eigs_value_as_num READ j +embed_smoke.c:1210 main eigs_value_as_num READ j embed_smoke.c:1228 main eigs_value_as_num READ j -embed_smoke.c:1233 main eigs_value_as_num READ j -embed_smoke.c:1244 main eigs_value_as_num READ j -embed_smoke.c:1249 main eigs_value_as_num READ j -embed_smoke.c:1258 main eigs_value_as_num READ j -embed_smoke.c:1277 main eigs_value_as_num READ j -embed_smoke.c:1281 main eigs_value_as_num READ j -embed_smoke.c:1290 main eigs_value_as_num READ j -embed_smoke.c:1294 main eigs_value_as_num READ j -embed_smoke.c:1301 main eigs_value_as_num READ j -embed_smoke.c:1357 main eigs_value_as_num READ j -embed_smoke.c:1381 main eigs_value_as_num READ j -embed_smoke.c:1408 main eigs_value_as_num READ j +embed_smoke.c:1236 main eigs_value_as_num READ j +embed_smoke.c:1240 main eigs_value_as_num READ j +embed_smoke.c:1245 main eigs_value_as_num READ j +embed_smoke.c:1256 main eigs_value_as_num READ j +embed_smoke.c:1261 main eigs_value_as_num READ j +embed_smoke.c:1270 main eigs_value_as_num READ j +embed_smoke.c:1289 main eigs_value_as_num READ j +embed_smoke.c:1293 main eigs_value_as_num READ j +embed_smoke.c:1302 main eigs_value_as_num READ j +embed_smoke.c:1306 main eigs_value_as_num READ j +embed_smoke.c:1313 main eigs_value_as_num READ j +embed_smoke.c:1369 main eigs_value_as_num READ j +embed_smoke.c:1393 main eigs_value_as_num READ j +embed_smoke.c:1420 main eigs_value_as_num READ j ext_db.c:65 db_build_query VAL_INT TEST h ext_db.c:66 db_build_query VAL_I64_RAW RAW h ext_db.c:68 db_build_query VAL_FLOAT TEST h diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 089fad7e0..8ad18bc1a 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -909,6 +909,27 @@ compare a NaN-containing buffer unequal to itself, matching NumPy shortcuts are deliberately rejected. Refusal would make equality partial; bit comparison would incorrectly distinguish signed zeros. +**R1.6z-D2 (ruling #1758 comment 6385903088): structural all the way down.** +A list or dict compared with itself is equal exactly when every element pair +it reaches is equal. A container reaching a NaN-holding buffer is unequal to +itself, including through nested or cyclic containers. This also governs +`!=`, `list_contains` and `list_index_of`. Measured prior art in D2: + +| language | `l == l`, `l = [nan-buffer]` | `d == d` | `a == a` (buffer) | +|---|---|---|---| +| Python 3 (`array('d')` in a list/dict) | `True` | `True` | `False` | +| Rust std (`Vec>`, `HashMap`) | `false` | `false` | `false` | + +Python's element identity shortcut produces the inconsistency rejected here +(Principles §2); Rust's `PartialEq` is consistent. Identity remains a fast +path only after a visited-set scan proves no reachable non-reflexive element. +Before R2.2 that element is a NaN-holding buffer; R2.2 extends the predicate to +NaN floats. The scan is linear in distinct containers and their stored edges +and elements, terminates on cycles, never raises and never writes +`g_math_flags`. Distinct containers retain today's pairwise traversal and +the #1665 depth cap unchanged. `N11.container-self-equal-ieee` pre-registers +the structural cases and a 40-level `[x, x]` finite-buffer DAG cost witness. + The public C getter `eigs_value_buffer_get` returns the stored double exactly, including NaN payloads, infinities and negative zero. It never normalizes, raises for a valid element, or writes math flags. It mirrors the setter's @@ -999,7 +1020,8 @@ catches a miss: with one float box on both sides today (EQ compares two floats in its fast path, and container comparisons pass fresh element views; read, not probed, since no NaN exists yet), so R2.2 excludes floats from the - shortcut as #1417 excluded buffers (see §2.6a, R1.6z-D1), and the C slot test calls it with + shortcut as #1417 excluded buffers, and extends the container reflexivity + scan to NaN floats (see §2.6a, R1.6z-D1/D2). The C slot test calls it with one NaN box on both sides; - C casts of a double to an integer type (undefined on NaN or inf): every builtin argument goes through a §2.6 reader, which refuses a non-finite @@ -2269,7 +2291,8 @@ written earlier (R1.1, R1.2) that goes live, or by code R1.3 adds: `log of 0` is -inf, `x/0` is ±inf, `0/0` and float `x%0` are NaN. Q8: `sort`/`sort_by` order floats by IEEE `totalOrder` (NaN after +inf), and `min`/`max` propagate NaN. `values_equal_impl`'s identity shortcut - excludes floats, extending the stored-buffer rule in §2.6a (R1.6z-D1). + excludes floats and extends the container reflexivity predicate to NaN + floats, following §2.6a (R1.6z-D1/D2). 3. **R2.3, N13 refusal inside the writers:** the JSON encoder, the store encoder (delete the pre-walk `store_nonfinite_scalar`), the byte encoders and the int conversion. This removes the class #1746 chased for diff --git a/src/eigenscript.c b/src/eigenscript.c index e23f68556..2c4cda8ac 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -3300,6 +3300,84 @@ int is_truthy(Value *v) { return 0; } +/* R1.6z-D2: identity is sound only if every reachable element is reflexive. + * Before R2.2 only a NaN-holding buffer is non-reflexive; R2.2 must extend + * this predicate to NaN floats (including immediate container slots). + * The work stack avoids C recursion and the pointer set visits shared + * containers/buffers once, so DAGs stay linear and cycles terminate. + * All pointers are borrowed for this call. No scalar boundary, raise or + * g_math_flags write belongs in this scan. */ +typedef struct { + Value **todo, **seen; + size_t count, capacity, seen_count, seen_capacity; +} EqualScan; + +static size_t equal_scan_hash(Value *v) { + uintptr_t x = (uintptr_t)v; + x ^= x >> 16; x *= 0x45d9f3bU; x ^= x >> 13; + return (size_t)x; +} + +/* Return true if already visited; otherwise insert before following edges. */ +static int equal_scan_seen(EqualScan *scan, Value *v) { + if (!scan->seen_capacity || scan->seen_count * 2 >= scan->seen_capacity) { + size_t old_capacity = scan->seen_capacity; + Value **old = scan->seen; + scan->seen_capacity = old_capacity ? old_capacity * 2 : 64; + scan->seen = xcalloc_array(scan->seen_capacity, sizeof(*scan->seen)); + for (size_t i = 0; i < old_capacity; i++) { + if (!old[i]) continue; + size_t slot = equal_scan_hash(old[i]) & (scan->seen_capacity - 1); + while (scan->seen[slot]) slot = (slot + 1) & (scan->seen_capacity - 1); + scan->seen[slot] = old[i]; + } + free(old); + } + size_t slot = equal_scan_hash(v) & (scan->seen_capacity - 1); + while (scan->seen[slot]) { + if (scan->seen[slot] == v) return 1; + slot = (slot + 1) & (scan->seen_capacity - 1); + } + scan->seen[slot] = v; + scan->seen_count++; + return 0; +} + +static void equal_scan_push(EqualScan *scan, Value *v) { + if (!v || (v->type != VAL_LIST && v->type != VAL_DICT && v->type != VAL_BUFFER)) + return; + if (scan->count == scan->capacity) { + scan->capacity = scan->capacity ? scan->capacity * 2 : 32; + scan->todo = xrealloc_array(scan->todo, scan->capacity, sizeof(*scan->todo)); + } + scan->todo[scan->count++] = v; +} + +static int equal_structure_reflexive(Value *root) { + EqualScan scan = {0}; + int reflexive = 1; + equal_scan_push(&scan, root); + while (scan.count && reflexive) { + Value *v = scan.todo[--scan.count]; + if (equal_scan_seen(&scan, v)) continue; + if (v->type == VAL_BUFFER) { + for (int i = 0; i < v->data.buffer.count; i++) { + if (isnan(v->data.buffer.data[i])) { reflexive = 0; break; } + } + } else if (v->type == VAL_LIST) { + for (int i = 0; i < v->data.list.count; i++) + equal_scan_push(&scan, list_get_ref(v, i)); + } else { + eigs_module_ns_sync(v); /* #1057 whole-dict reader */ + for (int i = 0; i < v->data.dict.count; i++) + equal_scan_push(&scan, dict_value_get_ref(v, i)); + } + } + free(scan.todo); + free(scan.seen); + return reflexive; +} + /* Structural equality for `==` / `!=`. * Scalars compare by value (numbers, strings, null); collections compare * recursively by structure (lists element-wise, dicts by key/value @@ -3318,9 +3396,12 @@ int is_truthy(Value *v) { * the operator (`==`, `!=`) or the builtin, for the message. Every other * mixed-type pair stays unequal. */ static int values_equal_impl(Value *a, Value *b, int depth, const char *op) { - /* #1417: a buffer compared with itself still exposes its elements. Do - * not make a NaN-holding buffer equal to itself through identity. */ - if (a == b && (!a || a->type != VAL_BUFFER)) return 1; + /* #1417 / R1.6z-D2: identity cannot hide a reachable NaN buffer. */ + if (a == b && (!a || a->type != VAL_BUFFER)) { + if (a && (a->type == VAL_LIST || a->type == VAL_DICT)) + return equal_structure_reflexive(a); + return 1; + } if (!a || !b) return 0; if (a->type != b->type) { /* #1758 N2 (design 7): an int and a float are both numbers and are diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index ca26ed45b..6ca39ea9f 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -651,7 +651,7 @@ The `O cfg` record's v8 shape is pinned by `O3.ocfg-no-hlow` (its file lists ### N11 - `N11.buffer-equal-ieee` [R1.6z] SGD stores -inf, then self-SGD stores NaN; IEEE element comparison: distinct/same NaN false, same infinity true, infinity versus finite false, signed zeros equal; strict modes 0/1 never raise or change math flags. Also exercises list_contains and list_index_of. R1.6z-D1. - `N11.container-self-equal-ieee` [R1.6z] Raw SGD stores -inf, then self-SGD stores NaN (`fixtures/r16z-container-self-equal.eigs`). Self-comparison of a list, dict, nested list and cyclic list reaching that buffer is false; a finite-buffer list and finite cycle are true. Membership/index search for the NaN-buffer list fail. Strict modes 0/1 never raise or change math flags. A finite shared DAG built as `[x, x]` 40 times compares true within the 30-second row timeout. R1.6z-D2; pre-registered red on d8a9d2c2 before the fix. -- `gate.N11.embed-buffer-get-raw` [R1.6z] `tools/phase2_readers.sh release embed_buffer_get_raw`: set/get canonical NaN, payload NaN, both infinities and negative zero by memcmp; reads SGD-program-stored NaN, with no error or flag change in strict modes 0/1. Mechanical gate, compiled outside timed rows. +- `gate.N11.embed-buffer-get-raw` [R1.6z] `tests/phase2/embed_buffer_get_raw.c` through `tools/phase2_readers.sh` (`release embed_buffer_get_raw`): set/get canonical NaN, payload NaN, both infinities and negative zero by memcmp; reads SGD-program-stored NaN, with no error or flag change in strict modes 0/1. Mechanical gate, compiled outside timed rows. ### N13 - `N13.vm-buffer-index-data` [R1.6z] SGD-stored NaN and both infinities through index; get_at oracle R1.6d-D1: value error, finite-number message (strict NaN first diagnostic/INVALID), line 2 in every execution tier. Sixty finite calls warm the function. diff --git a/tests/phase2/cost_expect.txt b/tests/phase2/cost_expect.txt index 9eb4905d8..f98279bb9 100644 --- a/tests/phase2/cost_expect.txt +++ b/tests/phase2/cost_expect.txt @@ -1,30 +1,30 @@ bench/alloc_heavy.eigs jit 50.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +64.3% (range-int control, measured at R1.3, against +64.0%) until R5; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8199903452, R1.4 Ir=8415252793, measured main delta=+68.4121%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range and hot len int results recover part of the existing generic mixed-operand/Value API cost; banked R1.6a Ir=8428313595, current Ir=7486166749, main Ir=4996461973, main delta=+49.82935504%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers bench/alloc_heavy.eigs off 29.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=8229622729, R1.4 Ir=8442823382, measured main delta=+44.6791%, bound=ceil(delta+0.2,0.1); R1.6a remeasurement of the inherited main-sync short-string layout component (4ac31e67 to 1fd4422c): controls attribute +8000006 Ir to __strlen_sse2 with unchanged hot VM/allocation counts; untouched 1fd control Ir=8457703595 versus main Ir=5835080986 (+44.945779%, already above old max44.9), same-alias candidate versus 1fd +0.00188828%; current native-tool measurement main Ir=5835080986, candidate Ir=8457872415, delta=+44.948672%; bound=ceil(delta+0.2,0.1), retaining R5 recovery of the existing generic interpreter int cost, no new reader allowance; R1.6b measured component: N3 range and hot len int results recover part of the existing generic mixed-operand/Value API cost; banked R1.6a Ir=8457872415, current Ir=7514744462, main Ir=5835072842, main delta=+28.78578666%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/conservative_observed_loop.eigs jit 27.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=80746036, current Ir=99538839, main Ir=79049516, main delta=+25.91960588%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685683 Ir (0.867 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.2 -> 27 by ceil(delta+0.2, 0.1); CI bench gate (bench/check_regression.sh, same jit row) measured +27.047% (Ir 76,743,802 -> 97,500,699 on the runner, against a local +26.72%): re-declared 27 -> 27.2: the only bound both gates accept (CI 27.047 <= 27.2; local 26.72 within the 0.5 STALE band). The two environments differ by 0.33 pp, which ceil(delta+0.2, 0.1) cannot cover on both sides -bench/conservative_observed_loop.eigs off 22.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.7% (range-int control, measured at R1.3, against +1.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=95920891, current Ir=115593684, main Ir=94884432, main delta=+21.82576379%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685036 Ir (0.722 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 22.1 -> 22.7 by ceil(delta+0.2, 0.1) -bench/conservative_unobserved_loop.eigs jit 33.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.6% (range-int control, measured at R1.3, against +2.7%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=64506354, current Ir=83299237, main Ir=62814824, main delta=+32.61079423%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685660 Ir (1.092 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 32.9 -> 33.9 by ceil(delta+0.2, 0.1) -bench/conservative_unobserved_loop.eigs off 27.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +26.1% (range-int control, measured at R1.3, against +1.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=79846282, current Ir=99519057, main Ir=78869757, main delta=+26.18151847%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685769 Ir (0.869 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.4 -> 27.2 by ceil(delta+0.2, 0.1) +bench/conservative_observed_loop.eigs jit 26.5 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.9% (range-int control, measured at R1.3, against +2.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=80746036, current Ir=99538839, main Ir=79049516, main delta=+25.91960588%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685683 Ir (0.867 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.2 -> 27 by ceil(delta+0.2, 0.1); CI bench gate (bench/check_regression.sh, same jit row) measured +27.047% (Ir 76,743,802 -> 97,500,699 on the runner, against a local +26.72%): re-declared 27 -> 27.2: the only bound both gates accept (CI 27.047 <= 27.2; local 26.72 within the 0.5 STALE band). The two environments differ by 0.33 pp, which ceil(delta+0.2, 0.1) cannot cover on both sides; R1.6z measured against pre-round2ba66cc8: old Ir=100175815, tip Ir=99685893, net -489922 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -9999 Ir (vm_run_ex -9999 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +99 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +107 Ir; every function delta preserved); main dde78c5c Ir=79048062, tip Ir=99675601, local delta=26.09493323%, max 27.2->26.5; Lesson10/#1939 prior CI bench run40097626469 job120883125106: main Ir=76743802, pre-R1.6z Ir=97500699, delta=27.04700114%; runtime matches control2ba66cc8 (21c56bae changes inventory only). Applying measured R1.6z component -489922 Ir projects current CI delta=26.40861473% (inference, no fresh remote run). Formula max 26.3 would fail that projection; choose 26.5, the only common one-decimal bound, within local STALE band [26.09493323,26.59493323]. All rows remain flagged within3% of allowed Ir; projection assumes the local absolute Ir component transfers to the prior Ubuntu/build.sh compiler configuration; source identity does not prove this layout assumption +bench/conservative_observed_loop.eigs off 22.1 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.7% (range-int control, measured at R1.3, against +1.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=95920891, current Ir=115593684, main Ir=94884432, main delta=+21.82576379%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685036 Ir (0.722 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 22.1 -> 22.7 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=116230547, tip Ir=115630461, net -600086 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -119999 Ir (vm_run_ex -119999 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual -65 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions -57 Ir; every function delta preserved); main dde78c5c Ir=94883464, tip Ir=115620966, local delta=21.85575982%, max 22.7->22.1; bound=ceil(delta+0.2,0.1) +bench/conservative_unobserved_loop.eigs jit 33.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.6% (range-int control, measured at R1.3, against +2.7%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=64506354, current Ir=83299237, main Ir=62814824, main delta=+32.61079423%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685660 Ir (1.092 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 32.9 -> 33.9 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=83937756, tip Ir=83452788, net -484968 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -4998 Ir (vm_run_ex -4998 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +52 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +60 Ir; every function delta preserved); main dde78c5c Ir=62814983, tip Ir=83442541, local delta=32.83859521%, max 33.9->33.1; bound=ceil(delta+0.2,0.1) +bench/conservative_unobserved_loop.eigs off 26.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +26.1% (range-int control, measured at R1.3, against +1.1%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=79846282, current Ir=99519057, main Ir=78869757, main delta=+26.18151847%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +685769 Ir (0.869 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 26.4 -> 27.2 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=100157519, tip Ir=99617487, net -540032 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -59998 Ir (vm_run_ex -59998 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual -12 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions -4 Ir; every function delta preserved); main dde78c5c Ir=78870274, tip Ir=99607935, local delta=26.29338019%, max 27.2->26.5; bound=ceil(delta+0.2,0.1) bench/dict_ops.eigs jit 22.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +22.1% (range-int control, measured at R1.3, against +0.7%) until R5; R1.6b measured component: N3 range int production activates generic Value API/dictionary int paths, as the pre-registered range-int control predicts; banked R1.6a Ir=109524332, current Ir=132542922, main Ir=108597020, main delta=+22.05023858%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers bench/dict_ops.eigs off 21.6 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +21.4% (range-int control, measured at R1.3, against +0.7%) until R5; R1.6b measured component: N3 range int production activates generic Value API/dictionary int paths, as the pre-registered range-int control predicts; banked R1.6a Ir=113283097, current Ir=136386349, main Ir=112435644, main delta=+21.30170126%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/observed_loop.eigs jit 48.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44850891, current Ir=63643989, main Ir=43104945, main delta=+47.64892752%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200959 Ir (0.466 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 47.9 -> 48.2 by ceil(delta+0.2, 0.1) -bench/observed_loop.eigs off 33.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=62500796, current Ir=82173713, main Ir=61524518, main delta=+33.56254656%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -bench/scalar_loop.eigs jit 89.3 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone removes 57.8% of this excess (range-int control, measured at R1.3: +88.6% against +210.1%), R5 the rest; merge of 94657581 component (#1171): env_store_slot bumps the assign-count inside its hold, so the branch's interpreted int stores pay +424,992 Ir there against -225,073 in vm_run_ex (CAND +200,055 Ir, +0.20%) while main's JIT-compiled loop moves BASE -9,041; measured +210.10% at R1.3, +210.81% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=99738384, R1.4 Ir=99697847, measured main delta=+210.5725%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=99747054, current Ir=60503359, main Ir=32101836, main delta=+88.47320446%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200647 Ir (0.625 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 88.7 -> 89.3 by ceil(delta+0.2, 0.1) -bench/scalar_loop.eigs off 43.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone removes 66.0% of this excess (range-int control, measured at R1.3: +43.1% against +126.8%), R5 the rest; merge of 94657581 component (#1171): env_store_slot +599,992 Ir (the assign-count bump moved inside its hold) against vm_run_ex -400,073 on the branch (CAND +200,037, +0.19%), while on main the same move saves (vm_run_ex -480,053, env_store_slot +399,995: BASE -78,939, -0.17%); measured +126.81% at R1.3, +127.64% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=104109956, R1.4 Ir=104069767, measured main delta=+127.3221%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=104118664, current Ir=65469785, main Ir=45780746, main delta=+43.00724807%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200664 Ir (0.439 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 43.3 -> 43.7 by ceil(delta+0.2, 0.1) +bench/observed_loop.eigs jit 47.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44850891, current Ir=63643989, main Ir=43104945, main delta=+47.64892752%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200959 Ir (0.466 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 47.9 -> 48.2 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=63796565, tip Ir=63311655, net -484910 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -5001 Ir (vm_run_ex -5001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +113 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +121 Ir; every function delta preserved); main dde78c5c Ir=43103521, tip Ir=63301644, local delta=46.85956630%, max 48.2->47.1; bound=ceil(delta+0.2,0.1) +bench/observed_loop.eigs off 33.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=62500796, current Ir=82173713, main Ir=61524518, main delta=+33.56254656%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6z measured against pre-round2ba66cc8: old Ir=82326014, tip Ir=81785998, net -540016 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -60001 Ir (vm_run_ex -60001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +7 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +15 Ir; every function delta preserved); main dde78c5c Ir=61523651, tip Ir=81776713, local delta=32.91914844%, max 33.8->33.2; bound=ceil(delta+0.2,0.1) +bench/scalar_loop.eigs jit 88.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone removes 57.8% of this excess (range-int control, measured at R1.3: +88.6% against +210.1%), R5 the rest; merge of 94657581 component (#1171): env_store_slot bumps the assign-count inside its hold, so the branch's interpreted int stores pay +424,992 Ir there against -225,073 in vm_run_ex (CAND +200,055 Ir, +0.20%) while main's JIT-compiled loop moves BASE -9,041; measured +210.10% at R1.3, +210.81% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=99738384, R1.4 Ir=99697847, measured main delta=+210.5725%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=99747054, current Ir=60503359, main Ir=32101836, main delta=+88.47320446%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200647 Ir (0.625 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 88.7 -> 89.3 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=60675645, tip Ir=60315786, net -359859 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -40001 Ir (vm_run_ex -40001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -320022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +164 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +172 Ir; every function delta preserved); main dde78c5c Ir=32095387, tip Ir=60305770, local delta=87.89544429%, max 89.3->88.1; bound=ceil(delta+0.2,0.1) +bench/scalar_loop.eigs off 43 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone removes 66.0% of this excess (range-int control, measured at R1.3: +43.1% against +126.8%), R5 the rest; merge of 94657581 component (#1171): env_store_slot +599,992 Ir (the assign-count bump moved inside its hold) against vm_run_ex -400,073 on the branch (CAND +200,037, +0.19%), while on main the same move saves (vm_run_ex -480,053, env_store_slot +399,995: BASE -78,939, -0.17%); measured +126.81% at R1.3, +127.64% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=104109956, R1.4 Ir=104069767, measured main delta=+127.3221%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 int range recovers the existing generic mixed-operand cost, as the pre-registered range-int control predicts; banked R1.6a Ir=104118664, current Ir=65469785, main Ir=45780746, main delta=+43.00724807%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200664 Ir (0.439 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 43.3 -> 43.7 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=65641792, tip Ir=65281914, net -359878 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -40001 Ir (vm_run_ex -40001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -320022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +145 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +153 Ir; every function delta preserved); main dde78c5c Ir=45739804, tip Ir=65272504, local delta=42.70394338%, max 43.7->43; bound=ceil(delta+0.2,0.1) bench/string_build.eigs jit 29.5 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +25.2% (range-int control, measured at R1.3, against +9.9%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=82669260, R1.4 Ir=83813773, measured main delta=+11.3960%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range-produced ints activate integer MOD and its non-pooled result allocation (the prior float-MOD component above is historical); banked R1.6a Ir=83852414, current Ir=97041191, main Ir=75239767, main delta=+28.97593237%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +199849 Ir (0.266 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 29.2 -> 29.5 by ceil(delta+0.2, 0.1) bench/string_build.eigs off 27.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +23.5% (range-int control, measured at R1.3, against +8.5%) until R5; R1.4 float MOD component: floor correction/result construction replaced truncating NUM_REUSE, adding make_num/freelist/release work; R5 must restore generic float result reuse in the off tier as well as native MOD; fresh6382b6a5 control Ir=85095023, R1.4 Ir=86239916, measured main delta=+9.9831%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 range-produced ints activate integer MOD and its non-pooled result allocation (the prior float-MOD component above is historical); banked R1.6a Ir=86278206, current Ir=99686896, main Ir=78411840, main delta=+27.13245347%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers bench/unobserved_armed_loop.eigs jit 66.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths -bench/unobserved_armed_loop.eigs off 9.0 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +3,000,000 Ir on both trees (600,000 stores; the assign-count bump moved inside its hold), which saves 2,400,031 in the branch's vm_run_ex (CAND +600,065, +0.06%) but 4,800,031 in main's (BASE -1,798,626, -0.21%); measured +8.85% at R1.3, +9.15% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=930827459, R1.4 Ir=928427649, measured main delta=+8.7891%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM code-generation component (this workload has no bitwise ops): vm_run_ex +1799999 Ir; R5 interpreter int/slot fast paths must recover this off-tier cost; fresh2d6587ee control Ir=929028193, R1.5 Ir=930826815, measured main delta=+9.0703%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 853419139->853412688 (-0.001%), candidate Ir 930826815->928420991 (-0.258%): the candidate got cheaper; main delta=+8.7892%; bound=ceil(delta+0.2,0.1) -bench/unobserved_loop.eigs jit 48.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44857870, current Ir=63651013, main Ir=43111802, main delta=+47.64173625%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200945 Ir (0.466 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 47.9 -> 48.2 by ceil(delta+0.2, 0.1) -bench/unobserved_loop.eigs off 33.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=62507730, current Ir=82180474, main Ir=61531677, main delta=+33.55799485%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -tests/bench_buf_mix.eigs jit 312.9 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=2997588303, R1.4 Ir=3102110794, measured main delta=+311.4903%, bound=ceil(delta+0.2,0.1); R1.6d measured component: default interp benchmark ends with buf_peak scanning 441000 cells; buffer_read_num -> buffer_read_f64 adds finite-data validation, measured peak+reader Ir +7938000 (18/cell); fresh4e77a9de control Ir=3103006291, R1.6d Ir=3110933042, net candidate increase +7926751 Ir (residual -11249 Ir in startup/argument checks); main88a1c911 Ir=753849828, main delta=+312.67277997%, bound=ceil(delta+0.2,0.1); R5 retains int VM/Value API recovery with required finite refusal preserved -tests/bench_buf_mix.eigs off 98.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=3014239251, R1.4 Ir=3118762031, measured main delta=+96.9936%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 1583179368->1576132391 (-0.445%), candidate Ir 3118762031->3118770881 (+0.000%): main sped up on this bench and the merged candidate did not share it; main delta=+97.8749%; bound=ceil(delta+0.2,0.1); R1.6d measured component: default interp benchmark ends with buf_peak scanning 441000 cells; buffer_read_num -> buffer_read_f64 adds finite-data validation, measured peak+reader Ir +7938000 (18/cell); fresh4e77a9de control Ir=3119656760, R1.6d Ir=3127584374, net candidate increase +7927614 Ir (residual -10386 Ir in startup/argument checks); main88a1c911 Ir=1576130830, main delta=+98.43431233%, bound=ceil(delta+0.2,0.1); R5 retains int VM/Value API recovery with required finite refusal preserved -tests/bench_buf_resample.eigs jit 202.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14070973095, R1.4 Ir=14341781156, measured main delta=+196.6971%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM code-generation component (this workload has no bitwise ops): vm_run_ex +16800000 Ir offset by eigs_num_arg -7200000 Ir; R5 int/slot fast paths must recover this shared VM cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=14344087931, R1.5 Ir=14353686973, measured main delta=+196.9435%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 floor exact-number-reader and non-pooled int-result boundary (1200000 calls), plus retained generic index/slot work; banked R1.6a Ir=14353692804, current Ir=14590083369, main Ir=4833804762, main delta=+201.83435383%; bound=ceil(delta+0.2,0.1); R5 must recover this generic int producer/read-boundary work in the interpreter as well as JIT/leaf execution while preserving the semantic checks -tests/bench_buf_resample.eigs off 70.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14114616143, R1.4 Ir=14385424763, measured main delta=+67.2701%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 floor exact-number-reader and non-pooled int-result boundary (1200000 calls), plus retained generic index/slot work; banked R1.6a Ir=14397335640, current Ir=14633726307, main Ir=8600110047, main delta=+70.15743086%; bound=ceil(delta+0.2,0.1); R5 must recover this generic int producer/read-boundary work in the interpreter as well as JIT/leaf execution while preserving the semantic checks; main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 8600110047->8579114636 (-0.244%), candidate Ir 14633726307->14620635542 (-0.089%): main sped up more than the merged candidate; main delta=+70.4213%; bound=ceil(delta+0.2,0.1) -tests/bench_dmg_shape.eigs jit 230.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; merge of 94657581 BASE component (#1171): jit_helper_call no longer calls the out-of-line slot_decref (0c16522f), so main's slot_decref drops 14,517,154 -> 28,754 Ir (BASE -14,503,457, -1.12%), while the branch runs this int code interpreted and does not reach it (CAND -445,382, -0.01%); measured +172.92% at R1.3, +175.98% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3527659645, R1.4 Ir=3944225152, measured main delta=+208.5522%, bound=ceil(delta+0.2,0.1); R1.5 N8 component on the DMG-shaped benchmark: exact int bitwise results retain int state through generic dictionary/boxed Value paths (dict_set_cached +101124922 Ir and _int_malloc +38500014 Ir); R5 must recover these paths in the interpreter as well as JIT/leaf int execution; fresh2d6587ee control Ir=3943793833, R1.5 Ir=4216636333, measured main delta=+229.8625%, bound=ceil(delta+0.2,0.1) -tests/bench_dmg_shape.eigs off 76.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3546396130, R1.4 Ir=3963267113, measured main delta=+66.2412%, bound=ceil(delta+0.2,0.1); R1.5 N8 component on the DMG-shaped benchmark: exact int bitwise results retain int state through generic dictionary/boxed Value paths (dict_set_cached +101124922 Ir and _int_malloc +38500146 Ir); R5 must recover these paths in the interpreter as well as JIT/leaf int execution; fresh2d6587ee control Ir=3962833268, R1.5 Ir=4198461839, measured main delta=+76.1062%, bound=ceil(delta+0.2,0.1); sync #6 (main 858bcc8e) component, measured on the exact controls: the main base moved +983 Ir (+0.00004%) and the branch side +1,009,678 Ir (+0.024%), all in vm_run_ex (+1,000,020 Ir: one more instruction per million executions, a codegen shift from main #1918's cold import-source arm in that function); delta 76.40004% re-declared by ceil(delta+0.2, 0.1) -tests/bench_idxset.eigs jit 457.5 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489963988, R1.4 Ir=531588673, measured main delta=+454.8994%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM/helper code-generation component (this workload has no bitwise ops): slot_from_int becomes out of line (+1200000 Ir), eigs_slot_store_owned +1000000 Ir and vm_run_ex +599999 Ir; R5 interpreter int/slot fast paths must recover the off-tier cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=531584777, R1.5 Ir=534388413, measured main delta=+457.8236%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 95798818->95787251 (-0.012%), candidate Ir 534388413->533777385 (-0.114%): the candidate got cheaper; main delta=+457.2531%; bound=ceil(delta+0.2,0.1) -tests/bench_idxset.eigs off 127.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489962938, R1.4 Ir=531587958, measured main delta=+126.6422%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM/helper code-generation component (this workload has no bitwise ops): slot_from_int becomes out of line (+1200000 Ir), eigs_slot_store_owned +1000000 Ir and vm_run_ex +599999 Ir; R5 interpreter int/slot fast paths must recover the off-tier cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=531588681, R1.5 Ir=534387392, measured main delta=+127.8315%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 234553779->234547230 (-0.003%), candidate Ir 534387392->533785956 (-0.113%): the candidate got cheaper; main delta=+127.5814%; bound=ceil(delta+0.2,0.1) -tests/bench_pcm_codec.eigs jit 376.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39010338030, measured main delta=+376.5029%, bound=ceil(delta+0.2,0.1) -tests/bench_pcm_codec.eigs off 98.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +74,400,025 Ir against vm_run_ex -63,600,434 on the branch (CAND +10,800,129, +0.03%), while on main the same move saves (vm_run_ex -92,400,393, env_store_slot +66,000,030: BASE -26,400,939, -0.13%); measured +89.39% at R1.3, +89.70% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39192628174, measured main delta=+97.5413%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 19840219829->19771919441 (-0.344%), candidate Ir 39192628174->39195119849 (+0.006%): main sped up on this bench and the merged candidate did not share it; main delta=+98.2363%; bound=ceil(delta+0.2,0.1) +bench/unobserved_armed_loop.eigs off 9.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +3,000,000 Ir on both trees (600,000 stores; the assign-count bump moved inside its hold), which saves 2,400,031 in the branch's vm_run_ex (CAND +600,065, +0.06%) but 4,800,031 in main's (BASE -1,798,626, -0.21%); measured +8.85% at R1.3, +9.15% after the merge; R1.4 remeasurement narrows this stale bound on the existing generic int VM component; fresh6382b6a5 control Ir=930827459, R1.4 Ir=928427649, measured main delta=+8.7891%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM code-generation component (this workload has no bitwise ops): vm_run_ex +1799999 Ir; R5 interpreter int/slot fast paths must recover this off-tier cost; fresh2d6587ee control Ir=929028193, R1.5 Ir=930826815, measured main delta=+9.0703%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 853419139->853412688 (-0.001%), candidate Ir 930826815->928420991 (-0.258%): the candidate got cheaper; main delta=+8.7892%; bound=ceil(delta+0.2,0.1); R1.6z measured against pre-round2ba66cc8: old Ir=929245584, tip Ir=930445331, net +1199747 Ir; shared VM dispatch/helper code-generation effect of bridge retirement +1200001 Ir (vm_run_ex +1200001 Ir); other-function residual -254 Ir (other runtime functions -13 Ir; external string/number-formatting/startup functions -241 Ir; every function delta preserved); main dde78c5c Ir=852818898, tip Ir=930435864, local delta=9.10122491%, max 9.0->9.4; bound=ceil(delta+0.2,0.1) +bench/unobserved_loop.eigs jit 47.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +47.6% (range-int control, measured at R1.3, against +4.0%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=44857870, current Ir=63651013, main Ir=43111802, main delta=+47.64173625%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +200945 Ir (0.466 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 47.9 -> 48.2 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=63804716, tip Ir=63319820, net -484896 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -5001 Ir (vm_run_ex -5001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +127 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +135 Ir; every function delta preserved); main dde78c5c Ir=43111629, tip Ir=63309643, local delta=46.85050059%, max 48.2->47.1; bound=ceil(delta+0.2,0.1) +bench/unobserved_loop.eigs off 33.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +33.4% (range-int control, measured at R1.3, against +1.4%) until R5; R1.6b measured component: N3 range int production activates generic int allocation/observer paths, as the pre-registered range-int control predicts; banked R1.6a Ir=62507730, current Ir=82180474, main Ir=61531677, main delta=+33.55799485%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6z measured against pre-round2ba66cc8: old Ir=82334123, tip Ir=81794226, net -539897 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -60001 Ir (vm_run_ex -60001 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -480022 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); other-function residual +126 Ir (other runtime functions -8 Ir; external string/number-formatting/startup functions +134 Ir; every function delta preserved); main dde78c5c Ir=61531733, tip Ir=81784783, local delta=32.91480511%, max 33.8->33.2; bound=ceil(delta+0.2,0.1) +tests/bench_buf_mix.eigs jit 321.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=2997588303, R1.4 Ir=3102110794, measured main delta=+311.4903%, bound=ceil(delta+0.2,0.1); R1.6d measured component: default interp benchmark ends with buf_peak scanning 441000 cells; buffer_read_num -> buffer_read_f64 adds finite-data validation, measured peak+reader Ir +7938000 (18/cell); fresh4e77a9de control Ir=3103006291, R1.6d Ir=3110933042, net candidate increase +7926751 Ir (residual -11249 Ir in startup/argument checks); main88a1c911 Ir=753849828, main delta=+312.67277997%, bound=ceil(delta+0.2,0.1); R5 retains int VM/Value API recovery with required finite refusal preserved; R1.6z measured against pre-round2ba66cc8: old Ir=3111202023, tip Ir=3178233059, net +67031036 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +48951663 Ir (eigs_float_arg +18524210 Ir, eigs_number_arg +38810652 Ir, eigs_num_arg_slow -8383199 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +15876000 Ir (buffer_read_f64 +21168000 Ir, jit_helper_index_get -5292000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +2203008 Ir (vm_run_ex +2203008 Ir); constructor alias retirement -2 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +362 Ir (other runtime functions -27 Ir; external string/number-formatting/startup functions +389 Ir; every function delta preserved); main dde78c5c Ir=753857361, tip Ir=3178222580, local delta=321.59468680%, max 312.9->321.8; bound=ceil(delta+0.2,0.1) +tests/bench_buf_mix.eigs off 103 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=3014239251, R1.4 Ir=3118762031, measured main delta=+96.9936%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 1583179368->1576132391 (-0.445%), candidate Ir 3118762031->3118770881 (+0.000%): main sped up on this bench and the merged candidate did not share it; main delta=+97.8749%; bound=ceil(delta+0.2,0.1); R1.6d measured component: default interp benchmark ends with buf_peak scanning 441000 cells; buffer_read_num -> buffer_read_f64 adds finite-data validation, measured peak+reader Ir +7938000 (18/cell); fresh4e77a9de control Ir=3119656760, R1.6d Ir=3127584374, net candidate increase +7927614 Ir (residual -10386 Ir in startup/argument checks); main88a1c911 Ir=1576130830, main delta=+98.43431233%, bound=ceil(delta+0.2,0.1); R5 retains int VM/Value API recovery with required finite refusal preserved; R1.6z measured against pre-round2ba66cc8: old Ir=3127852086, tip Ir=3194883016, net +67030930 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +48951663 Ir (eigs_float_arg +18524210 Ir, eigs_number_arg +38810652 Ir, eigs_num_arg_slow -8383199 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +15876000 Ir (buffer_read_f64 +21168000 Ir, jit_helper_index_get -5292000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +2203008 Ir (vm_run_ex +2203008 Ir); constructor alias retirement -2 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +256 Ir (other runtime functions -27 Ir; external string/number-formatting/startup functions +283 Ir; every function delta preserved); main dde78c5c Ir=1576138511, tip Ir=3194873687, local delta=102.70259655%, max 98.7->103; bound=ceil(delta+0.2,0.1) +tests/bench_buf_resample.eigs jit 207.4 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14070973095, R1.4 Ir=14341781156, measured main delta=+196.6971%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM code-generation component (this workload has no bitwise ops): vm_run_ex +16800000 Ir offset by eigs_num_arg -7200000 Ir; R5 int/slot fast paths must recover this shared VM cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=14344087931, R1.5 Ir=14353686973, measured main delta=+196.9435%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 floor exact-number-reader and non-pooled int-result boundary (1200000 calls), plus retained generic index/slot work; banked R1.6a Ir=14353692804, current Ir=14590083369, main Ir=4833804762, main delta=+201.83435383%; bound=ceil(delta+0.2,0.1); R5 must recover this generic int producer/read-boundary work in the interpreter as well as JIT/leaf execution while preserving the semantic checks; R1.6z measured against pre-round2ba66cc8: old Ir=14578356573, tip Ir=14840872110, net +262515537 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +207811659 Ir (eigs_float_arg +126290530 Ir, eigs_number_arg +216479136 Ir, eigs_num_arg_slow -134958007 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +43200018 Ir (buffer_read_f64 +57600024 Ir, jit_helper_index_get -14400006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +11503643 Ir (vm_run_ex +11503643 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +212 Ir (other runtime functions -26 Ir; external string/number-formatting/startup functions +238 Ir; every function delta preserved); main dde78c5c Ir=4831400200, tip Ir=14840861427, local delta=207.17516274%, max 202.1->207.4; bound=ceil(delta+0.2,0.1) +tests/bench_buf_resample.eigs off 73.7 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=14114616143, R1.4 Ir=14385424763, measured main delta=+67.2701%, bound=ceil(delta+0.2,0.1); R1.6b measured component: N3 floor exact-number-reader and non-pooled int-result boundary (1200000 calls), plus retained generic index/slot work; banked R1.6a Ir=14397335640, current Ir=14633726307, main Ir=8600110047, main delta=+70.15743086%; bound=ceil(delta+0.2,0.1); R5 must recover this generic int producer/read-boundary work in the interpreter as well as JIT/leaf execution while preserving the semantic checks; main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 8600110047->8579114636 (-0.244%), candidate Ir 14633726307->14620635542 (-0.089%): main sped up more than the merged candidate; main delta=+70.4213%; bound=ceil(delta+0.2,0.1); R1.6z measured against pre-round2ba66cc8: old Ir=14621999324, tip Ir=14884514976, net +262515652 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +207811659 Ir (eigs_float_arg +126290530 Ir, eigs_number_arg +216479136 Ir, eigs_num_arg_slow -134958007 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +43200018 Ir (buffer_read_f64 +57600024 Ir, jit_helper_index_get -14400006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +11503643 Ir (vm_run_ex +11503643 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +327 Ir (other runtime functions -26 Ir; external string/number-formatting/startup functions +353 Ir; every function delta preserved); main dde78c5c Ir=8579121088, tip Ir=14884505468, local delta=73.49685726%, max 70.7->73.7; bound=ceil(delta+0.2,0.1) +tests/bench_dmg_shape.eigs jit 231.1 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; merge of 94657581 BASE component (#1171): jit_helper_call no longer calls the out-of-line slot_decref (0c16522f), so main's slot_decref drops 14,517,154 -> 28,754 Ir (BASE -14,503,457, -1.12%), while the branch runs this int code interpreted and does not reach it (CAND -445,382, -0.01%); measured +172.92% at R1.3, +175.98% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3527659645, R1.4 Ir=3944225152, measured main delta=+208.5522%, bound=ceil(delta+0.2,0.1); R1.5 N8 component on the DMG-shaped benchmark: exact int bitwise results retain int state through generic dictionary/boxed Value paths (dict_set_cached +101124922 Ir and _int_malloc +38500014 Ir); R5 must recover these paths in the interpreter as well as JIT/leaf int execution; fresh2d6587ee control Ir=3943793833, R1.5 Ir=4216636333, measured main delta=+229.8625%, bound=ceil(delta+0.2,0.1); R1.6z measured against pre-round2ba66cc8: old Ir=4215433176, tip Ir=4229812330, net +14379154 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +196608 Ir (eigs_float_arg +655360 Ir, eigs_number_arg +786432 Ir, eigs_num_arg_slow -1245184 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +9000000 Ir (buffer_read_f64 +12000000 Ir, jit_helper_index_get -3000000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +5187517 Ir (vm_run_ex +5187517 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -4967 Ir (other runtime functions -103 Ir; external string/number-formatting/startup functions -4864 Ir; every function delta preserved); main dde78c5c Ir=1278280651, tip Ir=4229768558, local delta=230.89514065%, max 230.1->231.1; bound=ceil(delta+0.2,0.1) +tests/bench_dmg_shape.eigs off 77.3 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; its float op7 also loses NUM_REUSE; fresh6382b6a5 control Ir=3546396130, R1.4 Ir=3963267113, measured main delta=+66.2412%, bound=ceil(delta+0.2,0.1); R1.5 N8 component on the DMG-shaped benchmark: exact int bitwise results retain int state through generic dictionary/boxed Value paths (dict_set_cached +101124922 Ir and _int_malloc +38500146 Ir); R5 must recover these paths in the interpreter as well as JIT/leaf int execution; fresh2d6587ee control Ir=3962833268, R1.5 Ir=4198461839, measured main delta=+76.1062%, bound=ceil(delta+0.2,0.1); sync #6 (main 858bcc8e) component, measured on the exact controls: the main base moved +983 Ir (+0.00004%) and the branch side +1,009,678 Ir (+0.024%), all in vm_run_ex (+1,000,020 Ir: one more instruction per million executions, a codegen shift from main #1918's cold import-source arm in that function); delta 76.40004% re-declared by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=4197227719, tip Ir=4211611742, net +14384023 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +196608 Ir (eigs_float_arg +655360 Ir, eigs_number_arg +786432 Ir, eigs_num_arg_slow -1245184 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +9000000 Ir (buffer_read_f64 +12000000 Ir, jit_helper_index_get -3000000 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +5187517 Ir (vm_run_ex +5187517 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -98 Ir (other runtime functions -59 Ir; external string/number-formatting/startup functions -39 Ir; every function delta preserved); main dde78c5c Ir=2379233275, tip Ir=4211607423, local delta=77.01532116%, max 76.7->77.3; bound=ceil(delta+0.2,0.1) +tests/bench_idxset.eigs jit 459.2 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489963988, R1.4 Ir=531588673, measured main delta=+454.8994%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM/helper code-generation component (this workload has no bitwise ops): slot_from_int becomes out of line (+1200000 Ir), eigs_slot_store_owned +1000000 Ir and vm_run_ex +599999 Ir; R5 interpreter int/slot fast paths must recover the off-tier cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=531584777, R1.5 Ir=534388413, measured main delta=+457.8236%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 95798818->95787251 (-0.012%), candidate Ir 534388413->533777385 (-0.114%): the candidate got cheaper; main delta=+457.2531%; bound=ceil(delta+0.2,0.1); R1.6z measured against pre-round2ba66cc8: old Ir=534010570, tip Ir=535405691, net +1395121 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +300000 Ir (eigs_float_arg +1000000 Ir, eigs_number_arg +1200000 Ir, eigs_num_arg_slow -1900000 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +18 Ir (buffer_read_f64 +24 Ir, jit_helper_index_get -6 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +1100000 Ir (vm_run_ex +1100000 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -4893 Ir (other runtime functions -55 Ir; external string/number-formatting/startup functions -4838 Ir; every function delta preserved); main dde78c5c Ir=95788672, tip Ir=535395772, local delta=458.93432994%, max 457.5->459.2; bound=ceil(delta+0.2,0.1) +tests/bench_idxset.eigs off 128.5 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; fresh6382b6a5 control Ir=489962938, R1.4 Ir=531587958, measured main delta=+126.6422%, bound=ceil(delta+0.2,0.1); R1.5 N8 shared VM/helper code-generation component (this workload has no bitwise ops): slot_from_int becomes out of line (+1200000 Ir), eigs_slot_store_owned +1000000 Ir and vm_run_ex +599999 Ir; R5 interpreter int/slot fast paths must recover the off-tier cost as well as JIT/leaf int execution; fresh2d6587ee control Ir=531588681, R1.5 Ir=534387392, measured main delta=+127.8315%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 234553779->234547230 (-0.003%), candidate Ir 534387392->533785956 (-0.113%): the candidate got cheaper; main delta=+127.5814%; bound=ceil(delta+0.2,0.1); R1.6z measured against pre-round2ba66cc8: old Ir=534004479, tip Ir=535404391, net +1399912 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +300000 Ir (eigs_float_arg +1000000 Ir, eigs_number_arg +1200000 Ir, eigs_num_arg_slow -1900000 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +18 Ir (buffer_read_f64 +24 Ir, jit_helper_index_get -6 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +1100000 Ir (vm_run_ex +1100000 Ir); constructor alias retirement -4 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -102 Ir (other runtime functions -13 Ir; external string/number-formatting/startup functions -89 Ir; every function delta preserved); main dde78c5c Ir=234553336, tip Ir=535399894, local delta=128.26360227%, max 127.8->128.5; bound=ceil(delta+0.2,0.1) +tests/bench_pcm_codec.eigs jit 383.8 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39010338030, measured main delta=+376.5029%, bound=ceil(delta+0.2,0.1); R1.6z measured against pre-round2ba66cc8: old Ir=39023891158, tip Ir=39585491642, net +561600484 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +468002880 Ir (eigs_float_arg +280809600 Ir, eigs_number_arg +483611520 Ir, eigs_num_arg_slow -296418240 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +86400018 Ir (buffer_read_f64 +115200024 Ir, jit_helper_index_get -28800006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +7197108 Ir (vm_run_ex +7197108 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +473 Ir (other runtime functions -39 Ir; external string/number-formatting/startup functions +512 Ir; every function delta preserved); main dde78c5c Ir=8186872469, tip Ir=39585480607, local delta=383.52384573%, max 376.8->383.8; bound=ceil(delta+0.2,0.1) +tests/bench_pcm_codec.eigs off 101.4 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; merge of 94657581 component (#1171): env_store_slot +74,400,025 Ir against vm_run_ex -63,600,434 on the branch (CAND +10,800,129, +0.03%), while on main the same move saves (vm_run_ex -92,400,393, env_store_slot +66,000,030: BASE -26,400,939, -0.13%); measured +89.39% at R1.3, +89.70% after the merge; R1.4 int MOD component: exact results use non-pooled make_int instead of the make_num float freelist; retained int state also reaches generic Value API/index paths until R5 int slot/index fast paths; PCM component source-traced; fresh R13 PCM control interrupted, not claimed, R1.4 Ir=39192628174, measured main delta=+97.5413%, bound=ceil(delta+0.2,0.1); main->phase2 sync #5 component (main 0277d7a9->88a1c911): main Ir 19840219829->19771919441 (-0.344%), candidate Ir 39192628174->39195119849 (+0.006%): main sped up on this bench and the merged candidate did not share it; main delta=+98.2363%; bound=ceil(delta+0.2,0.1); R1.6z measured against pre-round2ba66cc8: old Ir=39206179064, tip Ir=39767779547, net +561600483 Ir; final numeric-reader migration at VM buffer stores/mixed arithmetic +468002880 Ir (eigs_float_arg +280809600 Ir, eigs_number_arg +483611520 Ir, eigs_num_arg_slow -296418240 Ir); VM index/iteration/leaf helper migration including R1.6d-D1 finite-data boundary on buffers +86400018 Ir (buffer_read_f64 +115200024 Ir, jit_helper_index_get -28800006 Ir); shared VM dispatch/helper code-generation effect of bridge retirement +7197108 Ir (vm_run_ex +7197108 Ir); IEEE/structural-equality dispatch change +5 Ir (values_equal_impl +5 Ir); other-function residual +472 Ir (other runtime functions -39 Ir; external string/number-formatting/startup functions +511 Ir; every function delta preserved); main dde78c5c Ir=19771925548, tip Ir=39767770128, local delta=101.13250999%, max 98.5->101.4; bound=ceil(delta+0.2,0.1) tests/bench_perf.eigs jit 32.6 R5 design §3: INT_* literal opcodes stop the JIT scanner and its guards bail on int operands, so int code runs interpreted until the R5 JIT/leaf int fast paths; R1.6 component: its int `range` alone raises this row to +32.4% (range-int control, measured at R1.3, against +15.7%) until R5; R1.6b measured component: N3 range-produced ints activate generic integer arithmetic/Value API paths, as the pre-registered range-int control predicts; banked R1.6a Ir=297793217, current Ir=340827242, main Ir=257477918, main delta=+32.37144554%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers -tests/bench_perf.eigs off 19.2 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +18.7% (range-int control, measured at R1.3, against +5.4%) until R5; R1.6b measured component: N3 range-produced ints activate generic integer arithmetic/Value API paths, as the pre-registered range-int control predicts; banked R1.6a Ir=309974276, current Ir=349154039, main Ir=294194185, main delta=+18.68148889%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +412584 Ir (0.140 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 18.9 -> 19.2 by ceil(delta+0.2, 0.1) +tests/bench_perf.eigs off 18.8 R5 design §3: interpreted int arithmetic takes the checked generic arm, and mixed int/float operands, int indexes and int / and % box through slow paths until the R5 int fast paths; R1.6 component: its int `range` alone raises this row to +18.7% (range-int control, measured at R1.3, against +5.4%) until R5; R1.6b measured component: N3 range-produced ints activate generic integer arithmetic/Value API paths, as the pre-registered range-int control predicts; banked R1.6a Ir=309974276, current Ir=349154039, main Ir=294194185, main delta=+18.68148889%; bound=ceil(delta+0.2,0.1); R5 retains recovery of the remaining generic int VM/Value API work in both tiers; R1.6g component +412584 Ir (0.140 pp, measured against pre-R1.6g 59d6bb70): a fixed cost per global-env creation from eagerly registering 77 more builtins (allocation, env_intern_name, env_set_local_hashed, env_hash_rebuild; per-function cg_annotate diff); re-declared 18.9 -> 19.2 by ceil(delta+0.2, 0.1); R1.6z measured against pre-round2ba66cc8: old Ir=349488837, tip Ir=348433201, net -1055636 Ir; shared VM dispatch/helper code-generation effect of bridge retirement -220005 Ir (vm_run_ex -220005 Ir); runtime/container bridge-retirement TU code-generation/inlining consequence in list_append -816088 Ir (source body unchanged; measured old/tip assembly drops three saved registers and stack adjustment, eight executed prologue/epilogue instructions per ordinary append); constructor alias retirement -20 Ir (make_num/make_float combined, avoiding a symbol-rename false cost); other-function residual -19523 Ir (other runtime functions -213 Ir; external string/number-formatting/startup functions -19310 Ir; every function delta preserved); main dde78c5c Ir=293908946, tip Ir=348433252, local delta=18.55142783%, max 19.2->18.8; bound=ceil(delta+0.2,0.1) diff --git a/tests/phase2/gfx_byte_boundary.c b/tests/phase2/gfx_byte_boundary.c index 093b6a164..1e378be40 100644 --- a/tests/phase2/gfx_byte_boundary.c +++ b/tests/phase2/gfx_byte_boundary.c @@ -1,4 +1,4 @@ -/* #1758 R1.6e: pre-registered deferred buffer_read_byte boundary. +/* #1758 R1.6e: pre-registered deferred buffer byte boundary. * Stock buffers receive raw stored payloads after construction, so this * reaches the actual gfx_fb/ppu_render_frame consumers before a scalar * producer can normalize or reject the fixture. SDL's real dummy renderer diff --git a/tools/phase2_check.py b/tools/phase2_check.py index 3603ddb97..d5deb0f5d 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -1192,8 +1192,8 @@ def stray(rd): 'make_int(lo_i + 1 + (eigs_random_long() % (int64_t)span))', 'build'), # R1.6z-D1: identity would make a NaN-holding buffer equal to itself. 'value-eq-identity': ('src/eigenscript.c', - ' if (a == b && (!a || a->type != VAL_BUFFER)) return 1;', - ' if (a == b) return 1; /* PLANT: bypass IEEE buffer elements */', 'build'), + ' if (a == b && (!a || a->type != VAL_BUFFER)) {', + ' if (a == b) return 1; /* PLANT: bypass IEEE buffer elements */\n if (a == b && (!a || a->type != VAL_BUFFER)) {', 'build'), } _PLANT_DIR = [] From d1efc6b879cb76fc61e3c512c27634b4446a5fe0 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 25 Oct 2026 10:26:17 -0500 Subject: [PATCH 178/188] test(numbers): preregister R1.7 text changes and invariant controls R1.7-D3/D4: 43/43 CHANGE tier observations red on b6f9db38; 8/8 invariant observations green. D1 direct literal already prints Python repr on the actual base (15..17 writer), so D3 general rule classifies it invariant. T1 includes0.1. Direct constant-pool probe base:8 checks,3 failures; DB:11 passed,3 failed,14 declared. Invariant wrong-output plant red; fresh critic7/7 controls and51/51 independent tier classification. No runtime source or frozen expectation changes. Continuation 6, R1.7-D7 (#1758, N6): change ctl.N8.refuse-mod's observable from print r (legacy 0 vs N6 0.0) to print (r == 0), true on both. The hot f, float operands, MOD body, warm-up and fn-stop f MOD witness are unchanged. MAP.md records D7. Derived all-18-control sweep: the only other float-output controls are leaf-float 2.25 and osr-float 150.5, already byte-stable under N6; no other stale control pin. D7 narrow checkpoint proofs (all requested commands rc=0): tier=off examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=default examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=osr examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=trace examined=105 rows tag_fail=105 branch_pass=105 vacuous=0 tag_timeout=0 tag_signal=0 controls=18 both_pass=18 witnessed=31 mapped=113 gates=8 through=R1.7 controls_witnessed=13 controls_vacuous=0 invariants=2 branch_pass=2 phase2-check: PASS RESULTS: 2/2 passed, 0 failed, 0 skipped Corpus attribution: 55 observed row explanations; 0 require judgment. Full evidence retained. Corpus adjudicated: 55 differences traced to R1.7 behavior/registration; sole expected runaway timeout; no other crash/timeout. Evidence: continue6-checks.json; sweep: continue6-sweep.json/.md; six clean-apply clones and verified extracted bundle: continue6-checkpoint-proof.json. Full train pending; not launched in continuation 6. Source fingerprint: ba0bd12bbd1a933ddf8540411388e5b4f1a78211cd78014d64f12a45923a859f Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 3 ++ tests/phase2/MAP.md | 17 ++++--- tests/phase2/const_dedup_bits.c | 28 ++++++++++++ tests/phase2/controls/ctl.N8.refuse-mod.eigs | 2 +- tests/phase2/controls/ctl.N8.refuse-mod.out | 2 +- tests/phase2/rows/N1.fn-float-literals.eigs | 16 +++++++ tests/phase2/rows/N1.fn-float-literals.out | 1 + tests/phase2/rows/N1.leaf-float-literal.eigs | 13 ++++++ tests/phase2/rows/N1.leaf-float-literal.out | 1 + .../rows/N1.negative-past-int64-is-float.eigs | 9 ++++ .../rows/N1.negative-past-int64-is-float.out | 2 + tests/phase2/rows/N14.encode-kinds.eigs | 7 +++ tests/phase2/rows/N14.encode-kinds.out | 1 + tests/phase2/rows/N14.store-exact-digits.out | 1 + tests/phase2/rows/N14.store-exact-digits.sh | 19 ++++++++ tests/phase2/rows/N4.div-always-float.eigs | 7 +++ tests/phase2/rows/N4.div-always-float.out | 1 + tests/phase2/rows/N4.fn-div-float.eigs | 15 +++++++ tests/phase2/rows/N4.fn-div-float.out | 1 + tests/phase2/rows/N5.leaf-buffer-index.eigs | 10 +++++ tests/phase2/rows/N5.leaf-buffer-index.out | 1 + tests/phase2/rows/N6.float-repr.eigs | 7 +++ tests/phase2/rows/N6.float-repr.out | 1 + tests/phase2/rows/N6.int-exact-digits.eigs | 7 +++ tests/phase2/rows/N6.int-exact-digits.out | 1 + .../rows/N6.neg-zero-literal-dedup.eigs | 9 ++++ .../phase2/rows/N6.neg-zero-literal-dedup.out | 1 + tests/phase2/rows/N6.str-fstring.eigs | 8 ++++ tests/phase2/rows/N6.str-fstring.out | 1 + tests/phase2/rows/T1.twice-float.out | 6 +++ tests/phase2/rows/T1.twice-float.sh | 33 ++++++++++++++ tests/test_db_params.c | 23 +++++++++- tools/phase2_check.py | 44 +++++++++++++++++-- tools/phase2_readers.sh | 7 +++ 34 files changed, 292 insertions(+), 13 deletions(-) create mode 100644 tests/phase2/const_dedup_bits.c create mode 100644 tests/phase2/rows/N1.fn-float-literals.eigs create mode 100644 tests/phase2/rows/N1.fn-float-literals.out create mode 100644 tests/phase2/rows/N1.leaf-float-literal.eigs create mode 100644 tests/phase2/rows/N1.leaf-float-literal.out create mode 100644 tests/phase2/rows/N1.negative-past-int64-is-float.eigs create mode 100644 tests/phase2/rows/N1.negative-past-int64-is-float.out create mode 100644 tests/phase2/rows/N14.encode-kinds.eigs create mode 100644 tests/phase2/rows/N14.encode-kinds.out create mode 100644 tests/phase2/rows/N14.store-exact-digits.out create mode 100644 tests/phase2/rows/N14.store-exact-digits.sh create mode 100644 tests/phase2/rows/N4.div-always-float.eigs create mode 100644 tests/phase2/rows/N4.div-always-float.out create mode 100644 tests/phase2/rows/N4.fn-div-float.eigs create mode 100644 tests/phase2/rows/N4.fn-div-float.out create mode 100644 tests/phase2/rows/N5.leaf-buffer-index.eigs create mode 100644 tests/phase2/rows/N5.leaf-buffer-index.out create mode 100644 tests/phase2/rows/N6.float-repr.eigs create mode 100644 tests/phase2/rows/N6.float-repr.out create mode 100644 tests/phase2/rows/N6.int-exact-digits.eigs create mode 100644 tests/phase2/rows/N6.int-exact-digits.out create mode 100644 tests/phase2/rows/N6.neg-zero-literal-dedup.eigs create mode 100644 tests/phase2/rows/N6.neg-zero-literal-dedup.out create mode 100644 tests/phase2/rows/N6.str-fstring.eigs create mode 100644 tests/phase2/rows/N6.str-fstring.out create mode 100644 tests/phase2/rows/T1.twice-float.out create mode 100644 tests/phase2/rows/T1.twice-float.sh diff --git a/Makefile b/Makefile index fac355e60..bc154680e 100644 --- a/Makefile +++ b/Makefile @@ -287,6 +287,9 @@ build/phase2/embed_buffer_get_raw_%: tests/phase2/embed_buffer_get_raw.c build/p # Q7 lands in R1.6e; an absent source is a build failure once selected. build/phase2/q7_readers_%: tests/phase2/q7_readers.c build/phase2/eigenscript_all.c tools/werror_flags.txt $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread +# R1.7-D4: signed-zero constant keys are compared by bits. +build/phase2/const_dedup_bits_%: tests/phase2/const_dedup_bits.c build/phase2/eigenscript_all.c tools/werror_flags.txt + $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread .PHONY: phase2-readers-test phase2-readers-test: build/phase2/$(PHASE2_READERS_FIXTURE)_$(PHASE2_READERS_VARIANT) @echo "phase2 reader test built: $<" diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 6ca39ea9f..48a35b578 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -49,6 +49,7 @@ gates (design §9.2). built 2026-10-13). Main differs from the tag only by #1740/#1741 (bitwise and range conversion) and #1735. - `(read)` is derived from the tag's source. +- **Invariants** (`[Rn, invariant]`, R1.7-D3) already pass on the pre-round base. They run on every declared branch tier and are counted separately from change rows; the v0.46 anchor predates their landed contract. Pre-registration records base-green evidence. - **Controls** (`ctl.*`) must PASS on both binaries. They guard behaviour the branch must preserve, and are counted separately: never in `tag_fail`. @@ -97,6 +98,9 @@ gates (design §9.2). --- ### N1 +- `N1.negative-past-int64-is-float` [R1.7, invariant] R1.7-D1: `-9223372036854775809` is a float equal to INT64_MIN; N6 prints Python repr + -> `[true, "float"]`, then `-9.223372036854776e+18` + tag: num_type undefined; R1.7-D3 prints the literal separately; observed base already prints the N6 text (15..17 round-trip writer), so the entire row is an invariant under D3. - `N1.leaf-float-kind` [R1.3] leaf helpers return 1.0, 0.0 and 0.5; `num_type` checks their kinds before N6 changes their display -> `["float", "float", "float"]` tag: `num_type` undefined. @@ -396,10 +400,11 @@ gates (design §9.2). shape: O witness: osr fill (the float counter keeps the loop native; the boxed int takes `INDEX_SET`'s C helper; witness probed main: `oadv 123` = `len 123`, 3 native `jit_helper_index_set` calls under gdb) ops: INDEX_SET NUM_ONE ADD GE JUMP_IF_FALSE SET_LOCAL POP ### N6 +- `gate.N6.const-dedup-bits` [R1.7] `tools/phase2_readers.sh` release/asan `const_dedup_bits`: direct `chunk_add_constant` of +0.0 and -0.0 has distinct indices and memcmp-exact stored doubles (R1.7-D4); repeated identical bits deduplicate. - `N6.float-repr` [R1.7] `print of [3.0, 1e3, -0.0, 0.1 + 0.2, 1e15, 1e16, 1e-05, 0.0001]` -> `[3.0, 1000.0, -0.0, 0.30000000000000004, 1000000000000000.0, 1e+16, 1e-05, 0.0001]` tag: `[3, 1000, 0, 0.30000000000000004, 1000000000000000, 1e+16, 1e-05, 0.0001]` (probed main for the first seven) -- `N6.int-exact-digits` [R1.7] `print of [9007199254740993, -9223372036854775807 - 1]` +- `N6.int-exact-digits` [R1.7, invariant] `print of [9007199254740993, -9223372036854775807 - 1]` -> `[9007199254740993, -9223372036854775808]` tag: rounded doubles - `N6.str-fstring` [R1.7] `x is 2.0 / print of [str of x, f"{x}", str of 2]` @@ -447,8 +452,10 @@ gates (design §9.2). - `ctl.N8.refuse-bnot` (control) a hot function applies `~a` to float operands 6.0 and 3.0 -> `-7` on both; the JIT scanner refuses this opcode at R1.3. shape: F witness: fn-stop f BNOT ops: BNOT -- `ctl.N8.refuse-mod` (control) a hot function applies `a % b` to float operands 6.0 and 3.0 - -> `0` on both; the JIT scanner refuses this opcode at R1.3. +- `ctl.N8.refuse-mod` (control) a hot function applies `a % b` to float operands 6.0 and 3.0; + print `(r == 0)` -> `true` on both. R1.7-D7 (#1758, N6) makes the + observable text-stable while retaining the hot float-MOD witness program. + The JIT scanner refuses this opcode at R1.3. shape: F witness: fn-stop f MOD ops: MOD - `N8.bitwise-results-int` [R1.5] `print of [6 & 3, 6 | 3, 6 ^ 3, ~0, num_type of (6 & 3)]` -> `[2, 7, 5, -1, "int"]` @@ -597,8 +604,8 @@ Names, operands and operations follow the decided [#1758 comment 6304880619](htt - `T1.twice-int` [R1.3] (sh row) the Done-when's "record twice": record `define sq(x) as: return x * x / x is 9007199254740993 / y is sq of 94906267 / print of [x, y]` twice (`EIGS_TRACE=t1.tape`, then `t2.tape`); print whether `cmp t1.tape t2.tape` finds them identical; replay `t1.tape` with `EIGS_REPLAY_STRICT=1` and print whether its stdout byte-equals the live run's (the live run computes `sq` in the leaf, the recording on the generic path); print the A records for `x` and `y` -> `tapes identical`, `replay identical`, `A 0 x=9007199254740993`, `A 0 y=9007199515875289` tag: `A 0 x=9007199254740992`, `A 0 y=9007199515875288` (the tape machinery is deterministic today: two recordings of a program without randomness differ only in recorded nondeterminism, probed main) -- `T1.twice-float` [R1.7] (sh row) the same procedure for `x is 3.0 / y is 0.1 + 0.2 / z is -0.0 / print of [x, y, z]` - -> `tapes identical`, `replay identical`, `A 0 x=3.0`, `A 0 y=0.30000000000000004`, `A 0 z=-0.0` (the kind on the tape; the exact text is N6's, R1.7) +- `T1.twice-float` [R1.7] (sh row) the same procedure for `x is 3.0 / y is 0.1 + 0.2 / z is -0.0 / w is 0.1 / print of [x, y, z, w]` + -> `tapes identical`, `replay identical`, `A 0 x=3.0`, `A 0 y=0.30000000000000004`, `A 0 z=-0.0`, `A 0 w=0.1` (R1.7-D3; the kind on the tape; the exact text is N6's, R1.7) tag: `A 0 x=3` and `A 0 z=-0` (read: `%.17g`) - `T1.int-replay-kind` [R1.3] (sh row) record a replayed `random_int` draw selecting an int literal; print its exact value and `num_type`, then replay and compare bytes -> `int replay identical`, `int assignment exact` (the int is carried by the v8 assignment record; `random_int` retains the float bridge until R1.6) diff --git a/tests/phase2/const_dedup_bits.c b/tests/phase2/const_dedup_bits.c new file mode 100644 index 000000000..fa7b3578d --- /dev/null +++ b/tests/phase2/const_dedup_bits.c @@ -0,0 +1,28 @@ +/* R1.7-D4: exercise the constant pool itself, not NUM_ZERO/NEG. */ +#include "eigenscript_all.c" +static int checks, failures; +static void check(int ok, const char *label) { + ++checks; + if (!ok) { ++failures; printf("phase2-const-dedup-test: FAIL %s\n", label); } +} +int main(void) { + EigsState *st = eigs_open(); + if (!st) return 1; + EigsChunk *c = chunk_new("signed-zero"); + double pos = 0.0, neg = -0.0; + Value *p = make_float(pos), *n = make_float(neg); + int pi = chunk_add_constant(c, p), ni = chunk_add_constant(c, n); + check(pi != ni, "signed zeros have distinct indices"); + check(c->const_count == 2, "two bit patterns stored"); + check(c->constants[pi]->type == VAL_FLOAT, "positive kind"); + check(c->constants[ni]->type == VAL_FLOAT, "negative kind"); + double ps = VAL_F64_RAW(c->constants[pi]), ns = VAL_F64_RAW(c->constants[ni]); + check(memcmp(&ps, &pos, sizeof pos) == 0, "positive bits exact"); + check(memcmp(&ns, &neg, sizeof neg) == 0, "negative bits exact"); + check(chunk_add_constant(c, p) == pi, "same positive bits deduplicate"); + check(chunk_add_constant(c, n) == ni, "same negative bits deduplicate"); + val_decref(p); val_decref(n); chunk_free(c); + eigs_close(st); + printf("phase2-const-dedup-test: %s checks=%d failures=%d\n", failures ? "FAIL" : "PASS", checks, failures); + return failures ? 1 : 0; +} diff --git a/tests/phase2/controls/ctl.N8.refuse-mod.eigs b/tests/phase2/controls/ctl.N8.refuse-mod.eigs index 154c25f62..4168193fc 100644 --- a/tests/phase2/controls/ctl.N8.refuse-mod.eigs +++ b/tests/phase2/controls/ctl.N8.refuse-mod.eigs @@ -13,4 +13,4 @@ i is 0.0 loop while i < 60.0: r is f of [6.0, 3.0] i is i + 1.0 -print of r +print of (r == 0) diff --git a/tests/phase2/controls/ctl.N8.refuse-mod.out b/tests/phase2/controls/ctl.N8.refuse-mod.out index 573541ac9..27ba77dda 100644 --- a/tests/phase2/controls/ctl.N8.refuse-mod.out +++ b/tests/phase2/controls/ctl.N8.refuse-mod.out @@ -1 +1 @@ -0 +true diff --git a/tests/phase2/rows/N1.fn-float-literals.eigs b/tests/phase2/rows/N1.fn-float-literals.eigs new file mode 100644 index 000000000..fea663f6e --- /dev/null +++ b/tests/phase2/rows/N1.fn-float-literals.eigs @@ -0,0 +1,16 @@ +# ROW: N1.fn-float-literals +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn f +# OPS: NUM_ONE NUM_ZERO MUL ADD +define f(a) as: + t is a * 1.0 + u is t + 0.0 + return u +r is null +i is 0.0 +loop while i < 60.0: + r is f of 2.0 + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N1.fn-float-literals.out b/tests/phase2/rows/N1.fn-float-literals.out new file mode 100644 index 000000000..cd5ac039d --- /dev/null +++ b/tests/phase2/rows/N1.fn-float-literals.out @@ -0,0 +1 @@ +2.0 diff --git a/tests/phase2/rows/N1.leaf-float-literal.eigs b/tests/phase2/rows/N1.leaf-float-literal.eigs new file mode 100644 index 000000000..3aabf5249 --- /dev/null +++ b/tests/phase2/rows/N1.leaf-float-literal.eigs @@ -0,0 +1,13 @@ +# ROW: N1.leaf-float-literal +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf onef zerof halff +# OPS: NUM_ONE NUM_ZERO CONST +define onef(x) as: + return 1.0 +define zerof(x) as: + return 0.0 +define halff(x) as: + return 0.5 +print of [onef of 7, zerof of 7, halff of 7] diff --git a/tests/phase2/rows/N1.leaf-float-literal.out b/tests/phase2/rows/N1.leaf-float-literal.out new file mode 100644 index 000000000..96cc29938 --- /dev/null +++ b/tests/phase2/rows/N1.leaf-float-literal.out @@ -0,0 +1 @@ +[1.0, 0.0, 0.5] diff --git a/tests/phase2/rows/N1.negative-past-int64-is-float.eigs b/tests/phase2/rows/N1.negative-past-int64-is-float.eigs new file mode 100644 index 000000000..7a6ddc2e7 --- /dev/null +++ b/tests/phase2/rows/N1.negative-past-int64-is-float.eigs @@ -0,0 +1,9 @@ +# ROW: N1.negative-past-int64-is-float +# ITEMS: N1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +x is -9223372036854775809 +print of [x == -9223372036854775807 - 1, num_type of x] +print of -9223372036854775809 diff --git a/tests/phase2/rows/N1.negative-past-int64-is-float.out b/tests/phase2/rows/N1.negative-past-int64-is-float.out new file mode 100644 index 000000000..376e1c582 --- /dev/null +++ b/tests/phase2/rows/N1.negative-past-int64-is-float.out @@ -0,0 +1,2 @@ +[true, "float"] +-9.223372036854776e+18 diff --git a/tests/phase2/rows/N14.encode-kinds.eigs b/tests/phase2/rows/N14.encode-kinds.eigs new file mode 100644 index 000000000..c3c94282f --- /dev/null +++ b/tests/phase2/rows/N14.encode-kinds.eigs @@ -0,0 +1,7 @@ +# ROW: N14.encode-kinds +# ITEMS: N14 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of (json_encode of [3, 3.0, 0.1, -0.0]) diff --git a/tests/phase2/rows/N14.encode-kinds.out b/tests/phase2/rows/N14.encode-kinds.out new file mode 100644 index 000000000..17fc2a71f --- /dev/null +++ b/tests/phase2/rows/N14.encode-kinds.out @@ -0,0 +1 @@ +[3,3.0,0.1,-0.0] diff --git a/tests/phase2/rows/N14.store-exact-digits.out b/tests/phase2/rows/N14.store-exact-digits.out new file mode 100644 index 000000000..601ef4cf6 --- /dev/null +++ b/tests/phase2/rows/N14.store-exact-digits.out @@ -0,0 +1 @@ +[true, true, true] diff --git a/tests/phase2/rows/N14.store-exact-digits.sh b/tests/phase2/rows/N14.store-exact-digits.sh new file mode 100644 index 000000000..7e66acf94 --- /dev/null +++ b/tests/phase2/rows/N14.store-exact-digits.sh @@ -0,0 +1,19 @@ +# ROW: N14.store-exact-digits +# ITEMS: N14 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +set -eu +bin=$1 +scratch=$(mktemp -d /tmp/eigs-r17-store.XXXXXX) +trap 'rm -rf "$scratch"' EXIT +rm -rf "$scratch/db" +cat > "$scratch/p.eigs" <<'EOF' +s is store_open of (env_get of "R17_STORE_PATH") +k is store_put of [s, "c", {"v": 1234567890123456, "f": 0.1 + 0.2, "t": 9007199254740991}] +r is store_get of [s, "c", 1] +print of [r["v"] == 1234567890123456, r["f"] == 0.1 + 0.2, r["t"] == 9007199254740991] +store_close of s +EOF +R17_STORE_PATH="$scratch/db" "$bin" "$scratch/p.eigs" diff --git a/tests/phase2/rows/N4.div-always-float.eigs b/tests/phase2/rows/N4.div-always-float.eigs new file mode 100644 index 000000000..84c3f3629 --- /dev/null +++ b/tests/phase2/rows/N4.div-always-float.eigs @@ -0,0 +1,7 @@ +# ROW: N4.div-always-float +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [7 / 2, 6 / 2, num_type of (6 / 2)] diff --git a/tests/phase2/rows/N4.div-always-float.out b/tests/phase2/rows/N4.div-always-float.out new file mode 100644 index 000000000..e4dcdb274 --- /dev/null +++ b/tests/phase2/rows/N4.div-always-float.out @@ -0,0 +1 @@ +[3.5, 3.0, "float"] diff --git a/tests/phase2/rows/N4.fn-div-float.eigs b/tests/phase2/rows/N4.fn-div-float.eigs new file mode 100644 index 000000000..f26e241c1 --- /dev/null +++ b/tests/phase2/rows/N4.fn-div-float.eigs @@ -0,0 +1,15 @@ +# ROW: N4.fn-div-float +# ITEMS: N4 +# EXPECT-RC: 0 +# SHAPE: F +# WITNESS: fn-stop d DIV +# OPS: DIV +define d(a, b) as: + t is a / b + return t +r is null +i is 0.0 +loop while i < 60.0: + r is d of [6, 2] + i is i + 1.0 +print of r diff --git a/tests/phase2/rows/N4.fn-div-float.out b/tests/phase2/rows/N4.fn-div-float.out new file mode 100644 index 000000000..9f55b2ccb --- /dev/null +++ b/tests/phase2/rows/N4.fn-div-float.out @@ -0,0 +1 @@ +3.0 diff --git a/tests/phase2/rows/N5.leaf-buffer-index.eigs b/tests/phase2/rows/N5.leaf-buffer-index.eigs new file mode 100644 index 000000000..db9e76b58 --- /dev/null +++ b/tests/phase2/rows/N5.leaf-buffer-index.eigs @@ -0,0 +1,10 @@ +# ROW: N5.leaf-buffer-index +# ITEMS: N5 +# EXPECT-RC: 0 +# SHAPE: L +# WITNESS: leaf-gen bat +# OPS: INDEX_GET +define bat(b, i) as: + return b[i] +b is buffer of 3 +print of (bat of [b, 1]) diff --git a/tests/phase2/rows/N5.leaf-buffer-index.out b/tests/phase2/rows/N5.leaf-buffer-index.out new file mode 100644 index 000000000..ba66466c2 --- /dev/null +++ b/tests/phase2/rows/N5.leaf-buffer-index.out @@ -0,0 +1 @@ +0.0 diff --git a/tests/phase2/rows/N6.float-repr.eigs b/tests/phase2/rows/N6.float-repr.eigs new file mode 100644 index 000000000..0fbe3afa4 --- /dev/null +++ b/tests/phase2/rows/N6.float-repr.eigs @@ -0,0 +1,7 @@ +# ROW: N6.float-repr +# ITEMS: N6 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [3.0, 1e3, -0.0, 0.1 + 0.2, 1e15, 1e16, 1e-05, 0.0001] diff --git a/tests/phase2/rows/N6.float-repr.out b/tests/phase2/rows/N6.float-repr.out new file mode 100644 index 000000000..213c53546 --- /dev/null +++ b/tests/phase2/rows/N6.float-repr.out @@ -0,0 +1 @@ +[3.0, 1000.0, -0.0, 0.30000000000000004, 1000000000000000.0, 1e+16, 1e-05, 0.0001] diff --git a/tests/phase2/rows/N6.int-exact-digits.eigs b/tests/phase2/rows/N6.int-exact-digits.eigs new file mode 100644 index 000000000..290f0c3bf --- /dev/null +++ b/tests/phase2/rows/N6.int-exact-digits.eigs @@ -0,0 +1,7 @@ +# ROW: N6.int-exact-digits +# ITEMS: N6 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +print of [9007199254740993, -9223372036854775807 - 1] diff --git a/tests/phase2/rows/N6.int-exact-digits.out b/tests/phase2/rows/N6.int-exact-digits.out new file mode 100644 index 000000000..182de25c9 --- /dev/null +++ b/tests/phase2/rows/N6.int-exact-digits.out @@ -0,0 +1 @@ +[9007199254740993, -9223372036854775808] diff --git a/tests/phase2/rows/N6.neg-zero-literal-dedup.eigs b/tests/phase2/rows/N6.neg-zero-literal-dedup.eigs new file mode 100644 index 000000000..933f2be95 --- /dev/null +++ b/tests/phase2/rows/N6.neg-zero-literal-dedup.eigs @@ -0,0 +1,9 @@ +# ROW: N6.neg-zero-literal-dedup +# ITEMS: N6 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +a is 0.0 +b is -0.0 +print of [a, b] diff --git a/tests/phase2/rows/N6.neg-zero-literal-dedup.out b/tests/phase2/rows/N6.neg-zero-literal-dedup.out new file mode 100644 index 000000000..c3b782610 --- /dev/null +++ b/tests/phase2/rows/N6.neg-zero-literal-dedup.out @@ -0,0 +1 @@ +[0.0, -0.0] diff --git a/tests/phase2/rows/N6.str-fstring.eigs b/tests/phase2/rows/N6.str-fstring.eigs new file mode 100644 index 000000000..2f71047e2 --- /dev/null +++ b/tests/phase2/rows/N6.str-fstring.eigs @@ -0,0 +1,8 @@ +# ROW: N6.str-fstring +# ITEMS: N6 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +x is 2.0 +print of [str of x, f"{x}", str of 2] diff --git a/tests/phase2/rows/N6.str-fstring.out b/tests/phase2/rows/N6.str-fstring.out new file mode 100644 index 000000000..9984edbf8 --- /dev/null +++ b/tests/phase2/rows/N6.str-fstring.out @@ -0,0 +1 @@ +["2.0", "2.0", "2"] diff --git a/tests/phase2/rows/T1.twice-float.out b/tests/phase2/rows/T1.twice-float.out new file mode 100644 index 000000000..4db12f306 --- /dev/null +++ b/tests/phase2/rows/T1.twice-float.out @@ -0,0 +1,6 @@ +tapes identical +replay identical +A 0 x=3.0 +A 0 y=0.30000000000000004 +A 0 z=-0.0 +A 0 w=0.1 diff --git a/tests/phase2/rows/T1.twice-float.sh b/tests/phase2/rows/T1.twice-float.sh new file mode 100644 index 000000000..2b1bed0db --- /dev/null +++ b/tests/phase2/rows/T1.twice-float.sh @@ -0,0 +1,33 @@ +# ROW: T1.twice-float +# ITEMS: T1 +# EXPECT-RC: 0 +# SHAPE: S +# WITNESS: none +# OPS: +# TIERS: off default osr +set -eu +bin=$1 +scratch=$(mktemp -d /tmp/eigs-r17-tape.XXXXXX) +trap 'rm -rf "$scratch"' EXIT +cd "$scratch" +rm -f t1.tape t2.tape +cat > p.eigs <<'EOF' +x is 3.0 +y is 0.1 + 0.2 +z is -0.0 +w is 0.1 +print of [x, y, z, w] +EOF +"$bin" p.eigs > live.out +EIGS_TRACE=t1.tape "$bin" p.eigs > record.out +EIGS_TRACE=t2.tape "$bin" p.eigs > record2.out +cmp t1.tape t2.tape +cmp live.out record.out +cmp live.out record2.out +printf 'tapes identical +' +EIGS_REPLAY=t1.tape EIGS_REPLAY_STRICT=1 "$bin" p.eigs > replay.out +cmp live.out replay.out +printf 'replay identical +' +sed -n '/^A [0-9][0-9]* x=/p; /^A [0-9][0-9]* y=/p; /^A [0-9][0-9]* z=/p; /^A [0-9][0-9]* w=/p' t1.tape diff --git a/tests/test_db_params.c b/tests/test_db_params.c index ca8c4e377..9143ec65c 100644 --- a/tests/test_db_params.c +++ b/tests/test_db_params.c @@ -41,7 +41,26 @@ int main(void) { "a dict parameter still raises"); eigs_clear_error(); val_decref(bad); + /* R1.7 N6/N14: exact int digits and Python-repr float text. */ + Value *numbers = make_list(8); + list_append_owned(numbers, make_str("select $1, $2, $3, $4, $5, $6, $7")); + list_append_owned(numbers, make_int(1234567)); + list_append_owned(numbers, make_int(INT64_C(9007199254740993))); + list_append_owned(numbers, make_float(0.1 + 0.2)); + list_append_owned(numbers, make_float(3.0)); + list_append_owned(numbers, make_float(-0.0)); + list_append_owned(numbers, make_float(0.1)); + list_append_owned(numbers, make_int(INT64_MIN)); + const char *expected[] = {"1234567", "9007199254740993", + "0.30000000000000004", "3.0", "-0.0", "0.1", "-9223372036854775808"}; + ok = db_build_query(numbers, &sql, &n, params, numbuf, types); + for (int i = 0; i < 7; i++) { + char label[96]; + snprintf(label, sizeof(label), "N6/N14 parameter %d: %s", i + 1, expected[i]); + check(ok && n == 7 && strcmp(params[i], expected[i]) == 0 && types[i] == 0, label); + } + val_decref(numbers); eigs_close(st); - printf("db params: %d passed, %d failed (7 declared)\n", passed, failed); - return failed || passed != 7; + printf("db params: %d passed, %d failed (14 declared)\n", passed, failed); + return failed || passed != 14; } diff --git a/tools/phase2_check.py b/tools/phase2_check.py index d5deb0f5d..20f18fcef 100755 --- a/tools/phase2_check.py +++ b/tools/phase2_check.py @@ -177,7 +177,12 @@ def parse_map(path): bad.append('MAP:%d: `%s`: a control must be marked (control), and only a control' % (n, rid)) row['kind'] = 'control' if ctl else 'gate' if rid.startswith('gate.') else 'row' if rnd: - parts = rnd.split('/') + round_text, *qualifiers = [part.strip() for part in rnd.split(',')] + if qualifiers not in ([], ['invariant']) or (qualifiers and row['kind'] != 'row'): + bad.append('MAP:%d: `%s` has invalid round qualifiers [%s]' % (n, rid, rnd)) + continue + row['invariant'] = qualifiers == ['invariant'] + parts = round_text.split('/') if any(p not in ROUNDS for p in parts): bad.append('MAP:%d: `%s` names an unknown round [%s]' % (n, rid, rnd)) continue @@ -504,19 +509,27 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): cnt = {t: dict(examined=0, tag_fail=0, branch_pass=0, vacuous=0, tag_timeout=0, tag_signal=0) for t in TIERS} ctl_n = ctl_both = witnessed = ctl_witnessed = ctl_vacuous = 0 + invariant_n = invariant_pass = 0 for r, p, h, (row_tag, row_branch) in todo: want = read_text(p.rsplit('.', 1)[0] + '.out') want_rc = int(h.get('EXPECT-RC', '0')) tiers = h.get('TIERS', ' '.join(TIERS)).split() + if not tiers or len(tiers) != len(set(tiers)) or any(t not in TIERS for t in tiers): + bad.append('%s: invalid or empty TIERS' % p) + continue is_ctl = r['kind'] == 'control' + is_invariant = r.get('invariant', False) passes = {} for t in tiers: res = {} - for who, b in (('tag', row_tag), ('branch', row_branch)): + # R1.7-D3: invariants preserve the landed branch contract. The + # v0.46 anchor predates ints; base-green is separately preregistered. + arms = [('branch', row_branch)] if is_invariant else [('tag', row_tag), ('branch', row_branch)] + for who, b in arms: rc, so, se = run(b, p, TIER_ENV[t], scratch) res[who] = (rc == want_rc and so == want, rc) passes[t] = res - if is_ctl: + if is_ctl or is_invariant: continue c = cnt[t] c['examined'] += 1 @@ -533,6 +546,20 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): ' TIMEOUT' if rc_br == 124 else ' SIGNAL' if rc_br >= 128 else '')) if ok_tag: out(' TAG-PASS %s tier=%s: the row does not fail on the tag' % (r['id'], t)) + if is_invariant: + invariant_n += 1 + if all(res['branch'][0] for res in passes.values()): + invariant_pass += 1 + else: + out(' INVARIANT-FAIL %s: %s' % (r['id'], passes)) + if r['witness']['kind'] != 'none' and all(res['branch'][0] for res in passes.values()): + holds, ev = witness(row_branch, p, r['witness'], scratch) + if not holds: + invariant_pass -= 1 + out(' INVARIANT-VACUOUS %s [%s]' % (r['id'], ev)) + else: + out(' INVARIANT-WITNESS %s [%s]' % (r['id'], ev)) + continue if is_ctl: ctl_n += 1 if all(v[0] for res in passes.values() for v in res.values()): @@ -569,9 +596,10 @@ def check(map_rows, rows_dir, ctl_dir, tag, branch, through, scratch, out): out('controls=%d both_pass=%d witnessed=%d mapped=%d gates=%d through=%s' % ( ctl_n, ctl_both, witnessed, len(landed), len(gates), through)) out('controls_witnessed=%d controls_vacuous=%d' % (ctl_witnessed, ctl_vacuous)) + out('invariants=%d branch_pass=%d' % (invariant_n, invariant_pass)) rows_ok = all(c['examined'] == c['tag_fail'] == c['branch_pass'] > 0 and c['vacuous'] == 0 for c in cnt.values()) - return (not bad, rows_ok, ctl_n == ctl_both and ctl_vacuous == 0, len(landed), cnt, witnessed) + return (not bad, rows_ok, ctl_n == ctl_both and ctl_vacuous == 0 and invariant_n == invariant_pass, len(landed), cnt, witnessed) # ---- mechanical gates ---------------------------------------------------------- @@ -711,6 +739,8 @@ def mechanical(through, baseline, branch, out, smi_trap=None, tag=None): gates.append('net-byte-boundary') if ROUNDS.index(through) >= ROUNDS.index('R1.6z'): gates.append('embed-buffer-get-raw') + if ROUNDS.index(through) >= ROUNDS.index('R1.7'): + gates.extend(('const-dedup-bits', 'db-param-exact')) for g in gates: if g == 'int-source': res[g] = int_source(os.path.join(ROOT, 'src'), out, through) @@ -756,6 +786,12 @@ def mechanical(through, baseline, branch, out, smi_trap=None, tag=None): res[g], text = tool(['bash', 'tools/phase2_readers.sh', 'release', 'embed_buffer_get_raw'], out, r'.*') res[g] = res[g] and len(re.findall( r'^phase2-embed-buffer-get: PASS variant=release$', text, re.M)) == 1 + elif g == 'const-dedup-bits': + res[g], text = tool(['bash', 'tools/phase2_readers.sh', 'release', 'const_dedup_bits'], out, r'.*') + res[g] = res[g] and len(re.findall(r'^phase2-const-dedup: PASS variant=release$', text, re.M)) == 1 + elif g == 'db-param-exact': + res[g], text = tool(['bash', '-c', 'make db-params-test && build/server-db/test_db_params'], out, r'.*') + res[g] = res[g] and len(re.findall(r'^db params: 14 passed, 0 failed \(14 declared\)$', text, re.M)) == 1 elif g == 'builtins-table': if not tag: out(' builtins-table: needs the tag binary') diff --git a/tools/phase2_readers.sh b/tools/phase2_readers.sh index 30081569e..5ec467fe5 100755 --- a/tools/phase2_readers.sh +++ b/tools/phase2_readers.sh @@ -7,6 +7,7 @@ FIXTURE=${2:-readers} LABEL=phase2-readers case "$FIXTURE" in readers) ;; + const_dedup_bits) LABEL=phase2-const-dedup ;; q7_readers) LABEL=phase2-q7-readers ;; gfx_audio_boundary) LABEL=phase2-gfx-audio ;; gfx_byte_boundary) LABEL=phase2-gfx-byte ;; @@ -39,6 +40,12 @@ fi cat "$TMP/out" if [ -s "$TMP/err" ]; then cat "$TMP/err"; fail 'reader fixture wrote stderr'; fi [ "$rc" -eq 0 ] || fail "reader fixture rc=$rc" +if [ "$FIXTURE" = const_dedup_bits ]; then + [ "$(grep -cE '^phase2-const-dedup-test: PASS checks=8 failures=0$' "$TMP/out")" -eq 1 ] || fail 'missing unique complete const dedup PASS' + [ "$(wc -l < "$TMP/out" | tr -d ' ')" -eq 1 ] || fail 'unexpected const dedup output' + echo "$LABEL: PASS variant=$VARIANT" + exit 0 +fi if [ "$FIXTURE" = embed_buffer_get_raw ]; then [ "$(grep -cE '^phase2-embed-buffer: PASS checks=36 failures=0$' "$TMP/out")" -eq 1 ] || fail 'missing unique complete getter PASS' [ "$(wc -l < "$TMP/out" | tr -d ' ')" -eq 1 ] || fail 'unexpected getter output' From 971eb2ed0369883f876a737959ddf9c8cc19f987 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 25 Oct 2026 11:19:33 -0500 Subject: [PATCH 179/188] feat(numbers): use N6 shortest float text across display and JSON Python repr actual C oracle42579/42579 patterns;54 pinned cases1038checks green; independent critic4202/4202 extra boundary cases. D2:7 frozen probes,6 amendments,16floatpayloads; live base/tip kind witnesses and11negative checker controls green. All238 doc examples green;34 observed output blocks and legacy MAP/suite text pins move with N6. Fixed-decimal format.fmt_num preserves3.14. Shared-writer census beforeedit; shape closure reviewed and planted; freestanding exact writer oracle green. Cost explicit --n6-text comparator has6positive/15negativecontrols; corpus remains exact. First full release inventory red is retained; final full train follows all runtime groups. Reviewed amendment (continuation 2, #1758): preserve the changelog entry on one line, prefix it with "- ", and retain its final newline. D2 is a one-time frozen-text proof; list the checker as local-only and remove its existing recurring phase2 dispatch. The frozen bar continues to SHA-pin the accepted amendments; future amendments need a new ruling. Requested checks in the checkpoint bank (all rc=0): PASS: test-enrolment: examined=129 enrolled=128 exempt=1; tools examined=77 enrolled=56 exempt=21 changelog: examined 99 changed path(s) against b6f9db3879be5578de787ad6cf0d235b809f0e7c; 1 fragment(s) added; cut=0 checks=7 Only these three checks ran; the orchestrator owns train.py. Source fingerprint: 32340700adaf48890a9884b2e61acee2336b7be2677ab6f5e6f9bcfdbcfb5e55 Continuation 3 calibration repair (#1758, N6): float ADD 1.5+2.5 prints 4.0; change only cal.fnstop-cat-plant.out from 4 to 4.0. The stale output failed all four tiers before the unchanged fn-stop ADD witness could run. Real row check before: vacuous=0, named=false, branch_pass=0/4; after: vacuous=1 in each tier, named=true, branch_pass=4/4. Native RETURN remains the deliberate wrong witness; the calibration still requires (1, True). No check or witness weakened. Requested public selftest rows in /tmp/es-r17-checkpoints, actual rc=0: make-lock selftest: 8/8 passed calibration: cases=54 as-expected=54 unexpected=0 All six clean-apply/tree/manifest checkpoint proofs and refreshed bundle extraction recorded in continue3-checkpoint-proof.json. The post-check amendment changes commit metadata only; tested trees are identical. Source fingerprint: 596b197d7775d094297d85265323f5ee14b8c8df73d76287843f612fa3c97152 Continuation 4, R1.7-D5 (#1758): json_build/json_encode close in R1.7; their and str changes_vs_pre derive yes (exactly five builtins.tsv cells). R1.7 closures reuse D2 source-bound kinds and check_pair on every pre/branch line; earlier A2 closures still require pre==branch. Declare R1.7 landed and check its closures against branch independently of their R1.6 group. No probe or expectation changed. Mandatory STOP: only the first tools/phase2_builtins.sh invocation ran, with release primary, matched extension binaries and PostgreSQL. The metadata/closure phase examined=310 section6=310 inventory=310 rowmeta=310 cases=312; guarded=217 yes=199 closed_in=18 pending_profile=0 vacuous=0; closure-r17 cases=2 floats=4; ran=312 requested=312 empty_or_hookless=62 hook_runs=14 pending_profile=0. Actual live gate rc=2 with 62 additional .branch output differences (empty_or_hookless=62), including acos 0 -> 0.0, add buffer 2 -> 2.0 and num integral floats. These are outside D5. No other frozen expectation was amended. Remaining three primary profiles and both planned public-entry plants were NOT RUN because the ruling says any other flag is a STOP. No precheck, suite, broad gate or final train launched. Receipts: continue4-checks.json. Six fresh clean-apply checkpoint trees and refreshed bundle extraction: continue4-checkpoint-proof.json. This commit is a checkpoint-only candidate, not green acceptance. Final acceptance remains pending. Source fingerprint: 78f076b25442a0577801ec1859f62dd6fb58c1cda2820c23f34203978ca4bb9d Continuation 5, R1.7-D6 (#1758), supersedes the historical D5 STOP above. Derive the union from the public gate's own four-profile transcripts: each profile examined 312 cases and found the same 62 new differences; cumulative D2/D6 population=68. Remove NAMES; prove every line, same double bits, integer spelling, all non-number bytes. 205 float tokens; source-bound kinds run on pre-N6 and all four tips; numeric-looking input strings have source-bound str witnesses and stay byte-identical. Frozen programs unchanged. All 68 cumulative amendments are SHA-pinned under D6, historical numeric rulings retained. Metadata: 33 derived changes_vs_pre cells; no additional already-closed rows among the new 62, so the two D5 R1.7 closures remain. D5 A2 scope retained. Public gate now checks every amended row with the shared D2 comparator, including unclosed rows. Flush parent stdout before launching the probe child so expanded SHA records cannot splice the runner summary; final profile logs each have one complete anchored ran= line. Actual public gate results: four profiles rc=0; each examined=310 section6=310 inventory=310 rowmeta=310 cases=312; guard guarded=217 yes=199 closed_in=18 pending_profile=0 vacuous=0; closure-r17 cases=2 floats=4; ran=312 requested=312 empty_or_hookless=0 hook_runs=14 pending_profile=0; phase2-builtins PASS rows=310 migrated=310 unchanged=0. Three isolated public-entry plants each actual rc=1 and only the named failure: json_build.pre a->z rejected as non-float text; abs.pre integer->float (derived flag synced) rejected by A2; acos.branch 0.0->1.0 (accepted SHA synced) rejected as changed double bits. Checker calibration positive=1 rejected=11 PASS. Receipts: continue5-population.json, continue5-amendment-proof.json, continue5-checks.json. Six fresh clean-apply trees and verified/extracted bundle: continue5-checkpoint-proof.json. This is checkpoint acceptance for D6; the complete final train remains pending and was NOT RUN. Source fingerprint: cdb82bb25958a59b981dd5c5d20d2f09bb2a6a7b68b6f356fef515b1f3408beb Continuation 6, R1.7-D7 (#1758, N6): explicitly attribute two retained corpus process-exit changes to this group's own expectation migration (historical abd76f98). test_boxed_int_containers.eigs: base Error line 13 ASSERT FAIL: sort exact order, module line 102; moved float spellings 140737488355328.0 and 9007199254740992.0. test_json_hard.eigs: base Error line 417 ASSERT FAIL: JH97 json_build renders huge values compactly; moved expectation {"v": 1230000000000000.0}. Each retained base arm exits 1, each tip arm exits 0. corpus-attribution-reviewed.json records the D7 authority, exact assertions, baseline diagnostics, original expectation diff and evidence hashes; the existing reviewed-attribution hook produces corpus-attribution-extra.json. General automatic refusal of process-exit changes is untouched. D7 narrow checkpoint proofs (all requested commands rc=0): tier=off examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=default examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=osr examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=trace examined=105 rows tag_fail=105 branch_pass=105 vacuous=0 tag_timeout=0 tag_signal=0 controls=18 both_pass=18 witnessed=31 mapped=113 gates=8 through=R1.7 controls_witnessed=13 controls_vacuous=0 invariants=2 branch_pass=2 phase2-check: PASS RESULTS: 2/2 passed, 0 failed, 0 skipped Corpus attribution: 55 observed row explanations; 0 require judgment. Full evidence retained. Corpus adjudicated: 55 differences traced to R1.7 behavior/registration; sole expected runaway timeout; no other crash/timeout. Evidence: continue6-checks.json; sweep: continue6-sweep.json/.md; six clean-apply clones and verified extracted bundle: continue6-checkpoint-proof.json. Full train pending; not launched in continuation 6. Source fingerprint: ba0bd12bbd1a933ddf8540411388e5b4f1a78211cd78014d64f12a45923a859f Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- Makefile | 3 + README.md | 18 +- changes/changed/1758-number-text.md | 1 + docs/BUILTINS.md | 8 + docs/COMPARISON.md | 18 +- docs/CONCURRENCY.md | 3 +- docs/SPEC.md | 52 +- docs/STDLIB.md | 14 +- docs/SYNTAX.md | 12 +- docs/design/phase2-inventory.txt | 41 +- docs/llms.txt | 16 +- lib/format.eigs | 3 + src/chunk.c | 7 +- src/eigenscript.c | 117 +- src/freestanding/mini_fmt.c | 2 + .../arming_mt_fixtures/arming_mt_st.expected | 2 +- tests/enrolment_exemptions.txt | 1 + tests/phase2/builtins/builtins.tsv | 72 +- tests/phase2/builtins/builtins/acos.branch | 2 +- tests/phase2/builtins/builtins/add.branch | 2 +- tests/phase2/builtins/builtins/asin.branch | 2 +- tests/phase2/builtins/builtins/atan.branch | 2 +- .../builtins/builtins/audio_gain.branch | 2 +- .../phase2/builtins/builtins/audio_mix.branch | 2 +- .../phase2/builtins/builtins/buf_copy.branch | 4 +- .../builtins/builtins/buf_deinterleave.branch | 4 +- tests/phase2/builtins/builtins/buf_dot.branch | 4 +- .../phase2/builtins/builtins/buf_fill.branch | 4 +- .../builtins/builtins/buf_from_list.branch | 2 +- .../builtins/builtins/buf_from_pcm16le.branch | 4 +- tests/phase2/builtins/builtins/buf_get.branch | 4 +- tests/phase2/builtins/builtins/buf_mix.branch | 4 +- .../phase2/builtins/builtins/buf_peak.branch | 4 +- .../builtins/buf_resample_linear.branch | 2 +- .../builtins/builtins/buf_scale_range.branch | 4 +- tests/phase2/builtins/builtins/buf_set.branch | 4 +- .../builtins/builtins/buf_to_pcm16le.branch | 2 +- .../phase2/builtins/builtins/copy_into.branch | 2 +- tests/phase2/builtins/builtins/cos.branch | 2 +- tests/phase2/builtins/builtins/divide.branch | 2 +- tests/phase2/builtins/builtins/dot.branch | 2 +- tests/phase2/builtins/builtins/exp.branch | 2 +- .../builtins/builtins/f64_from_bytes.branch | 2 +- tests/phase2/builtins/builtins/fround.branch | 4 +- tests/phase2/builtins/builtins/gather.branch | 2 +- tests/phase2/builtins/builtins/get_at.branch | 2 +- tests/phase2/builtins/builtins/join.branch | 2 +- .../builtins/builtins/json_build.branch | 2 +- .../builtins/builtins/json_decode.branch | 2 +- .../builtins/builtins/json_encode.branch | 2 +- .../builtins/builtins/leaky_relu.branch | 2 +- tests/phase2/builtins/builtins/log.branch | 2 +- tests/phase2/builtins/builtins/matmul.branch | 2 +- .../phase2/builtins/builtins/matmul_at.branch | 2 +- .../phase2/builtins/builtins/matmul_bt.branch | 2 +- tests/phase2/builtins/builtins/max.branch | 2 +- tests/phase2/builtins/builtins/mean.branch | 2 +- tests/phase2/builtins/builtins/min.branch | 2 +- tests/phase2/builtins/builtins/norm.branch | 2 +- tests/phase2/builtins/builtins/num.branch | 6 +- .../builtins/builtins/numerical_grad.branch | 2 +- .../builtins/numerical_grad_cols.branch | 4 +- .../builtins/numerical_grad_rows.branch | 4 +- tests/phase2/builtins/builtins/observe.branch | 2 +- tests/phase2/builtins/builtins/pow.branch | 2 +- .../builtins/builtins/ppu_render_frame.branch | 4 +- tests/phase2/builtins/builtins/print.branch | 2 +- .../builtins/builtins/proc_read_buf.hi.branch | 2 +- .../builtins/builtins/read_bytes_buf.branch | 2 +- tests/phase2/builtins/builtins/relu.branch | 4 +- .../builtins/builtins/scatter_add.branch | 4 +- tests/phase2/builtins/builtins/set_at.branch | 2 +- .../builtins/builtins/sgd_update.branch | 2 +- .../builtins/builtins/sgd_update_cols.branch | 4 +- .../builtins/builtins/sgd_update_rows.branch | 4 +- tests/phase2/builtins/builtins/sin.branch | 2 +- tests/phase2/builtins/builtins/sqrt.branch | 2 +- tests/phase2/builtins/builtins/str.branch | 2 +- .../builtins/builtins/stream_write.branch | 2 +- tests/phase2/builtins/builtins/tan.branch | 2 +- .../builtins/builtins/tensor_load.branch | 2 +- .../builtins/builtins/tensor_save.branch | 2 +- .../builtins/text_builder_append.branch | 2 +- tests/phase2/builtins/builtins/write.branch | 2 +- tests/phase2/builtins/builtins/zeros.branch | 2 +- .../builtins/builtins/zeros_like.branch | 4 +- tests/phase2/builtins/make_table.py | 42 +- tests/phase2/builtins/rowmeta.tsv | 4 +- tests/phase2/builtins/run_probes.sh | 14 +- tests/phase2/builtins_changes.md | 222 +- tests/phase2/builtins_landed.txt | 3 +- tests/phase2/calib/cal.fnstop-cat-plant.out | 2 +- tests/phase2/num_text.c | 120 + tests/phase2/r17_float_text.json | 4280 +++++++++++++++++ .../phase2/rows/N13.vm-buffer-index-data.out | 12 +- .../rows/N13.vm-buffer-int-index-data.out | 12 +- tests/phase2/rows/N13.vm-buffer-iter-data.out | 12 +- .../rows/N13.vm-buffer-leaf-index-data.out | 12 +- .../rows/N13.vm-buffer-local-index-data.out | 12 +- .../N4.compound-float-floordiv-boundaries.out | 2 +- tests/phase2/rows/N4.compound-floordiv.out | 2 +- .../rows/N4.float-floordiv-rounding.out | 2 +- .../rows/N4.float-floordiv-underflow.out | 2 +- tests/phase2/rows/N4.floordiv.out | 2 +- .../rows/N4.fn-float-floordiv-rounding.out | 2 +- .../rows/N4.fn-float-floordiv-underflow.out | 2 +- tests/phase2/rows/N4.fn-floordiv.out | 2 +- tests/phase2/slot_layer.c | 6 +- tests/roads/native_alternate.out | 6 +- tests/roads/native_catch.out | 6 +- tests/roads/native_inline.out | 4 +- tests/roads/native_late.out | 6 +- tests/roads/native_match.out | 6 +- tests/roads/native_outer.out | 6 +- tests/run_all_tests.sh | 30 +- tests/strict_shape_cases.json | 6 +- tests/test_boxed_int_containers.eigs | 2 +- tests/test_buffer_nonfinite_read.out | 2 +- tests/test_builtin_overflow.sh | 2 +- tests/test_corpus_ints.sh | 8 +- tests/test_json_hard.eigs | 11 +- tests/test_lint.sh | 4 +- tests/test_native_fn.c | 2 +- tests/test_read_bytes_cap.sh | 2 +- tests/test_replay.sh | 4 +- tests/test_sandbox_intern_lifetime.c | 4 +- tests/test_strict_math.sh | 12 +- tools/phase2_builtins.sh | 1 + tools/phase2_cost.sh | 134 +- tools/phase2_float_amend.py | 344 ++ tools/phase2_readers.sh | 7 + tools/selftests.txt | 2 + 132 files changed, 5618 insertions(+), 330 deletions(-) create mode 100644 changes/changed/1758-number-text.md create mode 100644 tests/phase2/num_text.c create mode 100644 tests/phase2/r17_float_text.json create mode 100644 tools/phase2_float_amend.py diff --git a/Makefile b/Makefile index bc154680e..9fb449856 100644 --- a/Makefile +++ b/Makefile @@ -287,6 +287,9 @@ build/phase2/embed_buffer_get_raw_%: tests/phase2/embed_buffer_get_raw.c build/p # Q7 lands in R1.6e; an absent source is a build failure once selected. build/phase2/q7_readers_%: tests/phase2/q7_readers.c build/phase2/eigenscript_all.c tools/werror_flags.txt $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread +# N6: actual shared writer plus Python repr/bit/truncation oracle cases. +build/phase2/num_text_%: tests/phase2/num_text.c build/phase2/eigenscript_all.c tools/werror_flags.txt + $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread # R1.7-D4: signed-zero constant keys are compared by bits. build/phase2/const_dedup_bits_%: tests/phase2/const_dedup_bits.c build/phase2/eigenscript_all.c tools/werror_flags.txt $(CC) $(PHASE2_SLOT_FLAGS_$*) -Ibuild/phase2 -o $@ $< -lm -lpthread diff --git a/README.md b/README.md index 106bb2006..ac56e2493 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ Hello hello, x is 42 positive Alice 15 -Error: {"kind": "undefined_name", "message": "undefined variable 'risky_operation'", "line": 41} +Error: {"kind": "undefined_name", "message": "undefined variable 'risky_operation'", "line": 41.0} ``` Comparisons, `not` and predicates return `true`/`false`, a `bool`. A bool is @@ -257,7 +257,7 @@ print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ```output [-4, -4, 2, -2, 0.5] ["int", "float"] -[9, 9, -1, 9, "float"] +[9.0, 9.0, -1.0, 9.0, "float"] ``` ### Ask Your Code @@ -296,7 +296,7 @@ print of (when is signal) ``` ```output 15 -3 +3.0 ``` (`how` is the sixth interrogative; see the observer guide for its current @@ -549,12 +549,18 @@ TCP handles, ports and sent-byte counts are integers. Numeric socket handles, po `http_early_bind` and `http_serve` require an exact integer port in 0..65535; integral floats convert and port zero requests an ephemeral port. Fractional or out-of-range ports raise `value` before binding. `shared_delete` and `shared_size` return integer counts. +N6 prints each float with Python's shortest round-trip spelling: integral +floats retain `.0`, negative zero is `-0.0`, and scientific notation starts +below `1e-4` or at `1e16`. Ints keep their exact decimal digits. `print`, +`write`, `str`, f-strings and JSON share the number writer. The executed +examples are `tests/phase2/rows/N6.float-repr.eigs` and +`tests/phase2/rows/N6.str-fstring.eigs`. + The HTTP shared counter `shared_incr` follows numeric `+`: two int operands return an exact int and int64 overflow raises `value` without changing the stored counter (A). A missing counter starts at int zero. A float operand -produces a float. The stored operand is its JSON-decoded value; existing -float text stays until R1.7, so an integer-valued float may read back as an -int during this transition. Executable shared-counter examples in +produces a float. The stored operand is its JSON-decoded value; N6 preserves an +integer-valued float as a float by retaining its `.0`. Executable shared-counter examples in `tests/test_http.eigs` cover exact values, both overflow directions and the next operation after a raise. diff --git a/changes/changed/1758-number-text.md b/changes/changed/1758-number-text.md new file mode 100644 index 000000000..42e0e3ff9 --- /dev/null +++ b/changes/changed/1758-number-text.md @@ -0,0 +1 @@ +- Float text now uses Python-style shortest round-trip spelling across display, f-strings and JSON (N6), preserving integral float `.0` and signed zero. Integer text remains exact. diff --git a/docs/BUILTINS.md b/docs/BUILTINS.md index 950d4b6ce..96cb3e15c 100644 --- a/docs/BUILTINS.md +++ b/docs/BUILTINS.md @@ -45,6 +45,14 @@ audio (`audio_open`, `audio_close`, `audio_pause`, `audio_play`, `audio_capture_close`, `audio_stream_open`, `audio_stream_push`, `audio_stream_queued`, `audio_stream_clear`, `audio_stream_close`), and +N6 prints each float with Python's shortest round-trip spelling: integral +floats retain `.0`, negative zero is `-0.0`, and scientific notation starts +below `1e-4` or at `1e16`. Ints keep their exact decimal digits. `print`, +`write`, `str`, f-strings and JSON share the number writer. The executed +examples are `tests/phase2/rows/N6.float-repr.eigs` and +`tests/phase2/rows/N6.str-fstring.eigs`. + + ## Runtime status and control | Function | Usage | Description | diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index d99f4f693..4d7b0eed5 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -66,7 +66,7 @@ print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ```output [-4, -4, 2, -2, 0.5] ["int", "float"] -[9, 9, -1, 9, "float"] +[9.0, 9.0, -1.0, 9.0, "float"] ``` ## At a glance @@ -264,12 +264,18 @@ TCP handles, ports and sent-byte counts are integers. Numeric socket handles, po `http_early_bind` and `http_serve` require an exact integer port in 0..65535; integral floats convert and port zero requests an ephemeral port. Fractional or out-of-range ports raise `value` before binding. `shared_delete` and `shared_size` return integer counts. +N6 prints each float with Python's shortest round-trip spelling: integral +floats retain `.0`, negative zero is `-0.0`, and scientific notation starts +below `1e-4` or at `1e16`. Ints keep their exact decimal digits. `print`, +`write`, `str`, f-strings and JSON share the number writer. The executed +examples are `tests/phase2/rows/N6.float-repr.eigs` and +`tests/phase2/rows/N6.str-fstring.eigs`. + The HTTP shared counter `shared_incr` follows numeric `+`: two int operands return an exact int and int64 overflow raises `value` without changing the stored counter (A). A missing counter starts at int zero. A float operand -produces a float. The stored operand is its JSON-decoded value; existing -float text stays until R1.7, so an integer-valued float may read back as an -int during this transition. Executable shared-counter examples in +produces a float. The stored operand is its JSON-decoded value; N6 preserves an +integer-valued float as a float by retaining its `.0`. Executable shared-counter examples in `tests/test_http.eigs` cover exact values, both overflow directions and the next operation after a raise. @@ -549,7 +555,7 @@ catch e: ``` ```output caught: boom -caught: type_mismatch at line 7 +caught: type_mismatch at line 7.0 ``` The optional model extension also uses catchable `value` errors for context @@ -721,7 +727,7 @@ print of (e < 0.001) ```output 30 x -3 +3.0 20 true ``` diff --git a/docs/CONCURRENCY.md b/docs/CONCURRENCY.md index 2032c1727..122474a6d 100644 --- a/docs/CONCURRENCY.md +++ b/docs/CONCURRENCY.md @@ -109,7 +109,8 @@ buf_set of [b, 0, 1] cb is channel of 1 send of [cb, b] buf_set of [b, 0, 99] -row of ["buffer ", "1", str of (buf_get of [(recv of cb), 0])] +# N6: compare buffer contents numerically; float text retains .0. +row of ["buffer ", 1.0, buf_get of [(recv of cb), 0]] t is text_builder_new of null text_builder_append of [t, "a"] diff --git a/docs/SPEC.md b/docs/SPEC.md index ff8b81156..5213a9338 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -255,7 +255,7 @@ print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ```output [-4, -4, 2, -2, 0.5] ["int", "float"] -[9, 9, -1, 9, "float"] +[9.0, 9.0, -1.0, 9.0, "float"] ``` Numeric literals accept the usual decimal forms plus a leading or @@ -282,7 +282,7 @@ print of (abs of -5) 3.5 1 0.3333333333333333 -1024 +1024.0 5 ``` @@ -1002,12 +1002,18 @@ TCP handles, ports and sent-byte counts are integers. Numeric socket handles, po `http_early_bind` and `http_serve` require an exact integer port in 0..65535; integral floats convert and port zero requests an ephemeral port. Fractional or out-of-range ports raise `value` before binding. `shared_delete` and `shared_size` return integer counts. +N6 prints each float with Python's shortest round-trip spelling: integral +floats retain `.0`, negative zero is `-0.0`, and scientific notation starts +below `1e-4` or at `1e16`. Ints keep their exact decimal digits. `print`, +`write`, `str`, f-strings and JSON share the number writer. The executed +examples are `tests/phase2/rows/N6.float-repr.eigs` and +`tests/phase2/rows/N6.str-fstring.eigs`. + The HTTP shared counter `shared_incr` follows numeric `+`: two int operands return an exact int and int64 overflow raises `value` without changing the stored counter (A). A missing counter starts at int zero. A float operand -produces a float. The stored operand is its JSON-decoded value; existing -float text stays until R1.7, so an integer-valued float may read back as an -int during this transition. Executable shared-counter examples in +produces a float. The stored operand is its JSON-decoded value; N6 preserves an +integer-valued float as a float by retaining its `.0`. Executable shared-counter examples in `tests/test_http.eigs` cover exact values, both overflow directions and the next operation after a raise. @@ -1407,7 +1413,7 @@ catch e: print of e.line ``` ```output -4 +4.0 ``` This deliberately differs from temporal filing. There, the same statement's @@ -1428,7 +1434,7 @@ catch e: print of e.line ``` ```output -5 +5.0 ``` ```eigenscript @@ -1450,7 +1456,7 @@ print of "execution continues" caught: custom failure undefined_name undefined variable 'undefined_name' -7 +7.0 execution continues ``` @@ -1813,7 +1819,7 @@ print of (when is x) ```output 30 x -3 +3.0 ``` ```eigenscript fragment x=1 @@ -1935,7 +1941,7 @@ print of why is d ``` ```output true -0 +0.0 ``` **Function values are `opaque`** (#708). A function has no content the @@ -2096,7 +2102,7 @@ print of (why is x) ```output moving 2 -0 +0.0 ``` ```eigenscript @@ -2109,7 +2115,7 @@ print of (when is c) print of (what is c when 3) ``` ```output -4 +4.0 2 ``` @@ -2131,7 +2137,7 @@ print of (why is x) print of (report of x) ``` ```output -4 +4.0 0.21866976011171657 0.21866976011171657 moving @@ -2151,7 +2157,7 @@ print of (why is x) print of (report of x) ``` ```output -4 +4.0 0.08170416594551044 moving ``` @@ -2232,7 +2238,7 @@ print of (when is x) 0 20 10 -4 +4.0 ``` Every interrogative takes the qualifier: `who is x when 2`, `where is x when @@ -2557,7 +2563,7 @@ buffer 2.5 list -[[0, 0, 0], [0, 0, 0]] +[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] buffer ``` @@ -2613,7 +2619,7 @@ print of (sum of v) print of (norm of v) ``` ```output -10 +10.0 5.477225575051661 ``` @@ -2634,7 +2640,7 @@ b[3] is 3.5 print of (dot of [a, b]) ``` ```output -25 +25.0 ``` For the floating forms of these reductions (`sum`, `norm`, `dot`), the @@ -2705,7 +2711,7 @@ catch e: print of e["message"] ``` ```output -[3, 4] +[3.0, 4.0] index_range gather: column index 3 out of range for row 1 (cols 3) ``` @@ -2757,8 +2763,8 @@ print of (type of (add of [b, l])) print of (mean of b) ``` ```output -[1, 2, 3] -3 +[1.0, 2.0, 3.0] +3.0 buffer list 4.666666666666667 @@ -2779,8 +2785,8 @@ print of y[1] print of (shape of w) ``` ```output -4 -6 +4.0 +6.0 [2, 2] ``` diff --git a/docs/STDLIB.md b/docs/STDLIB.md index c7d62d1e6..3ec472b04 100644 --- a/docs/STDLIB.md +++ b/docs/STDLIB.md @@ -374,9 +374,9 @@ print of g[2] ``` ```output 3 -5 -7 -9 +5.0 +7.0 +9.0 ``` `x` is `[[1, 2, 3], [4, 5, 6]]` and `s` scales each column, so the gradient @@ -407,9 +407,9 @@ autograd.ag_sgd_step of [wn, 0.1] print of w[0] ``` ```output -7 -4 -6 +7.0 +4.0 +6.0 0.6 ``` @@ -1265,7 +1265,7 @@ print of (data.df_mean of [rows, "score"]) ```output 85.4 88 -80 +80.0 ``` ### lib/data.eigs diff --git a/docs/SYNTAX.md b/docs/SYNTAX.md index ef2cc0b9f..a2111cce9 100644 --- a/docs/SYNTAX.md +++ b/docs/SYNTAX.md @@ -247,7 +247,7 @@ catch err: print of f"Caught: {err}" ``` ```output -Caught: {"kind": "undefined_name", "message": "undefined variable 'items'", "line": 2} +Caught: {"kind": "undefined_name", "message": "undefined variable 'items'", "line": 2.0} ``` Errors inside a `try` block are caught and bound to the variable after @@ -507,8 +507,8 @@ print of (when is loss) # 3 — three assignments ```output 0.2 -0.26827341240613545 -0 -3 +0.0 +3.0 ``` Note that `why` tracks the *entropy* trajectory, not the raw value: a @@ -535,7 +535,7 @@ loss is 80.0 print of (prev of loss) # 100 — the value before the latest assign ``` ```output -100 +100.0 ``` Returns `null` when `x` has been assigned fewer than two times. Note @@ -561,7 +561,7 @@ print of (why is x at 2) # dH as of the line-2 assign ```output 2 2 -2 +2.0 x 0.9182958340544896 -0.08170416594551044 @@ -581,7 +581,7 @@ print of (when is total at 3) # 5 — all five assignments, seed included ``` ```output 6 -5 +5.0 ``` To pin a single iteration, record it yourself (`snapshots[i] is total`); diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index d5ba2474a..92c5eaada 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2120 classified=2120 unclassified=0 +examined=2125 classified=2125 unclassified=0 files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 # Retired (required absent): buf_num_arg -- R1.6z: bridge deleted; every caller migrated @@ -29,7 +29,7 @@ files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 (b) payload reads 593 RAW=123 READ=470 (c) producers 538 GUARD=75 PARSE=3 PRODUCE=433 TAGSET=9 WRITE=18 (d) JIT emitters and guards 125 EMIT=87 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 -(e) number formatting 18 CASE=2 FORMAT=3 PARSE=1 RAW=4 READ=3 TEST=5 +(e) number formatting 23 CASE=2 FORMAT=4 PARSE=1 RAW=8 READ=3 TEST=5 (f) equality, ordering and hashing 51 CASE=2 PRODUCE=4 RAW=15 READ=7 TEST=23 (g) tape encode and decode 37 CASE=4 DATA=5 PARSE=7 PRODUCE=8 RAW=6 READ=2 TEST=5 (h) JSON, store and db encoders 85 CASE=4 FORMAT=3 PARSE=5 PRODUCE=22 RAW=8 READ=24 TEST=19 @@ -54,10 +54,10 @@ slot_from_f64 44 slot_is_f64 44 eigs_int_arg 34 eigs_int_arg_range 34 +number 30 slot_is_smi 28 eigs_slot_float 27 buffer_read_f64 26 -number 26 eigs_number_arg 23 slot_f64_value 23 list_set_f64 22 @@ -74,9 +74,9 @@ eigs_geom_shape 10 eigs_slot_opt_float 9 num_to_i64_exact 9 eigs_byte_arg 8 +eigs_num_text 8 EIGS_NUM_MAX 7 eigs_bounded_arg 7 -eigs_num_text 7 eigs_list_bounded 6 eigs_list_magnitude 6 eigs_opt_int_range 6 @@ -176,9 +176,9 @@ trace.c 32 g=32 jit_smoke.c 31 d=31 lint.c 29 a=29 compiler.c 26 a=14 b=8 c=2 i=2 +chunk.c 25 a=4 e=9 f=12 value_slot.h 23 a=8 b=11 c=4 ext_net.c 22 a=4 b=11 c=7 -chunk.c 20 a=4 e=4 f=12 model_infer.c 18 a=2 b=7 c=9 ext_http.c 14 a=3 b=4 c=7 builtins_int.c 11 b=4 c=7 @@ -1415,11 +1415,16 @@ chunk.c:223 const_equal VAL_I64_RAW RAW f chunk.c:243 const_dedup_grow val_is_number TEST a chunk.c:252 chunk_add_constant_ex val_is_number TEST a chunk.c:431 chunk_disassemble VAL_FLOAT TEST e -chunk.c:432 chunk_disassemble VAL_F64_RAW RAW e -chunk.c:433 chunk_disassemble VAL_INT TEST e -chunk.c:434 chunk_disassemble VAL_I64_RAW RAW e -chunk.c:800 chunk_verify_impl VAL_INT TEST a -chunk.c:1107 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a +chunk.c:432 chunk_disassemble number RAW e +chunk.c:433 chunk_disassemble VAL_F64_RAW RAW e +chunk.c:433 chunk_disassemble eigs_num_text FORMAT e +chunk.c:433 chunk_disassemble number RAW e +chunk.c:433 chunk_disassemble number RAW e +chunk.c:434 chunk_disassemble number RAW e +chunk.c:436 chunk_disassemble VAL_INT TEST e +chunk.c:437 chunk_disassemble VAL_I64_RAW RAW e +chunk.c:803 chunk_verify_impl VAL_INT TEST a +chunk.c:1110 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a compiler.c:583 add_num_constant make_float PRODUCE c compiler.c:590 add_int_constant make_int PRODUCE c compiler.c:599 literal_index_u16 data.number RAW b @@ -1751,14 +1756,14 @@ eigenscript.c:3431 values_equal_impl VAL_I64_RAW RAW f eigenscript.c:3431 values_equal_impl VAL_I64_RAW RAW f eigenscript.c:3431 values_equal_impl VAL_INT CASE f eigenscript.c:3501 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3516 eigs_num_text strtod PARSE e -eigenscript.c:3526 value_to_string VAL_FLOAT CASE e -eigenscript.c:3527 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3527 value_to_string eigs_num_text FORMAT e -eigenscript.c:3530 value_to_string VAL_INT CASE e -eigenscript.c:3531 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4832 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4833 gc_value_is_node VAL_INT CASE a +eigenscript.c:3562 eigs_num_text strtod PARSE e +eigenscript.c:3617 value_to_string VAL_FLOAT CASE e +eigenscript.c:3618 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3618 value_to_string eigs_num_text FORMAT e +eigenscript.c:3621 value_to_string VAL_INT CASE e +eigenscript.c:3622 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4923 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4924 gc_value_is_node VAL_INT CASE a eigenscript.h:196 number RAW b eigenscript.h:214 AST_NUM DATA a eigenscript.h:240 number RAW b diff --git a/docs/llms.txt b/docs/llms.txt index 5f10a79c1..3c0413401 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -291,7 +291,7 @@ print of [1.0 // 0.1, 1 // 0.1, 1e-300 // -1e300, y, num_type of y] ```output [-4, -4, 2, -2, 0.5] ["int", "float"] -[9, 9, -1, 9, "float"] +[9.0, 9.0, -1.0, 9.0, "float"] ``` - Hex integer literals: `0xFF`, `0X10` (digits only). Hex-float forms @@ -421,7 +421,7 @@ print of (buf_get of [(recv of c), 0]) # the BUFFER copied ``` ```output [1, 2] -1 +1.0 ``` - The measured kind-by-kind table lives in docs/CONCURRENCY.md and is itself an @@ -561,12 +561,18 @@ TCP handles, ports and sent-byte counts are integers. Numeric socket handles, po `http_early_bind` and `http_serve` require an exact integer port in 0..65535; integral floats convert and port zero requests an ephemeral port. Fractional or out-of-range ports raise `value` before binding. `shared_delete` and `shared_size` return integer counts. +N6 prints each float with Python's shortest round-trip spelling: integral +floats retain `.0`, negative zero is `-0.0`, and scientific notation starts +below `1e-4` or at `1e16`. Ints keep their exact decimal digits. `print`, +`write`, `str`, f-strings and JSON share the number writer. The executed +examples are `tests/phase2/rows/N6.float-repr.eigs` and +`tests/phase2/rows/N6.str-fstring.eigs`. + The HTTP shared counter `shared_incr` follows numeric `+`: two int operands return an exact int and int64 overflow raises `value` without changing the stored counter (A). A missing counter starts at int zero. A float operand -produces a float. The stored operand is its JSON-decoded value; existing -float text stays until R1.7, so an integer-valued float may read back as an -int during this transition. Executable shared-counter examples in +produces a float. The stored operand is its JSON-decoded value; N6 preserves an +integer-valued float as a float by retaining its `.0`. Executable shared-counter examples in `tests/test_http.eigs` cover exact values, both overflow directions and the next operation after a raise. diff --git a/lib/format.eigs b/lib/format.eigs index ffe59f1fe..33d56e512 100644 --- a/lib/format.eigs +++ b/lib/format.eigs @@ -27,6 +27,9 @@ define fmt_num(value, decimals) as: int_part is floor of (rounded / factor) frac_part is rounded - (int_part * factor) frac_str is str of frac_part + # N6: fixed decimals need digits, without integral float text suffix. + if ends_with of [frac_str, ".0"]: + frac_str is substr of [frac_str, 0, (len of frac_str) - 2] loop while (len of frac_str) < decimals: frac_str is "0" + frac_str return (str of int_part) + "." + frac_str diff --git a/src/chunk.c b/src/chunk.c index 10b0e5b15..4f8030a22 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -428,8 +428,11 @@ void chunk_disassemble(EigsChunk *chunk, const char *label) { fprintf(stderr, " %d", arg); if ((op == OP_CONST || op == OP_INT_CONST) && arg < (uint16_t)chunk->const_count) { Value *v = chunk->constants[arg]; - if (v->type == VAL_FLOAT) - fprintf(stderr, " (%.6g)", VAL_F64_RAW(v)); + if (v->type == VAL_FLOAT) { + char number[32]; + eigs_num_text(number, sizeof number, VAL_F64_RAW(v)); + fprintf(stderr, " (%s)", number); + } else if (v->type == VAL_INT) fprintf(stderr, " (%lld)", (long long)VAL_I64_RAW(v)); else if (v->type == VAL_STR) diff --git a/src/eigenscript.c b/src/eigenscript.c index d14e55573..4fc4ffdba 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -3499,22 +3499,113 @@ void eigs_int_text(char *buf, size_t nbuf, int64_t i) { } void eigs_num_text(char *buf, size_t nbuf, double n) { - /* Exact integers up to 2^53 (the largest integer all doubles represent - * exactly) print without a decimal point or exponent. The magnitude test - * runs BEFORE the cast — casting an out-of-range double is UB (#816). */ - if (fabs(n) < 9007199254740992.0 && n == (long long)n) { - snprintf(buf, nbuf, "%lld", (long long)n); + if (nbuf == 0) return; + if (isnan(n)) { snprintf(buf, nbuf, "nan"); return; } + int neg = signbit(n) != 0; + if (isinf(n)) { snprintf(buf, nbuf, "%sinf", neg ? "-" : ""); return; } + if (n == 0.0) { snprintf(buf, nbuf, "%s0.0", neg ? "-" : ""); return; } + /* In Python's fixed range every integral float has its exact integer + * digits followed by .0. The range check makes the cast safe. */ + if (fabs(n) < 1e16 && n == (int64_t)n) { + snprintf(buf, nbuf, "%lld.0", (long long)(int64_t)n); return; } - /* Otherwise the shortest representation that round-trips: try 15..17 - * significant digits and stop at the first that parses back to the same - * double. %.6g (the old `str of` default) silently truncated every float - * to 6 figures — lossy for the numerical/STEM workloads this language - * targets — and %.15g loses the 17th digit a double can need. */ - for (int prec = 15; prec <= 17; prec++) { - snprintf(buf, nbuf, "%.*g", prec, n); - if (strtod(buf, NULL) == n) return; + + /* The first decimal precision that round-trips is the shortest. The + * correctly-rounded %e candidate is closest, with decimal half-even + * ties. At a binary power of two the rounding interval is asymmetric: + * its closest decimal can fail while the adjacent decimal succeeds + * (2^-24 needs 5.960464477539063e-08). Check the neighbors too. */ + double magnitude = fabs(n); + uint64_t significand = 0; + int scale = 0; + /* Existence of a round-tripping decimal is monotone in precision: + * appending a zero preserves that decimal at the next precision. + * Most binary64 values need 16 or 17 digits; try 15 first, then 16/17. + * If 15 works, test 1 and binary-search the remaining smaller range. */ + int low = 1, high = 17, precision = 15; + while (low <= high) { + char rounded[32]; + snprintf(rounded, sizeof rounded, "%.*e", precision - 1, magnitude); + uint64_t nearest = 0; + const char *p = rounded; + while (*p != 'e' && *p != 'E') { + /* Ignore the locale's decimal separator. Candidate text below + * has an integer significand, so strtod needs no separator. */ + if (*p >= '0' && *p <= '9') nearest = nearest * 10 + (unsigned)(*p - '0'); + p++; + } + p++; + int exponent_negative = *p == '-'; + if (*p == '+' || *p == '-') p++; + int exponent = 0; + while (*p >= '0' && *p <= '9') exponent = exponent * 10 + (*p++ - '0'); + if (exponent_negative) exponent = -exponent; + int rounded_scale = exponent - precision + 1; + uint64_t minimum = 1; + for (int i = 1; i < precision; i++) minimum *= 10; + int found = 0; + for (int neighbor = 0; neighbor < 3; neighbor++) { + uint64_t candidate = neighbor == 0 ? nearest : + neighbor == 1 ? nearest - 1 : nearest + 1; + int candidate_scale = rounded_scale; + /* The predecessor of 1.00eE is 9.99e(E-1), where the decimal + * grid is ten times finer. Keep the actual p-digit neighbor. */ + if (neighbor == 1 && nearest == minimum) { + candidate = nearest * 10 - 1; + candidate_scale--; + } + if (candidate == 0) continue; + char decimal[32]; + snprintf(decimal, sizeof decimal, "%llue%+d", + (unsigned long long)candidate, candidate_scale); + if (strtod(decimal, NULL) == magnitude) { + significand = candidate; + scale = candidate_scale; + found = 1; + break; + } + } + if (found) { + high = precision - 1; + precision = precision == 15 ? 1 : (low + high) / 2; + } else { + low = precision + 1; + precision = precision >= 15 ? precision + 1 : (low + high) / 2; + } + } + + while (significand % 10 == 0) { significand /= 10; scale++; } + char digits[24], text[32]; + snprintf(digits, sizeof digits, "%llu", (unsigned long long)significand); + int count = (int)strlen(digits); + int exponent = scale + count - 1; + int len = 0; + if (neg) text[len++] = '-'; + if (exponent >= -4 && exponent < 16) { + int point = exponent + 1; + if (point <= 0) { + text[len++] = '0'; + text[len++] = '.'; + for (int i = 0; i < -point; i++) text[len++] = '0'; + for (int i = 0; i < count; i++) text[len++] = digits[i]; + } else { + for (int i = 0; i < point || i < count; i++) { + if (i == point) text[len++] = '.'; + text[len++] = i < count ? digits[i] : '0'; + } + if (point >= count) { text[len++] = '.'; text[len++] = '0'; } + } + text[len] = '\0'; + } else { + text[len++] = digits[0]; + if (count > 1) { + text[len++] = '.'; + for (int i = 1; i < count; i++) text[len++] = digits[i]; + } + snprintf(text + len, sizeof text - (size_t)len, "e%+03d", exponent); } + snprintf(buf, nbuf, "%s", text); } char* value_to_string(Value *v) { diff --git a/src/freestanding/mini_fmt.c b/src/freestanding/mini_fmt.c index e369699a5..5de34b6b2 100644 --- a/src/freestanding/mini_fmt.c +++ b/src/freestanding/mini_fmt.c @@ -258,6 +258,8 @@ static void fmt_f(Sink *s, const Spec *sp, const BigDec *b) { emit_padded(s, &sp2, sign, "", body, n, 0); } +/* N6 uses this correctly-rounded %e operation to select shortest decimal + * candidates. Keep printf semantics here; eigs_num_text owns language text. */ static void fmt_e(Sink *s, const Spec *sp, const BigDec *b, int upper) { int P = (sp->prec >= 0) ? sp->prec : 6; int is_zero; diff --git a/tests/arming_mt_fixtures/arming_mt_st.expected b/tests/arming_mt_fixtures/arming_mt_st.expected index ba570e5f4..6300fa49e 100644 --- a/tests/arming_mt_fixtures/arming_mt_st.expected +++ b/tests/arming_mt_fixtures/arming_mt_st.expected @@ -1,4 +1,4 @@ -PREV 2 +PREV 2.0 WHEN1 1 WHEN2 2 NOW 3 diff --git a/tests/enrolment_exemptions.txt b/tests/enrolment_exemptions.txt index 0dfdfc723..0a921fef9 100644 --- a/tests/enrolment_exemptions.txt +++ b/tests/enrolment_exemptions.txt @@ -12,6 +12,7 @@ tools/gen_lsp_stdlib_index.sh | a generator, not a gate: make writes src/lsp_std tools/mutants.sh | the manual mutation trains (its header); its --selftest is a tools/selftests.txt row tools/phase2_corpus_diff.sh | the corpus differential of Phase 2's mechanical rounds (R1.1, R1.2, R2.1): tools/phase2_check.py runs it under such a --through and in its --selftest, and no landed round selects one tools/phase2_cost.sh | each Phase 2 round's builder runs its BASE CAND gate (design section 8); CI's bench job reads its declarations through bench/check_regression.sh (--declared jit), which this scan does not read +tools/phase2_float_amend.py | local-only, one-time proof of R1.7-D2 (the frozen float-text re-render); afterwards the frozen bar SHA-pins the accepted amendments, and any future amendment needs a new ruling tools/phase2_plants.sh | self-test only, Phase 2's planted faults: its tools/selftests.txt row runs when the checks it names change, and nightly tools/release_skill_check.sh | checks the release runbook (.claude/skills/release/SKILL.md) by hand; only its --selftest runs, as a tools/selftests.txt row tools/section_fragments_check.sh | self-test only (--selftest is its one mode); its tools/selftests.txt row runs when the runner-text gates change, and nightly diff --git a/tests/phase2/builtins/builtins.tsv b/tests/phase2/builtins/builtins.tsv index 347162661..506f3ed9e 100644 --- a/tests/phase2/builtins/builtins.tsv +++ b/tests/phase2/builtins/builtins.tsv @@ -1,16 +1,16 @@ builtin file class loss q7 round closed_in profile hook stdin changes_vs_pre changes_vs_tag abs builtins.c int-preserving LOSS - b R1.2/R1.3 release - - no yes -acos builtins.c float-producing - - c - release - - no yes +acos builtins.c float-producing - - c - release - - yes yes add builtins_tensor.c int-preserving LOSS - b - release - - yes yes append builtins.c other - - c - release - - no yes -asin builtins.c float-producing - - c - release - - no yes +asin builtins.c float-producing - - c - release - - yes yes assert builtins.c other - - c - release - - no yes -atan builtins.c float-producing - - c - release - - no yes +atan builtins.c float-producing - - c - release - - yes yes atan2 builtins.c float-producing - - c - release - - no yes audio_capture_open ext_gfx.c int-requiring - - e - release - - yes yes audio_envelope ext_gfx.c float-producing - magnitude e - release - - yes yes -audio_gain ext_gfx.c float-producing - - e - release - - no yes -audio_mix ext_gfx.c float-producing - - e - release - - no yes +audio_gain ext_gfx.c float-producing - - e - release - - yes yes +audio_mix ext_gfx.c float-producing - - e - release - - yes yes audio_music_play ext_gfx.c int-requiring - - e - release - - yes yes audio_music_volume ext_gfx.c other - bounded e - release mixvol - yes yes audio_noise ext_gfx.c float-producing - magnitude e main #1767 release - - no yes @@ -38,7 +38,7 @@ buf_copy builtins_buf.c int-requiring - - d - release - - yes yes buf_deinterleave builtins_buf.c int-requiring - - d - release - - yes yes buf_dot builtins_buf.c float-producing - - d - release - - yes yes buf_fill builtins_buf.c float-producing - - d - release - - yes yes -buf_from_list builtins_buf.c float-producing - - d - release - - no yes +buf_from_list builtins_buf.c float-producing - - d - release - - yes yes buf_from_pcm16le builtins_buf.c int-requiring - - d - release - - yes yes buf_get builtins_buf.c int-requiring - - d - release - - yes yes buf_len builtins_buf.c int-preserving - - d - release - - yes yes @@ -58,19 +58,19 @@ chr builtins.c int-requiring - - c main release - - no no clock_unix builtins.c float-producing - - c - release - - no yes close_channel builtins.c int-requiring - - c - release - - yes yes copy_into builtins.c int-requiring - - c - release - - yes yes -cos builtins.c float-producing - - c - release - - no yes +cos builtins.c float-producing - - c - release - - yes yes db_execute ext_db.c other LOSS - b - db - - yes yes db_query_json ext_db.c other LOSS - b - db - - yes yes db_query_value ext_db.c other LOSS - b - db - - yes yes dispatch builtins.c int-requiring - - c main release - - no no -divide builtins_tensor.c float-producing - - d - release - - no yes -dot builtins.c float-producing - - c - release - - no yes +divide builtins_tensor.c float-producing - - d - release - - yes yes +dot builtins.c float-producing - - c - release - - yes yes eigen_eval_loss model_infer.c float-producing - - d - server - - yes yes eigen_generate model_infer.c int-requiring - - d - server - - yes yes eigen_model_load model_io.c other - - d - server - - no no exec_capture builtins_host.c other - magnitude c - release - - yes yes exit builtins.c int-requiring - - c - release - - yes yes -exp builtins_tensor.c float-producing - - d - release - - no yes +exp builtins_tensor.c float-producing - - d - release - - yes yes f64_from_bytes builtins_buf.c int-requiring - - d - release - - yes yes f64_to_bytes builtins_buf.c other - - d - release - - yes yes fill builtins.c int-requiring - - c - release - - yes yes @@ -140,12 +140,12 @@ i8_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes i8_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes index_of builtins.c int-preserving - - b - release - - yes yes inflate builtins_buf.c int-requiring - - d - zlib - - yes yes -join builtins.c other - - c - release - - no yes -json_build builtins.c other LOSS - b R1.2/R1.3 release - - no yes +join builtins.c other - - c - release - - yes yes +json_build builtins.c other LOSS - b R1.7 release - - yes yes json_decode builtins.c other LOSS - b - release - - yes yes -json_encode builtins.c other LOSS - b R1.2/R1.3 release - - no yes +json_encode builtins.c other LOSS - b R1.7 release - - yes yes json_path builtins.c other LOSS - b - release - - yes yes -leaky_relu builtins_tensor.c float-producing - - d - release - - no yes +leaky_relu builtins_tensor.c float-producing - - d - release - - yes yes len builtins.c int-preserving - - b - release - - yes yes list_contains builtins.c other - - c - release - - no yes list_index_of builtins.c int-preserving - - b - release - - yes yes @@ -153,13 +153,13 @@ list_insert_at builtins.c int-requiring - - c - release - - yes yes list_remove_at builtins.c int-requiring - - c - release - - yes yes list_slice builtins.c int-requiring - - c - release - - yes yes list_truncate builtins.c int-requiring - - c - release - - yes yes -log builtins_tensor.c float-producing - - d - release - - no yes +log builtins_tensor.c float-producing - - d - release - - yes yes log_softmax builtins_tensor.c float-producing - - d - release - - no yes -matmul builtins_tensor.c float-producing - - d - release - - no yes -matmul_at builtins_tensor.c float-producing - - d - release - - no yes -matmul_bt builtins_tensor.c float-producing - - d - release - - no yes +matmul builtins_tensor.c float-producing - - d - release - - yes yes +matmul_at builtins_tensor.c float-producing - - d - release - - yes yes +matmul_bt builtins_tensor.c float-producing - - d - release - - yes yes max builtins.c int-preserving LOSS - b - release - - yes yes -mean builtins_tensor.c float-producing - - d - release - - no yes +mean builtins_tensor.c float-producing - - d - release - - yes yes min builtins.c int-preserving LOSS - b - release - - yes yes model_load_weights model_io.c other - - d - server - - no no monotonic_ms builtins.c float-producing - - c - release - - no yes @@ -176,19 +176,19 @@ net_listen ext_net.c int-requiring - - f - server - - yes yes net_port ext_net.c int-requiring - - f - server - - yes yes net_recv ext_net.c int-requiring - - f - server - - yes yes net_send ext_net.c int-requiring - - f - server - - yes yes -norm builtins_tensor.c float-producing - - d - release - - no yes +norm builtins_tensor.c float-producing - - d - release - - yes yes num builtins.c other LOSS - b - release - - yes yes num_copy builtins.c int-preserving LOSS - b - release - - yes yes num_type builtins.c other - - c - release - - no yes -numerical_grad builtins_tensor.c float-producing - - d - release - - no yes +numerical_grad builtins_tensor.c float-producing - - d - release - - yes yes numerical_grad_cols builtins_tensor.c float-producing - - d - release - - yes yes numerical_grad_rows builtins_tensor.c float-producing - - d - release - - yes yes -observe builtins.c other - - c - release - - no yes +observe builtins.c other - - c - release - - yes yes ord builtins.c int-preserving - - b - release - - yes yes pi builtins.c float-producing - - c - release - - no yes -pow builtins_tensor.c float-producing - - d - release - - no yes +pow builtins_tensor.c float-producing - - d - release - - yes yes ppu_render_frame ext_gfx.c int-requiring - - e - release - - yes yes -print builtins.c other - - c - release - - no yes +print builtins.c other - - c - release - - yes yes proc_read_buf builtins_host.c int-requiring - - c - release - -,hi yes yes random builtins.c float-producing - - c - release - - no yes random_hex builtins_host.c int-requiring - - c - release - - yes yes @@ -201,7 +201,7 @@ read_text builtins_host.c other - - c - release - - no yes record_history builtins.c other - - c - release - - yes yes recv builtins.c int-requiring - - c - release - - yes yes recv_timeout builtins.c int-requiring - magnitude c - release - - yes yes -relu builtins_tensor.c float-producing - - d - release - - no yes +relu builtins_tensor.c float-producing - - d - release - - yes yes reshape builtins_buf.c int-requiring - - d - release - - yes yes round builtins.c int-preserving LOSS - b - release - - yes yes sandbox_run builtins.c int-requiring - - c - release - - yes yes @@ -212,7 +212,7 @@ seed_random builtins.c int-requiring LOSS - b - release - - yes yes send builtins.c int-requiring - - c - release - - yes yes set_at builtins.c int-requiring - - c - release - - yes yes set_exit_code builtins.c int-requiring - - c R1.6-S2 release - - no yes -sgd_update builtins_tensor.c float-producing - - d - release - - no yes +sgd_update builtins_tensor.c float-producing - - d - release - - yes yes sgd_update_cols builtins_tensor.c float-producing - - d - release - - yes yes sgd_update_rows builtins_tensor.c float-producing - - d - release - - yes yes shape builtins_tensor.c int-preserving - - d - release - - yes yes @@ -220,12 +220,12 @@ shared_delete ext_http.c int-preserving - - f - server - - yes yes shared_incr ext_http.c int-preserving LOSS - b - server - - yes yes shared_size ext_http.c int-preserving - - f - server - - yes yes sign_extend builtins.c int-requiring LOSS - b - release - - yes yes -sin builtins.c float-producing - - c - release - - no yes +sin builtins.c float-producing - - c - release - - yes yes softmax builtins_tensor.c float-producing - - d - release - - no yes sort builtins.c other LOSS - b R1.2/R1.3 release - - no yes sort_by builtins.c other LOSS - b R1.2/R1.3 release - - no yes spawn builtins.c int-preserving - - b - release - - yes yes -sqrt builtins_tensor.c float-producing - - d - release - - no yes +sqrt builtins_tensor.c float-producing - - d - release - - yes yes state_at builtins.c int-requiring - - c - release - - yes yes store_close ext_store.c int-requiring - - f - release - - yes yes store_collections ext_store.c int-requiring - - f - release - - yes yes @@ -237,14 +237,14 @@ store_open ext_store.c int-preserving - - f - release - - yes yes store_put ext_store.c other LOSS - b - release - - yes yes store_query ext_store.c other LOSS - b - release - - yes yes store_update ext_store.c other LOSS - b - release - - yes yes -str builtins.c other - - c - release - - no yes +str builtins.c other - - c - release - - yes yes str_from_bytes builtins_buf.c int-requiring - - d - release - - yes yes stream_open builtins_host.c int-requiring - - c - release - - yes yes -stream_write builtins_host.c float-producing - - c - release - - no yes +stream_write builtins_host.c float-producing - - c - release - - yes yes substr builtins.c int-requiring - - c - release - - yes yes subtract builtins_tensor.c int-preserving LOSS - b - release - - yes yes sum builtins_tensor.c int-preserving LOSS - b - release - - yes yes -tan builtins.c float-producing - - c - release - - no yes +tan builtins.c float-producing - - c - release - - yes yes task_alive builtins.c int-requiring - - c - release - - yes yes task_detach builtins.c int-requiring - - c - release - - yes yes task_join builtins.c int-requiring - - c - release - - yes yes @@ -254,9 +254,9 @@ task_self builtins.c int-preserving - - b - release - - yes yes task_send builtins.c int-requiring - - c - release - - yes yes task_sleep builtins.c other - - c - release - - no no task_spawn builtins.c int-preserving - - b - release - - yes yes -tensor_load builtins_tensor.c float-producing - - d - release - - no yes -tensor_save builtins_tensor.c float-producing - - d - release - - no yes -text_builder_append builtins.c other - - c - release - - no yes +tensor_load builtins_tensor.c float-producing - - d - release - - yes yes +tensor_save builtins_tensor.c float-producing - - d - release - - yes yes +text_builder_append builtins.c other - - c - release - - yes yes text_builder_append_line builtins.c other - - c - release - - no yes thread_join builtins.c int-requiring - - c - release - - yes yes throw builtins.c other - - c - release - - no yes @@ -305,7 +305,7 @@ u8_wrapping_mul builtins_int.c int-requiring - - g - release - - yes yes u8_wrapping_sub builtins_int.c int-requiring - - g - release - - yes yes usleep builtins.c other - magnitude c - release - - yes yes vm_run_bytecode builtins.c int-requiring - - c - release - - yes yes -write builtins.c other - - c - release - - no yes +write builtins.c other - - c - release - - yes yes write_bytes builtins_host.c int-requiring - - c - release - - yes yes zeros builtins_tensor.c int-requiring - - d - release - - yes yes -zeros_like builtins_tensor.c float-producing - - d - release - - no yes +zeros_like builtins_tensor.c float-producing - - d - release - - yes yes diff --git a/tests/phase2/builtins/builtins/acos.branch b/tests/phase2/builtins/builtins/acos.branch index 21e7c33cf..0d016631a 100644 --- a/tests/phase2/builtins/builtins/acos.branch +++ b/tests/phase2/builtins/builtins/acos.branch @@ -1,3 +1,3 @@ -[0, "float"] +[0.0, "float"] [1.5707963267948966, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/add.branch b/tests/phase2/builtins/builtins/add.branch index b416047af..16bdcad70 100644 --- a/tests/phase2/builtins/builtins/add.branch +++ b/tests/phase2/builtins/builtins/add.branch @@ -1,5 +1,5 @@ [9007199254740994, "int"] ["overflow", "value"] -[2, "float", "buffer"] +[2.0, "float", "buffer"] [[3, 9007199254740994], "int", "int"] rc=0 diff --git a/tests/phase2/builtins/builtins/asin.branch b/tests/phase2/builtins/builtins/asin.branch index 21e7c33cf..0d016631a 100644 --- a/tests/phase2/builtins/builtins/asin.branch +++ b/tests/phase2/builtins/builtins/asin.branch @@ -1,3 +1,3 @@ -[0, "float"] +[0.0, "float"] [1.5707963267948966, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/atan.branch b/tests/phase2/builtins/builtins/atan.branch index 6954a46e6..db6afadc4 100644 --- a/tests/phase2/builtins/builtins/atan.branch +++ b/tests/phase2/builtins/builtins/atan.branch @@ -1,3 +1,3 @@ [0.7853981633974483, "float"] -[0, "float"] +[0.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/audio_gain.branch b/tests/phase2/builtins/builtins/audio_gain.branch index d4a0a418d..baecc92c5 100644 --- a/tests/phase2/builtins/builtins/audio_gain.branch +++ b/tests/phase2/builtins/builtins/audio_gain.branch @@ -1,2 +1,2 @@ -[[1, -1, 0.5], "float"] +[[1.0, -1.0, 0.5], "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/audio_mix.branch b/tests/phase2/builtins/builtins/audio_mix.branch index bcf573a26..e3efa6d35 100644 --- a/tests/phase2/builtins/builtins/audio_mix.branch +++ b/tests/phase2/builtins/builtins/audio_mix.branch @@ -1,2 +1,2 @@ -[[0.75, 1], "float"] +[[0.75, 1.0], "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_copy.branch b/tests/phase2/builtins/builtins/buf_copy.branch index c4d99ad96..bbd9de68c 100644 --- a/tests/phase2/builtins/builtins/buf_copy.branch +++ b/tests/phase2/builtins/builtins/buf_copy.branch @@ -1,5 +1,5 @@ -[2, 3, 0] +[2.0, 3.0, 0.0] ["offset-fraction", "value"] ["count-fraction", "value"] -[2, 1, 2] +[2.0, 1.0, 2.0] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_deinterleave.branch b/tests/phase2/builtins/builtins/buf_deinterleave.branch index 5ecd4c2cd..13f15752b 100644 --- a/tests/phase2/builtins/builtins/buf_deinterleave.branch +++ b/tests/phase2/builtins/builtins/buf_deinterleave.branch @@ -1,5 +1,5 @@ -[3, 10, 30] +[3, 10.0, 30.0] ["channel-fraction", "value"] ["nch-fraction", "value"] -[1, 2, 3] +[1.0, 2.0, 3.0] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_dot.branch b/tests/phase2/builtins/builtins/buf_dot.branch index 416a9b4d9..2ee948452 100644 --- a/tests/phase2/builtins/builtins/buf_dot.branch +++ b/tests/phase2/builtins/builtins/buf_dot.branch @@ -1,4 +1,4 @@ -[32, "float"] +[32.0, "float"] ["offset-fraction", "value"] -28 +28.0 rc=0 diff --git a/tests/phase2/builtins/builtins/buf_fill.branch b/tests/phase2/builtins/builtins/buf_fill.branch index de36b7143..e1d0bbf17 100644 --- a/tests/phase2/builtins/builtins/buf_fill.branch +++ b/tests/phase2/builtins/builtins/buf_fill.branch @@ -1,5 +1,5 @@ -[0, 7, 7, 0, "float"] +[0.0, 7.0, 7.0, 0.0, "float"] ["offset-fraction", "value"] ["count-fraction", "value"] -[0, 5] +[0.0, 5.0] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_from_list.branch b/tests/phase2/builtins/builtins/buf_from_list.branch index 652b245e0..62168d251 100644 --- a/tests/phase2/builtins/builtins/buf_from_list.branch +++ b/tests/phase2/builtins/builtins/buf_from_list.branch @@ -1,2 +1,2 @@ -[1, "float", 9007199254740992, "float", 2.5] +[1.0, "float", 9007199254740992.0, "float", 2.5] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_from_pcm16le.branch b/tests/phase2/builtins/builtins/buf_from_pcm16le.branch index 5b64e7d1d..7105dfded 100644 --- a/tests/phase2/builtins/builtins/buf_from_pcm16le.branch +++ b/tests/phase2/builtins/builtins/buf_from_pcm16le.branch @@ -1,5 +1,5 @@ ["byte-300", "value"] ["byte-fraction", "value"] -[1, "float"] -[-1.000030518509476, 0] +[1.0, "float"] +[-1.000030518509476, 0.0] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_get.branch b/tests/phase2/builtins/builtins/buf_get.branch index ba1c62cc3..def5932f2 100644 --- a/tests/phase2/builtins/builtins/buf_get.branch +++ b/tests/phase2/builtins/builtins/buf_get.branch @@ -1,4 +1,4 @@ -[20, "float"] +[20.0, "float"] ["index-fraction", "value"] -[30, "float"] +[30.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_mix.branch b/tests/phase2/builtins/builtins/buf_mix.branch index a79abf176..189331421 100644 --- a/tests/phase2/builtins/builtins/buf_mix.branch +++ b/tests/phase2/builtins/builtins/buf_mix.branch @@ -1,4 +1,4 @@ -[2, 3, "float"] +[2.0, 3.0, "float"] ["offset-fraction", "value"] -[2, 5] +[2.0, 5.0] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_peak.branch b/tests/phase2/builtins/builtins/buf_peak.branch index 28a9cf21f..08f7d0feb 100644 --- a/tests/phase2/builtins/builtins/buf_peak.branch +++ b/tests/phase2/builtins/builtins/buf_peak.branch @@ -1,4 +1,4 @@ -[5, "float"] +[5.0, "float"] ["offset-fraction", "value"] -3 +3.0 rc=0 diff --git a/tests/phase2/builtins/builtins/buf_resample_linear.branch b/tests/phase2/builtins/builtins/buf_resample_linear.branch index ec30708db..3a21e2a59 100644 --- a/tests/phase2/builtins/builtins/buf_resample_linear.branch +++ b/tests/phase2/builtins/builtins/buf_resample_linear.branch @@ -1,4 +1,4 @@ -[0, 5, 10, "float"] +[0.0, 5.0, 10.0, "float"] ["count-fraction", "value"] 3 rc=0 diff --git a/tests/phase2/builtins/builtins/buf_scale_range.branch b/tests/phase2/builtins/builtins/buf_scale_range.branch index d6ad833f4..07b9d3d71 100644 --- a/tests/phase2/builtins/builtins/buf_scale_range.branch +++ b/tests/phase2/builtins/builtins/buf_scale_range.branch @@ -1,4 +1,4 @@ -[1, 4, 6, "float"] +[1.0, 4.0, 6.0, "float"] ["offset-fraction", "value"] -3 +3.0 rc=0 diff --git a/tests/phase2/builtins/builtins/buf_set.branch b/tests/phase2/builtins/builtins/buf_set.branch index 1549a0749..9b7a1c21d 100644 --- a/tests/phase2/builtins/builtins/buf_set.branch +++ b/tests/phase2/builtins/builtins/buf_set.branch @@ -1,4 +1,4 @@ -[7, "float"] +[7.0, "float"] ["index-fraction", "value"] -[9007199254740992, "float"] +[9007199254740992.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/buf_to_pcm16le.branch b/tests/phase2/builtins/builtins/buf_to_pcm16le.branch index 892604fff..d4c2871d0 100644 --- a/tests/phase2/builtins/builtins/buf_to_pcm16le.branch +++ b/tests/phase2/builtins/builtins/buf_to_pcm16le.branch @@ -1,4 +1,4 @@ -[0, 64, 255, 127, 1, 128, "float"] +[0.0, 64.0, 255.0, 127.0, 1.0, 128.0, "float"] ["offset-fraction", "value"] ["count-fraction", "value"] rc=0 diff --git a/tests/phase2/builtins/builtins/copy_into.branch b/tests/phase2/builtins/builtins/copy_into.branch index 1c95c6a3f..c231045e4 100644 --- a/tests/phase2/builtins/builtins/copy_into.branch +++ b/tests/phase2/builtins/builtins/copy_into.branch @@ -1,5 +1,5 @@ [0, 7, 8] ["offset-fraction", "value"] [5, 7, 8] -[3, "float"] +[3.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/cos.branch b/tests/phase2/builtins/builtins/cos.branch index 447c0fc5b..8ef8ee243 100644 --- a/tests/phase2/builtins/builtins/cos.branch +++ b/tests/phase2/builtins/builtins/cos.branch @@ -1,3 +1,3 @@ -[1, "float"] +[1.0, "float"] [0.5403023058681398, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/divide.branch b/tests/phase2/builtins/builtins/divide.branch index a573216a2..cd22636ef 100644 --- a/tests/phase2/builtins/builtins/divide.branch +++ b/tests/phase2/builtins/builtins/divide.branch @@ -1,3 +1,3 @@ [3.5, "float"] -[2, "float"] +[2.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/dot.branch b/tests/phase2/builtins/builtins/dot.branch index 20df20dfa..3cc7f2389 100644 --- a/tests/phase2/builtins/builtins/dot.branch +++ b/tests/phase2/builtins/builtins/dot.branch @@ -1,2 +1,2 @@ -[11, "float"] +[11.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/exp.branch b/tests/phase2/builtins/builtins/exp.branch index 1c199dbc0..a2f48d449 100644 --- a/tests/phase2/builtins/builtins/exp.branch +++ b/tests/phase2/builtins/builtins/exp.branch @@ -1,3 +1,3 @@ -[1, "float"] +[1.0, "float"] [2.718281828459045, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/f64_from_bytes.branch b/tests/phase2/builtins/builtins/f64_from_bytes.branch index 04709de68..3b4027a6c 100644 --- a/tests/phase2/builtins/builtins/f64_from_bytes.branch +++ b/tests/phase2/builtins/builtins/f64_from_bytes.branch @@ -1,4 +1,4 @@ -[1, "float"] +[1.0, "float"] ["byte-fraction", "value"] ["byte-319", "value"] [2.5, "float"] diff --git a/tests/phase2/builtins/builtins/fround.branch b/tests/phase2/builtins/builtins/fround.branch index b8c93c2eb..3bf8a39ed 100644 --- a/tests/phase2/builtins/builtins/fround.branch +++ b/tests/phase2/builtins/builtins/fround.branch @@ -1,8 +1,8 @@ [0.10000000149011612, "float"] [1e+308, "float"] [-1e+308, "float"] -[16777216, "float"] -[9007199254740992, "float"] +[16777216.0, "float"] +[9007199254740992.0, "float"] ["non-number", "type_mismatch"] true rc=0 diff --git a/tests/phase2/builtins/builtins/gather.branch b/tests/phase2/builtins/builtins/gather.branch index 6b6410541..8427716d2 100644 --- a/tests/phase2/builtins/builtins/gather.branch +++ b/tests/phase2/builtins/builtins/gather.branch @@ -1,5 +1,5 @@ ["index-fraction", "value"] -[11, 22, "float"] +[11.0, 22.0, "float"] [[2, 3], "int"] ["list-index-fraction", "value"] rc=0 diff --git a/tests/phase2/builtins/builtins/get_at.branch b/tests/phase2/builtins/builtins/get_at.branch index 7a20efa47..94f2416b7 100644 --- a/tests/phase2/builtins/builtins/get_at.branch +++ b/tests/phase2/builtins/builtins/get_at.branch @@ -1,7 +1,7 @@ 20 ["index-fraction", "value"] 20 -[5, "float"] +[5.0, "float"] 3 ["col-fraction", "value"] rc=0 diff --git a/tests/phase2/builtins/builtins/join.branch b/tests/phase2/builtins/builtins/join.branch index ba816510e..d68d28cb6 100644 --- a/tests/phase2/builtins/builtins/join.branch +++ b/tests/phase2/builtins/builtins/join.branch @@ -1,2 +1,2 @@ -1,9007199254740993,2.5,3 +1,9007199254740993,2.5,3.0 rc=0 diff --git a/tests/phase2/builtins/builtins/json_build.branch b/tests/phase2/builtins/builtins/json_build.branch index ece4d1c4c..08a558edb 100644 --- a/tests/phase2/builtins/builtins/json_build.branch +++ b/tests/phase2/builtins/builtins/json_build.branch @@ -1,2 +1,2 @@ -{"a": 9007199254740993, "b": 2.5, "c": -9223372036854775808, "d": 3} +{"a": 9007199254740993, "b": 2.5, "c": -9223372036854775808, "d": 3.0} rc=0 diff --git a/tests/phase2/builtins/builtins/json_decode.branch b/tests/phase2/builtins/builtins/json_decode.branch index af654c2c3..37d980a65 100644 --- a/tests/phase2/builtins/builtins/json_decode.branch +++ b/tests/phase2/builtins/builtins/json_decode.branch @@ -1,3 +1,3 @@ ["int", "float", 9223372036854775807, "float", 9007199254740993, "int", "float"] -[3, 3, 9223372036854775807, 1.8446744073709552e+19, 9007199254740993, -7, 100] +[3, 3.0, 9223372036854775807, 1.8446744073709552e+19, 9007199254740993, -7, 100.0] rc=0 diff --git a/tests/phase2/builtins/builtins/json_encode.branch b/tests/phase2/builtins/builtins/json_encode.branch index fb7cdf479..f76a895d9 100644 --- a/tests/phase2/builtins/builtins/json_encode.branch +++ b/tests/phase2/builtins/builtins/json_encode.branch @@ -1,2 +1,2 @@ -[3,9007199254740993,9223372036854775807,-9223372036854775808,2.5,3,{"k":9007199254740993}] +[3,9007199254740993,9223372036854775807,-9223372036854775808,2.5,3.0,{"k":9007199254740993}] rc=0 diff --git a/tests/phase2/builtins/builtins/leaky_relu.branch b/tests/phase2/builtins/builtins/leaky_relu.branch index 557cbf0a1..d1b461ccb 100644 --- a/tests/phase2/builtins/builtins/leaky_relu.branch +++ b/tests/phase2/builtins/builtins/leaky_relu.branch @@ -1,2 +1,2 @@ -[[-0.01, 2], "float", "float"] +[[-0.01, 2.0], "float", "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/log.branch b/tests/phase2/builtins/builtins/log.branch index 09e1e8cf0..09aefb679 100644 --- a/tests/phase2/builtins/builtins/log.branch +++ b/tests/phase2/builtins/builtins/log.branch @@ -1,3 +1,3 @@ -[0, "float"] +[0.0, "float"] [2.0794415416798357, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/matmul.branch b/tests/phase2/builtins/builtins/matmul.branch index 0a55f5d57..e1678b977 100644 --- a/tests/phase2/builtins/builtins/matmul.branch +++ b/tests/phase2/builtins/builtins/matmul.branch @@ -1,2 +1,2 @@ -[[[19, 22], [43, 50]], "float"] +[[[19.0, 22.0], [43.0, 50.0]], "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/matmul_at.branch b/tests/phase2/builtins/builtins/matmul_at.branch index 2b3f1acd0..208da68e6 100644 --- a/tests/phase2/builtins/builtins/matmul_at.branch +++ b/tests/phase2/builtins/builtins/matmul_at.branch @@ -1,2 +1,2 @@ -[[[26, 30], [38, 44]], "float"] +[[[26.0, 30.0], [38.0, 44.0]], "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/matmul_bt.branch b/tests/phase2/builtins/builtins/matmul_bt.branch index 7c0fbc983..669c119ad 100644 --- a/tests/phase2/builtins/builtins/matmul_bt.branch +++ b/tests/phase2/builtins/builtins/matmul_bt.branch @@ -1,2 +1,2 @@ -[[[17, 23], [39, 53]], "float"] +[[[17.0, 23.0], [39.0, 53.0]], "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/max.branch b/tests/phase2/builtins/builtins/max.branch index f79fab4de..3e667187d 100644 --- a/tests/phase2/builtins/builtins/max.branch +++ b/tests/phase2/builtins/builtins/max.branch @@ -2,7 +2,7 @@ [3, "int"] [2.5, "float"] [7, "int"] -[3, "int", 3, "float"] +[3, "int", 3.0, "float"] ["empty", "value"] ["empty-list", "value"] rc=0 diff --git a/tests/phase2/builtins/builtins/mean.branch b/tests/phase2/builtins/builtins/mean.branch index 4abaddb8e..9d1e9d386 100644 --- a/tests/phase2/builtins/builtins/mean.branch +++ b/tests/phase2/builtins/builtins/mean.branch @@ -1,3 +1,3 @@ [1.5, "float"] -[3, "float"] +[3.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/min.branch b/tests/phase2/builtins/builtins/min.branch index 4befa6b63..e8f606712 100644 --- a/tests/phase2/builtins/builtins/min.branch +++ b/tests/phase2/builtins/builtins/min.branch @@ -2,7 +2,7 @@ [3, "int"] [3.5, "float"] [7, "int"] -[3, "int", 3, "float"] +[3, "int", 3.0, "float"] ["empty", "value"] ["empty-list", "value"] rc=0 diff --git a/tests/phase2/builtins/builtins/norm.branch b/tests/phase2/builtins/builtins/norm.branch index a7f117d08..735ae1227 100644 --- a/tests/phase2/builtins/builtins/norm.branch +++ b/tests/phase2/builtins/builtins/norm.branch @@ -1,2 +1,2 @@ -[5, "float"] +[5.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/num.branch b/tests/phase2/builtins/builtins/num.branch index bb0f03b25..55865497d 100644 --- a/tests/phase2/builtins/builtins/num.branch +++ b/tests/phase2/builtins/builtins/num.branch @@ -1,5 +1,5 @@ ["3", 3, "int"] -["3.0", 3, "float"] +["3.0", 3.0, "float"] ["9007199254740993", 9007199254740993, "int"] ["9223372036854775808", 9.223372036854776e+18, "float"] [" 12 ", 12, "int"] @@ -9,8 +9,8 @@ ["0X1f", 31, "int"] ["0xFFFFFFFFFFFFFFFF", -1, "int"] [".5", 0.5, "float"] -["1.", 1, "float"] -["1e5", 100000, "float"] +["1.", 1.0, "float"] +["1e5", 100000.0, "float"] ["12abc", "value"] ["0b101", "value"] ["0o17", "value"] diff --git a/tests/phase2/builtins/builtins/numerical_grad.branch b/tests/phase2/builtins/builtins/numerical_grad.branch index 0980a1401..0daf753da 100644 --- a/tests/phase2/builtins/builtins/numerical_grad.branch +++ b/tests/phase2/builtins/builtins/numerical_grad.branch @@ -1,2 +1,2 @@ -[[[0, 0], [6, 0]], "float"] +[[[0.0, 0.0], [6.0, 0.0]], "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/numerical_grad_cols.branch b/tests/phase2/builtins/builtins/numerical_grad_cols.branch index 71cca663a..212857f10 100644 --- a/tests/phase2/builtins/builtins/numerical_grad_cols.branch +++ b/tests/phase2/builtins/builtins/numerical_grad_cols.branch @@ -1,4 +1,4 @@ -[[[0, 0], [6, 0]], "float"] +[[[0.0, 0.0], [6.0, 0.0]], "float"] ["col-fraction", "value"] -[[0, 0], [6, 0]] +[[0.0, 0.0], [6.0, 0.0]] rc=0 diff --git a/tests/phase2/builtins/builtins/numerical_grad_rows.branch b/tests/phase2/builtins/builtins/numerical_grad_rows.branch index 7e223b118..45c62a37e 100644 --- a/tests/phase2/builtins/builtins/numerical_grad_rows.branch +++ b/tests/phase2/builtins/builtins/numerical_grad_rows.branch @@ -1,4 +1,4 @@ -[[[0, 0], [6, 0]], "float"] +[[[0.0, 0.0], [6.0, 0.0]], "float"] ["row-fraction", "value"] -[[0, 0], [6, 0]] +[[0.0, 0.0], [6.0, 0.0]] rc=0 diff --git a/tests/phase2/builtins/builtins/observe.branch b/tests/phase2/builtins/builtins/observe.branch index 830736f5c..6c96c90ee 100644 --- a/tests/phase2/builtins/builtins/observe.branch +++ b/tests/phase2/builtins/builtins/observe.branch @@ -1,2 +1,2 @@ -[["equilibrium", 0, 0, 0], "float", "float", "float"] +[["equilibrium", 0.0, 0.0, 0.0], "float", "float", "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/pow.branch b/tests/phase2/builtins/builtins/pow.branch index 1d8fc62ec..7d2176202 100644 --- a/tests/phase2/builtins/builtins/pow.branch +++ b/tests/phase2/builtins/builtins/pow.branch @@ -1,3 +1,3 @@ -[1024, "float"] +[1024.0, "float"] [1.4142135623730951, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/ppu_render_frame.branch b/tests/phase2/builtins/builtins/ppu_render_frame.branch index 142bf3bed..e2885adaa 100644 --- a/tests/phase2/builtins/builtins/ppu_render_frame.branch +++ b/tests/phase2/builtins/builtins/ppu_render_frame.branch @@ -1,5 +1,5 @@ -["lcd-off", 0] +["lcd-off", 0.0] ["lcdc-fraction", "value"] ["lcdc-401", "value"] -["bg-on", 3, 3, "float"] +["bg-on", 3.0, 3.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/print.branch b/tests/phase2/builtins/builtins/print.branch index c6eff81fa..163bce63c 100644 --- a/tests/phase2/builtins/builtins/print.branch +++ b/tests/phase2/builtins/builtins/print.branch @@ -1,5 +1,5 @@ 9007199254740993 2.5 -3 +3.0 [9007199254740993, 1e+300] rc=0 diff --git a/tests/phase2/builtins/builtins/proc_read_buf.hi.branch b/tests/phase2/builtins/builtins/proc_read_buf.hi.branch index b6b53ae4b..c4c00ae69 100644 --- a/tests/phase2/builtins/builtins/proc_read_buf.hi.branch +++ b/tests/phase2/builtins/builtins/proc_read_buf.hi.branch @@ -1,3 +1,3 @@ -[2, 72, 105, "float", "float"] +[2, 72.0, 105.0, "float", "float"] ["eof-after", null] rc=0 diff --git a/tests/phase2/builtins/builtins/read_bytes_buf.branch b/tests/phase2/builtins/builtins/read_bytes_buf.branch index 05a651748..e3f437123 100644 --- a/tests/phase2/builtins/builtins/read_bytes_buf.branch +++ b/tests/phase2/builtins/builtins/read_bytes_buf.branch @@ -1,4 +1,4 @@ -[3, 1, "float"] +[3, 1.0, "float"] ["cap-fraction", "value"] [3, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/relu.branch b/tests/phase2/builtins/builtins/relu.branch index 045a22507..ac07adeee 100644 --- a/tests/phase2/builtins/builtins/relu.branch +++ b/tests/phase2/builtins/builtins/relu.branch @@ -1,3 +1,3 @@ -[[0, 2], "float", "float"] -[3, "float"] +[[0.0, 2.0], "float", "float"] +[3.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/scatter_add.branch b/tests/phase2/builtins/builtins/scatter_add.branch index a44654ade..fdaa07fa0 100644 --- a/tests/phase2/builtins/builtins/scatter_add.branch +++ b/tests/phase2/builtins/builtins/scatter_add.branch @@ -1,4 +1,4 @@ -[1, 0, 5, "float"] +[1.0, 0.0, 5.0, "float"] ["index-fraction", "value"] -[1, 5] +[1.0, 5.0] rc=0 diff --git a/tests/phase2/builtins/builtins/set_at.branch b/tests/phase2/builtins/builtins/set_at.branch index fc7fe9af7..492a97bb3 100644 --- a/tests/phase2/builtins/builtins/set_at.branch +++ b/tests/phase2/builtins/builtins/set_at.branch @@ -1,5 +1,5 @@ [10, 99, 30] ["index-fraction", "value"] [10, 99, 5] -[7, "float"] +[7.0, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/sgd_update.branch b/tests/phase2/builtins/builtins/sgd_update.branch index 6bba358eb..cf75cc2bb 100644 --- a/tests/phase2/builtins/builtins/sgd_update.branch +++ b/tests/phase2/builtins/builtins/sgd_update.branch @@ -1,2 +1,2 @@ -[[0, 1], "float"] +[[0.0, 1.0], "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/sgd_update_cols.branch b/tests/phase2/builtins/builtins/sgd_update_cols.branch index 55308d755..e0a3ee70b 100644 --- a/tests/phase2/builtins/builtins/sgd_update_cols.branch +++ b/tests/phase2/builtins/builtins/sgd_update_cols.branch @@ -1,4 +1,4 @@ -[[[-1, 2], [1, 4]], "float"] +[[[-1.0, 2.0], [1.0, 4.0]], "float"] ["col-fraction", "value"] -[[-1, 0], [1, 2]] +[[-1.0, 0.0], [1.0, 2.0]] rc=0 diff --git a/tests/phase2/builtins/builtins/sgd_update_rows.branch b/tests/phase2/builtins/builtins/sgd_update_rows.branch index 7e737f5ce..79c3cdbf5 100644 --- a/tests/phase2/builtins/builtins/sgd_update_rows.branch +++ b/tests/phase2/builtins/builtins/sgd_update_rows.branch @@ -1,4 +1,4 @@ -[[[1, 2], [1, 2]], "float"] +[[[1.0, 2.0], [1.0, 2.0]], "float"] ["row-fraction", "value"] -[[-1, 0], [1, 2]] +[[-1.0, 0.0], [1.0, 2.0]] rc=0 diff --git a/tests/phase2/builtins/builtins/sin.branch b/tests/phase2/builtins/builtins/sin.branch index db4f7ee0a..ce787b86a 100644 --- a/tests/phase2/builtins/builtins/sin.branch +++ b/tests/phase2/builtins/builtins/sin.branch @@ -1,3 +1,3 @@ -[0, "float"] +[0.0, "float"] [0.8414709848078965, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/sqrt.branch b/tests/phase2/builtins/builtins/sqrt.branch index ac31f6992..d1f4ecfd8 100644 --- a/tests/phase2/builtins/builtins/sqrt.branch +++ b/tests/phase2/builtins/builtins/sqrt.branch @@ -1,3 +1,3 @@ -[2, "float"] +[2.0, "float"] [1.4142135623730951, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/str.branch b/tests/phase2/builtins/builtins/str.branch index aa053e4f2..6a0ef490b 100644 --- a/tests/phase2/builtins/builtins/str.branch +++ b/tests/phase2/builtins/builtins/str.branch @@ -1,2 +1,2 @@ -["9007199254740993", "2.5", "3", "-9223372036854775808"] +["9007199254740993", "2.5", "3.0", "-9223372036854775808"] rc=0 diff --git a/tests/phase2/builtins/builtins/stream_write.branch b/tests/phase2/builtins/builtins/stream_write.branch index 1dd436491..e9f52604b 100644 --- a/tests/phase2/builtins/builtins/stream_write.branch +++ b/tests/phase2/builtins/builtins/stream_write.branch @@ -1,3 +1,3 @@ [true, true, true, true] -[[3, 2.5], "float", "float"] +[[3.0, 2.5], "float", "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/tan.branch b/tests/phase2/builtins/builtins/tan.branch index f49e83313..384ef45af 100644 --- a/tests/phase2/builtins/builtins/tan.branch +++ b/tests/phase2/builtins/builtins/tan.branch @@ -1,3 +1,3 @@ -[0, "float"] +[0.0, "float"] [1.5574077246549023, "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/tensor_load.branch b/tests/phase2/builtins/builtins/tensor_load.branch index bbc9be316..2c5512484 100644 --- a/tests/phase2/builtins/builtins/tensor_load.branch +++ b/tests/phase2/builtins/builtins/tensor_load.branch @@ -1,2 +1,2 @@ -[[[1, 2], [3, 4]], "float", [2, 2]] +[[[1.0, 2.0], [3.0, 4.0]], "float", [2, 2]] rc=0 diff --git a/tests/phase2/builtins/builtins/tensor_save.branch b/tests/phase2/builtins/builtins/tensor_save.branch index 48e2ab899..b239c2f69 100644 --- a/tests/phase2/builtins/builtins/tensor_save.branch +++ b/tests/phase2/builtins/builtins/tensor_save.branch @@ -1,3 +1,3 @@ true -[[1, 9007199254740992, 2.5], "float", "float"] +[[1.0, 9007199254740992.0, 2.5], "float", "float"] rc=0 diff --git a/tests/phase2/builtins/builtins/text_builder_append.branch b/tests/phase2/builtins/builtins/text_builder_append.branch index da3da8a33..594c0a55f 100644 --- a/tests/phase2/builtins/builtins/text_builder_append.branch +++ b/tests/phase2/builtins/builtins/text_builder_append.branch @@ -1,2 +1,2 @@ -9007199254740993|2.5|3 +9007199254740993|2.5|3.0 rc=0 diff --git a/tests/phase2/builtins/builtins/write.branch b/tests/phase2/builtins/builtins/write.branch index 5e5e7829b..9a1b2c014 100644 --- a/tests/phase2/builtins/builtins/write.branch +++ b/tests/phase2/builtins/builtins/write.branch @@ -1,2 +1,2 @@ -9007199254740993 2.5 3 +9007199254740993 2.5 3.0 rc=0 diff --git a/tests/phase2/builtins/builtins/zeros.branch b/tests/phase2/builtins/builtins/zeros.branch index a8e6f2de9..fbe74c63d 100644 --- a/tests/phase2/builtins/builtins/zeros.branch +++ b/tests/phase2/builtins/builtins/zeros.branch @@ -1,6 +1,6 @@ [3, "float"] ["size-fraction", "value"] -[[[0, 0], [0, 0]], "float"] +[[[0.0, 0.0], [0.0, 0.0]], "float"] ["cols-fraction", "value"] 2 rc=0 diff --git a/tests/phase2/builtins/builtins/zeros_like.branch b/tests/phase2/builtins/builtins/zeros_like.branch index 3f510d785..5cde5b592 100644 --- a/tests/phase2/builtins/builtins/zeros_like.branch +++ b/tests/phase2/builtins/builtins/zeros_like.branch @@ -1,3 +1,3 @@ -[[0, 0], "float"] -[0, "float"] +[[0.0, 0.0], "float"] +[0.0, "float"] rc=0 diff --git a/tests/phase2/builtins/make_table.py b/tests/phase2/builtins/make_table.py index 2388d2eba..3e5fdf479 100644 --- a/tests/phase2/builtins/make_table.py +++ b/tests/phase2/builtins/make_table.py @@ -8,8 +8,9 @@ used to record observations and emits the phase2-builtins PASS contract. """ import argparse, atexit, hashlib, importlib.util, json, os, re, shutil, subprocess, sys, tempfile +from pathlib import Path -ROUNDS = ("R1.6a", "R1.6b", "R1.6c", "R1.6d", "R1.6e", "R1.6f", "R1.6g", "R1.6z") +ROUNDS = ("R1.6a", "R1.6b", "R1.6c", "R1.6d", "R1.6e", "R1.6f", "R1.6g", "R1.6z", "R1.7") # Author-ruled import, independent of the candidate's expectation files. @@ -180,6 +181,26 @@ def round_of(file, cls, loss): meta[b] = (closed_in, profile) both_ways(set(sec6), set(meta), "section 6", "rowmeta.tsv") + # D5 scopes A2 to earlier closures. R1.7 closures must prove the exact + # D2 transformation, using its anchored source-bound kinds and comparator. + float_amend, float_files = None, {} + if any(ci == "R1.7" for ci, _ in meta.values()): + try: + spec = importlib.util.spec_from_file_location("phase2_float_amend", os.path.join(ROOT, "tools/phase2_float_amend.py")) + float_amend = importlib.util.module_from_spec(spec) + spec.loader.exec_module(float_amend) + data, _ = float_amend.load(Path(ROOT), Path(ROOT) / "tests/phase2/r17_float_text.json") + float_files = data["files"] + except (OSError, ValueError, KeyError, IndexError, TypeError) as error: + fail.append("R1.7-D5: cannot load D2 kind provenance: " + str(error)) + if float_files: + try: + # D6 covers every amended row, including rows without closed_in. + # Reuse D2's comparator, independently of the amendment SHA waiver. + float_amend.check(Path(ROOT), Path(ROOT) / "tests/phase2/r17_float_text.json") + except (OSError, ValueError, KeyError, IndexError, TypeError) as error: + fail.append("R1.7-D6: " + str(error)) + cases = {} for c, b, hook, stdin in tsv("cases.tsv", 4): if c in cases: fail.append("cases.tsv: duplicate case " + c) @@ -239,6 +260,7 @@ def agg(b, kind): return "yes" if "differs" in s else "no" rows, counts, tally = [], {}, {} + r17_cases, r17_floats = 0, 0 guard = {"guarded": 0, "yes": 0, "closed_in": 0, "pending-profile": 0, "vacuous": 0} for n in sorted(sec6): cls, loss, q7 = sec6[n] @@ -315,7 +337,19 @@ def agg(b, kind): guarded = loss == "LOSS" or cls == "int-requiring" or q7 != "-" if closed_in != "-": if not guarded: fail.append("%s: closed_in %r on a row the vacuity guard does not cover" % (n, closed_in)) - if vs_pre != "no": fail.append("%s: closed_in %r but changes_vs_pre is %s: the closure must hold as .pre == .branch (ruling A2)" % (n, closed_in, vs_pre)) + if closed_in == "R1.7": + for c in mine: + path = "tests/phase2/builtins/builtins/" + c + ".branch" + try: + if path not in float_files: + raise ValueError(path + ": no source-bound D2 kind provenance") + r17_floats += float_amend.check_pair( + (Path(BDIR) / (c + ".pre")).read_bytes(), + (Path(ROOT) / path).read_bytes(), float_files[path]["line_kinds"], path) + r17_cases += 1 + except (OSError, ValueError, KeyError, IndexError, TypeError) as error: + fail.append("%s: closed_in R1.7 must be exactly the D2 float re-render (R1.7-D5): %s" % (n, error)) + elif vs_pre != "no": fail.append("%s: closed_in %r but changes_vs_pre is %s: the closure must hold as .pre == .branch (ruling A2)" % (n, closed_in, vs_pre)) if guarded: guard["guarded"] += 1 if closed_in != "-": guard["closed_in"] += 1 @@ -370,6 +404,7 @@ def agg(b, kind): tally.get((r, k, "pending-profile"), 0)) for k in ("pre", "tag"))) print("guard: guarded=%(guarded)d yes=%(yes)d closed_in=%(closed_in)d pending_profile=%(pending-profile)d vacuous=%(vacuous)d" % guard + (" (final)" if FINAL else "")) + print("closure-r17: cases=%d floats=%d (R1.7-D5)" % (r17_cases, r17_floats)) for f in fail: print("FAIL: " + f) if fail: return 1 if args.run: @@ -378,9 +413,10 @@ def agg(b, kind): print("FAIL: builtins_landed.txt: " + str(error)); return 1 env = os.environ.copy() env["R16_LANDED"] = " ".join(landed) + sys.stdout.flush() rc = subprocess.call(["bash", os.path.join(HERE, "run_probes.sh"), "--check", *args.run], env=env) if rc: return rc - migrated = sum(1 for row in rows if "R1.6" + row[5] in landed) + migrated = sum(1 for row in rows if "R1.6" + row[5] in landed or row[6] == "R1.7" and "R1.7" in landed) print("phase2-builtins: PASS rows=%d landed=%s migrated=%d unchanged=%d" % (len(rows), ",".join(landed) or "-", migrated, len(rows) - migrated)) return 0 diff --git a/tests/phase2/builtins/rowmeta.tsv b/tests/phase2/builtins/rowmeta.tsv index ac23175d8..c3e11504b 100644 --- a/tests/phase2/builtins/rowmeta.tsv +++ b/tests/phase2/builtins/rowmeta.tsv @@ -104,9 +104,9 @@ http_static - server index_of - release inflate - zlib join - release -json_build R1.2/R1.3 release +json_build R1.7 release json_decode - release -json_encode R1.2/R1.3 release +json_encode R1.7 release json_path - release leaky_relu - release len - release diff --git a/tests/phase2/builtins/run_probes.sh b/tests/phase2/builtins/run_probes.sh index 3608d0fde..64ac0b4cd 100755 --- a/tests/phase2/builtins/run_probes.sh +++ b/tests/phase2/builtins/run_probes.sh @@ -47,9 +47,9 @@ cleanup() { [ -z "$CAPTURE_PID" ] || { kill "$CAPTURE_PID" 2>/dev/null || :; wai trap cleanup EXIT gcc -shared -fPIC -O0 -Wall -Wextra -Werror "$HERE/../observation_hooks.c" -ldl -o "$SHIM" \ || { echo "FAIL: the observation shim did not build"; exit 2; } -declare -A HOOK STDIN BUILTIN PROFILE ROUND CHECKED +declare -A HOOK STDIN BUILTIN PROFILE CLOSED ROUND CHECKED while IFS=$'\t' read -r c b h s; do BUILTIN[$c]=$b; HOOK[$c]=$h; STDIN[$c]=$s; done < <(tail -n +2 "$HERE/cases.tsv") -while IFS=$'\t' read -r b ci p; do PROFILE[$b]=$p; done < <(tail -n +2 "$HERE/rowmeta.tsv") +while IFS=$'\t' read -r b ci p; do PROFILE[$b]=$p; CLOSED[$b]=$ci; done < <(tail -n +2 "$HERE/rowmeta.tsv") while IFS=$'\t' read -r b file class loss q7 round rest; do ROUND[$b]=$round; done < <(tail -n +2 "$HERE/builtins.tsv") [ ${#BUILTIN[@]} -gt 0 ] && [ ${#PROFILE[@]} -gt 0 ] || { echo "FAIL: empty cases.tsv or rowmeta.tsv"; exit 2; } cd "$HERE/builtins" || exit 2 @@ -108,6 +108,11 @@ run_one() { # run_one else echo "FAIL: $c.$kind ran without its hook $hook (no hook-loaded line)"; bad=$((bad + 1)); fi fi echo "rc=$rc" >> "$out" + # Optional evidence export from this exact gate run; never an expectation. + if [ "$CHECK" -eq 1 ] && [ -n "${PROBE_OBSERVATIONS_DIR:-}" ]; then + mkdir -p "$PROBE_OBSERVATIONS_DIR" || exit 2 + cp "$out" "$PROBE_OBSERVATIONS_DIR/$c.$kind" || exit 2 + fi if [ -n "$CAPTURE_PID" ]; then # A failed request must not leave a fixture waiting for its one client. if [ ! -f "$tmp/capture.request" ]; then kill "$CAPTURE_PID" 2>/dev/null || :; fi @@ -123,6 +128,11 @@ run_one() { # run_one if [ "$kind" = branch ]; then expected=pre case " ${R16_LANDED:-} " in *" R1.6${ROUND[${BUILTIN[$c]}]} "*) expected=branch ;; esac + # D5: an R1.7 closure is live as soon as R1.7 is declared, + # independently of the row's original R1.6 migration group. + if [ "${CLOSED[${BUILTIN[$c]}]}" = R1.7 ]; then + case " ${R16_LANDED:-} " in *" R1.7 "*) expected=branch ;; esac + fi fi if ! cmp -s "$out" "$HERE/builtins/$c.$expected"; then echo "FAIL: ${BUILTIN[$c]}: $c.$kind differs from .$expected" diff --git a/tests/phase2/builtins_changes.md b/tests/phase2/builtins_changes.md index fdcd28176..a066fbf76 100644 --- a/tests/phase2/builtins_changes.md +++ b/tests/phase2/builtins_changes.md @@ -234,12 +234,12 @@ Historical import records above are already included in the pin. | Path | SHA-256 | Ruling | Reason | |---|---|---|---| -| `tests/phase2/builtins/builtins/max.branch` | `540ee7840bf80662918b4d4189add017778d08c503488529c6fec539d0e6bb8a` | R1.6b-D2 | an empty `max` raises `value` in both call forms, `max of []` and `max of ([])` (#1895) | -| `tests/phase2/builtins/builtins/min.branch` | `f45bde7acd9b053b3379e15b35c9e06f2ba11243437f5a5926b62aad588d2118` | R1.6b-D2 | an empty `min` raises `value` in both call forms, `min of []` and `min of ([])` (#1895) | +| `tests/phase2/builtins/builtins/max.branch` | `1ca8c1c885cd796015304677d87b4782642d0a79026bd63fd28b67632b25ed9c` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/min.branch` | `eee02d9e7cd24809addb54e3c2df45f401134d5c279a7971a87fea26848781bc` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | | `tests/phase2/builtins/builtins/sign_extend.branch` | `bfc48781e0e0ab7eb480899c9975ccdbb810c36cbd2b297fd62231b41ee03bdf` | R1.6b-D1 | the subtraction is checked int64 arithmetic under rule (A): `sign_extend of [-9223372036854775553, 8]` raises `value` (#1894) | | `tests/phase2/builtins/builtins/set_exit_code.branch` | `6e6f540c7b879ca35185d74c3840327c3f14ef37c5eb74c5d60531aef340620b` | R1.6-S2 | new int-requiring round-c builtin; main already rejects fractions and values outside 0..255; matched main and merged output agree | -| `tests/phase2/builtins/builtins/fround.branch` | `12ca1750befb2a38111ec77d9ff236e9dada8e5c7d297aa5cf4f489c2c1f22fa` | R1.6g-D1 | new N9 builtin; Rust std plus the brief operand/shape rules | +| `tests/phase2/builtins/builtins/fround.branch` | `0eef9c22f27663cb7b9cffcc4704039adacba202777e3b4eb254c5462d851118` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | | `tests/phase2/builtins/builtins/i16_checked_add.branch` | `0d1db8055bba756521c06186282a8e52dea9a69497170c24307c4963f642c52d` | R1.6g-D1 | new N9 builtin; Rust std plus the brief operand/shape rules | | `tests/phase2/builtins/builtins/i16_checked_mul.branch` | `e3364392ccc01620ab16d1f686af6e6b32c23fff34c307e87953f9e3ed9752c1` | R1.6g-D1 | new N9 builtin; Rust std plus the brief operand/shape rules | | `tests/phase2/builtins/builtins/i16_checked_sub.branch` | `83430b1d05a7910f3cb358019d96be745ae4ecff96738583cb1098c11c21fb2c` | R1.6g-D1 | new N9 builtin; Rust std plus the brief operand/shape rules | @@ -316,6 +316,71 @@ Historical import records above are already included in the pin. | `tests/phase2/builtins/builtins/u8_wrapping_add.branch` | `dc311d0bac5980796200806862c231f38cba5bbae9ed68addba3fdf6631ee469` | R1.6g-D1 | new N9 builtin; Rust std plus the brief operand/shape rules | | `tests/phase2/builtins/builtins/u8_wrapping_mul.branch` | `60da423dcf7c733566c6dc8786eacdfca47f445b4c545a692a33b2c2fdbbfb7d` | R1.6g-D1 | new N9 builtin; Rust std plus the brief operand/shape rules | | `tests/phase2/builtins/builtins/u8_wrapping_sub.branch` | `f6caf9ca2c493a27eced40c47c9a000e8d0ac95b70fd12de204823880b55e686` | R1.6g-D1 | new N9 builtin; Rust std plus the brief operand/shape rules | +| `tests/phase2/builtins/builtins/str.branch` | `0c399d98c18da266dc150e39e78e616faadc324cca6e7c6c62ceb270e867913f` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/json_encode.branch` | `2ae19e560a3ea73c416cce1162049d723037f5b529e06806bc605c33fcdc2133` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/json_build.branch` | `c2b8bacb39eb6eef288670e99b3ba01d46c7cab2f94f7c05f47724c1488d9cb1` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/acos.branch` | `5958e4ae7fcc01a39f99fdd66c0a9618a9fad69c6e1d470d948f9129c1f6f4cd` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/add.branch` | `fe0387ddfdd246a088888fd214fed1abb2503f3e06a3b57cc6ea610bc0b578ec` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/asin.branch` | `5958e4ae7fcc01a39f99fdd66c0a9618a9fad69c6e1d470d948f9129c1f6f4cd` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/atan.branch` | `f242d5c6ac68248384bda8aa073f2ff5d23bb74e6fced26ba5ad2ac391d98ee6` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/audio_gain.branch` | `b7839145f6b8b9f413311bb0f984dad297356c9d7407628ba2e93a2f6c317c19` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/audio_mix.branch` | `512a7308c426e7ed94676d4c96400d79920afab58c39da9ea68270d8906de059` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_copy.branch` | `9ea81eba48f5b1b9e1f9799c9d8e8f275a0c805a082190eb7a683003a5e4ebb2` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_deinterleave.branch` | `2c8c419b85c034fbd529fd396fb0854d2982be71c29358c171e162c2b9721808` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_dot.branch` | `f9b37d961e959be8c731c30a43a007defa5fa16d3e5e60260bb3c356dbc51c00` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_fill.branch` | `38e227a7b6ada697071d60d8460bab5de95d9a4cdedcae32ccbc987be5e1752c` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_from_list.branch` | `e4a3b6623dd3f422e5712cdaf9f6b32133970df10636edb40f0e2143cbb889e1` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_from_pcm16le.branch` | `036cc08edd6d3a419692c4b1a85ac42d9a891591f55bc5fb806c4d7c8628dff8` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_get.branch` | `077ba41e4a2f93aeb44f20cb2928a585d7bc05cc158087e54aec2d097592081e` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_mix.branch` | `c78a105cdb9774cbbae3417e4aacb73742cdace27313acc705733b80b109d75b` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_peak.branch` | `b69875ae508284a12270c6791980349f86ff7d6ae32f9dfb29a05abccdc8e970` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_resample_linear.branch` | `e37904ae42856ac5a70eaea9fb9e29dd6fd35c5a17a6b31a846bc1e25c23c22d` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_scale_range.branch` | `c8f7e9898eb8c72ffa1bbed04503e8b4867f112300c617db3829aa67981e1d18` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_set.branch` | `b8c58d0a2f26c3baa094a66d073b236ae89d5e12ae0330a4afe75c85728be0a9` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/buf_to_pcm16le.branch` | `63e6df418a4e5f7f819bef3ee88186fd6548d13c06a9073b803868961e01c4e4` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/copy_into.branch` | `a46c24a542bf109a46c4c71890100268ffcfe361b97d42781df51080c27cd7b4` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/cos.branch` | `cf5baf9404a28aab2b4f931c9273949f0072ba197c2bdc27fa58d3d21b54ef0f` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/divide.branch` | `a23f3e073d81fba8891829bb4b4457f39f3b7fb1017bf46a25ef07487d441352` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/dot.branch` | `02946f430ffc9d87a7939a1a2fc200d8367fbcb42feaf973ca0a784500c78966` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/exp.branch` | `a61898dfe0d5ce58736cacff6a0c5ca15e39b3f3aecd198990cb9fd611786479` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/f64_from_bytes.branch` | `731e864c5cb1cb1d39f14554a42eaa605d14019315acedcfacfc332b0fffb172` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/gather.branch` | `824cd2ba031d256ef19a25fe1eedae6cad151a9f7791cd52aa38c717ce599461` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/get_at.branch` | `447670d74eca66707e4805343956d16e27c37428081713849ca3c1c9d1f6889a` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/join.branch` | `4e2dd8e15a945d27912c461362bb70083cabdaf0b4e31a18eac4fa5c5980d557` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/json_decode.branch` | `c0057af18be5254f0f9d1131b02b0d0cbf3594f3d277a9ed153d80463ebfab12` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/leaky_relu.branch` | `ef90cedf931e7e04a61ae277ac5ac010bf33cfca9e5213ea0082221651f34896` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/log.branch` | `b02e0dada2cf9a63f5086fbf5e8501f85dba7cf73b6eda01029647865e8c2986` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/matmul.branch` | `14616b915a5fcfdb5de37ee29ba8d6c547c90e14f0139940b3e313afadab0865` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/matmul_at.branch` | `70bae5f918939bebaf25f312aade4592af6172b2eb587dea09d6f3076a38c050` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/matmul_bt.branch` | `ba1e66cb245a46a025f5d6ee5bf6dce760552982acef6a4ec2599848c6c73569` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/mean.branch` | `ce229cfb4718fca2a9b298d927c341ea796ed6f961db2c4360b25e802c1b5225` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/norm.branch` | `d044f83f1db49f9968c9db1f30f1beafb2b8d39e4c7f162cadcc1474ddaa84ba` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/num.branch` | `7fb58551b9d82163c6703111cf84f5de26bb191de8a66d7fc5102ef8b8688162` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/numerical_grad.branch` | `4500785a3c9519176df2ab02f77fcad440fbf11f26227b29cb52496fd640e005` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/numerical_grad_cols.branch` | `2743a0bc2cabf3858d33ccd68cfab234c86adedc9665a0dbfc477f96aeb7a849` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/numerical_grad_rows.branch` | `0f8312d184ac73b4eeaeec5dfc903859353e0a783dd350c32c73a2855f0e2a03` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/observe.branch` | `1e0ee913120a78b044cf7b567cda8b1672e18fdb5faaa1af94ebb6db1193813a` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/pow.branch` | `68ab07f20b3ee61e305f67fa87230fd2c8a7730bbd4954642fd45136b37b9081` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/ppu_render_frame.branch` | `79f74efe5a437cbb3097669f3da297fb55c36d5682be19c74ba615679d486a47` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/print.branch` | `d2eaac663b00862a70c3ecd6d5f29aaaf9b793021e433025fb403ac65d6d6f01` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/proc_read_buf.hi.branch` | `f786f6b5395f54fa5f9c39c32f18ebc2d0fcda2099395156af684f37783cfe3b` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/read_bytes_buf.branch` | `0b52c1d8294591447cc198a3e8eb027ff8990555c52bf12fbdf93c912428ca84` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/relu.branch` | `24ae0c94c3ef3adf70443d1c90ab71b51e6212e09a7794c2dfc6d44c1a934601` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/scatter_add.branch` | `6efe02323a3891ed6ea11712c44546913ea92f4d0a064f1c5ec8daaaedc8a92d` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/set_at.branch` | `c90f8b78b48c20fae416587af85cc8277342614fa8935a3019ac814e3ac946c1` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/sgd_update.branch` | `42c640c625a2ea086262edc98062262e808ecfc56a0e700970575d9b4c5c10fd` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/sgd_update_cols.branch` | `74b47ef7f49936afc57f2858c3ead68863dd07091681bb275499ad4698237cce` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/sgd_update_rows.branch` | `9ab519ac1c069e9ba1b13cee49b34569bd3da3a72fdf6efe541e92d6e64a3379` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/sin.branch` | `e85163cfbb1a56ed2e29fc5ae75307f2a914acde489f6053e8e16ad55401d4bd` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/sqrt.branch` | `d02ec73520e2db4aa636bed3abe146241425f4b02141efce7a13e0b38ad22639` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/stream_write.branch` | `33b3dae3eecb631329b1c727730d240df187e9c7b7e5bb4cbe737d0d561803e0` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/tan.branch` | `1390b34eb629f519c834cd599144878efae95d3d6a8e1f80a51694a1d051ebad` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/tensor_load.branch` | `ba6c76c1208e36214edb1aadaddf6bc0507f2163720ad681a11ca9d0d39c1fa3` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/tensor_save.branch` | `be16c42b1944c56fbfad22e242be1472004e60995d31735a08237d9ca4d0b975` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/text_builder_append.branch` | `264d7aac65f70767b435d80e1c3a301a2025121d6fa39503c01b0ef0cc7d6ad5` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/write.branch` | `d646570e76559c96769f89afa8d1160cde5e12bed99a3b36f2fb7d6bb7ca7b7b` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/zeros.branch` | `2530cd624a068d1882816dec67cdb9848c1011f5307c0c27fb514cc108b18160` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | +| `tests/phase2/builtins/builtins/zeros_like.branch` | `8d3e0cdb2aee733291b724abd3f038bd9cdf2a90288d24072b87838c538a130c` | R1.7-D6 | N6 Python repr only; source-bound kinds and per-line bit proof; prior numeric/value rulings retained | ## R1.6b bar amendments @@ -415,3 +480,154 @@ ceiling stays unchanged. No frozen probe or expectation is amended. ## R1.6g-D1 — N9 pre-registration The R1.6g brief authorizes 77 new Rust-derived branch expectations and five MAP rows before builtins_int.c exists. No existing .branch changes. Table membership follows when the builtins exist. Oracle inputs, sources and verbatim results are in oracle/n9*. + +## R1.7-D2 float text amendments + +R1.7-D2 authorizes only the N6 Python `repr` re-render of numeric float payloads. +Seven frozen probes were examined: str, fround, json_encode, json_build, +json_path, min and max. Six are amended; json_path already has the N6 spelling +`2.5` and stays byte-identical. The checker compares each line with the +pre-N6 commit b6f9db3879be5578de787ad6cf0d235b809f0e7c: numeric positions, +bit-identical doubles, exact integer spellings, and every non-float byte. +Source-bound runtime kind witnesses disambiguate old integral float spellings; +old text such as `3` cannot itself establish a kind. For json_path the numeric +payload has the JSON input's lexical kind, before raw-text extraction. + +The historical R1.6b-D2 ruling still establishes min/max empty-call errors +(#1895), and R1.6g-D1 still establishes fround's N9 semantics. The accepted +rows above now pin their D2-rendered bytes; the prior byte hashes and probe-source +hashes remain recorded in `r17_float_text.json`. No earlier value or kind ruling +is superseded. + +Run `python3 tools/phase2_float_amend.py --baseline-binary BASE --binary TIP` +to check the delivered amendments and their source-bound kind witnesses. +Its one-time `--self-test` calibration rejects changed values, kinds, integers, +non-float text, positions and missing/extra tokens or files. + +## R1.7-D5 — table metadata after the D2 re-render + +Ruling R1.7-D5 on #1758 scopes A2 to earlier closures and records the final +float text deferred by the design to R1.7. In both rowmeta.tsv and the derived +builtins.tsv, json_build and json_encode change closed_in from R1.2/R1.3 to +R1.7. In builtins.tsv, changes_vs_pre changes from no to yes for json_build, +json_encode and str. These are all five changed table cells; no other cell +changes. The other D2 rows already derive yes; json_path was not amended. + +The R1.7 closure check reuses phase2_float_amend.py's source-bound kind +metadata and check_pair on each .pre/.branch pair: same line/token positions, +bit-identical doubles, identical integer spellings and non-float bytes, and +the complete Python repr re-render. It refuses an R1.7 closure without D2 +kind provenance. Every other closed row retains A2's .pre == .branch check. +No expectation or probe source changes in this amendment. + +builtins_landed.txt now declares R1.7, which make_table.py's shared parser +accepts. run_probes.sh checks a row closed in R1.7 against .branch whenever +R1.7 is declared, independently of the row's original R1.6 migration group. +The public tools/phase2_builtins.sh entry point retains all profile, hook, +stdin, frozen-bar, membership and accounting checks. This follows principle +5, Checks are anchored outside the system, narrow, and few: the D2 comparator +has one implementation, and the two fault plants are one-time calibration. + +Continuation 4's plants run through that public entry point in isolated +clones. json_build.pre changes a non-float key (a to z) while leaving the +frozen .branch hash intact; D5 must reject it. abs.pre changes an integer +spelling to a float spelling with its derived flag synchronized to yes; +the pre-R1.6 A2 closure must still reject it. Each plant must produce only +its named closure diagnostic, rather than a neighboring metadata/hash error. +Checkpoint ownership and exact run receipts are in the continuation handoff. + +## R1.7-D6 — derived float re-render population + +The expanded proof prints each amendment's SHA. Flush the parent checker's +stdout before starting the probe runner, so these records and the child's +`ran=` summary remain complete lines. The final profile receipts require +exactly one complete runner summary; the earlier spliced logs are retained +as calibration evidence, superseded by the final reruns. + +The population is the union of the gate's live comparisons over release, server, server-db and zlib. Every frozen row is examined on each profile. D6 adds 62 rows to the six already amended under D2; the cumulative population is 68. The unchanged json_path control is outside the amendment set. Exact per-profile observations, commands and hashes: continue5-population.json in the R1.7 handoff. + +The checker retains D2's per-line, bit-identical double comparison, integer spelling and all other bytes. All numeric tokens have source-bound kinds executed on the pre-N6 binary and all four candidate profiles. Numeric-looking strings echoed by num are source-bound string witnesses and remain byte-identical; only num's numeric results are re-rendered. The original frozen programs are unchanged; the R17-D2-KINDS marker and witnesses are appended only to temporary copies, using the registered stdin fixture where present. + +Metadata is derived after amendment. Previously closed amended rows close in R1.7 under D5; every other pre-R1.6 closure retains A2 pre == branch. The existing R1.7 closures are unchanged in this continuation. Derived changes_vs_pre cells and all prior amendment records are detailed below. + +| Path | SHA-256 | Profiles | Metadata | +|---|---|---|---| +| `tests/phase2/builtins/builtins/acos.branch` | `5958e4ae7fcc01a39f99fdd66c0a9618a9fad69c6e1d470d948f9129c1f6f4cd` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/add.branch` | `fe0387ddfdd246a088888fd214fed1abb2503f3e06a3b57cc6ea610bc0b578ec` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/asin.branch` | `5958e4ae7fcc01a39f99fdd66c0a9618a9fad69c6e1d470d948f9129c1f6f4cd` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/atan.branch` | `f242d5c6ac68248384bda8aa073f2ff5d23bb74e6fced26ba5ad2ac391d98ee6` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/audio_gain.branch` | `b7839145f6b8b9f413311bb0f984dad297356c9d7407628ba2e93a2f6c317c19` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/audio_mix.branch` | `512a7308c426e7ed94676d4c96400d79920afab58c39da9ea68270d8906de059` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/buf_copy.branch` | `9ea81eba48f5b1b9e1f9799c9d8e8f275a0c805a082190eb7a683003a5e4ebb2` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_deinterleave.branch` | `2c8c419b85c034fbd529fd396fb0854d2982be71c29358c171e162c2b9721808` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_dot.branch` | `f9b37d961e959be8c731c30a43a007defa5fa16d3e5e60260bb3c356dbc51c00` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_fill.branch` | `38e227a7b6ada697071d60d8460bab5de95d9a4cdedcae32ccbc987be5e1752c` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_from_list.branch` | `e4a3b6623dd3f422e5712cdaf9f6b32133970df10636edb40f0e2143cbb889e1` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/buf_from_pcm16le.branch` | `036cc08edd6d3a419692c4b1a85ac42d9a891591f55bc5fb806c4d7c8628dff8` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_get.branch` | `077ba41e4a2f93aeb44f20cb2928a585d7bc05cc158087e54aec2d097592081e` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_mix.branch` | `c78a105cdb9774cbbae3417e4aacb73742cdace27313acc705733b80b109d75b` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_peak.branch` | `b69875ae508284a12270c6791980349f86ff7d6ae32f9dfb29a05abccdc8e970` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_resample_linear.branch` | `e37904ae42856ac5a70eaea9fb9e29dd6fd35c5a17a6b31a846bc1e25c23c22d` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_scale_range.branch` | `c8f7e9898eb8c72ffa1bbed04503e8b4867f112300c617db3829aa67981e1d18` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_set.branch` | `b8c58d0a2f26c3baa094a66d073b236ae89d5e12ae0330a4afe75c85728be0a9` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/buf_to_pcm16le.branch` | `63e6df418a4e5f7f819bef3ee88186fd6548d13c06a9073b803868961e01c4e4` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/copy_into.branch` | `a46c24a542bf109a46c4c71890100268ffcfe361b97d42781df51080c27cd7b4` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/cos.branch` | `cf5baf9404a28aab2b4f931c9273949f0072ba197c2bdc27fa58d3d21b54ef0f` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/divide.branch` | `a23f3e073d81fba8891829bb4b4457f39f3b7fb1017bf46a25ef07487d441352` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/dot.branch` | `02946f430ffc9d87a7939a1a2fc200d8367fbcb42feaf973ca0a784500c78966` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/exp.branch` | `a61898dfe0d5ce58736cacff6a0c5ca15e39b3f3aecd198990cb9fd611786479` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/f64_from_bytes.branch` | `731e864c5cb1cb1d39f14554a42eaa605d14019315acedcfacfc332b0fffb172` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/fround.branch` | `0eef9c22f27663cb7b9cffcc4704039adacba202777e3b4eb254c5462d851118` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/gather.branch` | `824cd2ba031d256ef19a25fe1eedae6cad151a9f7791cd52aa38c717ce599461` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/get_at.branch` | `447670d74eca66707e4805343956d16e27c37428081713849ca3c1c9d1f6889a` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/join.branch` | `4e2dd8e15a945d27912c461362bb70083cabdaf0b4e31a18eac4fa5c5980d557` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/json_build.branch` | `c2b8bacb39eb6eef288670e99b3ba01d46c7cab2f94f7c05f47724c1488d9cb1` | release, server, server-db, zlib | closed_in R1.7; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/json_decode.branch` | `c0057af18be5254f0f9d1131b02b0d0cbf3594f3d277a9ed153d80463ebfab12` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/json_encode.branch` | `2ae19e560a3ea73c416cce1162049d723037f5b529e06806bc605c33fcdc2133` | release, server, server-db, zlib | closed_in R1.7; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/leaky_relu.branch` | `ef90cedf931e7e04a61ae277ac5ac010bf33cfca9e5213ea0082221651f34896` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/log.branch` | `b02e0dada2cf9a63f5086fbf5e8501f85dba7cf73b6eda01029647865e8c2986` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/matmul.branch` | `14616b915a5fcfdb5de37ee29ba8d6c547c90e14f0139940b3e313afadab0865` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/matmul_at.branch` | `70bae5f918939bebaf25f312aade4592af6172b2eb587dea09d6f3076a38c050` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/matmul_bt.branch` | `ba1e66cb245a46a025f5d6ee5bf6dce760552982acef6a4ec2599848c6c73569` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/max.branch` | `1ca8c1c885cd796015304677d87b4782642d0a79026bd63fd28b67632b25ed9c` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/mean.branch` | `ce229cfb4718fca2a9b298d927c341ea796ed6f961db2c4360b25e802c1b5225` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/min.branch` | `eee02d9e7cd24809addb54e3c2df45f401134d5c279a7971a87fea26848781bc` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/norm.branch` | `d044f83f1db49f9968c9db1f30f1beafb2b8d39e4c7f162cadcc1474ddaa84ba` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/num.branch` | `7fb58551b9d82163c6703111cf84f5de26bb191de8a66d7fc5102ef8b8688162` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/numerical_grad.branch` | `4500785a3c9519176df2ab02f77fcad440fbf11f26227b29cb52496fd640e005` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/numerical_grad_cols.branch` | `2743a0bc2cabf3858d33ccd68cfab234c86adedc9665a0dbfc477f96aeb7a849` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/numerical_grad_rows.branch` | `0f8312d184ac73b4eeaeec5dfc903859353e0a783dd350c32c73a2855f0e2a03` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/observe.branch` | `1e0ee913120a78b044cf7b567cda8b1672e18fdb5faaa1af94ebb6db1193813a` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/pow.branch` | `68ab07f20b3ee61e305f67fa87230fd2c8a7730bbd4954642fd45136b37b9081` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/ppu_render_frame.branch` | `79f74efe5a437cbb3097669f3da297fb55c36d5682be19c74ba615679d486a47` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/print.branch` | `d2eaac663b00862a70c3ecd6d5f29aaaf9b793021e433025fb403ac65d6d6f01` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/proc_read_buf.hi.branch` | `f786f6b5395f54fa5f9c39c32f18ebc2d0fcda2099395156af684f37783cfe3b` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/read_bytes_buf.branch` | `0b52c1d8294591447cc198a3e8eb027ff8990555c52bf12fbdf93c912428ca84` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/relu.branch` | `24ae0c94c3ef3adf70443d1c90ab71b51e6212e09a7794c2dfc6d44c1a934601` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/scatter_add.branch` | `6efe02323a3891ed6ea11712c44546913ea92f4d0a064f1c5ec8daaaedc8a92d` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/set_at.branch` | `c90f8b78b48c20fae416587af85cc8277342614fa8935a3019ac814e3ac946c1` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/sgd_update.branch` | `42c640c625a2ea086262edc98062262e808ecfc56a0e700970575d9b4c5c10fd` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/sgd_update_cols.branch` | `74b47ef7f49936afc57f2858c3ead68863dd07091681bb275499ad4698237cce` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/sgd_update_rows.branch` | `9ab519ac1c069e9ba1b13cee49b34569bd3da3a72fdf6efe541e92d6e64a3379` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/sin.branch` | `e85163cfbb1a56ed2e29fc5ae75307f2a914acde489f6053e8e16ad55401d4bd` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/sqrt.branch` | `d02ec73520e2db4aa636bed3abe146241425f4b02141efce7a13e0b38ad22639` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/str.branch` | `0c399d98c18da266dc150e39e78e616faadc324cca6e7c6c62ceb270e867913f` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/stream_write.branch` | `33b3dae3eecb631329b1c727730d240df187e9c7b7e5bb4cbe737d0d561803e0` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/tan.branch` | `1390b34eb629f519c834cd599144878efae95d3d6a8e1f80a51694a1d051ebad` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/tensor_load.branch` | `ba6c76c1208e36214edb1aadaddf6bc0507f2163720ad681a11ca9d0d39c1fa3` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/tensor_save.branch` | `be16c42b1944c56fbfad22e242be1472004e60995d31735a08237d9ca4d0b975` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/text_builder_append.branch` | `264d7aac65f70767b435d80e1c3a301a2025121d6fa39503c01b0ef0cc7d6ad5` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/write.branch` | `d646570e76559c96769f89afa8d1160cde5e12bed99a3b36f2fb7d6bb7ca7b7b` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | +| `tests/phase2/builtins/builtins/zeros.branch` | `2530cd624a068d1882816dec67cdb9848c1011f5307c0c27fb514cc108b18160` | release, server, server-db, zlib | closed_in -; changes_vs_pre yes -> yes | +| `tests/phase2/builtins/builtins/zeros_like.branch` | `8d3e0cdb2aee733291b724abd3f038bd9cdf2a90288d24072b87838c538a130c` | release, server, server-db, zlib | closed_in -; changes_vs_pre no -> yes | + +Prior accepted-amendment records (preserved provenance): + +- | `tests/phase2/builtins/builtins/fround.branch` | `0eef9c22f27663cb7b9cffcc4704039adacba202777e3b4eb254c5462d851118` | R1.7-D2 | N6 Python repr float text only; prior R1.6g-D1 fround numeric semantics | +- | `tests/phase2/builtins/builtins/json_build.branch` | `c2b8bacb39eb6eef288670e99b3ba01d46c7cab2f94f7c05f47724c1488d9cb1` | R1.7-D2 | N6 Python repr float text only | +- | `tests/phase2/builtins/builtins/json_encode.branch` | `2ae19e560a3ea73c416cce1162049d723037f5b529e06806bc605c33fcdc2133` | R1.7-D2 | N6 Python repr float text only | +- | `tests/phase2/builtins/builtins/max.branch` | `1ca8c1c885cd796015304677d87b4782642d0a79026bd63fd28b67632b25ed9c` | R1.7-D2 | N6 Python repr float text only; prior R1.6b-D2 empty-call errors (#1895) | +- | `tests/phase2/builtins/builtins/min.branch` | `eee02d9e7cd24809addb54e3c2df45f401134d5c279a7971a87fea26848781bc` | R1.7-D2 | N6 Python repr float text only; prior R1.6b-D2 empty-call errors (#1895) | +- | `tests/phase2/builtins/builtins/str.branch` | `0c399d98c18da266dc150e39e78e616faadc324cca6e7c6c62ceb270e867913f` | R1.7-D2 | N6 Python repr float text only | + +One-time public-entry plants: json_build.pre a -> z must fail the D5 non-float comparator; abs.pre integer -> float spelling (with derived flag synchronized) must fail A2; acos' derived candidate digit 0.0 -> 1.0 must fail D2's double-bit comparator naming acos. The last plant is checked through phase2_builtins.sh's population-proof preflight, rather than a stale frozen hash. This follows principle 5, Checks are anchored outside the system, narrow, and few. diff --git a/tests/phase2/builtins_landed.txt b/tests/phase2/builtins_landed.txt index ff5d05100..7c7288c24 100644 --- a/tests/phase2/builtins_landed.txt +++ b/tests/phase2/builtins_landed.txt @@ -1,4 +1,4 @@ -# Completed R1.6 sub-rounds, one full name per line. +# Completed builtin rounds, one full name per line. # R1.6a migrates no builtin rows. R1.6b R1.6c @@ -7,3 +7,4 @@ R1.6e R1.6f R1.6g R1.6z +R1.7 diff --git a/tests/phase2/calib/cal.fnstop-cat-plant.out b/tests/phase2/calib/cal.fnstop-cat-plant.out index 4022b19ee..25d453785 100644 --- a/tests/phase2/calib/cal.fnstop-cat-plant.out +++ b/tests/phase2/calib/cal.fnstop-cat-plant.out @@ -1,2 +1,2 @@ -4 +4.0 value diff --git a/tests/phase2/num_text.c b/tests/phase2/num_text.c new file mode 100644 index 000000000..a5198a98d --- /dev/null +++ b/tests/phase2/num_text.c @@ -0,0 +1,120 @@ +/* R1.7 N6: Python repr oracle pins for the shared float text writer. + * --bits reads binary64 words from stdin for an external Python oracle. */ +#include "eigenscript_all.c" + +typedef struct { uint64_t bits; const char *text; } NumTextCase; +static const NumTextCase num_text_cases[] = { + {UINT64_C(0x0000000000000000), "0.0"}, + {UINT64_C(0x4008000000000000), "3.0"}, + {UINT64_C(0x408f400000000000), "1000.0"}, + {UINT64_C(0x3fd3333333333334), "0.30000000000000004"}, + {UINT64_C(0x430c6bf526340000), "1000000000000000.0"}, + {UINT64_C(0x4341c37937e08000), "1e+16"}, + {UINT64_C(0x3ee4f8b588e368f1), "1e-05"}, + {UINT64_C(0x3f1a36e2eb1c432d), "0.0001"}, + {UINT64_C(0x44b52d02c7e14af6), "1e+23"}, + {UINT64_C(0x3f1a36e2eb1c432c), "9.999999999999999e-05"}, + {UINT64_C(0x4341c37937e07fff), "9999999999999998.0"}, + {UINT64_C(0x4341c37937e08001), "1.0000000000000002e+16"}, + /* Exact decimal halfway values choose an even last digit. */ + {UINT64_C(0x430c6bf526340002), "1000000000000000.2"}, + {UINT64_C(0x430c6bf526340006), "1000000000000000.8"}, + {UINT64_C(0x42d6bcc41e900008), "100000000000000.12"}, + {UINT64_C(0x42d6bcc41e900018), "100000000000000.38"}, + /* The nearest rounded decimal misses the shorter round-trip interval. */ + {UINT64_C(0x3e70000000000000), "5.960464477539063e-08"}, + {UINT64_C(0x3d30000000000000), "5.684341886080802e-14"}, + {UINT64_C(0x4580000000000000), "6.189700196426902e+26"}, + {UINT64_C(0x5120000000000000), "6.070840288205404e+82"}, + {UINT64_C(0x7fefffffffffffff), "1.7976931348623157e+308"}, + {UINT64_C(0x0010000000000000), "2.2250738585072014e-308"}, + {UINT64_C(0x000fffffffffffff), "2.225073858507201e-308"}, + {UINT64_C(0x0000000000000001), "5e-324"}, + {UINT64_C(0x0000000000000002), "1e-323"} +}; +static int num_text_checks, num_text_failures; + +static void num_text_check(int ok, const char *label, uint64_t bits, size_t cap) { + num_text_checks++; + if (!ok) { + num_text_failures++; + printf("phase2-num-text-test: FAIL %s bits=%016llx cap=%zu\n", + label, (unsigned long long)bits, cap); + } +} + +static void num_text_test(uint64_t bits, const char *want, int finite) { + double value; + memcpy(&value, &bits, sizeof value); + char got[32]; + eigs_num_text(got, sizeof got, value); + num_text_check(strcmp(got, want) == 0, "Python repr", bits, sizeof got); + if (finite) { + double parsed = strtod(got, NULL); + uint64_t parsed_bits; + memcpy(&parsed_bits, &parsed, sizeof parsed_bits); + num_text_check(parsed_bits == bits, "bit-exact round trip", bits, sizeof got); + } + size_t len = strlen(want); + for (size_t cap = 0; cap <= len + 2; cap++) { + unsigned char bounded[40]; + memset(bounded, 0xa5, sizeof bounded); + eigs_num_text((char *)bounded + 1, cap, value); + size_t copied = cap == 0 ? 0 : len < cap ? len : cap - 1; + int ok = bounded[0] == 0xa5 && + memcmp(bounded + 1, want, copied) == 0; + if (cap > 0) ok = ok && bounded[copied + 1] == 0; + size_t untouched = cap == 0 ? 1 : copied + 2; + for (size_t i = untouched; i < sizeof bounded; i++) + if (bounded[i] != 0xa5) ok = 0; + num_text_check(ok, "bounded output", bits, cap); + } +} + +static int num_text_bits(void) { + char line[32]; + size_t count = 0; + while (fgets(line, sizeof line, stdin)) { + size_t len = strlen(line); + if (len == 17 && line[16] == '\n') len--; + if (len != 16) return 2; + uint64_t bits = 0; + for (size_t i = 0; i < len; i++) { + int digit = line[i] >= '0' && line[i] <= '9' ? line[i] - '0' : + line[i] >= 'a' && line[i] <= 'f' ? line[i] - 'a' + 10 : + line[i] >= 'A' && line[i] <= 'F' ? line[i] - 'A' + 10 : -1; + if (digit < 0) return 2; + bits = (bits << 4) | (unsigned)digit; + } + double value; + char text[32]; + memcpy(&value, &bits, sizeof value); + eigs_num_text(text, sizeof text, value); + puts(text); + count++; + } + return ferror(stdin) || count == 0 ? 2 : 0; +} + +int main(int argc, char **argv) { + if (argc == 2 && strcmp(argv[1], "--bits") == 0) return num_text_bits(); + if (argc != 1) return 2; + for (size_t i = 0; i < sizeof num_text_cases / sizeof num_text_cases[0]; i++) { + const NumTextCase *c = &num_text_cases[i]; + num_text_test(c->bits, c->text, 1); + char negative[32]; + snprintf(negative, sizeof negative, "-%s", c->text); + num_text_test(c->bits | UINT64_C(0x8000000000000000), negative, 1); + } + num_text_test(UINT64_C(0x7ff0000000000000), "inf", 0); + num_text_test(UINT64_C(0xfff0000000000000), "-inf", 0); + num_text_test(UINT64_C(0x7ff8000000000000), "nan", 0); + num_text_test(UINT64_C(0xfff8000000000000), "nan", 0); + /* A zero capacity also permits a null destination. */ + eigs_num_text(NULL, 0, 1.25); + printf("phase2-num-text-test: %s cases=%zu checks=%d failures=%d\n", + num_text_failures ? "FAIL" : "PASS", + 2 * (sizeof num_text_cases / sizeof num_text_cases[0]) + 4, + num_text_checks, num_text_failures); + return num_text_failures ? 1 : 0; +} diff --git a/tests/phase2/r17_float_text.json b/tests/phase2/r17_float_text.json new file mode 100644 index 000000000..6041264be --- /dev/null +++ b/tests/phase2/r17_float_text.json @@ -0,0 +1,4280 @@ +{ + "schema": 2, + "ruling": "R1.7-D6", + "base": "b6f9db3879be5578de787ad6cf0d235b809f0e7c", + "profiles": [ + "release", + "server", + "server-db", + "zlib" + ], + "population": { + "tests/phase2/builtins/builtins/acos.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/add.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/asin.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/atan.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/audio_gain.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/audio_mix.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_copy.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_deinterleave.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_dot.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_fill.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_from_list.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_from_pcm16le.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_get.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_mix.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_peak.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_resample_linear.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_scale_range.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_set.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/buf_to_pcm16le.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/copy_into.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/cos.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/divide.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/dot.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/exp.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/f64_from_bytes.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/fround.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/gather.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/get_at.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/join.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/json_build.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/json_decode.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/json_encode.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/leaky_relu.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/log.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/matmul.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/matmul_at.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/matmul_bt.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/max.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/mean.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/min.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/norm.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/num.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/numerical_grad.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/numerical_grad_cols.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/numerical_grad_rows.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/observe.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/pow.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/ppu_render_frame.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/print.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/proc_read_buf.hi.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/read_bytes_buf.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/relu.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/scatter_add.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/set_at.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/sgd_update.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/sgd_update_cols.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/sgd_update_rows.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/sin.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/sqrt.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/str.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/stream_write.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/tan.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/tensor_load.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/tensor_save.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/text_builder_append.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/write.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/zeros.branch": [ + "release", + "server", + "server-db", + "zlib" + ], + "tests/phase2/builtins/builtins/zeros_like.branch": [ + "release", + "server", + "server-db", + "zlib" + ] + }, + "population_sha256": "b4228b248a44d778106ee7874651c80a29df743f81cc869dd0839587e645644e", + "kind_domain": "Numeric payload before printing/encoding; source-bound text witnesses preserve numeric-looking input strings byte for byte. rc=0 is a fixed integer trailer. Never infer kind from old spelling.", + "files": { + "tests/phase2/builtins/builtins/acos.branch": { + "old_sha256": "569dbfeb45288a7fdc73dbe3968e33077ead4fb60b286edb0452706e86a46fa7", + "source_sha256": "d50a0a98e2fbbce230f62aac651bbe8384d0d12b50218804c314e0af1c237fbf", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/add.branch": { + "old_sha256": "44cb4a950acc6a46b3995372f1d7cfac1b391606d08bbb23791b59d3c0139441", + "source_sha256": "cc15f8196d96099e8d63563cbddeabf68e22c67cc4f27d4e04299e652a62514f", + "witnesses": [ + { + "line": 8, + "expression": "r", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "The exact integer scalar result remains in r." + }, + { + "line": 15, + "expression": "s[0]", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Buffer result stores float cells; read the printed s[0]." + }, + { + "line": 17, + "expression": "l[0]", + "kind": "int", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Original list scalar result remains accessible." + }, + { + "line": 17, + "expression": "l[1]", + "kind": "int", + "positions": [ + [ + 4, + 2 + ] + ], + "provenance": "Original list scalar result remains accessible." + } + ] + }, + "tests/phase2/builtins/builtins/asin.branch": { + "old_sha256": "569dbfeb45288a7fdc73dbe3968e33077ead4fb60b286edb0452706e86a46fa7", + "source_sha256": "dd02a681476467ec2fc842b450f4312187de86be8d43b4e905dffe2fac93533e", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/atan.branch": { + "old_sha256": "3bc01a9ceb8c27725c8c651e2da1fa3c8bcc04c2540218f88960a2792deaf053", + "source_sha256": "1036030adfdf440f3f629445c7bc4071f558a53f6abccae57ebe2819c1913335", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/audio_gain.branch": { + "old_sha256": "1f1d88cd0050f69c989b3be281ea0fcf212b6ffa36cb26dde89ddeb6528dd83b", + "source_sha256": "c39f7bd8f30d77d96f9e74b0ba05ace39c5e83ccff8ee09a4c42081d46b51503", + "witnesses": [ + { + "line": 8, + "expression": "g", + "index_path": [ + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained result leaf after the marker; each printed sample gets an independent kind check." + }, + { + "line": 8, + "expression": "g", + "index_path": [ + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained result leaf after the marker; each printed sample gets an independent kind check." + }, + { + "line": 8, + "expression": "g", + "index_path": [ + 2 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained result leaf after the marker; each printed sample gets an independent kind check." + } + ] + }, + "tests/phase2/builtins/builtins/audio_mix.branch": { + "old_sha256": "94f7af8ec23efc86083e896fd86961d344d63d8c4c4ee2c8f1a52e6d1d77f883", + "source_sha256": "ac8b550d4d6c26a040575c58929ab88be0f5383993a95c8a3b34a9f5215c54c5", + "witnesses": [ + { + "line": 8, + "expression": "m", + "index_path": [ + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained result leaf after the marker; each printed sample gets an independent kind check." + }, + { + "line": 8, + "expression": "m", + "index_path": [ + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained result leaf after the marker; each printed sample gets an independent kind check." + } + ] + }, + "tests/phase2/builtins/builtins/buf_copy.branch": { + "old_sha256": "dac04f02f3803f898bf8d1f64a1e4e489aa151a1a2a1913d397277097f379c71", + "source_sha256": "c5b84980049af61a9aaea744b3b3fd8de21224ef939ec168bb87161ad54bc938", + "witnesses": [ + { + "line": 10, + "expression": "d[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 4, + 1 + ] + ], + "provenance": "d is a buffer throughout; later copies change cell values, never their float numeric kind." + }, + { + "line": 10, + "expression": "d[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "d is a buffer throughout; later copies change cell values, never their float numeric kind." + }, + { + "line": 10, + "expression": "d[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ], + [ + 4, + 2 + ] + ], + "provenance": "d is a buffer throughout; later copies change cell values, never their float numeric kind." + }, + { + "line": 22, + "expression": "d[3]", + "kind": "float", + "positions": [ + [ + 4, + 3 + ] + ], + "provenance": "d is a buffer throughout; later copies change cell values, never their float numeric kind." + } + ] + }, + "tests/phase2/builtins/builtins/buf_deinterleave.branch": { + "old_sha256": "dd951eaad4bbf3c157f5eec675129e0f2d26e33b71b78740c0e8a8e8dcc18f2a", + "source_sha256": "6585d6f7df55b57528dc84d8c0b8b5397228623116774fb7d7d052c30e4da8ce", + "witnesses": [ + { + "line": 9, + "expression": "buf_len of r", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "buf_len returns an integer count." + }, + { + "line": 9, + "expression": "r[0]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 9, + "expression": "r[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 19, + "expression": "f[0]", + "kind": "float", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 19, + "expression": "f[1]", + "kind": "float", + "positions": [ + [ + 4, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 19, + "expression": "f[2]", + "kind": "float", + "positions": [ + [ + 4, + 3 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/buf_dot.branch": { + "old_sha256": "c1ecf705f32d6094a9a033c649c8b05c47d09447bc3cd04f5d3f70bdd2181ba0", + "source_sha256": "90e2d0479003cc49b12a3a73be84bb991fa28e063ba9370da496e3f8abe2c56d", + "witnesses": [ + { + "line": 10, + "expression": "d", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 15, + "expression": "buf_dot of [a, b, 1.0, 1.0, 2.0]", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Reevaluate the same pure buffer dot call after the marker; a and b were not mutated." + } + ] + }, + "tests/phase2/builtins/builtins/buf_fill.branch": { + "old_sha256": "8c479bf8e435ada89ad51e52521b6e34eb59cda2cf71b4b8188747dc4628428d", + "source_sha256": "4b63a7b983759d7d8b85dedceff46569c04c0088c7453d811455012ad5926b47", + "witnesses": [ + { + "line": 9, + "expression": "b[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 4, + 1 + ] + ], + "provenance": "b is always a buffer; later fills preserve each cell's float numeric kind." + }, + { + "line": 9, + "expression": "b[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "b is always a buffer; later fills preserve each cell's float numeric kind." + }, + { + "line": 9, + "expression": "b[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "b is always a buffer; later fills preserve each cell's float numeric kind." + }, + { + "line": 9, + "expression": "b[3]", + "kind": "float", + "positions": [ + [ + 1, + 4 + ], + [ + 4, + 2 + ] + ], + "provenance": "b is always a buffer; later fills preserve each cell's float numeric kind." + } + ] + }, + "tests/phase2/builtins/builtins/buf_from_list.branch": { + "old_sha256": "351878b86efd9ca2e8211a62b334ded544593dbf2162176a2f47c9589c255d9f", + "source_sha256": "d7fe7ccfbb42a1a7a563c0cb894d0abce9ebbb64813f2b0f1bec8e331a14b9e9", + "witnesses": [ + { + "line": 8, + "expression": "b[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "buf_from_list converts every input to float storage; read the original cell." + }, + { + "line": 8, + "expression": "b[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "buf_from_list converts every input to float storage; read the original cell." + }, + { + "line": 8, + "expression": "b[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "buf_from_list converts every input to float storage; read the original cell." + } + ] + }, + "tests/phase2/builtins/builtins/buf_from_pcm16le.branch": { + "old_sha256": "62cc915f80add810815cf56816c78ed4ce2ea6ac7226d78a0dc32c75c7c88d01", + "source_sha256": "7924d636a16bb793bc25382cd7b98967816439e66fae08eb02cb51c6f5aca556", + "witnesses": [ + { + "line": 14, + "expression": "\"byte-300\"", + "kind": "text", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Immutable source string literal names the invalid input. Its numeric-looking token is text, so preserve it byte for byte; type of the source expression must be string.", + "reader": "type" + }, + { + "line": 24, + "expression": "u[0]", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 27, + "expression": "s[0]", + "kind": "float", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 27, + "expression": "s[1]", + "kind": "float", + "positions": [ + [ + 4, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/buf_get.branch": { + "old_sha256": "1d01ac9d51aceadaf2c618d631ff744e61c90338281246f409610361a1329b70", + "source_sha256": "74894382fd9beeed66da5bc76199242a5b0a0a17f951687d154b7896b737f00e", + "witnesses": [ + { + "line": 9, + "expression": "g", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 15, + "expression": "h", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/buf_mix.branch": { + "old_sha256": "5b90b6a82b8f23b9d4fc822439292a10d8298636f6bf0e7d06cd0ce8b2da8561", + "source_sha256": "3fb8175de9e7d360051a7e3b2762b514303392a15fd01c4972d34843807d953f", + "witnesses": [ + { + "line": 10, + "expression": "d[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 3, + 1 + ] + ], + "provenance": "d is always a buffer; subsequent mixing preserves float numeric kinds." + }, + { + "line": 10, + "expression": "d[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ], + [ + 3, + 2 + ] + ], + "provenance": "d is always a buffer; subsequent mixing preserves float numeric kinds." + } + ] + }, + "tests/phase2/builtins/builtins/buf_peak.branch": { + "old_sha256": "fb99580cbc37068854d652493bb0543547dd3e4c4db541bbbfc26471ca4a1c14", + "source_sha256": "8b06cd047d040c08c130b32d9b3b02f8ba8dffe262dafda3ecbc4355ddb094c2", + "witnesses": [ + { + "line": 9, + "expression": "p", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 14, + "expression": "buf_peak of [b, 2.0, 1.0]", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Reevaluate the identical pure peak call; b is unchanged." + } + ] + }, + "tests/phase2/builtins/builtins/buf_resample_linear.branch": { + "old_sha256": "e4a5237c04513a69773ede55bf480984d7e62e3ee8ad53facc3fcffbed902d14", + "source_sha256": "018060c9ec08097ee3543963cdb88985fe62f52589bb31672786fad2a1ad210f", + "witnesses": [ + { + "line": 9, + "expression": "r[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 9, + "expression": "r[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 9, + "expression": "r[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 14, + "expression": "buf_len of (buf_resample_linear of [s, 3.0])", + "kind": "int", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Reevaluate the identical pure resample/count call; the result is an integer length." + } + ] + }, + "tests/phase2/builtins/builtins/buf_scale_range.branch": { + "old_sha256": "c513bc3bdb60883eba661b853a331456e9518a93ab0759d6f82bdf3235a0db1a", + "source_sha256": "6875495bdd87c5adfe2f703e5cc8db0b6f9c14c25347906e81fd0383e1e98d9f", + "witnesses": [ + { + "line": 9, + "expression": "b[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 3, + 1 + ] + ], + "provenance": "b remains a buffer; later scaling changes values while each cell remains float." + }, + { + "line": 9, + "expression": "b[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "b remains a buffer; later scaling changes values while each cell remains float." + }, + { + "line": 9, + "expression": "b[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "b remains a buffer; later scaling changes values while each cell remains float." + } + ] + }, + "tests/phase2/builtins/builtins/buf_set.branch": { + "old_sha256": "82df09c6853981b39cf330a7dd33f9295d0faa0ad7bf75abe24509c9d051f86a", + "source_sha256": "bde8d975bfd9490a9de7475a2184323406f0557c6bd2dffdc93fbff133996793", + "witnesses": [ + { + "line": 9, + "expression": "b[1]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 16, + "expression": "b[2]", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/buf_to_pcm16le.branch": { + "old_sha256": "eecad0ac215863e0085e43178799f26fcb8c0b1780113a3bd7277ce154ad495a", + "source_sha256": "96e73c0eec4fccfa6c228e2ea1cd6d624c07619080c99dc2988d6728f936a5a2", + "witnesses": [ + { + "line": 9, + "expression": "r[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "The returned PCM byte buffer uses float storage, as the frozen probe explicitly witnesses with nt of r[0]." + }, + { + "line": 9, + "expression": "r[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "The returned PCM byte buffer uses float storage, as the frozen probe explicitly witnesses with nt of r[0]." + }, + { + "line": 9, + "expression": "r[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "The returned PCM byte buffer uses float storage, as the frozen probe explicitly witnesses with nt of r[0]." + }, + { + "line": 9, + "expression": "r[3]", + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "The returned PCM byte buffer uses float storage, as the frozen probe explicitly witnesses with nt of r[0]." + }, + { + "line": 9, + "expression": "r[4]", + "kind": "float", + "positions": [ + [ + 1, + 5 + ] + ], + "provenance": "The returned PCM byte buffer uses float storage, as the frozen probe explicitly witnesses with nt of r[0]." + }, + { + "line": 9, + "expression": "r[5]", + "kind": "float", + "positions": [ + [ + 1, + 6 + ] + ], + "provenance": "The returned PCM byte buffer uses float storage, as the frozen probe explicitly witnesses with nt of r[0]." + } + ] + }, + "tests/phase2/builtins/builtins/copy_into.branch": { + "old_sha256": "83e31940d21f04bb371335e5d1f74382c08e09f70b5a5cdb1295a9e3a669ebd3", + "source_sha256": "8441abf4a97bd4f8a550893d08b305734e0266814863063d9e3b9537f6020344", + "witnesses": [ + { + "line": 7, + "expression": "0", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "The initial list zero is an int source literal; it was later overwritten with another int." + }, + { + "line": 8, + "expression": "7", + "kind": "int", + "positions": [ + [ + 1, + 2 + ], + [ + 3, + 2 + ] + ], + "provenance": "The source list copies integer literal 7 unchanged." + }, + { + "line": 8, + "expression": "8", + "kind": "int", + "positions": [ + [ + 1, + 3 + ], + [ + 3, + 3 + ] + ], + "provenance": "The source list copies integer literal 8 unchanged." + }, + { + "line": 15, + "expression": "5", + "kind": "int", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "The later list copy writes integer literal 5." + }, + { + "line": 19, + "expression": "b[0]", + "kind": "float", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/cos.branch": { + "old_sha256": "dd0c0693f01f952a0f3e40928fd06dfdb51814ae805433c1d0a828ee411fd7e6", + "source_sha256": "371fbcf49fcd0fc61b6f90d670f0aabe7d2c8e1dd1d7d96577211281a24123f3", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/divide.branch": { + "old_sha256": "c86138c24b149017797aea5e0cc1713267adffdb227658ccd12f9d7f14ea27b2", + "source_sha256": "ec0510af18a82cf234626f896d5b944147529a7bdbe17f92e9b1ddb3d23a65ed", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/dot.branch": { + "old_sha256": "2bae8e58272d6a882be4cf8cfbfe6eb01b005f76710ee6b3a7c3787b2f0e5318", + "source_sha256": "1ddf07b64a5e4789b99bab885c6167d50cb570d5fcbd4d743b76421d39dc4498", + "witnesses": [ + { + "line": 8, + "expression": "d", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/exp.branch": { + "old_sha256": "28fa610a97dead760b26a1bec1205054a98da65898ce7131bbc786890d78f924", + "source_sha256": "352095768e8589397a64f0cbf9f14d421f0c8d324288a06528de72d9133a14df", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/f64_from_bytes.branch": { + "old_sha256": "e5600eea405b87eb0819d55f44082cd60a7f8126c15bb1d0253991e7a00681bf", + "source_sha256": "c1418ff7dfa0d48b0bd7f8bbb8ab409c4cd109ebad0b2ac5702a08a45d9174c1", + "witnesses": [ + { + "line": 8, + "expression": "v", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 18, + "expression": "w", + "kind": "float", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 16, + "expression": "\"byte-319\"", + "kind": "text", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Immutable source string literal names the invalid input. Its numeric-looking token is text, so preserve it byte for byte; type of the source expression must be string.", + "reader": "type" + } + ] + }, + "tests/phase2/builtins/builtins/fround.branch": { + "old_sha256": "12ca1750befb2a38111ec77d9ff236e9dada8e5c7d297aa5cf4f489c2c1f22fa", + "source_sha256": "8195efefa3df62764addec397a097371ca255236efed4149b395116ecdfeeb1f", + "witnesses": [ + { + "line": 3, + "expression": "fround of 0.1", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ] + }, + { + "line": 8, + "expression": "fround of 1e39", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ] + }, + { + "line": 13, + "expression": "fround of -1e39", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ] + }, + { + "line": 18, + "expression": "fround of 16777217", + "kind": "float", + "positions": [ + [ + 4, + 1 + ] + ] + }, + { + "line": 23, + "expression": "fround of 9007199254740993", + "kind": "float", + "positions": [ + [ + 5, + 1 + ] + ] + } + ] + }, + "tests/phase2/builtins/builtins/gather.branch": { + "old_sha256": "2d0ec782b3eaca9a4f0308177593be3c25d34c27ed42e54c8f4878784a503f50", + "source_sha256": "5c4ce04f61e1181c3a2f30f7cab7ff11fe1d0f148cf11d7e43a16c4f7ec9fdb7", + "witnesses": [ + { + "line": 18, + "expression": "h[0]", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 18, + "expression": "h[1]", + "kind": "float", + "positions": [ + [ + 2, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 21, + "expression": "k", + "index_path": [ + 0 + ], + "kind": "int", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Read this exact retained list-gather result leaf; each printed int cell gets an independent kind check." + }, + { + "line": 21, + "expression": "k", + "index_path": [ + 1 + ], + "kind": "int", + "positions": [ + [ + 3, + 2 + ] + ], + "provenance": "Read this exact retained list-gather result leaf; each printed int cell gets an independent kind check." + } + ] + }, + "tests/phase2/builtins/builtins/get_at.branch": { + "old_sha256": "0d8f23ecef670cb4b94c02e5131773d4ca520dd9aaa0528969f693bd0cb75e03", + "source_sha256": "cc90608c75801ed3c366eecdf48e5d449485175b6b03116769918cb49a09b869", + "witnesses": [ + { + "line": 8, + "expression": "get_at of [xs, 1]", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Pure read from the unchanged integer list." + }, + { + "line": 13, + "expression": "get_at of [xs, 1.0]", + "kind": "int", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Pure read from the unchanged integer list; integral-float index does not alter value kind." + }, + { + "line": 16, + "expression": "g", + "kind": "float", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 18, + "expression": "get_at of [m, 1, 0]", + "kind": "int", + "positions": [ + [ + 5, + 1 + ] + ], + "provenance": "Pure read from the unchanged integer matrix." + } + ] + }, + "tests/phase2/builtins/builtins/join.branch": { + "old_sha256": "91e4b9fc32e6f0aef9e817248f48398942b53c92d8a07dec3074740ac757c319", + "source_sha256": "88f2e3278f06a6310c376e78a74cf57b010c08c32673d68778ca4560176d6bfc", + "witnesses": [ + { + "line": 7, + "expression": "1", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "The source literal is the numeric payload formatted into join's output string; reevaluating the literal has no effects." + }, + { + "line": 7, + "expression": "9007199254740993", + "kind": "int", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "The source literal is the numeric payload formatted into join's output string; reevaluating the literal has no effects." + }, + { + "line": 7, + "expression": "2.5", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "The source literal is the numeric payload formatted into join's output string; reevaluating the literal has no effects." + }, + { + "line": 7, + "expression": "3.0", + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "The source literal is the numeric payload formatted into join's output string; reevaluating the literal has no effects." + } + ] + }, + "tests/phase2/builtins/builtins/json_build.branch": { + "old_sha256": "b263c9dc708a82505e5afef5b3dabcb2601699e66deb9d8205e866bb041b4308", + "source_sha256": "079f944da77214d3a2b54e207ecc6f9db03870ea5818adc82d11c40f2e26f5ed", + "witnesses": [ + { + "line": 7, + "expression": "9007199254740993", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ] + }, + { + "line": 7, + "expression": "2.5", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ] + }, + { + "line": 7, + "expression": "-9223372036854775807 - 1", + "kind": "int", + "positions": [ + [ + 1, + 3 + ] + ] + }, + { + "line": 7, + "expression": "3.0", + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ] + } + ] + }, + "tests/phase2/builtins/builtins/json_decode.branch": { + "old_sha256": "b0c99b544ec22490674d987f0d5de7cef9872b11a8e39e2be368ef74874d1ea1", + "source_sha256": "4c2d193b22e2440a66f872b375d94a5a12bb67d78c8123c963a2cf1d6534bf79", + "witnesses": [ + { + "line": 8, + "expression": "v[0]", + "kind": "int", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Read the original decoded scalar; the decoder retains integer/float kinds determined by JSON lexical form and int64 range." + }, + { + "line": 8, + "expression": "v[1]", + "kind": "float", + "positions": [ + [ + 2, + 2 + ] + ], + "provenance": "Read the original decoded scalar; the decoder retains integer/float kinds determined by JSON lexical form and int64 range." + }, + { + "line": 8, + "expression": "v[2]", + "kind": "int", + "positions": [ + [ + 1, + 1 + ], + [ + 2, + 3 + ] + ], + "provenance": "Read the original decoded scalar; the decoder retains integer/float kinds determined by JSON lexical form and int64 range." + }, + { + "line": 8, + "expression": "v[3]", + "kind": "float", + "positions": [ + [ + 2, + 4 + ] + ], + "provenance": "Read the original decoded scalar; the decoder retains integer/float kinds determined by JSON lexical form and int64 range." + }, + { + "line": 8, + "expression": "v[4]", + "kind": "int", + "positions": [ + [ + 1, + 2 + ], + [ + 2, + 5 + ] + ], + "provenance": "Read the original decoded scalar; the decoder retains integer/float kinds determined by JSON lexical form and int64 range." + }, + { + "line": 8, + "expression": "v[5]", + "kind": "int", + "positions": [ + [ + 2, + 6 + ] + ], + "provenance": "Read the original decoded scalar; the decoder retains integer/float kinds determined by JSON lexical form and int64 range." + }, + { + "line": 8, + "expression": "v[6]", + "kind": "float", + "positions": [ + [ + 2, + 7 + ] + ], + "provenance": "Read the original decoded scalar; the decoder retains integer/float kinds determined by JSON lexical form and int64 range." + } + ] + }, + "tests/phase2/builtins/builtins/json_encode.branch": { + "old_sha256": "81bc7821029d6e28236e73ce74331fa3155c7cd5188589e29ecb7c282816c3a9", + "source_sha256": "57ad4bb2bb19eb81781f03e55156d514859df43d4ef15c1f6573b64cc23c90ae", + "witnesses": [ + { + "line": 7, + "expression": "3", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ] + }, + { + "line": 7, + "expression": "9007199254740993", + "kind": "int", + "positions": [ + [ + 1, + 2 + ], + [ + 1, + 7 + ] + ] + }, + { + "line": 7, + "expression": "9223372036854775807", + "kind": "int", + "positions": [ + [ + 1, + 3 + ] + ] + }, + { + "line": 7, + "expression": "-9223372036854775807 - 1", + "kind": "int", + "positions": [ + [ + 1, + 4 + ] + ] + }, + { + "line": 7, + "expression": "2.5", + "kind": "float", + "positions": [ + [ + 1, + 5 + ] + ] + }, + { + "line": 7, + "expression": "3.0", + "kind": "float", + "positions": [ + [ + 1, + 6 + ] + ] + } + ] + }, + "tests/phase2/builtins/builtins/leaky_relu.branch": { + "old_sha256": "0bc1fd4db8d4a538c959960a5a577e5242a7b0bbb7f9c985d30d3721b19cb281", + "source_sha256": "3919d59d22ef87d757cee26bc7b813650db6be68524223b550caca1e2dfe8a09", + "witnesses": [ + { + "line": 8, + "expression": "r[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 8, + "expression": "r[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/log.branch": { + "old_sha256": "2d22f33b55ea4de06d1a0b8b46253953e26465dd16dcda4e8f1eb5646801f375", + "source_sha256": "7d2cc7a3d6484ab5d99ddb8ee207468db47c2ade5bf166c8a1a5bab7e4428c17", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/matmul.branch": { + "old_sha256": "f1cb59029c7fad2bf37a37f4389a2076ce102a775d4f575a661b595c3345058f", + "source_sha256": "9391c3abf201eb80be85b1796d478e4e924a6fbb02009fb74bb8a437e76502e8", + "witnesses": [ + { + "line": 8, + "expression": "r", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + } + ] + }, + "tests/phase2/builtins/builtins/matmul_at.branch": { + "old_sha256": "d6c713a4570fedbd238455087008936022d2c56dc2620685634baa6494fb986a", + "source_sha256": "26b7bf0e171cb8cfa7d8780f715f8e7a3e8161ccff1542fe979b1ede70ce216c", + "witnesses": [ + { + "line": 8, + "expression": "r", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + } + ] + }, + "tests/phase2/builtins/builtins/matmul_bt.branch": { + "old_sha256": "3de3670fc9b3b36b00949e2965d35f9e581f4ea7616249aa884dc2ef414318a6", + "source_sha256": "c757d9ca816f613245f83c9c2bc2dcc909aca6cb08a1c2ab8c9e40f07490d717", + "witnesses": [ + { + "line": 8, + "expression": "r", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "Read this exact retained matrix-product result leaf; each printed cell gets an independent kind check." + } + ] + }, + "tests/phase2/builtins/builtins/max.branch": { + "old_sha256": "540ee7840bf80662918b4d4189add017778d08c503488529c6fec539d0e6bb8a", + "source_sha256": "8c551f0aa27fdf3c9408c88f65fa5c2dde3209f5df1fc9d12d4c09319a119002", + "witnesses": [ + { + "line": 7, + "expression": "max of [9007199254740993, 9007199254740992]", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ] + }, + { + "line": 9, + "expression": "max of [3, 2.5]", + "kind": "int", + "positions": [ + [ + 2, + 1 + ] + ] + }, + { + "line": 11, + "expression": "max of [2, 2.5]", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ] + }, + { + "line": 13, + "expression": "max of 7", + "kind": "int", + "positions": [ + [ + 4, + 1 + ] + ] + }, + { + "line": 15, + "expression": "max of [3, 3.0]", + "kind": "int", + "positions": [ + [ + 5, + 1 + ] + ] + }, + { + "line": 15, + "expression": "max of [3.0, 3]", + "kind": "float", + "positions": [ + [ + 5, + 2 + ] + ] + } + ] + }, + "tests/phase2/builtins/builtins/mean.branch": { + "old_sha256": "957ab0974154733d37d6fbc3004e82e924761e9c64cae7126984329110a0743b", + "source_sha256": "5cefaf4912e7cbc795a09e20d0edb0576419b6eeea0b89d10435a9cf2711dbd6", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/min.branch": { + "old_sha256": "f45bde7acd9b053b3379e15b35c9e06f2ba11243437f5a5926b62aad588d2118", + "source_sha256": "e4e3051cdc28551753d2a29e4e6667a0e8e63b4cd9b4d072e48226fd8b244b9f", + "witnesses": [ + { + "line": 7, + "expression": "min of [9007199254740993, 9007199254740994]", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ] + }, + { + "line": 9, + "expression": "min of [3, 3.5]", + "kind": "int", + "positions": [ + [ + 2, + 1 + ] + ] + }, + { + "line": 11, + "expression": "min of [4, 3.5]", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ] + }, + { + "line": 13, + "expression": "min of 7", + "kind": "int", + "positions": [ + [ + 4, + 1 + ] + ] + }, + { + "line": 15, + "expression": "min of [3, 3.0]", + "kind": "int", + "positions": [ + [ + 5, + 1 + ] + ] + }, + { + "line": 15, + "expression": "min of [3.0, 3]", + "kind": "float", + "positions": [ + [ + 5, + 2 + ] + ] + } + ] + }, + "tests/phase2/builtins/builtins/norm.branch": { + "old_sha256": "5c2f187cf2973b5b1a305d592804123f3574578e251042668adb284090d811a1", + "source_sha256": "2932993a0b0ec38b07f0bf641aca8ec85829e6dcc159b5a3bf9a72262ae1141c", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/num.branch": { + "old_sha256": "5bd7970cd996eb2a437018da3aa033c297f38aa4a877af74f8ad4221ecee0660", + "source_sha256": "52194b92bf0af47121356671a2d608c4adfbf32664d21028641a6fb0e196ed9c", + "witnesses": [ + { + "line": 13, + "expression": "\"3\"", + "kind": "text", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\"3\"", + "kind": "int", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"3.0\"", + "kind": "text", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\"3.0\"", + "kind": "float", + "positions": [ + [ + 2, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"9007199254740993\"", + "kind": "text", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\"9007199254740993\"", + "kind": "int", + "positions": [ + [ + 3, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"9223372036854775808\"", + "kind": "text", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\"9223372036854775808\"", + "kind": "float", + "positions": [ + [ + 4, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\" 12 \"", + "kind": "text", + "positions": [ + [ + 5, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\" 12 \"", + "kind": "int", + "positions": [ + [ + 5, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"+5\"", + "kind": "text", + "positions": [ + [ + 6, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\"+5\"", + "kind": "int", + "positions": [ + [ + 6, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"-0x10\"", + "kind": "int", + "positions": [ + [ + 7, + 1 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"0x1F\"", + "kind": "int", + "positions": [ + [ + 8, + 1 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"0X1f\"", + "kind": "int", + "positions": [ + [ + 9, + 1 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"0xFFFFFFFFFFFFFFFF\"", + "kind": "int", + "positions": [ + [ + 10, + 1 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\".5\"", + "kind": "text", + "positions": [ + [ + 11, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\".5\"", + "kind": "float", + "positions": [ + [ + 11, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"1.\"", + "kind": "float", + "positions": [ + [ + 12, + 1 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"1e5\"", + "kind": "text", + "positions": [ + [ + 13, + 1 + ] + ], + "provenance": "Echoed input is the literal string s. type of this same string must be string; its numeric-looking bytes must remain byte-identical.", + "reader": "type" + }, + { + "line": 13, + "expression": "\"1e5\"", + "kind": "float", + "positions": [ + [ + 13, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; this duplicates only the pure conversion, avoiding p's scoped local v.", + "transform": "num" + }, + { + "line": 13, + "expression": "\"-9223372036854775808\"", + "kind": "text", + "positions": [ + [ + 25, + 1 + ] + ], + "provenance": "Echoed numeric-looking string is immutable text.", + "reader": "type" + }, + { + "line": 13, + "expression": "\"-9223372036854775808\"", + "kind": "int", + "positions": [ + [ + 25, + 2 + ] + ], + "provenance": "Apply num to the exact source string input; it returns the exact int64 minimum.", + "transform": "num" + }, + { + "line": 16, + "expression": "n", + "kind": "int", + "positions": [ + [ + 26, + 1 + ] + ], + "provenance": "The original conversion result remains in module binding n." + }, + { + "line": 18, + "expression": "f", + "kind": "float", + "positions": [ + [ + 27, + 1 + ] + ], + "provenance": "The original conversion result remains in module binding f." + } + ] + }, + "tests/phase2/builtins/builtins/numerical_grad.branch": { + "old_sha256": "b6d80c99de9aebf09340531468149f1bba9b5d4283725ff6ab78610fc9e21a53", + "source_sha256": "b0138b8120cd306c55a49e648f1538650f59a42a191edc3f79a7a752aea814c7", + "witnesses": [ + { + "line": 11, + "expression": "g", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + } + ] + }, + "tests/phase2/builtins/builtins/numerical_grad_cols.branch": { + "old_sha256": "e1a11fe248d17b6348dcaf4bfc7b4d6cb62d18255ffbadd96d57e6c53491596a", + "source_sha256": "5fd0e6755d72987cff2efbe8c5e5cfae3c418cd41df14c0e2ab6b6ba05b08fdc", + "witnesses": [ + { + "line": 11, + "expression": "g", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 16, + "expression": "numerical_grad_cols of [loss, q, [0.0, 1.0], 0.5]", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + }, + { + "line": 16, + "expression": "numerical_grad_cols of [loss, q, [0.0, 1.0], 0.5]", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 3, + 2 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + }, + { + "line": 16, + "expression": "numerical_grad_cols of [loss, q, [0.0, 1.0], 0.5]", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 3, + 3 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + }, + { + "line": 16, + "expression": "numerical_grad_cols of [loss, q, [0.0, 1.0], 0.5]", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 3, + 4 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + } + ] + }, + "tests/phase2/builtins/builtins/numerical_grad_rows.branch": { + "old_sha256": "2b81582aa2f984d195ccdae96c505598820bfd38931ecbd81c9d376a16c74691", + "source_sha256": "aac32d799947b0fcae207b17dec48614b622c71ad7e4b3fd2a55e5b1d161e788", + "witnesses": [ + { + "line": 11, + "expression": "g", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 11, + "expression": "g", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "Read this exact retained finite-difference gradient leaf after the marker." + }, + { + "line": 16, + "expression": "numerical_grad_rows of [loss, q, [1.0, 0.0], 0.5]", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + }, + { + "line": 16, + "expression": "numerical_grad_rows of [loss, q, [1.0, 0.0], 0.5]", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 3, + 2 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + }, + { + "line": 16, + "expression": "numerical_grad_rows of [loss, q, [1.0, 0.0], 0.5]", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 3, + 3 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + }, + { + "line": 16, + "expression": "numerical_grad_rows of [loss, q, [1.0, 0.0], 0.5]", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 3, + 4 + ] + ], + "provenance": "Reevaluate the exact source finite-difference call and read this output leaf. The kernel restores perturbed q cells, prints nothing, and performs no I/O; no scoped local is required." + } + ] + }, + "tests/phase2/builtins/builtins/observe.branch": { + "old_sha256": "5e443e730314fd12810eab1f7403adb88dc7d14a60b7c7be3b801da6d9555c59", + "source_sha256": "71cc7d272af662bc7694768b0a8ed16f8a30fd06bf0b9fff6ca99b8e9d388e85", + "witnesses": [ + { + "line": 9, + "expression": "r[1]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "The original observe result readout remains accessible; no observer read is rerun." + }, + { + "line": 9, + "expression": "r[2]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "The original observe result readout remains accessible; no observer read is rerun." + }, + { + "line": 9, + "expression": "r[3]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "The original observe result readout remains accessible; no observer read is rerun." + } + ] + }, + "tests/phase2/builtins/builtins/pow.branch": { + "old_sha256": "9f38b23f8ce783c1d4a5342c371df39fcbe9c247676b4b395c591138e964dd2c", + "source_sha256": "a8b832fa09a2679eec35184a551036c4627f6236d7fad4b5537d8dc6f5eb954b", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/ppu_render_frame.branch": { + "old_sha256": "4c5783197fa7af691cb64ab41271f11a1fbe9ecda8e6f11ad6868f2e867a5a78", + "source_sha256": "7864916dbbdaee01210c1ebd894a3c33eb93354c823fb820ca3fb3d31280aac6", + "witnesses": [ + { + "line": 11, + "expression": "fb[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 4, + 1 + ] + ], + "provenance": "fb is always a float buffer; later rendering changes values, never the float kind." + }, + { + "line": 27, + "expression": "fb[23039]", + "kind": "float", + "positions": [ + [ + 4, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 24, + "expression": "\"lcdc-401\"", + "kind": "text", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Immutable source string literal names the invalid input. Its numeric-looking token is text, so preserve it byte for byte; type of the source expression must be string.", + "reader": "type" + } + ] + }, + "tests/phase2/builtins/builtins/print.branch": { + "old_sha256": "c1bb91c32873e25fec016b1c8a33a9dd8626601a39518971a9bcfe71cd71351c", + "source_sha256": "850240e1bcf99689a236882af26025615203f90067b935385a70dea81bf97d8f", + "witnesses": [ + { + "line": 7, + "expression": "9007199254740993", + "kind": "int", + "positions": [ + [ + 1, + 1 + ], + [ + 4, + 1 + ] + ], + "provenance": "Both printed occurrences are the same exact integer source literal." + }, + { + "line": 8, + "expression": "2.5", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original printed numeric payload is this source float literal." + }, + { + "line": 9, + "expression": "3.0", + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Original printed numeric payload is this source float literal." + }, + { + "line": 10, + "expression": "1e300", + "kind": "float", + "positions": [ + [ + 4, + 2 + ] + ], + "provenance": "Original printed numeric payload is this source float literal." + } + ] + }, + "tests/phase2/builtins/builtins/proc_read_buf.hi.branch": { + "old_sha256": "6a4eac6578eaf7ddde381600841f2c7f83ed104a443ead1da21ce8824ccf1c7a", + "source_sha256": "7af30b36bd60d04b0ff0e6bd5d690fa15db493dd25c88cd56813304d0be6cce3", + "witnesses": [ + { + "line": 8, + "expression": "buf_len of b", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Integer count of original stdin fixture buffer. run_witnesses must supply cases.tsv's Hi bytes." + }, + { + "line": 8, + "expression": "b[0]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read the original byte buffer retained from the Hi stdin fixture; never reread stdin." + }, + { + "line": 8, + "expression": "b[1]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read the original byte buffer retained from the Hi stdin fixture; never reread stdin." + } + ] + }, + "tests/phase2/builtins/builtins/read_bytes_buf.branch": { + "old_sha256": "92cd179b023bfae64f3ac77dc15312982db17e17da8415916797aaa0b48d6abf", + "source_sha256": "f315f8491954fadb590b6e8c523e68d9188a95bd2035991ad64af4a95d8cbe6d", + "witnesses": [ + { + "line": 11, + "expression": "buf_len of b", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original byte-buffer length is an integer count; EIGS_PROBE_TMP must name the per-run temporary fixture directory." + }, + { + "line": 11, + "expression": "b[0]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 18, + "expression": "buf_len of d", + "kind": "int", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Original byte-buffer length is an integer count." + } + ] + }, + "tests/phase2/builtins/builtins/relu.branch": { + "old_sha256": "2eb77d7f928006355c24388638f58ef6731548e2786028e8addb9bdf79c7e86f", + "source_sha256": "89ebd3e9db35aac2b4226e5d2096bb7e5712efe11d85bd46b8d023c895928f17", + "witnesses": [ + { + "line": 8, + "expression": "r[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 8, + "expression": "r[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 10, + "expression": "s", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/scatter_add.branch": { + "old_sha256": "33667024c1bd1f4c53e0e69beeb861d1216a69d8e15f7baa564e09b02eb8b945", + "source_sha256": "7ac0197139235dd9278418fc3ff0391a58fb3b33d9059f23c89566795c4d4f2c", + "witnesses": [ + { + "line": 9, + "expression": "d[0]", + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 3, + 1 + ] + ], + "provenance": "d is always a float buffer; later accumulation preserves numeric kinds." + }, + { + "line": 9, + "expression": "d[1]", + "kind": "float", + "positions": [ + [ + 1, + 2 + ], + [ + 3, + 2 + ] + ], + "provenance": "d is always a float buffer; later accumulation preserves numeric kinds." + }, + { + "line": 9, + "expression": "d[2]", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "d is always a float buffer; later accumulation preserves numeric kinds." + } + ] + }, + "tests/phase2/builtins/builtins/set_at.branch": { + "old_sha256": "220750d891ed80228512827027ba0cbc25c44ee8f1faefe1d0f0726b78138842", + "source_sha256": "7e598419b13989f17b453bfaab59db90804f6fe9bf2b92a7a0e3acd49016df5e", + "witnesses": [ + { + "line": 7, + "expression": "10", + "kind": "int", + "positions": [ + [ + 1, + 1 + ], + [ + 3, + 1 + ] + ], + "provenance": "Integer source literal copied or retained in the list; later writes preserve the separately witnessed source integer kind." + }, + { + "line": 8, + "expression": "99", + "kind": "int", + "positions": [ + [ + 1, + 2 + ], + [ + 3, + 2 + ] + ], + "provenance": "Integer source literal copied or retained in the list; later writes preserve the separately witnessed source integer kind." + }, + { + "line": 7, + "expression": "30", + "kind": "int", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Integer source literal copied or retained in the list; later writes preserve the separately witnessed source integer kind." + }, + { + "line": 15, + "expression": "5", + "kind": "int", + "positions": [ + [ + 3, + 3 + ] + ], + "provenance": "Integer source literal copied or retained in the list; later writes preserve the separately witnessed source integer kind." + }, + { + "line": 19, + "expression": "b[0]", + "kind": "float", + "positions": [ + [ + 4, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/sgd_update.branch": { + "old_sha256": "f02d7a678590875247424cf99d02cf8c15c9402c1be559db90566aec0395c1f5", + "source_sha256": "3036dfed6fdb67f969596d88709c5b9dd93aaf1f7247dfd3f9e6e27b2b0efa4e", + "witnesses": [ + { + "line": 8, + "expression": "r", + "index_path": [ + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained SGD result leaf after the marker." + }, + { + "line": 8, + "expression": "r", + "index_path": [ + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained SGD result leaf after the marker." + } + ] + }, + "tests/phase2/builtins/builtins/sgd_update_cols.branch": { + "old_sha256": "b3db713df38a6acc28f8e8996caf7201528f9ea4d314c28b0849959ac7179e7f", + "source_sha256": "e66955425b033ec9033ad9a6abf0ba2b18a6f26ba83327439dcc5e09d97ba649", + "witnesses": [ + { + "line": 10, + "expression": "m", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 3, + 1 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + }, + { + "line": 10, + "expression": "m", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ], + [ + 3, + 2 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + }, + { + "line": 10, + "expression": "m", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ], + [ + 3, + 3 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + }, + { + "line": 10, + "expression": "m", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ], + [ + 3, + 4 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + } + ] + }, + "tests/phase2/builtins/builtins/sgd_update_rows.branch": { + "old_sha256": "823d398fec95c5ac6dcd1c1576ebbcb6420989a6a5b61bc8fedd696cc2e48cb5", + "source_sha256": "e53fc455967a9657fa51f1283b409685ab23b51e5dec0d332c0fad0e209cf295", + "witnesses": [ + { + "line": 10, + "expression": "m", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ], + [ + 3, + 1 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + }, + { + "line": 10, + "expression": "m", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ], + [ + 3, + 2 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + }, + { + "line": 10, + "expression": "m", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ], + [ + 3, + 3 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + }, + { + "line": 10, + "expression": "m", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ], + [ + 3, + 4 + ] + ], + "provenance": "Read this exact retained SGD matrix leaf. Later in-place updates change its value but the scalar kind remains independently witnessed after the marker; original/candidate value bits are checked separately." + } + ] + }, + "tests/phase2/builtins/builtins/sin.branch": { + "old_sha256": "3e39f8107440abe2750bf55634e12e4d1e4f47b971dbf84ad77e03afa0b18ec2", + "source_sha256": "1b7c5e1f0ffcc48aaa6fa0696d16e25ecad4ba4614ff9752a3ead1c8b8dabae1", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/sqrt.branch": { + "old_sha256": "3ccf9c32fa8d3cd6bf5fb1acd09297ad27ff5085362415eec99c863bc551c810", + "source_sha256": "519b5eb0aeb32605b60a169df5114e18d89ebe85e156e916862dbe807a699cb1", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/str.branch": { + "old_sha256": "a546d0eca3bf4900e12fe97f116b9881419c5c99efcda9e22adba6d6816f1b5d", + "source_sha256": "43810df34d1ad8464b7b7e8c9e78412878d94074c6faa2676d226c9f61811178", + "witnesses": [ + { + "line": 7, + "expression": "9007199254740993", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ] + }, + { + "line": 7, + "expression": "2.5", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ] + }, + { + "line": 7, + "expression": "3.0", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ] + }, + { + "line": 7, + "expression": "-9223372036854775807 - 1", + "kind": "int", + "positions": [ + [ + 1, + 4 + ] + ] + } + ] + }, + "tests/phase2/builtins/builtins/stream_write.branch": { + "old_sha256": "0ba1d1ba909707a169442d449cdd4fc5dd1f1043a38adea49dbee22cc087fc7a", + "source_sha256": "fe3f6d4b99020167af724c5ed8497a08b3e42290152d966dd61f359eaac168bd", + "witnesses": [ + { + "line": 11, + "expression": "t[0]", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Read the original float decoded from the raw-f64 stream; the source int 3 became f64 storage before printing." + }, + { + "line": 11, + "expression": "t[1]", + "kind": "float", + "positions": [ + [ + 2, + 2 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + } + ] + }, + "tests/phase2/builtins/builtins/tan.branch": { + "old_sha256": "7d8dba4273be72ed366e4f8bcdf05715c466ebec943055ea56d723e8271ae95f", + "source_sha256": "3e40600bf9d8c9166350f2bd2fa850186a28108373a6838bdd5ad6dbba89c3fa", + "witnesses": [ + { + "line": 8, + "expression": "a", + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding a." + }, + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Original scalar result remains in module binding b." + } + ] + }, + "tests/phase2/builtins/builtins/tensor_load.branch": { + "old_sha256": "7f45bd23e6a6487be2111a9ab04b407205be16abe6d5654e852c9c3a23f1ba26", + "source_sha256": "1d2d20071e9e6c1b6eb0faf90ef5c6d486ed0f09dcdcb08f7b35bd786157ab71", + "witnesses": [ + { + "line": 11, + "expression": "t", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained loaded tensor leaf after the marker." + }, + { + "line": 11, + "expression": "t", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained loaded tensor leaf after the marker." + }, + { + "line": 11, + "expression": "t", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "Read this exact retained loaded tensor leaf after the marker." + }, + { + "line": 11, + "expression": "t", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 4 + ] + ], + "provenance": "Read this exact retained loaded tensor leaf after the marker." + }, + { + "line": 11, + "expression": "shape of t", + "index_path": [ + 0 + ], + "kind": "int", + "positions": [ + [ + 1, + 5 + ] + ], + "provenance": "Reevaluate the pure shape read and inspect this exact integer dimension count." + }, + { + "line": 11, + "expression": "shape of t", + "index_path": [ + 1 + ], + "kind": "int", + "positions": [ + [ + 1, + 6 + ] + ], + "provenance": "Reevaluate the pure shape read and inspect this exact integer dimension count." + } + ] + }, + "tests/phase2/builtins/builtins/tensor_save.branch": { + "old_sha256": "1b73968293611b206533cb27ee3b3066aa56e222b9a3fe2473880e2ec6cd5057", + "source_sha256": "c57ecd8feca7dc827290c5ed891ae841165a63e5d8446c23a75b6b3af63490ab", + "witnesses": [ + { + "line": 11, + "expression": "t", + "index_path": [ + 0 + ], + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Read this exact retained tensor-load leaf after the marker; no filesystem operation is repeated." + }, + { + "line": 11, + "expression": "t", + "index_path": [ + 1 + ], + "kind": "float", + "positions": [ + [ + 2, + 2 + ] + ], + "provenance": "Read this exact retained tensor-load leaf after the marker; no filesystem operation is repeated." + }, + { + "line": 11, + "expression": "t", + "index_path": [ + 2 + ], + "kind": "float", + "positions": [ + [ + 2, + 3 + ] + ], + "provenance": "Read this exact retained tensor-load leaf after the marker; no filesystem operation is repeated." + } + ] + }, + "tests/phase2/builtins/builtins/text_builder_append.branch": { + "old_sha256": "b312faffe01ba083116c315f35e3bc3fd990944496f95274d38f6ca84af2115d", + "source_sha256": "6aa3d98ab5d07f8ddcd19dc34696289a194977ffde8e9a2c01c00cdcf8e9ae6b", + "witnesses": [ + { + "line": 8, + "expression": "9007199254740993", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "The numeric source literal was formatted into text by this exact source call; evaluating only the literal has no effects." + }, + { + "line": 10, + "expression": "2.5", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "The numeric source literal was formatted into text by this exact source call; evaluating only the literal has no effects." + }, + { + "line": 12, + "expression": "3.0", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "The numeric source literal was formatted into text by this exact source call; evaluating only the literal has no effects." + } + ] + }, + "tests/phase2/builtins/builtins/write.branch": { + "old_sha256": "a69d7121ddc382dd987c69d1cdff1572a48936c3d6c8494f30cd22eee34159c0", + "source_sha256": "a25b9b9d7ab2fa20b4a13b1c0250ca8a7f020fe290b2d94712b84b31ee0cf242", + "witnesses": [ + { + "line": 7, + "expression": "9007199254740993", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "The numeric source literal was formatted into text by this exact source call; evaluating only the literal has no effects." + }, + { + "line": 9, + "expression": "2.5", + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "The numeric source literal was formatted into text by this exact source call; evaluating only the literal has no effects." + }, + { + "line": 11, + "expression": "3.0", + "kind": "float", + "positions": [ + [ + 1, + 3 + ] + ], + "provenance": "The numeric source literal was formatted into text by this exact source call; evaluating only the literal has no effects." + } + ] + }, + "tests/phase2/builtins/builtins/zeros.branch": { + "old_sha256": "b44706dfefc4bdc12c69f66975b8ff7e59cda39b00b17a252c5b00228996bcd9", + "source_sha256": "cc0718a4bf38f3ae20cb9734919a5d3688d6c68afeabf9341ac78648ab080df2", + "witnesses": [ + { + "line": 8, + "expression": "buf_len of z", + "kind": "int", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Original buffer length is an integer count." + }, + { + "line": 19, + "expression": "buf_len of (zeros of 2.0)", + "kind": "int", + "positions": [ + [ + 5, + 1 + ] + ], + "provenance": "Reevaluate the pure source count expression; integral-float size does not change integer count kind." + }, + { + "line": 14, + "expression": "m", + "index_path": [ + 0, + 0 + ], + "kind": "float", + "positions": [ + [ + 3, + 1 + ] + ], + "provenance": "Read this exact retained zero-matrix leaf after the marker." + }, + { + "line": 14, + "expression": "m", + "index_path": [ + 0, + 1 + ], + "kind": "float", + "positions": [ + [ + 3, + 2 + ] + ], + "provenance": "Read this exact retained zero-matrix leaf after the marker." + }, + { + "line": 14, + "expression": "m", + "index_path": [ + 1, + 0 + ], + "kind": "float", + "positions": [ + [ + 3, + 3 + ] + ], + "provenance": "Read this exact retained zero-matrix leaf after the marker." + }, + { + "line": 14, + "expression": "m", + "index_path": [ + 1, + 1 + ], + "kind": "float", + "positions": [ + [ + 3, + 4 + ] + ], + "provenance": "Read this exact retained zero-matrix leaf after the marker." + } + ] + }, + "tests/phase2/builtins/builtins/zeros_like.branch": { + "old_sha256": "b872d9da1b235b3cd0c42c014f5be6666e3d2afea756ed338f72e66c71aa749f", + "source_sha256": "6c97e2bf0c18e9f4efd0eddfb9b3d0fceeb017e0fb5e791c7cd5eb7aad4dda33", + "witnesses": [ + { + "line": 10, + "expression": "b", + "kind": "float", + "positions": [ + [ + 2, + 1 + ] + ], + "provenance": "Stored result is a float; the expression remains accessible after the frozen source completes." + }, + { + "line": 8, + "expression": "a", + "index_path": [ + 0 + ], + "kind": "float", + "positions": [ + [ + 1, + 1 + ] + ], + "provenance": "Read this exact retained zeros_like result leaf after the marker." + }, + { + "line": 8, + "expression": "a", + "index_path": [ + 1 + ], + "kind": "float", + "positions": [ + [ + 1, + 2 + ] + ], + "provenance": "Read this exact retained zeros_like result leaf after the marker." + } + ] + } + } +} diff --git a/tests/phase2/rows/N13.vm-buffer-index-data.out b/tests/phase2/rows/N13.vm-buffer-index-data.out index 0b86f3498..56bdf8f8c 100644 --- a/tests/phase2/rows/N13.vm-buffer-index-data.out +++ b/tests/phase2/rows/N13.vm-buffer-index-data.out @@ -1,6 +1,6 @@ -["nan", "value", true, 2, false] -["inf", "value", true, 2, false] -["-inf", "value", true, 2, false] -["nan", "value", true, 2, true] -["inf", "value", true, 2, true] -["-inf", "value", true, 2, true] +["nan", "value", true, 2.0, false] +["inf", "value", true, 2.0, false] +["-inf", "value", true, 2.0, false] +["nan", "value", true, 2.0, true] +["inf", "value", true, 2.0, true] +["-inf", "value", true, 2.0, true] diff --git a/tests/phase2/rows/N13.vm-buffer-int-index-data.out b/tests/phase2/rows/N13.vm-buffer-int-index-data.out index 0b86f3498..56bdf8f8c 100644 --- a/tests/phase2/rows/N13.vm-buffer-int-index-data.out +++ b/tests/phase2/rows/N13.vm-buffer-int-index-data.out @@ -1,6 +1,6 @@ -["nan", "value", true, 2, false] -["inf", "value", true, 2, false] -["-inf", "value", true, 2, false] -["nan", "value", true, 2, true] -["inf", "value", true, 2, true] -["-inf", "value", true, 2, true] +["nan", "value", true, 2.0, false] +["inf", "value", true, 2.0, false] +["-inf", "value", true, 2.0, false] +["nan", "value", true, 2.0, true] +["inf", "value", true, 2.0, true] +["-inf", "value", true, 2.0, true] diff --git a/tests/phase2/rows/N13.vm-buffer-iter-data.out b/tests/phase2/rows/N13.vm-buffer-iter-data.out index 21155cc28..9a08f5d54 100644 --- a/tests/phase2/rows/N13.vm-buffer-iter-data.out +++ b/tests/phase2/rows/N13.vm-buffer-iter-data.out @@ -1,6 +1,6 @@ -["nan", "value", true, 3, false] -["inf", "value", true, 3, false] -["-inf", "value", true, 3, false] -["nan", "value", true, 3, true] -["inf", "value", true, 3, true] -["-inf", "value", true, 3, true] +["nan", "value", true, 3.0, false] +["inf", "value", true, 3.0, false] +["-inf", "value", true, 3.0, false] +["nan", "value", true, 3.0, true] +["inf", "value", true, 3.0, true] +["-inf", "value", true, 3.0, true] diff --git a/tests/phase2/rows/N13.vm-buffer-leaf-index-data.out b/tests/phase2/rows/N13.vm-buffer-leaf-index-data.out index 0b86f3498..56bdf8f8c 100644 --- a/tests/phase2/rows/N13.vm-buffer-leaf-index-data.out +++ b/tests/phase2/rows/N13.vm-buffer-leaf-index-data.out @@ -1,6 +1,6 @@ -["nan", "value", true, 2, false] -["inf", "value", true, 2, false] -["-inf", "value", true, 2, false] -["nan", "value", true, 2, true] -["inf", "value", true, 2, true] -["-inf", "value", true, 2, true] +["nan", "value", true, 2.0, false] +["inf", "value", true, 2.0, false] +["-inf", "value", true, 2.0, false] +["nan", "value", true, 2.0, true] +["inf", "value", true, 2.0, true] +["-inf", "value", true, 2.0, true] diff --git a/tests/phase2/rows/N13.vm-buffer-local-index-data.out b/tests/phase2/rows/N13.vm-buffer-local-index-data.out index 0b86f3498..56bdf8f8c 100644 --- a/tests/phase2/rows/N13.vm-buffer-local-index-data.out +++ b/tests/phase2/rows/N13.vm-buffer-local-index-data.out @@ -1,6 +1,6 @@ -["nan", "value", true, 2, false] -["inf", "value", true, 2, false] -["-inf", "value", true, 2, false] -["nan", "value", true, 2, true] -["inf", "value", true, 2, true] -["-inf", "value", true, 2, true] +["nan", "value", true, 2.0, false] +["inf", "value", true, 2.0, false] +["-inf", "value", true, 2.0, false] +["nan", "value", true, 2.0, true] +["inf", "value", true, 2.0, true] +["-inf", "value", true, 2.0, true] diff --git a/tests/phase2/rows/N4.compound-float-floordiv-boundaries.out b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.out index ad6dccf15..b5da3a842 100644 --- a/tests/phase2/rows/N4.compound-float-floordiv-boundaries.out +++ b/tests/phase2/rows/N4.compound-float-floordiv-boundaries.out @@ -1 +1 @@ -[9, 9, [-1, -1], "float", "float"] +[9.0, 9.0, [-1.0, -1.0], "float", "float"] diff --git a/tests/phase2/rows/N4.compound-floordiv.out b/tests/phase2/rows/N4.compound-floordiv.out index 5e7764260..a88b09bc0 100644 --- a/tests/phase2/rows/N4.compound-floordiv.out +++ b/tests/phase2/rows/N4.compound-floordiv.out @@ -1 +1 @@ -[-4, -4, [-4, -4], "int", "float"] +[-4, -4.0, [-4, -4.0], "int", "float"] diff --git a/tests/phase2/rows/N4.float-floordiv-rounding.out b/tests/phase2/rows/N4.float-floordiv-rounding.out index 7e673045d..be0c5f218 100644 --- a/tests/phase2/rows/N4.float-floordiv-rounding.out +++ b/tests/phase2/rows/N4.float-floordiv-rounding.out @@ -1 +1 @@ -[9, 9, 9, 74, -10, -30, "float"] +[9.0, 9.0, 9.0, 74.0, -10.0, -30.0, "float"] diff --git a/tests/phase2/rows/N4.float-floordiv-underflow.out b/tests/phase2/rows/N4.float-floordiv-underflow.out index 02c90e177..080cfd107 100644 --- a/tests/phase2/rows/N4.float-floordiv-underflow.out +++ b/tests/phase2/rows/N4.float-floordiv-underflow.out @@ -1 +1 @@ -[-1, -1, 0, "float"] +[-1.0, -1.0, 0.0, "float"] diff --git a/tests/phase2/rows/N4.floordiv.out b/tests/phase2/rows/N4.floordiv.out index f13b0757d..43a8bf5f2 100644 --- a/tests/phase2/rows/N4.floordiv.out +++ b/tests/phase2/rows/N4.floordiv.out @@ -1 +1 @@ -[3, -4, 3, "int", "float"] +[3, -4, 3.0, "int", "float"] diff --git a/tests/phase2/rows/N4.fn-float-floordiv-rounding.out b/tests/phase2/rows/N4.fn-float-floordiv-rounding.out index f3f9746e5..f0d17590a 100644 --- a/tests/phase2/rows/N4.fn-float-floordiv-rounding.out +++ b/tests/phase2/rows/N4.fn-float-floordiv-rounding.out @@ -1 +1 @@ -[9, 9, 9, 74, -30, "float"] +[9.0, 9.0, 9.0, 74.0, -30.0, "float"] diff --git a/tests/phase2/rows/N4.fn-float-floordiv-underflow.out b/tests/phase2/rows/N4.fn-float-floordiv-underflow.out index 2157a2566..5d21c00a3 100644 --- a/tests/phase2/rows/N4.fn-float-floordiv-underflow.out +++ b/tests/phase2/rows/N4.fn-float-floordiv-underflow.out @@ -1 +1 @@ -[-1, -1, "float"] +[-1.0, -1.0, "float"] diff --git a/tests/phase2/rows/N4.fn-floordiv.out b/tests/phase2/rows/N4.fn-floordiv.out index e25c371f9..7bef99a48 100644 --- a/tests/phase2/rows/N4.fn-floordiv.out +++ b/tests/phase2/rows/N4.fn-floordiv.out @@ -1 +1 @@ -[-4, "float"] +[-4.0, "float"] diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index 3c2033492..474b813cd 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -720,11 +720,11 @@ static const Arm ARMS[] = { {"shl", "xs[0] << 1", "10", "10", 0}, {"shr", "xs[0] >> 1", "2", "2", 0}, {"band_in_try", "xs[0] & 3", "1", "1", 1}, - {"neg", "-(xs[0])", "-5", "-5", 0}, - {"neg_in_try", "-(xs[0])", "-5", "-5", 1}, + {"neg", "-(xs[0])", "-5.0", "-5", 0}, + {"neg_in_try", "-(xs[0])", "-5.0", "-5", 1}, {"bnot", "~(xs[0])", "-6", "-6", 0}, {"eq", "xs[0] == 5", "true", "true", 0}, - {"add", "xs[0] + 1", "6", "6", 0}, + {"add", "xs[0] + 1", "6.0", "6", 0}, {"overflow_add", "9223372036854775807 + xs[0]", "9.223372036854776e+18", "value", 1}, }; #define N_ARMS ((int)(sizeof ARMS / sizeof ARMS[0])) diff --git a/tests/roads/native_alternate.out b/tests/roads/native_alternate.out index 1e387a0ac..152435c74 100644 --- a/tests/roads/native_alternate.out +++ b/tests/roads/native_alternate.out @@ -1,3 +1,3 @@ -[7300, 26762400] -["v", 1, 7300] -["total", 1, 26762400] +[7300.0, 26762400.0] +["v", 1, 7300.0] +["total", 1, 26762400.0] diff --git a/tests/roads/native_catch.out b/tests/roads/native_catch.out index 83a84dffc..0511910b1 100644 --- a/tests/roads/native_catch.out +++ b/tests/roads/native_catch.out @@ -1,3 +1,3 @@ -[100, 237600] -["v", 1, 100] -["total", 1, 237600] +[100.0, 237600.0] +["v", 1, 100.0] +["total", 1, 237600.0] diff --git a/tests/roads/native_inline.out b/tests/roads/native_inline.out index 12f180dd9..f96655935 100644 --- a/tests/roads/native_inline.out +++ b/tests/roads/native_inline.out @@ -1,2 +1,2 @@ -14999 -["v", 1, 14999] +14999.0 +["v", 1, 14999.0] diff --git a/tests/roads/native_late.out b/tests/roads/native_late.out index fbeebb42a..3534abdc6 100644 --- a/tests/roads/native_late.out +++ b/tests/roads/native_late.out @@ -1,3 +1,3 @@ -[6112, 18814680] -["v", 1, 6112] -["total", 1, 18814680] +[6112.0, 18814680.0] +["v", 1, 6112.0] +["total", 1, 18814680.0] diff --git a/tests/roads/native_match.out b/tests/roads/native_match.out index 83a84dffc..0511910b1 100644 --- a/tests/roads/native_match.out +++ b/tests/roads/native_match.out @@ -1,3 +1,3 @@ -[100, 237600] -["v", 1, 100] -["total", 1, 237600] +[100.0, 237600.0] +["v", 1, 100.0] +["total", 1, 237600.0] diff --git a/tests/roads/native_outer.out b/tests/roads/native_outer.out index a0fef0be5..7cb75fa38 100644 --- a/tests/roads/native_outer.out +++ b/tests/roads/native_outer.out @@ -1,3 +1,3 @@ -[14500, 105451200] -["v", 1, 14500] -["total", 1, 105451200] +[14500.0, 105451200.0] +["v", 1, 14500.0] +["total", 1, 105451200.0] diff --git a/tests/run_all_tests.sh b/tests/run_all_tests.sh index 377a045ef..49a1921e9 100755 --- a/tests/run_all_tests.sh +++ b/tests/run_all_tests.sh @@ -825,7 +825,7 @@ check "T02 String Assignment" "$(echo "$OUTPUT" | grep -A1 'T02' | tail -1)" "he check "T03 Addition" "$(echo "$OUTPUT" | grep -A1 'T03' | tail -1)" "30" check "T04 Subtraction" "$(echo "$OUTPUT" | grep -A1 'T04' | tail -1)" "63" check "T05 Multiplication" "$(echo "$OUTPUT" | grep -A1 'T05' | tail -1)" "42" -check "T06 Division" "$(echo "$OUTPUT" | grep -A1 'T06' | tail -1)" "25" +check "T06 Division" "$(echo "$OUTPUT" | grep -A1 'T06' | tail -1)" "25.0" check "T07 String Concat" "$(echo "$OUTPUT" | grep -A1 'T07' | tail -1)" "hello world" check "T08 Boolean And" "$(echo "$OUTPUT" | grep -A1 'T08' | tail -1)" "1" check "T09 Boolean Or" "$(echo "$OUTPUT" | grep -A1 'T09' | tail -1)" "1" @@ -851,13 +851,13 @@ echo "" echo "[2/15] Interrogative Spec Compliance (LLVM IR parity)" OUTPUT=$(./eigenscript ../tests/test_interrogative_spec.eigs 2>&1) check "WHAT scalar (42)" "$(echo "$OUTPUT" | grep -A1 'eigen_get_value' | tail -1)" "42" -check "WHAT list length (5)" "$(echo "$OUTPUT" | grep -A1 'list length' | tail -1)" "5" -check "WHAT string length (5)" "$(echo "$OUTPUT" | grep -A1 'string length' | tail -1)" "5" +check "WHAT list length (5)" "$(echo "$OUTPUT" | grep -A1 'list length' | tail -1)" "5.0" +check "WHAT string length (5)" "$(echo "$OUTPUT" | grep -A1 'string length' | tail -1)" "5.0" check "WHAT computed (42)" "$(echo "$OUTPUT" | grep -A1 'computed value' | tail -1)" "42" check "WHO name (myvar)" "$(echo "$OUTPUT" | grep -A1 'variable name' | tail -1)" "myvar" check "WHO name (counter)" "$(echo "$OUTPUT" | grep -A1 'different variable' | tail -1)" "counter" -check "WHEN step (1)" "$(echo "$OUTPUT" | grep -A1 'temporal step' | tail -1)" "1" -check "WHEN multi-assign (3)" "$(echo "$OUTPUT" | grep -A1 'multiple assignments' | tail -1)" "3" +check "WHEN step (1)" "$(echo "$OUTPUT" | grep -A1 'temporal step' | tail -1)" "1.0" +check "WHEN multi-assign (3)" "$(echo "$OUTPUT" | grep -A1 'multiple assignments' | tail -1)" "3.0" WHERE_VAL=$(echo "$OUTPUT" | grep -A1 'WHERE returns entropy' | tail -1) check_numeric "WHERE entropy >= 0" "$WHERE_VAL" "0" "10" @@ -889,7 +889,7 @@ echo "[4/15] Keyword Reservation" OUTPUT=$(./eigenscript ../tests/test_keyword_reservation.eigs 2>&1) check "what is keyword" "$(echo "$OUTPUT" | grep -A1 '^what:' | tail -1)" "42" check "who is keyword" "$(echo "$OUTPUT" | grep -A1 '^who:' | tail -1)" "x" -check "when is keyword" "$(echo "$OUTPUT" | grep -A1 '^when:' | tail -1)" "1" +check "when is keyword" "$(echo "$OUTPUT" | grep -A1 '^when:' | tail -1)" "1.0" CONVERGED=$(echo "$OUTPUT" | grep 'converged=' | head -1) echo " INFO: Predicate values: $CONVERGED" @@ -1025,7 +1025,7 @@ else fi HS_DH=$(echo "$HS_OUTPUT" | grep -A2 'HS2:' | tail -1) -check "HS4 dH~0" "$HS_DH" "0" +check "HS4 dH~0" "$HS_DH" "0.0" HS_REPORT=$(echo "$HS_OUTPUT" | grep -A3 'HS2:' | tail -1) check "HS5 report=converged (#861)" "$HS_REPORT" "converged" @@ -1145,7 +1145,9 @@ check "LE1 runaway exit=stalled (#861: false-converged exit gone)" "$LE1_EXIT" " LE1_ITERS=$(echo "$LE_OUTPUT" | grep -A2 'LE1:' | tail -1) TOTAL=$((TOTAL + 1)) -if [ -n "$LE1_ITERS" ] && [ "$LE1_ITERS" -gt 0 ] 2>/dev/null; then +# N6 prints this whole observer count with .0; retain the positive-count check. +LE1_ITERS_WHOLE=${LE1_ITERS%.0} +if [ -n "$LE1_ITERS" ] && [ "$LE1_ITERS_WHOLE" -gt 0 ] 2>/dev/null; then echo " PASS: LE1 iterations=$LE1_ITERS" PASS=$((PASS + 1)) else @@ -5161,26 +5163,26 @@ obs_hoist_verdict() { OBS_HOIST_JIT_EXPECT=compiled; [ "$(uname -m)" = x86_64 ] || OBS_HOIST_JIT_EXPECT="n/a" # 45. Interpreter, module-level names (OBSERVE_NAME_POST): closed -> no calls. OBS_G44=$(obs_hoist_verdict interp "$OBS_GATE_TMP/hoist_mod.eigs") -check "gate closed: OBSERVE_NAME_POST never enters the observer (interpreter)" "$OBS_G44" "1500/calls=0/jit=off" +check "gate closed: OBSERVE_NAME_POST never enters the observer (interpreter)" "$OBS_G44" "1500.0/calls=0/jit=off" # 46. Interpreter, fn-local slots (OBSERVE_ASSIGN_LOCAL): closed -> no calls. OBS_G45=$(obs_hoist_verdict interp "$OBS_GATE_TMP/hoist_fn.eigs") -check "gate closed: OBSERVE_ASSIGN_LOCAL never enters the observer (interpreter)" "$OBS_G45" "1500/calls=0/jit=off" +check "gate closed: OBSERVE_ASSIGN_LOCAL never enters the observer (interpreter)" "$OBS_G45" "1500.0/calls=0/jit=off" # 47. JIT, module-level names: the emitter's inline gate test skips the helper. OBS_G46=$(obs_hoist_verdict jit "$OBS_GATE_TMP/hoist_mod.eigs") -check "gate closed: the JIT skips jit_helper_observe_name_post (thunk witnessed)" "$OBS_G46" "1500/calls=0/jit=$OBS_HOIST_JIT_EXPECT" +check "gate closed: the JIT skips jit_helper_observe_name_post (thunk witnessed)" "$OBS_G46" "1500.0/calls=0/jit=$OBS_HOIST_JIT_EXPECT" # 48. JIT, fn-local slots. OBS_G47=$(obs_hoist_verdict jit "$OBS_GATE_TMP/hoist_fn.eigs") -check "gate closed: the JIT skips jit_helper_observe_assign_local (thunk witnessed)" "$OBS_G47" "1500/calls=0/jit=$OBS_HOIST_JIT_EXPECT" +check "gate closed: the JIT skips jit_helper_observe_assign_local (thunk witnessed)" "$OBS_G47" "1500.0/calls=0/jit=$OBS_HOIST_JIT_EXPECT" # 49. Control — a reader opens the gate at compile time and the same JIT'd loop # must then RECORD (populated tally, `diverging` verdict on the ramp). A # do-nothing counter or a gate test that skips the call unconditionally # scores 0 here and goes red. OBS_G48=$(obs_hoist_verdict jit "$OBS_GATE_TMP/hoist_reader.eigs") -check "control: with a reader the JIT'd loop still records every assignment" "$OBS_G48" "1500/calls=populated/jit=$OBS_HOIST_JIT_EXPECT" +check "control: with a reader the JIT'd loop still records every assignment" "$OBS_G48" "1500.0/calls=populated/jit=$OBS_HOIST_JIT_EXPECT" # 50. Control — EIGS_OBS_FORCE=1 opens the gate from process start on the # read-free program; the interpreter's hoisted test must see it open. OBS_G49=$(obs_hoist_verdict interp "$OBS_GATE_TMP/hoist_mod.eigs" EIGS_OBS_FORCE=1) -check "control: EIGS_OBS_FORCE=1 still records the read-free program (interpreter)" "$OBS_G49" "1500/calls=populated/jit=off" +check "control: EIGS_OBS_FORCE=1 still records the read-free program (interpreter)" "$OBS_G49" "1500.0/calls=populated/jit=off" # The count pin itself (§37). Also the vacuity floor: a section that ran zero # checks is not a section that passed. TOTAL=$((TOTAL + 1)) diff --git a/tests/strict_shape_cases.json b/tests/strict_shape_cases.json index e51dda456..e2d16ef44 100644 --- a/tests/strict_shape_cases.json +++ b/tests/strict_shape_cases.json @@ -275,14 +275,14 @@ "0.001", "0" ], - "valid_assert": "(len of shape_result) == 44 and (sum of shape_result) == 0", + "valid_assert": "(len of shape_result) == 44 and (len of ([shape_sample for shape_sample in shape_result if shape_sample != 0])) == 0", "setup": "", - "observe": "print of shape_result", + "observe": "print of [len of shape_result, len of ([shape_sample for shape_sample in shape_result if shape_sample != 0])]", "cleanup": "", "unchanged": "# No observable mutable argument; entry-guard ordering is independently checked from source.", "optional_args": [], "requirements": [], - "resource_notes": "Zero amplitude makes output deterministic; checks shape acceptance, not random distribution.", + "resource_notes": "N6 exposes randomly signed zeros at zero amplitude. Check every sample equals numeric zero and retain exact length; observe length/nonzero count, not random zero sign bits. This checks shape acceptance, not random distribution.", "source": { "file": "src/ext_gfx.c", "line": 2056, diff --git a/tests/test_boxed_int_containers.eigs b/tests/test_boxed_int_containers.eigs index 1fa6eedbc..72a0d2a1d 100644 --- a/tests/test_boxed_int_containers.eigs +++ b/tests/test_boxed_int_containers.eigs @@ -99,7 +99,7 @@ xs[1] is IMIN ck of [xs[1] == IMIN, "set boxed over smi"] ck of [(str of xs[0:3]) == "[140737488355328, -9223372036854775808, 9223372036854775807]", "slice text"] srt is sort of [B53, 9007199254740992.0, 9007199254740992, IMAX, IMIN, F47, P47, -1] -ck of [(str of srt) == "[-9223372036854775808, -1, 140737488355328, 140737488355328, 9007199254740992, 9007199254740992, 9007199254740993, 9223372036854775807]", "sort exact order"] +ck of [(str of srt) == "[-9223372036854775808, -1, 140737488355328.0, 140737488355328, 9007199254740992.0, 9007199254740992, 9007199254740993, 9223372036854775807]", "sort exact order"] ck of [(num_type of srt[2]) != (num_type of srt[3]), "sort keeps both kinds at the tie"] sb is sort_by of [[P47, 3, IMIN, IMAX], (v) => 0.0 - v] ck of [sb[0] == IMAX and sb[3] == IMIN, "sort_by order"] diff --git a/tests/test_buffer_nonfinite_read.out b/tests/test_buffer_nonfinite_read.out index 39564245a..fdcca1c24 100644 --- a/tests/test_buffer_nonfinite_read.out +++ b/tests/test_buffer_nonfinite_read.out @@ -13,5 +13,5 @@ value false value value -0 +0.0 false diff --git a/tests/test_builtin_overflow.sh b/tests/test_builtin_overflow.sh index 95cdc45a1..a478a4267 100755 --- a/tests/test_builtin_overflow.sh +++ b/tests/test_builtin_overflow.sh @@ -78,7 +78,7 @@ print of caught' "1" # A normal matmul still produces the right answer (guards the cap refactor). run_case "matmul normal correctness" \ 'print of (matmul of [[[1.0, 2.0], [3.0, 4.0]], [[5.0, 6.0], [7.0, 8.0]]])' \ -'[[19, 22], [43, 50]]' +'[[19.0, 22.0], [43.0, 50.0]]' # substr: a huge length overflowed `start + rlen` (int) past the clamp, then the # allocation aborted (SIGABRT). Now clamped via subtraction to the string tail. diff --git a/tests/test_corpus_ints.sh b/tests/test_corpus_ints.sh index 9fff88741..3076ed690 100755 --- a/tests/test_corpus_ints.sh +++ b/tests/test_corpus_ints.sh @@ -96,10 +96,10 @@ else fi # genuine zeros run stays ONE repeated token -- real repetition is not destroyed. -if [ "$(g ZERO_COUNT)" = "5" ]; then +if [ "$(g ZERO_COUNT)" = "5.0" ]; then ok "IL02 a genuine zeros run stays one repeated token (real repetition kept)" else - fail "IL02 zeros run wrong" "zero_count=$(g ZERO_COUNT), want 5" + fail "IL02 zeros run wrong" "zero_count=$(g ZERO_COUNT), want 5.0" fi # 100 (>= int_count) and 3.5 (non-integer) must NOT occupy int tokens: exactly @@ -122,10 +122,10 @@ for i in range of nint: print of ("DISTINCT_TOTAL " + (str of tot)) RNG ROUT=$("$EIGS" "$WORK/range.eigs" "$WORK" 2>/dev/null | sed -n 's/^DISTINCT_TOTAL //p') -if [ "$ROUT" = "6" ]; then +if [ "$ROUT" = "6.0" ]; then ok "IL03 out-of-range (100) and non-integer (3.5) literals stay lossy, not int tokens" else - fail "IL03 wrong distinct int total" "distinct=$ROUT, want 6 (values 0..5 only)" + fail "IL03 wrong distinct int total" "distinct=$ROUT, want 6.0 (values 0..5 only)" fi # Backward compat: no 7th arg -> no int region, stream byte-identical to slot-only. diff --git a/tests/test_json_hard.eigs b/tests/test_json_hard.eigs index 834068f92..2b33ddd30 100644 --- a/tests/test_json_hard.eigs +++ b/tests/test_json_hard.eigs @@ -410,14 +410,13 @@ assert of [jb_tiny == "{\"v\": 1e-09}", "JH94 json_build keeps tiny magnitude"] rt_enc is json_encode of {"k": 0.000000001} assert of [rt_enc == "{\"k\":1e-09}", "JH95 json_encode writes tiny magnitude"] assert of [json_path of [rt_enc, "k"] == "1e-09", "JH96 json_path round-trips what json_encode wrote"] -# #875: 1.23e15 is an exact integer below 2^53, so it now renders the way -# `str of` renders it — bare, not in exponent form. The two used to disagree, -# which is the drift this fix removed; the compactness #725 was protecting -# (no 22-char fixed-point blob) still holds at 16 characters. +# #875/N6: JSON and str share the Python-repr writer. The float 1.23e15 +# uses fixed notation with .0; float magnitudes at 1e16 and above use +# scientific notation. jb_huge is json_build of ["v", 1.23e15] -assert of [jb_huge == "{\"v\": 1230000000000000}", "JH97 json_build renders huge values compactly"] +assert of [jb_huge == "{\"v\": 1230000000000000.0}", "JH97 json_build renders huge values compactly"] assert of [jb_huge == ("{\"v\": " + (str of 1.23e15) + "}"), "JH97 json_build agrees with str of"] -# A magnitude that is NOT an exact integer still uses exponent form. +# A float above the fixed-notation range still uses exponent form. jb_huge2 is json_build of ["v", 1.23e300] assert of [jb_huge2 == "{\"v\": 1.23e+300}", "JH97 json_build keeps exponent form past 2^53"] diff --git a/tests/test_lint.sh b/tests/test_lint.sh index ed9fdffe5..e8375eb24 100644 --- a/tests/test_lint.sh +++ b/tests/test_lint.sh @@ -2357,8 +2357,8 @@ define f as: f of [] EIGS RUN=$($EIGS "$TMPFILE" 2>&1 || true) -check_contains "#1048 module-level for-body local is fresh per iteration (when=1)" "$RUN" "^module when=1$" -check_contains "#1048 function for-body local persists across iterations (when=30)" "$RUN" "^function when=30$" +check_contains "#1048 module-level for-body local is fresh per iteration (when=1.0)" "$RUN" "^module when=1[.]0$" +check_contains "#1048 function for-body local persists across iterations (when=30.0)" "$RUN" "^function when=30[.]0$" rm -f "$TMPFILE" # --- #1048 round 2: a long identifier may not break the message ---------- diff --git a/tests/test_native_fn.c b/tests/test_native_fn.c index 87af4e7b4..3f2fa81cc 100644 --- a/tests/test_native_fn.c +++ b/tests/test_native_fn.c @@ -39,7 +39,7 @@ int main(void) { s = eval_str("str of g"); check(strcmp(s, "") == 0, "str of a named native fn is "); free(s); s = eval_str("g of 41"); - check(strcmp(s, "42") == 0, "a named native fn still calls through (g of 41 = 42)"); free(s); + check(strcmp(s, "42.0") == 0, "a named native fn still calls through (g of 41 = 42.0)"); free(s); s = eval_str("type of b"); check(strcmp(s, "builtin") == 0, "a plain builtin still reports \"builtin\""); free(s); s = eval_str("str of b"); diff --git a/tests/test_read_bytes_cap.sh b/tests/test_read_bytes_cap.sh index 09495e987..dd1901563 100755 --- a/tests/test_read_bytes_cap.sh +++ b/tests/test_read_bytes_cap.sh @@ -74,7 +74,7 @@ print of f\"kind={caught}\"" \ run_case "1-arg small read unchanged" \ "b is read_bytes_buf of \"$SMALL\" print of f\"{buf_len of b} {b[0]} {b[2]}\"" \ -"3 7 9" +"3 7.0 9.0" # 5. max_bytes validation: zero, over-ceiling, and non-numeric raise value. run_case "max_bytes 0 raises value" \ diff --git a/tests/test_replay.sh b/tests/test_replay.sh index 07da7d9ce..6570c466e 100755 --- a/tests/test_replay.sh +++ b/tests/test_replay.sh @@ -64,7 +64,7 @@ REC_B=$(EIGS_TRACE="$TAPE_B" "$EIGS" "$TMPDIR/p_buf.eigs" 2>&1) printf '\xff\xfe\xfd' > "$INPUT" REP_B=$(EIGS_REPLAY="$TAPE_B" "$EIGS" "$TMPDIR/p_buf.eigs" 2>&1) -EXPECTED_B=$'1\n2\n3' +EXPECTED_B=$'1.0\n2.0\n3.0' if [ "$REC_B" = "$EXPECTED_B" ] && [ "$REP_B" = "$EXPECTED_B" ]; then ok "buffer replay: read_bytes_buf restored as VAL_BUFFER (b[…] disambiguator)" else @@ -120,7 +120,7 @@ N 0 ls=[{"k": 42}, {"k": "ok"}, b[10, 20, 30]] EOF REP_N=$(EIGS_REPLAY="$TMPDIR/nested.tape" "$EIGS" "$TMPDIR/p_nested.eigs" 2>/dev/null) -EXPECTED_N=$'{"k": 42}\nok\n20' +EXPECTED_N=$'{"k": 42}\nok\n20.0' if [ "$REP_N" = "$EXPECTED_N" ]; then ok "nested replay: list[dict, dict, buffer] round-trip" diff --git a/tests/test_sandbox_intern_lifetime.c b/tests/test_sandbox_intern_lifetime.c index 0269d4cea..a3fc14760 100644 --- a/tests/test_sandbox_intern_lifetime.c +++ b/tests/test_sandbox_intern_lifetime.c @@ -105,7 +105,7 @@ int main(void) { char key[64]; for (int i = 0; i < 128; i++) { - snprintf(key, sizeof key, "sandbox-only-key-%d", i); + snprintf(key, sizeof key, "sandbox-only-key-%d.0", i); Value *out = sandbox_call(i); assert(out != NULL); EigsView ok_view, result_view; @@ -124,7 +124,7 @@ int main(void) { const size_t sandbox_retained = intern_count() - baseline; const size_t sandbox_prefix_retained = sandbox_only_intern_count() - sandbox_baseline; - snprintf(key, sizeof key, "sandbox-only-key-%d", 0); + snprintf(key, sizeof key, "sandbox-only-key-%d.0", 0); /* Check the escaped-result control before the retention assertion: a * mutant that restores the leak must still demonstrate that the returned * key remains readable through the run boundary. */ diff --git a/tests/test_strict_math.sh b/tests/test_strict_math.sh index 08fc8b4c8..a9ee6ecf7 100755 --- a/tests/test_strict_math.sh +++ b/tests/test_strict_math.sh @@ -205,7 +205,7 @@ run "SM35 strict: JSON false decodes to false (#1637)" 1 0 "false" \ # error, repaired scalar, trailing garbage) as a catchable `value` error naming # the position. EIGS_STRICT=0: byte-identical (SM36/SM37 pin the lenient walk). JSON # `false`/`null`/absent-key are ANSWERS and stay quiet in both modes. -run "SM36 opt-out json_path(bad number) still walks partial" 0 0 "[0]" \ +run "SM36 opt-out json_path(bad number) still walks partial" 0 0 "[0.0]" \ 'print of f"[{json_path of ["{\"a\": 1e", "a"]}]"' run "SM37 opt-out json_path(truncated array) still partial" 0 0 "[[1,2]]" \ 'print of f"[{json_path of ["{\"a\": [1, 2", "a"]}]"' @@ -235,10 +235,10 @@ run "SM46 strict: valid nested path still resolves" 1 0 "x" 'print of (json # and buffer paths), `tensor_load` of a file carrying NaN bytes, and the # elementwise `divide` by zero (pre-collapsed to 0 where `/` raises). EIGS_STRICT=0 # collapses to 0 + math_flags.invalid exactly as before (SM47-SM49 pin it). -run "SM47 opt-out pow(-8, 0.5) still 0" 0 0 "0" 'print of (pow of [0 - 8, 0.5])' +run "SM47 opt-out pow(-8, 0.5) still 0" 0 0 "0.0" 'print of (pow of [0 - 8, 0.5])' # N10: invalid literal text raises even under EIGS_STRICT=0. run "SM48 N10 opt-out num nan refuses grammar" 0 1 "num: expected complete numeric-literal text" 'num of "nan"' -run "SM49a opt-out matmul(inf-inf) LIST path still collapses to 0 + invalid" 0 0 "[0] true" \ +run "SM49a opt-out matmul(inf-inf) LIST path still collapses to 0 + invalid" 0 0 "[0.0] true" \ 'local r is matmul of [[[1e200, 1e200]], [[1e200], [0 - 1e200]]] print of f"{r} {(math_flags of null).invalid}"' # #1417 applies the same scalar-read rule to buffer and list results. The @@ -314,15 +314,15 @@ catch e: # --- #1438: finite-difference losses must be scalar numbers ----------------- BAD_LOSS='define bad(_) as: return "bad"' -run "T1438a opt-out numerical_grad keeps zero stand-in" 0 0 "[0]" \ +run "T1438a opt-out numerical_grad keeps zero stand-in" 0 0 "[0.0]" \ "$BAD_LOSS p is [1.0] print of (numerical_grad of [bad, p, 0.001])" -run "T1438b opt-out numerical_grad_rows keeps zero stand-in" 0 0 "[[0]]" \ +run "T1438b opt-out numerical_grad_rows keeps zero stand-in" 0 0 "[[0.0]]" \ "$BAD_LOSS m is [[1.0]] print of (numerical_grad_rows of [bad, m, [0], 0.001])" -run "T1438c opt-out numerical_grad_cols keeps zero stand-in" 0 0 "[[0]]" \ +run "T1438c opt-out numerical_grad_cols keeps zero stand-in" 0 0 "[[0.0]]" \ "$BAD_LOSS m is [[1.0]] print of (numerical_grad_cols of [bad, m, [0], 0.001])" diff --git a/tools/phase2_builtins.sh b/tools/phase2_builtins.sh index 71f7c7776..512ad8f53 100755 --- a/tools/phase2_builtins.sh +++ b/tools/phase2_builtins.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # The pre-registered bar owns the predicates and probe execution. +# R1.7-D5: earlier closures retain A2; R1.7 closures prove D2 per line. set -eu ROOT=$(cd "$(dirname "$0")/.." && pwd) [ "$#" -eq 2 ] || { echo "usage: tools/phase2_builtins.sh " >&2; exit 2; } diff --git a/tools/phase2_cost.sh b/tools/phase2_cost.sh index 01b6bfe46..b945cdd80 100755 --- a/tools/phase2_cost.sh +++ b/tools/phase2_cost.sh @@ -23,6 +23,8 @@ set -eu cd "$(dirname "$0")/.." exec python3 - "$@" <<'PY' import argparse +import math +import struct from decimal import Decimal, InvalidOperation import os from pathlib import Path @@ -36,8 +38,115 @@ import tempfile THRESHOLD_PCT = Decimal('0.3') NOISE = Decimal('0.2') STALE_TOLERANCE = 2 * NOISE + Decimal('0.1') +# N6 is an explicit cost-only comparison mode. Corpus diffs remain exact. +# Legacy unadorned integer text can denote an integral float; allow its .0 or +# scientific repr only when conversion retains its exact integer value. +NUMBER = re.compile(rb'(?ms', out) + + +def output_tokens(text): + matches = list(NUMBER.finditer(text)) + parts, end = [], 0 + for match in matches: + parts.append(text[end:match.start()]) + end = match.end() + return parts + [text[end:]], [match.group() for match in matches] + + +def compare_result_text(old, new, n6_text=False): + if not n6_text: + if old != new: + raise ValueError('strict byte comparison differs') + return 0 + before, a = output_tokens(old) + after, b = output_tokens(new) + if before != after or len(a) != len(b): + raise ValueError('non-numeric bytes, numeric positions or token count differ') + changed = 0 + for ordinal, (left, right) in enumerate(zip(a, b), 1): + where = 'numeric token %d: ' % ordinal + x, y = float(left), float(right) + if not math.isfinite(x) or not math.isfinite(y): + raise ValueError(where + 'non-finite decimal token') + old_bits, new_bits = struct.pack('>d', x), struct.pack('>d', y) + if old_bits != new_bits: + raise ValueError(where + 'binary64 value/sign bits differ') + if left == right: + continue + if INTEGER.fullmatch(right): + raise ValueError(where + 'exact integer text changed or float became integer') + if INTEGER.fullmatch(left) and int(x) != int(left): + raise ValueError(where + 'integer-to-float conversion loses exact digits') + if right != repr(y).encode('ascii'): + raise ValueError(where + 'changed float text is not Python repr') + changed += 1 + return changed + + +def output_self_test(): + good = [ + (b'answer=[3, 0.10000000000000001]\n', b'answer=[3.0, 0.1]\n'), + (b'x=1e+15\n', b'x=1000000000000000.0\n'), + (b'x=-0\n', b'x=-0.0\n'), + (b'x=9007199254740994\n', b'x=9007199254740994.0\n'), + (b'x=10000000000000000\n', b'x=1e+16\n'), + (b'x=3 time=1.5ms\n', b'x=3.0 time=999ms\n'), + ] + bad = [ + ('value', b'x=1.0\n', b'x=1.0000000000000002\n'), + ('float-to-int-kind', b'x=3.0\n', b'x=3\n'), + ('integer-digits', b'x=9007199254740993\n', b'x=9007199254740992\n'), + ('integer-precision', b'x=9007199254740993\n', b'x=9007199254740992.0\n'), + ('int64-precision', b'x=9223372036854775807\n', b'x=9.223372036854776e+18\n'), + ('integer-spelling', b'x=3\n', b'x=03\n'), + ('signed-zero-erased', b'x=-0.0\n', b'x=0.0\n'), + ('signed-zero-added', b'x=0\n', b'x=-0.0\n'), + ('noncanonical-float', b'x=0.10000000000000001\n', b'x=0.100000000000000010\n'), + ('non-finite-decimal', b'x=1e+308\n', b'x=1e+309\n'), + ('non-numeric', b'answer=3\n', b'wrong=3.0\n'), + ('missing-token', b'x=[3, 4]\n', b'x=[3.0]\n'), + ('extra-token', b'x=3\n', b'x=[3.0, 4.0]\n'), + ('position', b'x=3 y=4\n', b'x=4.0 y=3.0\n'), + ('non-finite-text', b'x=inf\n', b'x=nan\n'), + ] + for old, new in good: + if compare_result_text(elapsed_text(old), elapsed_text(new), True) <= 0: + raise ValueError('self-test positive did not compare a changed token') + for label, old, new in bad: + try: + compare_result_text(elapsed_text(old), elapsed_text(new), True) + except ValueError: + continue + raise ValueError('self-test plant survived: ' + label) + # The default remains byte strict, including the permitted N6 changes. + try: + compare_result_text(good[0][0], good[0][1]) + except ValueError: + pass + else: + raise ValueError('self-test strict comparison accepted N6 text') + identical = b'x=3 0.10000000000000001\n' + for n6_text in (False, True): + if compare_result_text(identical, identical, n6_text) != 0: + raise ValueError('self-test unchanged text failed') + if compare_result_text(elapsed_text(b'x=3 time=1.25ms\n'), + elapsed_text(b'x=3 time=999ms\n'), n6_text) != 0: + raise ValueError('self-test elapsed milliseconds handling failed') + print('phase2-cost-self-test: positive=%d rejected=%d strict=PASS elapsed=PASS PASS' % (len(good), len(bad))) + + root = Path.cwd() ap = argparse.ArgumentParser(prog='tools/phase2_cost.sh') +ap.add_argument('--n6-text', action='store_true', + help='cost only: allow exact-value Python-repr float text changes; integer digits stay exact') +ap.add_argument('--self-test', action='store_true', + help='one-time output-comparator calibration; runs no workload or build') ap.add_argument('--final', action='store_true', help='require empty cost_expect.txt and oracle_expect.txt (the pre-merge condition)') ap.add_argument('--declared', choices=('jit', 'off'), @@ -45,6 +154,16 @@ ap.add_argument('--declared', choices=('jit', 'off'), ap.add_argument('base', nargs='?') ap.add_argument('cand', nargs='?') args = ap.parse_args() +if args.self_test: + if args.base or args.cand or args.final or args.declared or args.n6_text: + ap.error('--self-test runs alone') + try: + output_self_test() + except (AssertionError, ValueError, OverflowError) as error: + sys.exit('phase2-cost-self-test: FAIL: ' + str(error)) + sys.exit(0) +if args.n6_text and (not args.base or not args.cand or args.declared): + ap.error('--n6-text requires ') expect_path = root / 'tests/phase2/cost_expect.txt' if not expect_path.is_file(): sys.exit('phase2-cost: FAIL: missing tests/phase2/cost_expect.txt') @@ -126,6 +245,8 @@ logdir = Path(tempfile.mkdtemp(prefix='phase2-cost-')) print('phase2-cost: source=codspeed.yml workloads=%d tiers=2 undeclared_max=+%s%% declarations=%d ' 'stale_below_max=%s logs=%s' % (len(workloads), THRESHOLD_PCT, len(expectations), STALE_TOLERANCE, logdir), flush=True) +if args.n6_text: + print('phase2-cost: output_compare=n6-text (exact values/bits, exact integer digits, Python repr)', flush=True) over = stale = 0 for workload in sorted(workloads): for tier in ('jit', 'off'): @@ -149,13 +270,20 @@ for workload in sorted(workloads): sys.exit('phase2-cost: FAIL: missing/ambiguous Ir: ' + str(prefix)) out = Path(str(prefix) + '.stdout').read_bytes() # The bench prints elapsed milliseconds; compare every result field. - out = re.sub(rb'\b[0-9]+(?:\.[0-9]+)?ms\b', b'ms', out) + out = elapsed_text(out) err = Path(str(prefix) + '.stderr').read_text() err = re.sub(r'^==\d+==.*\n?', '', err, flags=re.M) results.append((int(summary[0]), out, err)) (base, out_a, err_a), (cand, out_b, err_b) = results - if (out_a, err_a) != (out_b, err_b): - sys.exit('phase2-cost: FAIL: output differs: %s %s (see %s)' % (workload, tier, logdir)) + try: + changed = compare_result_text(out_a, out_b, args.n6_text) + changed += compare_result_text(err_a.encode(), err_b.encode(), args.n6_text) + except (ValueError, OverflowError) as error: + sys.exit('phase2-cost: FAIL: output differs: %s %s: %s (see %s)' % + (workload, tier, error, logdir)) + if args.n6_text and changed: + print('phase2-cost: n6-text workload=%s tier=%s changed_tokens=%d' % + (workload, tier, changed), flush=True) delta = 100 * (cand - base) / base maximum, recover_round, reason = expectations.get((workload, tier), (THRESHOLD_PCT, None, None)) diff --git a/tools/phase2_float_amend.py b/tools/phase2_float_amend.py new file mode 100644 index 000000000..74336b442 --- /dev/null +++ b/tools/phase2_float_amend.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python3 +"""R1.7-D6: derive the frozen re-render population from four live gate runs. + +Kinds come from source-bound witnesses, never from legacy text ("3" can be a +float). Numeric position means line and ordinal plus identical separating +bytes; character offsets may move when a rendering grows. The anchor is the +last pre-N6 commit, including earlier accepted frozen-bar amendments. +""" +import argparse +import hashlib +import io +import json +import math +from pathlib import Path +import re +import struct +import subprocess +import sys +import tempfile +import os + +BASE = 'b6f9db3879be5578de787ad6cf0d235b809f0e7c' +BAR = 'tests/phase2/builtins/builtins/' +PROFILES = ('release', 'server', 'server-db', 'zlib') +NUMBER = re.compile(rb'(?d', value) + + +def render(old, kinds, path): + lines = old.splitlines(keepends=True) + require(len(lines) == len(kinds), path + ': line count differs from kind metadata') + result = [] + for number, (line, line_kinds) in enumerate(zip(lines, kinds), 1): + parts, tokens = split(line) + require(len(tokens) == len(line_kinds), '%s:%d: numeric population differs from kind metadata' % (path, number)) + out = parts[0] + for token, kind, suffix in zip(tokens, line_kinds, parts[1:]): + require(kind in ('int', 'float', 'text'), path + ': unknown numeric kind ' + str(kind)) + if kind == 'text': + replacement = token + elif kind == 'int': + require(re.fullmatch(rb'-?(?:0|[1-9][0-9]*)', token) is not None, path + ': non-integral int token') + replacement = token + else: + double(token) + replacement = repr(float(token)).encode('ascii') + out += replacement + suffix + result.append(out) + return b''.join(result) + + +def check_pair(old, new, kinds, path): + expected = render(old, kinds, path) + a, b = old.splitlines(keepends=True), new.splitlines(keepends=True) + require(len(a) == len(b), path + ': line count changed') + floats = 0 + for number, (left, right, line_kinds) in enumerate(zip(a, b, kinds), 1): + lp, lt = split(left) + rp, rt = split(right) + label = '%s:%d' % (path, number) + require(len(lt) == len(rt), label + ': numeric token count changed') + require(lp == rp, label + ': non-float text or numeric position changed') + for ordinal, (x, y, kind) in enumerate(zip(lt, rt, line_kinds), 1): + where = label + ' token ' + str(ordinal) + if kind in ('int', 'text'): + require(x == y, where + ': integer spelling/value/kind changed') + else: + require(double(x) == double(y), where + ': double bits changed') + require(y.decode('ascii') == repr(float(y)), where + ': float kind/text is not Python repr') + floats += 1 + require(new == expected, path + ': amendment is not the complete N6 re-render') + return floats + + +def load(root, metadata): + data = json.loads(metadata.read_text()) + require(data.get('schema') == 2 and data.get('ruling') == 'R1.7-D6' and data.get('base') == BASE, + 'unsupported metadata schema/ruling/anchor') + files = data.get('files', {}) + population = data.get('population', {}) + require(bool(files) and set(files) == set(population), 'metadata file population differs from the derived gate population') + require(set(data.get('profiles', [])) == set(PROFILES), 'population must cover all four profiles') + for path, profiles in population.items(): + require(path.startswith(BAR) and path.endswith('.branch') and '/' not in path[len(BAR):], 'invalid population path: ' + path) + require(bool(profiles) and set(profiles) <= set(PROFILES), path + ': invalid profile population') + paths = git(root, 'ls-tree', '-r', '--name-only', BASE, '--', BAR).decode().splitlines() + branch_paths = [path for path in paths if path.endswith('.branch')] + source_paths = [path.removesuffix('.branch') + '.eigs' for path in files] + anchored = anchor_files(root, branch_paths + source_paths) + frozen = {path: anchored[path] for path in branch_paths} + require(bool(frozen), 'anchor has no frozen files') + for path, entry in files.items(): + old = frozen.get(path) + require(old is not None and sha(old) == entry['old_sha256'], path + ': old bytes do not match pinned pre-N6 hash') + source = path.removesuffix('.branch') + '.eigs' + baseline = anchored[source] + require(sha(baseline) == entry['source_sha256'] and (root / source).read_bytes() == baseline, + source + ': probe source changed; kind provenance must be reviewed') + source_lines = baseline.decode().splitlines() + old_lines = old.splitlines(keepends=True) + require(old_lines[-1] == b'rc=0\n', path + ': missing fixed rc=0 trailer') + line_kinds = [[None] * len(split(line)[1]) for line in old_lines] + line_kinds[-1] = ['int'] + require(bool(entry['witnesses']), path + ': no kind witnesses') + for witness in entry['witnesses']: + require(witness['expression'] in source_lines[witness['line'] - 1], source + ': kind witness no longer comes from its source line') + require(witness['kind'] in ('int', 'float', 'text'), source + ': invalid kind witness') + require(witness.get('reader', 'num_type') == ('type' if witness['kind'] == 'text' else 'num_type'), source + ': invalid kind reader') + require(witness.get('transform') in (None, 'num'), source + ': invalid witness transform') + require(all(type(i) is int and i >= 0 for i in witness.get('index_path', [])), source + ': invalid witness index path') + require(bool(witness['positions']), source + ': kind witness explains no tokens') + for line, ordinal in witness['positions']: + require(1 <= line < len(old_lines) and 1 <= ordinal <= len(line_kinds[line - 1]), + path + ': kind witness position outside numeric population') + require(line_kinds[line - 1][ordinal - 1] is None, path + ': duplicate numeric kind witness') + line_kinds[line - 1][ordinal - 1] = witness['kind'] + require(all(kind is not None for row in line_kinds for kind in row), path + ': numeric token has no kind witness') + entry['line_kinds'] = line_kinds + render(old, entry['line_kinds'], path) + return data, frozen + + +def run_witnesses(root, binary, data, expected): + env = {key: value for key, value in os.environ.items() + if not key.startswith('EIGS_') and key not in ('LD_PRELOAD', 'LD_AUDIT')} + for path, entry in data['files'].items(): + source = (root / (path.removesuffix('.branch') + '.eigs')).read_bytes() + def expression(w): + e = '(' + w['expression'] + ')' + e += ''.join('[' + str(i) + ']' for i in w.get('index_path', [])) + return '(num of ' + e + ')' if w.get('transform') == 'num' else e + tail = '\nprint of "R17-D2-KINDS-BEGIN"\n' + ''.join( + 'print of (' + w.get('reader', 'num_type') + ' of ' + expression(w) + ')\n' for w in entry['witnesses']) + with tempfile.TemporaryDirectory(prefix='r17-d2-kind-') as temp: + probe = Path(temp) / 'witness.eigs' + probe.write_bytes(source + tail.encode()) + case = Path(path).stem + rows = [line.split('\t') for line in (root / 'tests/phase2/builtins/cases.tsv').read_text().splitlines()[1:]] + row = next(r for r in rows if r[0] == case) + require(row[2] == '-', path + ': kind witness needs an observation hook') + stdin = b'' if row[3] == '-' else (root / BAR / '_stdin' / row[3]).read_bytes() + result = subprocess.run([str(binary), str(probe)], cwd=temp, env={**env, 'EIGS_PROBE_TMP':temp}, + input=stdin, capture_output=True, timeout=10) + require(result.returncode == 0 and not result.stderr, + path + ': kind witness failed rc=%d stderr=%r' % (result.returncode, result.stderr)) + require(result.stdout.count(MARKER) == 1, path + ': kind witness marker missing/duplicated') + actual, kinds = result.stdout.split(MARKER) + require(actual + b'rc=0\n' == expected[path], path + ': runtime probe differs from the checked frozen text') + wanted = ''.join(('str' if w['kind'] == 'text' else w['kind']) + '\n' for w in entry['witnesses']).encode() + require(kinds == wanted, path + ': runtime kind witness changed: ' + repr(kinds)) + print('float-amend: runtime kind witnesses binary=%s files=%d PASS' % (binary, len(data['files']))) + + +def check(root, metadata, candidate_dir=None, baseline_binary=None, binary=None): + data, frozen = load(root, metadata) + if candidate_dir: + paths = list(candidate_dir.rglob('*')) + require({p.relative_to(candidate_dir).as_posix() for p in paths} == {Path(p).name for p in data['files']}, + 'candidate file population differs from the derived population') + actual = {path: (candidate_dir / Path(path).name).read_bytes() for path in data['files']} + else: + actual = {p.relative_to(root).as_posix(): p.read_bytes() for p in (root / BAR).rglob('*.branch')} + require(set(actual) == set(frozen), 'frozen .branch file population changed') + require(all(actual[p] == frozen[p] for p in frozen if p not in data['files']), + 'a frozen file outside the derived population changed') + changed, tokens = [], 0 + for path, entry in data['files'].items(): + tokens += check_pair(frozen[path], actual[path], entry['line_kinds'], path) + if actual[path] != frozen[path]: + changed.append(path) + print('float-amend: R1.7-D6 path=%s SHA-256=%s' % (path, sha(actual[path]))) + require(len(changed) == len(data['files']), 'derived population contains an unchanged row') + if baseline_binary: + run_witnesses(root, baseline_binary, data, frozen) + if binary: + run_witnesses(root, binary, data, actual) + print('float-amend: examined=%d amended=%d floats=%d PASS' % (len(data['files']), len(changed), tokens)) + return data, actual, changed + + +def self_test(root, metadata): + data, frozen = load(root, metadata) + with tempfile.TemporaryDirectory(prefix='r17-d2-selftest-') as temp: + directory = Path(temp) + good = {Path(p).name: render(frozen[p], e['line_kinds'], p) for p, e in data['files'].items()} + def invoke(): + return subprocess.run([sys.executable, str(Path(__file__).resolve()), '--root', str(root), + '--metadata', str(metadata), '--candidate-dir', str(directory)], capture_output=True) + def write(files): + for p in directory.glob('*'): + p.unlink() + for name, body in files.items(): + (directory / name).write_bytes(body) + write(good) + require(invoke().returncode == 0, 'self-test positive complete Python-repr amendment failed') + plants = { + 'value': ('fround.branch', lambda b: b.replace(b'0.10000000149011612', b'0.2')), + 'kind': ('str.branch', lambda b: b.replace(b'"3.0"', b'"3"')), + 'integer': ('json_encode.branch', lambda b: b.replace(b'9007199254740993', b'9007199254740992', 1)), + 'integer-kind': ('json_encode.branch', lambda b: b.replace(b'[3,', b'[3.0,', 1)), + 'non-float-text': ('json_build.branch', lambda b: b.replace(b'"a"', b'"z"')), + 'missing-token': ('min.branch', lambda b: b.replace(b'[3, "int"]', b'["int"]', 1)), + 'extra-token': ('max.branch', lambda b: b.replace(b'[3, "int"]', b'[3, 4, "int"]', 1)), + 'float-render': ('str.branch', lambda b: b.replace(b'"3.0"', b'"3.00"')), + 'position': ('json_build.branch', lambda b: b.replace(b'"d": 3.0', b'3.0: "d"')), + } + count = 0 + for label, (name, mutate) in plants.items(): + bad = dict(good) + bad[name] = mutate(bad[name]) + require(bad[name] != good[name], 'self-test plant did not take: ' + label) + write(bad) + result = invoke() + require(result.returncode == 1 and b'FAIL:' in result.stderr, 'self-test plant survived: ' + label) + print('float-amend-self-test: %s rejected PASS' % label) + count += 1 + for label, files in [('missing-file', {k: v for k, v in good.items() if k != 'str.branch'}), + ('extra-file', dict(good, extra_branch=b'0\n'))]: + if label == 'extra-file': + files['extra.branch'] = files.pop('extra_branch') + write(files) + result = invoke() + require(result.returncode == 1 and b'FAIL:' in result.stderr, 'self-test plant survived: ' + label) + print('float-amend-self-test: %s rejected PASS' % label) + count += 1 + print('float-amend-self-test: positive=1 rejected=%d PASS' % count) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--root', type=Path, default=Path(__file__).resolve().parents[1]) + parser.add_argument('--metadata', type=Path) + parser.add_argument('--candidate-dir', type=Path, help='isolated directory containing exactly the derived candidate .branch files') + parser.add_argument('--observations', action='append', help='derive from PROFILE=DIR gate transcripts; repeat for all four profiles') + parser.add_argument('--population-output', type=Path, help='write the derived population JSON; never changes expectations') + parser.add_argument('--baseline-binary', type=Path, help='also execute source-bound kind witnesses on the pre-N6 binary') + parser.add_argument('--binary', type=Path, help='also execute source-bound kind witnesses on the candidate binary') + parser.add_argument('--self-test', action='store_true', help='one-time planted-fault calibration; never modifies the checkout') + args = parser.parse_args() + metadata = args.metadata or args.root / 'tests/phase2/r17_float_text.json' + try: + if args.observations: + require(args.population_output is not None, 'derive needs --population-output') + derive(args.root, args.observations, args.population_output) + elif args.self_test: + self_test(args.root, metadata) + else: + check(args.root, metadata, args.candidate_dir, args.baseline_binary, args.binary) + except (OSError, ValueError, KeyError, IndexError, TypeError, subprocess.TimeoutExpired) as error: + print('FAIL: float-amend: ' + str(error), file=sys.stderr) + return 1 + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/phase2_readers.sh b/tools/phase2_readers.sh index 5ec467fe5..e16c4221d 100755 --- a/tools/phase2_readers.sh +++ b/tools/phase2_readers.sh @@ -7,6 +7,7 @@ FIXTURE=${2:-readers} LABEL=phase2-readers case "$FIXTURE" in readers) ;; + num_text) LABEL=phase2-num-text ;; const_dedup_bits) LABEL=phase2-const-dedup ;; q7_readers) LABEL=phase2-q7-readers ;; gfx_audio_boundary) LABEL=phase2-gfx-audio ;; @@ -40,6 +41,12 @@ fi cat "$TMP/out" if [ -s "$TMP/err" ]; then cat "$TMP/err"; fail 'reader fixture wrote stderr'; fi [ "$rc" -eq 0 ] || fail "reader fixture rc=$rc" +if [ "$FIXTURE" = num_text ]; then + [ "$(grep -cE '^phase2-num-text-test: PASS cases=54 checks=1038 failures=0$' "$TMP/out")" -eq 1 ] || fail 'missing unique complete number text PASS' + [ "$(wc -l < "$TMP/out" | tr -d ' ')" -eq 1 ] || fail 'unexpected number text output' + echo "$LABEL: PASS variant=$VARIANT" + exit 0 +fi if [ "$FIXTURE" = const_dedup_bits ]; then [ "$(grep -cE '^phase2-const-dedup-test: PASS checks=8 failures=0$' "$TMP/out")" -eq 1 ] || fail 'missing unique complete const dedup PASS' [ "$(wc -l < "$TMP/out" | tr -d ' ')" -eq 1 ] || fail 'unexpected const dedup output' diff --git a/tools/selftests.txt b/tools/selftests.txt index a5352e4fb..e1d18ab74 100644 --- a/tools/selftests.txt +++ b/tools/selftests.txt @@ -61,3 +61,5 @@ tools/observer_oracle/* | timeout 600 python3 tools/observer_oracle/plants.py -- # Keyed on the checkers, never on src/ (#1352). tools/phase2_check.py tools/phase2_check.sh tools/phase2_corpus_diff.sh tools/phase2_inventory.py tests/phase2/calib/* tests/phase2/corpus_nonzero.txt tests/suite_program_env.sh tests/suite_program_env.txt | timeout 3600 python3 -W error tools/phase2_check.py --selftest | [{"pattern":"^calibration: cases=54 as-expected=54 unexpected=0$","count":1}] tools/phase2_plants.sh tests/phase2/slot_layer.sh tests/phase2/slot_layer.c tools/phase2_inventory.py | timeout 1500 bash tools/phase2_plants.sh --selftest | [{"pattern":"^plants=5 killed=5 survived=0 broken=0 transverse=5$","count":1}] +tools/phase2_cost.sh | timeout 30 bash tools/phase2_cost.sh --self-test | [{"pattern":"^phase2-cost-self-test: positive=6 rejected=15 strict=PASS elapsed=PASS PASS$","count":1}] +tools/phase2_float_amend.py tests/phase2/r17_float_text.json | timeout 30 python3 tools/phase2_float_amend.py --self-test | [{"pattern":"^float-amend-self-test: positive=1 rejected=11 PASS$","count":1}] From 0ea1b8d9780d7bda862acd58c0182f0133ad13ae Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 25 Oct 2026 11:20:19 -0500 Subject: [PATCH 180/188] fix(numbers): preserve N14 record and SQL numeric text N14/#1762 routes all finite record scalar/slot/buffer and DB float parameters through N6; exact int64 digits through eigs_int_text. N14 MAP8/8 tier checks green; DB14 passed,0 failed(14 declared); release/DB builds0 warnings. N13 nonfinite policies unchanged. Continuation 6, R1.7-D7 (#1758, N6/N14): [0fc] pins the db harness's own 14 passed, 0 failed (14 declared), accounting for this group's seven added numeric rows. The slot-layer store encoder matrix expects f64 -0.0 -> s:-0.0, replacing old s:0. Derived C-source/population/matrix sweep found no additional stale pins; existing num_text, const_dedup_bits, native_fn, sandbox-key and slot tape/operator expectations already agree. D7 narrow checkpoint proofs (all requested commands rc=0): tier=off examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=default examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=osr examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0 tier=trace examined=105 rows tag_fail=105 branch_pass=105 vacuous=0 tag_timeout=0 tag_signal=0 controls=18 both_pass=18 witnessed=31 mapped=113 gates=8 through=R1.7 controls_witnessed=13 controls_vacuous=0 invariants=2 branch_pass=2 phase2-check: PASS RESULTS: 2/2 passed, 0 failed, 0 skipped Corpus attribution: 55 observed row explanations; 0 require judgment. Full evidence retained. Corpus adjudicated: 55 differences traced to R1.7 behavior/registration; sole expected runaway timeout; no other crash/timeout. Evidence: continue6-checks.json; sweep: continue6-sweep.json/.md; six clean-apply clones and verified extracted bundle: continue6-checkpoint-proof.json. Full train pending; not launched in continuation 6. Source fingerprint: ba0bd12bbd1a933ddf8540411388e5b4f1a78211cd78014d64f12a45923a859f Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- README.md | 5 +- changes/changed/1758-number-text.md | 2 +- docs/BUILTINS.md | 4 + docs/COMPARISON.md | 5 +- docs/SPEC.md | 5 +- docs/design/phase2-inventory.txt | 128 ++++++++++++++-------------- docs/llms.txt | 5 +- src/ext_db.c | 4 +- src/ext_store.c | 34 +++----- tests/phase2/slot_layer.c | 2 +- tests/sections/0fc-db-params.sh | 2 +- tests/test_db_params.c | 4 +- tools/strict_shape_contracts.json | 6 +- 13 files changed, 107 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index ac56e2493..c48fbd163 100644 --- a/README.md +++ b/README.md @@ -541,8 +541,9 @@ PostgreSQL integer columns (`smallint`, `integer`, `bigint`, `oid`) return exact int64 values through `db_query_value`; `db_query_json` retains their exact decimal digits (N14, Q-DB253). A `bigint` beyond 2^53 is an int, including both int64 boundaries. `numeric` remains text, and finite real -columns returned directly remain floats. Float parameter text stays in its -existing format until R1.7. The executable DB examples and boundary assertions +columns returned directly remain floats. Float parameters use N6 shortest round-trip text, preserving `.0` and +signed zero. Store records use the same float writer and exact int64 digits +(N14, #1762). The executable DB examples and boundary assertions in `tests/test_db.eigs` run on the server-db profile with PostgreSQL. TCP handles, ports and sent-byte counts are integers. Numeric socket handles, ports, receive counts and outgoing bytes require exact integers (integral floats convert); bytes must be in 0..255. `net_send` validates the entire payload before sending any byte. Poll timeouts are continuous milliseconds rounded to the C int range; an unrepresentable duration raises `value`. diff --git a/changes/changed/1758-number-text.md b/changes/changed/1758-number-text.md index 42e0e3ff9..1603c1008 100644 --- a/changes/changed/1758-number-text.md +++ b/changes/changed/1758-number-text.md @@ -1 +1 @@ -- Float text now uses Python-style shortest round-trip spelling across display, f-strings and JSON (N6), preserving integral float `.0` and signed zero. Integer text remains exact. +- Float text now uses Python-style shortest round-trip spelling across display, f-strings and JSON (N6), preserving integral float `.0` and signed zero. Integer text remains exact. Store records and SQL parameters use the same writer, fixing dropped digits (#1762). diff --git a/docs/BUILTINS.md b/docs/BUILTINS.md index 96cb3e15c..663b8f700 100644 --- a/docs/BUILTINS.md +++ b/docs/BUILTINS.md @@ -1199,3 +1199,7 @@ true false false ``` + +N14 record and SQL writers use the same N6 float text and exact int64 digits. +The executed cases are `tests/phase2/rows/N14.store-exact-digits.sh` and +`tests/test_db_params.c` (#1762). diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index 4d7b0eed5..e1fb7c47d 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -256,8 +256,9 @@ PostgreSQL integer columns (`smallint`, `integer`, `bigint`, `oid`) return exact int64 values through `db_query_value`; `db_query_json` retains their exact decimal digits (N14, Q-DB253). A `bigint` beyond 2^53 is an int, including both int64 boundaries. `numeric` remains text, and finite real -columns returned directly remain floats. Float parameter text stays in its -existing format until R1.7. The executable DB examples and boundary assertions +columns returned directly remain floats. Float parameters use N6 shortest round-trip text, preserving `.0` and +signed zero. Store records use the same float writer and exact int64 digits +(N14, #1762). The executable DB examples and boundary assertions in `tests/test_db.eigs` run on the server-db profile with PostgreSQL. TCP handles, ports and sent-byte counts are integers. Numeric socket handles, ports, receive counts and outgoing bytes require exact integers (integral floats convert); bytes must be in 0..255. `net_send` validates the entire payload before sending any byte. Poll timeouts are continuous milliseconds rounded to the C int range; an unrepresentable duration raises `value`. diff --git a/docs/SPEC.md b/docs/SPEC.md index 5213a9338..5ce98b553 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -994,8 +994,9 @@ PostgreSQL integer columns (`smallint`, `integer`, `bigint`, `oid`) return exact int64 values through `db_query_value`; `db_query_json` retains their exact decimal digits (N14, Q-DB253). A `bigint` beyond 2^53 is an int, including both int64 boundaries. `numeric` remains text, and finite real -columns returned directly remain floats. Float parameter text stays in its -existing format until R1.7. The executable DB examples and boundary assertions +columns returned directly remain floats. Float parameters use N6 shortest round-trip text, preserving `.0` and +signed zero. Store records use the same float writer and exact int64 digits +(N14, #1762). The executable DB examples and boundary assertions in `tests/test_db.eigs` run on the server-db profile with PostgreSQL. TCP handles, ports and sent-byte counts are integers. Numeric socket handles, ports, receive counts and outgoing bytes require exact integers (integral floats convert); bytes must be in 0..255. `net_send` validates the entire payload before sending any byte. Poll timeouts are continuous milliseconds rounded to the C int range; an unrepresentable duration raises `value`. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 92c5eaada..8a6aa2931 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2125 classified=2125 unclassified=0 +examined=2129 classified=2129 unclassified=0 files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 # Retired (required absent): buf_num_arg -- R1.6z: bridge deleted; every caller migrated @@ -32,7 +32,7 @@ files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 (e) number formatting 23 CASE=2 FORMAT=4 PARSE=1 RAW=8 READ=3 TEST=5 (f) equality, ordering and hashing 51 CASE=2 PRODUCE=4 RAW=15 READ=7 TEST=23 (g) tape encode and decode 37 CASE=4 DATA=5 PARSE=7 PRODUCE=8 RAW=6 READ=2 TEST=5 -(h) JSON, store and db encoders 85 CASE=4 FORMAT=3 PARSE=5 PRODUCE=22 RAW=8 READ=24 TEST=19 +(h) JSON, store and db encoders 89 CASE=4 FORMAT=7 PARSE=5 PRODUCE=22 RAW=8 READ=24 TEST=19 (i) observer numeric paths 108 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=24 READ=6 TEST=34 (j) embed API 71 CASE=2 DATA=2 PRODUCE=1 RAW=6 READ=55 TEST=2 WRITE=3 @@ -66,6 +66,7 @@ strtod 16 slot_smi_val 15 eigs_list_int 13 slot_from_int 13 +eigs_num_text 12 slot_int_value 12 eigs_magnitude_arg 11 NUM_REUSE 10 @@ -74,7 +75,6 @@ eigs_geom_shape 10 eigs_slot_opt_float 9 num_to_i64_exact 9 eigs_byte_arg 8 -eigs_num_text 8 EIGS_NUM_MAX 7 eigs_bounded_arg 7 eigs_list_bounded 6 @@ -170,7 +170,7 @@ builtins_buf.c 105 a=33 b=33 c=39 jit.c 94 d=94 eigenscript.h 59 a=6 b=41 c=11 e=1 builtins_host.c 58 a=24 b=19 c=15 -ext_store.c 55 h=55 +ext_store.c 58 h=58 embed_smoke.c 54 j=54 trace.c 32 g=32 jit_smoke.c 31 d=31 @@ -184,8 +184,8 @@ ext_http.c 14 a=3 b=4 c=7 builtins_int.c 11 b=4 c=7 lexer.c 11 b=10 c=1 eigs_embed.c 10 j=10 +ext_db.c 8 h=8 model_train.c 8 a=2 b=4 c=1 i=1 -ext_db.c 7 h=7 embed_concurrent.c 6 j=6 task.c 6 a=1 b=1 c=4 parser.c 5 a=2 b=2 c=1 @@ -455,9 +455,9 @@ clock_unix builtin_clock_unix float-producing close_channel builtin_close_channel int-requiring - - eigs_int_arg_range,val_is_number copy_into builtin_copy_into int-requiring - - eigs_float_arg,eigs_int_arg_range,val_is_number cos builtin_cos float-producing - - eigs_float_arg,make_float,val_is_number -db_execute builtin_db_execute other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_float_arg -db_query_json builtin_db_query_json other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_float_arg -db_query_value builtin_db_query_value other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_float_arg,make_float,make_int,strtod +db_execute builtin_db_execute other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_float_arg,eigs_num_text +db_query_json builtin_db_query_json other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_float_arg,eigs_num_text +db_query_value builtin_db_query_value other LOSS - VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_float_arg,eigs_num_text,make_float,make_int,strtod dispatch builtin_dispatch int-requiring - - eigs_int_arg_range,val_is_number divide builtin_tensor_divide float-producing - - eigs_float_arg,eigs_number_arg,make_float,make_int,num_guard,val_is_number dot builtin_dot float-producing - - buffer_read_f64,make_float,num_guard @@ -623,16 +623,16 @@ sort_by builtin_sort_by other spawn builtin_spawn int-preserving - - make_int sqrt builtin_tensor_sqrt float-producing - - eigs_number_arg,make_float,make_int,val_is_number state_at builtin_state_at int-requiring - - eigs_int_arg_range,val_is_number -store_close builtin_store_close int-requiring - - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg_range,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number +store_close builtin_store_close int-requiring - - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg_range,eigs_num_text,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number store_collections builtin_store_collections int-requiring - - eigs_int_arg_range,val_is_number store_count builtin_store_count int-requiring - - eigs_int_arg_range,make_int,val_is_number store_delete builtin_store_delete int-requiring LOSS - eigs_int_arg,eigs_int_arg_range,val_is_number -store_drop builtin_store_drop int-requiring - - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg_range,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number +store_drop builtin_store_drop int-requiring - - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg_range,eigs_num_text,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number store_get builtin_store_get int-requiring LOSS - eigs_float_arg,eigs_int_arg,eigs_int_arg_range,eigs_number_arg,make_float,make_int,num_to_i64_exact,strtod,val_is_number store_open builtin_store_open int-preserving - - eigs_int_arg_range,make_float,make_int,strtod,val_is_number -store_put builtin_store_put other LOSS - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg_range,make_int,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number +store_put builtin_store_put other LOSS - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg_range,eigs_num_text,make_int,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number store_query builtin_store_query other LOSS - eigs_float_arg,eigs_int_arg_range,eigs_number_arg,make_float,make_int,num_to_i64_exact,strtod,val_is_number -store_update builtin_store_update other LOSS - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg,eigs_int_arg_range,make_int,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number +store_update builtin_store_update other LOSS - SLOT_F64_RAW,VAL_F64_RAW,VAL_FLOAT,VAL_I64_RAW,VAL_INT,eigs_int_arg,eigs_int_arg_range,eigs_num_text,make_int,slot_is_f64,slot_is_smi,slot_smi_val,val_is_number str builtin_str other - - eigs_num_text str_from_bytes builtin_str_from_bytes int-requiring - - VAL_FLOAT,VAL_INT,buffer_byte_at,eigs_byte_arg,eigs_slot_byte,val_is_number stream_open builtin_stream_open int-requiring - - eigs_int_arg,val_is_number @@ -1898,6 +1898,7 @@ ext_db.c:59 db_build_query VAL_INT TEST h ext_db.c:60 db_build_query VAL_I64_RAW RAW h ext_db.c:62 db_build_query VAL_FLOAT TEST h ext_db.c:64 db_build_query eigs_float_arg READ h +ext_db.c:66 db_build_query eigs_num_text FORMAT h ext_db.c:286 builtin_db_query_value make_int PRODUCE h ext_db.c:298 builtin_db_query_value make_float PRODUCE h ext_db.c:298 builtin_db_query_value strtod PARSE h @@ -2197,61 +2198,64 @@ ext_net.c:375 builtin_net_send buffer_byte_at READ b ext_net.c:380 builtin_net_send eigs_elem_byte READ b ext_net.c:397 builtin_net_close val_is_number TEST a ext_net.c:403 builtin_net_close eigs_int_arg READ b +ext_store.c:164 store_json_encode_buf_elem eigs_num_text FORMAT h ext_store.c:175 store_json_encode_slot slot_is_f64 TEST h ext_store.c:178 store_json_encode_slot SLOT_F64_RAW RAW h -ext_store.c:185 store_json_encode_slot slot_is_smi TEST h +ext_store.c:180 store_json_encode_slot eigs_num_text FORMAT h +ext_store.c:184 store_json_encode_slot slot_is_smi TEST h ext_store.c:187 store_json_encode_slot slot_smi_val RAW h -ext_store.c:199 store_json_encode VAL_FLOAT CASE h -ext_store.c:202 store_json_encode VAL_F64_RAW RAW h -ext_store.c:215 store_json_encode VAL_INT CASE h -ext_store.c:217 store_json_encode VAL_I64_RAW RAW h -ext_store.c:340 store_json_parse_number strtod PARSE h -ext_store.c:353 store_json_parse_number make_int PRODUCE h -ext_store.c:354 store_json_parse_number make_float PRODUCE h -ext_store.c:390 store_buffer_from_tag val_is_number TEST h -ext_store.c:390 store_buffer_from_tag val_is_number TEST h -ext_store.c:395 store_buffer_from_tag eigs_number_arg READ h -ext_store.c:396 store_buffer_from_tag eigs_number_arg READ h -ext_store.c:400 store_buffer_from_tag num_to_i64_exact READ h -ext_store.c:402 store_buffer_from_tag num_to_i64_exact READ h -ext_store.c:420 store_buffer_from_tag val_is_number TEST h -ext_store.c:435 store_buffer_from_tag eigs_float_arg READ h -ext_store.c:435 store_buffer_from_tag val_is_number TEST h -ext_store.c:773 store_load_catalog val_is_number TEST h -ext_store.c:773 store_load_catalog val_is_number TEST h -ext_store.c:779 store_load_catalog eigs_int_arg_range READ h -ext_store.c:852 get_store_why val_is_number TEST h -ext_store.c:854 get_store_why eigs_int_arg_range READ h -ext_store.c:857 get_store_why val_is_number TEST h -ext_store.c:858 get_store_why eigs_int_arg_range READ h -ext_store.c:997 builtin_store_open make_int PRODUCE h -ext_store.c:998 builtin_store_open make_int PRODUCE h -ext_store.c:1012 builtin_store_close eigs_int_arg_range READ h -ext_store.c:1015 builtin_store_close eigs_int_arg_range READ h -ext_store.c:1061 builtin_store_put make_int PRODUCE h -ext_store.c:1062 builtin_store_put make_int PRODUCE h -ext_store.c:1077 builtin_store_put eigs_int_arg_range READ h -ext_store.c:1079 builtin_store_put eigs_int_arg_range READ h -ext_store.c:1094 builtin_store_put make_int PRODUCE h -ext_store.c:1218 builtin_store_get val_is_number TEST h -ext_store.c:1219 builtin_store_get eigs_int_arg READ h -ext_store.c:1231 builtin_store_get eigs_int_arg_range READ h -ext_store.c:1291 store_locate eigs_int_arg_range READ h -ext_store.c:1388 builtin_store_delete val_is_number TEST h -ext_store.c:1389 builtin_store_delete eigs_int_arg READ h -ext_store.c:1438 builtin_store_query eigs_int_arg_range READ h -ext_store.c:1474 builtin_store_count make_int PRODUCE h -ext_store.c:1482 builtin_store_count make_int PRODUCE h -ext_store.c:1483 builtin_store_count make_int PRODUCE h +ext_store.c:200 store_json_encode VAL_FLOAT CASE h +ext_store.c:203 store_json_encode VAL_F64_RAW RAW h +ext_store.c:205 store_json_encode eigs_num_text FORMAT h +ext_store.c:209 store_json_encode VAL_INT CASE h +ext_store.c:211 store_json_encode VAL_I64_RAW RAW h +ext_store.c:334 store_json_parse_number strtod PARSE h +ext_store.c:347 store_json_parse_number make_int PRODUCE h +ext_store.c:348 store_json_parse_number make_float PRODUCE h +ext_store.c:384 store_buffer_from_tag val_is_number TEST h +ext_store.c:384 store_buffer_from_tag val_is_number TEST h +ext_store.c:389 store_buffer_from_tag eigs_number_arg READ h +ext_store.c:390 store_buffer_from_tag eigs_number_arg READ h +ext_store.c:394 store_buffer_from_tag num_to_i64_exact READ h +ext_store.c:396 store_buffer_from_tag num_to_i64_exact READ h +ext_store.c:414 store_buffer_from_tag val_is_number TEST h +ext_store.c:429 store_buffer_from_tag eigs_float_arg READ h +ext_store.c:429 store_buffer_from_tag val_is_number TEST h +ext_store.c:767 store_load_catalog val_is_number TEST h +ext_store.c:767 store_load_catalog val_is_number TEST h +ext_store.c:773 store_load_catalog eigs_int_arg_range READ h +ext_store.c:846 get_store_why val_is_number TEST h +ext_store.c:848 get_store_why eigs_int_arg_range READ h +ext_store.c:851 get_store_why val_is_number TEST h +ext_store.c:852 get_store_why eigs_int_arg_range READ h +ext_store.c:991 builtin_store_open make_int PRODUCE h +ext_store.c:992 builtin_store_open make_int PRODUCE h +ext_store.c:1006 builtin_store_close eigs_int_arg_range READ h +ext_store.c:1009 builtin_store_close eigs_int_arg_range READ h +ext_store.c:1055 builtin_store_put make_int PRODUCE h +ext_store.c:1056 builtin_store_put make_int PRODUCE h +ext_store.c:1071 builtin_store_put eigs_int_arg_range READ h +ext_store.c:1073 builtin_store_put eigs_int_arg_range READ h +ext_store.c:1088 builtin_store_put make_int PRODUCE h +ext_store.c:1212 builtin_store_get val_is_number TEST h +ext_store.c:1213 builtin_store_get eigs_int_arg READ h +ext_store.c:1225 builtin_store_get eigs_int_arg_range READ h +ext_store.c:1285 store_locate eigs_int_arg_range READ h +ext_store.c:1382 builtin_store_delete val_is_number TEST h +ext_store.c:1383 builtin_store_delete eigs_int_arg READ h +ext_store.c:1432 builtin_store_query eigs_int_arg_range READ h +ext_store.c:1468 builtin_store_count make_int PRODUCE h +ext_store.c:1476 builtin_store_count make_int PRODUCE h +ext_store.c:1477 builtin_store_count make_int PRODUCE h +ext_store.c:1480 builtin_store_count make_int PRODUCE h ext_store.c:1486 builtin_store_count make_int PRODUCE h -ext_store.c:1492 builtin_store_count make_int PRODUCE h -ext_store.c:1496 builtin_store_count make_int PRODUCE h -ext_store.c:1498 builtin_store_count eigs_int_arg_range READ h +ext_store.c:1490 builtin_store_count make_int PRODUCE h +ext_store.c:1492 builtin_store_count eigs_int_arg_range READ h +ext_store.c:1504 builtin_store_count make_int PRODUCE h ext_store.c:1510 builtin_store_count make_int PRODUCE h -ext_store.c:1516 builtin_store_count make_int PRODUCE h -ext_store.c:1550 builtin_store_update val_is_number TEST h -ext_store.c:1551 builtin_store_update eigs_int_arg READ h -ext_store.c:1695 builtin_store_drop eigs_int_arg_range READ h +ext_store.c:1544 builtin_store_update val_is_number TEST h +ext_store.c:1545 builtin_store_update eigs_int_arg READ h +ext_store.c:1689 builtin_store_drop eigs_int_arg_range READ h jit.c:1275 emit_conditional_incref_rax TAG-IMM 0xFFFB EMIT d jit.c:1399 emit_addsd_xmm0_xmm1 emit_addsd_xmm0_xmm1 EMIT d jit.c:1403 emit_subsd_xmm0_xmm1 emit_subsd_xmm0_xmm1 EMIT d diff --git a/docs/llms.txt b/docs/llms.txt index 3c0413401..900374e0f 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -553,8 +553,9 @@ PostgreSQL integer columns (`smallint`, `integer`, `bigint`, `oid`) return exact int64 values through `db_query_value`; `db_query_json` retains their exact decimal digits (N14, Q-DB253). A `bigint` beyond 2^53 is an int, including both int64 boundaries. `numeric` remains text, and finite real -columns returned directly remain floats. Float parameter text stays in its -existing format until R1.7. The executable DB examples and boundary assertions +columns returned directly remain floats. Float parameters use N6 shortest round-trip text, preserving `.0` and +signed zero. Store records use the same float writer and exact int64 digits +(N14, #1762). The executable DB examples and boundary assertions in `tests/test_db.eigs` run on the server-db profile with PostgreSQL. TCP handles, ports and sent-byte counts are integers. Numeric socket handles, ports, receive counts and outgoing bytes require exact integers (integral floats convert); bytes must be in 0..255. `net_send` validates the entire payload before sending any byte. Poll timeouts are continuous milliseconds rounded to the C int range; an unrepresentable duration raises `value`. diff --git a/src/ext_db.c b/src/ext_db.c index 34064c3ba..82028755c 100644 --- a/src/ext_db.c +++ b/src/ext_db.c @@ -60,10 +60,10 @@ static int db_build_query(Value *arg, const char **sql, int *nparams, eigs_int_text(numbuf[i], 64, VAL_I64_RAW(v)); params[i] = numbuf[i]; } else if (v && v->type == VAL_FLOAT) { - /* N6's float text writer changes in R1.7, not this reader round. */ + /* N6/N14: exact round-trip parameter text, shared with display/JSON. */ double f = eigs_float_arg(v, __func__); if (g_has_error) return 0; - snprintf(numbuf[i], 64, "%g", f); + eigs_num_text(numbuf[i], 64, f); params[i] = numbuf[i]; } else { rt_error(EK_TYPE, 0, "db: parameter %d is not a string, number or bool (got %s)", diff --git a/src/ext_store.c b/src/ext_store.c index 0ac9f74f4..a20001927 100644 --- a/src/ext_store.c +++ b/src/ext_store.c @@ -155,14 +155,14 @@ static int store_nonfinite_sentinel(const char *s, double *out) { return 0; } -/* Buffer elements use the 17-significant-digit form, as trace.c's buffer tape - * encoding does: %.17g is the shortest width that round-trips a double - * bit-exactly, and a buffer holding samples or weights would otherwise come - * back subtly altered. (VAL_FLOAT's own %d/%.15g encoding is untouched.) */ +/* N6/N14: all finite record numbers share the one shortest writer. + * The existing non-finite buffer sentinels stay strings until N13. */ static void store_json_encode_buf_elem(strbuf *out, double d) { if (isnan(d)) { strbuf_append(out, "\"nan\""); return; } if (isinf(d)) { strbuf_append(out, d < 0 ? "\"-inf\"" : "\"inf\""); return; } - strbuf_append_fmt(out, "%.17g", d); + char nb[32]; + eigs_num_text(nb, sizeof nb, d); + strbuf_append(out, nb); } static void store_json_encode(Value *v, strbuf *out); @@ -176,15 +176,16 @@ static void store_json_encode_slot(EigsSlot slot, strbuf *out) { /* This is persisted float data, not a finite builtin argument. * Keep the existing NaN/inf spelling until N13 (R2.3). */ double n = SLOT_F64_RAW(slot); - if (fabs(n) < 2147483648.0 && n == (int)n) - strbuf_append_fmt(out, "%d", (int)n); - else - strbuf_append_fmt(out, "%.15g", n); + char nb[32]; + eigs_num_text(nb, sizeof nb, n); + strbuf_append(out, nb); return; } if (slot_is_smi(slot)) { /* #1758: an int is written as its exact digits (design 7). */ - strbuf_append_fmt(out, "%lld", (long long)slot_smi_val(slot)); + char nb[24]; + eigs_int_text(nb, sizeof nb, slot_smi_val(slot)); + strbuf_append(out, nb); return; } store_json_encode(eigs_slot_ref(slot), out); @@ -200,16 +201,9 @@ static void store_json_encode(Value *v, strbuf *out) { /* The switch proves VAL_FLOAT; serialization also accepts the * historical non-finite payloads until N13 (R2.3). */ double n = VAL_F64_RAW(v); - /* #816: magnitude BEFORE the narrowing cast (same class as - * #695) — converting a double beyond int's range is UB, and - * the old `n == (int)n && fabs(n) < 1e15` order ran the cast - * first. The bound is int's own range: integral values beyond - * it never took the %d path anyway (the equality failed), so - * output is unchanged and the cast is now always defined. */ - if (fabs(n) < 2147483648.0 && n == (int)n) - strbuf_append_fmt(out, "%d", (int)n); - else - strbuf_append_fmt(out, "%.15g", n); + char nb[32]; + eigs_num_text(nb, sizeof nb, n); + strbuf_append(out, nb); break; } case VAL_INT: { /* #1758 R1.2a: an int encodes as its exact digits */ diff --git a/tests/phase2/slot_layer.c b/tests/phase2/slot_layer.c index 474b813cd..f63bb4b42 100644 --- a/tests/phase2/slot_layer.c +++ b/tests/phase2/slot_layer.c @@ -388,7 +388,7 @@ EXP(ent_child) { } } EXP(store_json) { - static const char *f64[3] = {"s:1.5", "s:nan", "s:0"}; /* -0.0 takes the %d branch */ + static const char *f64[3] = {"s:1.5", "s:nan", "s:-0.0"}; /* R1.7-D7: N6/N14 preserve signed-zero text. */ switch (kclass(k)) { case C_F64: snprintf(b, n, "%s", f64[k]); break; case C_NULL: snprintf(b, n, "s:null"); break; diff --git a/tests/sections/0fc-db-params.sh b/tests/sections/0fc-db-params.sh index 605464367..03ec9a5dc 100644 --- a/tests/sections/0fc-db-params.sh +++ b/tests/sections/0fc-db-params.sh @@ -9,7 +9,7 @@ else DBP_BUILD=$(make --no-print-directory -C "$TESTS_DIR/.." build/server-db/test_db_params 2>&1); DBP_RC=$? DBP_OUT="" [ "$DBP_RC" = 0 ] && { DBP_OUT=$($EIGS_TMO "$TESTS_DIR/../build/server-db/test_db_params" 2>&1); DBP_RC=$?; } - if rc_ok "$DBP_RC" "$DBP_OUT" && grep -qx 'db params: 7 passed, 0 failed (7 declared)' <<< "$DBP_OUT"; then + if rc_ok "$DBP_RC" "$DBP_OUT" && grep -qx 'db params: 14 passed, 0 failed (14 declared)' <<< "$DBP_OUT"; then PASS=$((PASS + 1)); echo " PASS: a bool db parameter binds as SQL boolean text with OID 16" else FAIL=$((FAIL + 1)); echo " FAIL: db parameter binding (rc=$DBP_RC)" diff --git a/tests/test_db_params.c b/tests/test_db_params.c index 9143ec65c..c35abb450 100644 --- a/tests/test_db_params.c +++ b/tests/test_db_params.c @@ -29,7 +29,7 @@ int main(void) { int ok = db_build_query(arg, &sql, &n, params, numbuf, types); check(ok && n == 4, "four parameters built"); check(ok && strcmp(params[0], "true") == 0 && types[0] == 16, "true binds as SQL boolean 'true' (OID 16)"); - check(ok && strcmp(params[1], "3") == 0 && types[1] == 0, "a number keeps the inferred type"); + check(ok && strcmp(params[1], "3.0") == 0 && types[1] == 0, "a number keeps the inferred type"); check(ok && strcmp(params[2], "s") == 0 && types[2] == 0, "a string keeps the inferred type"); check(ok && strcmp(params[3], "false") == 0 && types[3] == 16, "false binds as SQL boolean 'false' (OID 16)"); check(DB_PARAM_OID_BOOL == DB_OID_BOOL, "the parameter OID is the column classifier's boolean OID"); @@ -37,8 +37,10 @@ int main(void) { Value *bad = make_list(2); list_append_owned(bad, make_str("select $1")); list_append_owned(bad, make_dict(1)); + ++g_try_depth; /* catch the expected type error without a diagnostic */ check(!db_build_query(bad, &sql, &n, params, numbuf, types) && eigs_has_error(), "a dict parameter still raises"); + --g_try_depth; eigs_clear_error(); val_decref(bad); /* R1.7 N6/N14: exact int digits and Python-repr float text. */ diff --git a/tools/strict_shape_contracts.json b/tools/strict_shape_contracts.json index dbeb7f13a..cdf008822 100644 --- a/tools/strict_shape_contracts.json +++ b/tools/strict_shape_contracts.json @@ -638,7 +638,7 @@ "6b2fd24e37e2c8815cc09b9c56984e8b2393f6af707ff41170c97457f39a4f9f" ], "db_build_query": [ - "2c0c401e39d0237a8d4e5b3b591b2491352d41f7e2de9a33c8bffb2a11eac1aa" + "d57ab589c31eb96aa0cff79085ddad9fa4e924b84bd472c3b6b3622c6ca09dcd" ], "db_exec_from_arg": [ "cbcf24fbb55c5a6f9bfdbb6535dc22a89086dab2ed311d0fc0892eb6eb287145" @@ -664,7 +664,7 @@ "042bcba19f5cfaa379a1a81e037057a06c2dfbe3341257c3b2a84b8555ffc43a" ], "db_build_query": [ - "2c0c401e39d0237a8d4e5b3b591b2491352d41f7e2de9a33c8bffb2a11eac1aa" + "d57ab589c31eb96aa0cff79085ddad9fa4e924b84bd472c3b6b3622c6ca09dcd" ], "db_exec_from_arg": [ "cbcf24fbb55c5a6f9bfdbb6535dc22a89086dab2ed311d0fc0892eb6eb287145" @@ -690,7 +690,7 @@ "b8cb843d720732f72f332fc03363ec834cc9fdb98dc018edf1011c7508cab784" ], "db_build_query": [ - "2c0c401e39d0237a8d4e5b3b591b2491352d41f7e2de9a33c8bffb2a11eac1aa" + "d57ab589c31eb96aa0cff79085ddad9fa4e924b84bd472c3b6b3622c6ca09dcd" ], "db_exec_from_arg": [ "cbcf24fbb55c5a6f9bfdbb6535dc22a89086dab2ed311d0fc0892eb6eb287145" From 72c02c1816840a5165e8ed51a27b404c00649662 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 25 Oct 2026 11:21:02 -0500 Subject: [PATCH 181/188] fix(trace): use N6 shortest number text in tape records T1 keeps the existing tape version and kind markers; shortest shared text for scalar,buffer and observer config records. T1 twice-float3/3 tiers green; each records twice and strictly replays identical output. Release0 warnings. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/changed/1758-number-text.md | 2 +- docs/design/phase2-inventory.txt | 65 +++++++++++++++++++---------- src/trace.c | 28 +++++++------ 3 files changed, 60 insertions(+), 35 deletions(-) diff --git a/changes/changed/1758-number-text.md b/changes/changed/1758-number-text.md index 1603c1008..e29ad5b6b 100644 --- a/changes/changed/1758-number-text.md +++ b/changes/changed/1758-number-text.md @@ -1 +1 @@ -- Float text now uses Python-style shortest round-trip spelling across display, f-strings and JSON (N6), preserving integral float `.0` and signed zero. Integer text remains exact. Store records and SQL parameters use the same writer, fixing dropped digits (#1762). +- Float text now uses Python-style shortest round-trip spelling across display, f-strings and JSON (N6), preserving integral float `.0` and signed zero. Integer text remains exact. Store records and SQL parameters use the same writer, fixing dropped digits (#1762). Trace number records use the same spelling without a tape format version change (T1). diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 8a6aa2931..9f14c6dcd 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1,6 +1,6 @@ # docs/design/phase2-inventory.txt -- generated by tools/phase2_inventory.py; do not edit. # Population: VOCAB token occurrences in src/*.c src/*.h, comments and literals stripped. -examined=2129 classified=2129 unclassified=0 +examined=2152 classified=2152 unclassified=0 files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 # Retired (required absent): buf_num_arg -- R1.6z: bridge deleted; every caller migrated @@ -31,7 +31,7 @@ files=65 tokens=117 role_rules=8 derived_accessors=20 wrappers=7 (d) JIT emitters and guards 125 EMIT=87 GUARD=1 PRODUCE=6 RAW=27 TAGSET=1 TEST=2 WRITE=1 (e) number formatting 23 CASE=2 FORMAT=4 PARSE=1 RAW=8 READ=3 TEST=5 (f) equality, ordering and hashing 51 CASE=2 PRODUCE=4 RAW=15 READ=7 TEST=23 -(g) tape encode and decode 37 CASE=4 DATA=5 PARSE=7 PRODUCE=8 RAW=6 READ=2 TEST=5 +(g) tape encode and decode 60 CASE=4 DATA=5 FORMAT=6 PARSE=7 PRODUCE=8 RAW=23 READ=2 TEST=5 (h) JSON, store and db encoders 89 CASE=4 FORMAT=7 PARSE=5 PRODUCE=22 RAW=8 READ=24 TEST=19 (i) observer numeric paths 108 CASE=6 FORMAT=1 GUARD=1 PARSE=1 PRODUCE=35 RAW=24 READ=6 TEST=34 (j) embed API 71 CASE=2 DATA=2 PRODUCE=1 RAW=6 READ=55 TEST=2 WRITE=3 @@ -50,11 +50,11 @@ AST_NUM 53 eigs_value_as_num 53 VAL_I64_RAW 50 eigs_list_float 47 +number 47 slot_from_f64 44 slot_is_f64 44 eigs_int_arg 34 eigs_int_arg_range 34 -number 30 slot_is_smi 28 eigs_slot_float 27 buffer_read_f64 26 @@ -62,11 +62,11 @@ eigs_number_arg 23 slot_f64_value 23 list_set_f64 22 eigs_list_int_range 21 +eigs_num_text 18 strtod 16 slot_smi_val 15 eigs_list_int 13 slot_from_int 13 -eigs_num_text 12 slot_int_value 12 eigs_magnitude_arg 11 NUM_REUSE 10 @@ -171,8 +171,8 @@ jit.c 94 d=94 eigenscript.h 59 a=6 b=41 c=11 e=1 builtins_host.c 58 a=24 b=19 c=15 ext_store.c 58 h=58 +trace.c 55 g=55 embed_smoke.c 54 j=54 -trace.c 32 g=32 jit_smoke.c 31 d=31 lint.c 29 a=29 compiler.c 26 a=14 b=8 c=2 i=2 @@ -2471,22 +2471,40 @@ trace.c:742 trace_query_at slot_from_f64 PRODUCE g trace.c:757 trace_query_at slot_from_f64 PRODUCE g trace.c:806 trace_query_when slot_from_f64 PRODUCE g trace.c:827 trace_query_when slot_from_f64 PRODUCE g -trace.c:1927 #define TK_NUM_ VAL_FLOAT DATA g -trace.c:1927 #define TK_NUM_ VAL_INT DATA g -trace.c:2039 kinds_text VAL_FLOAT DATA g -trace.c:2039 kinds_text VAL_INT DATA g -trace.c:2040 kinds_text VAL_FLOAT DATA g -trace.c:2349 parse_value_p strtod PARSE g -trace.c:2455 parse_value_p make_int PRODUCE g -trace.c:2458 parse_value_p strtod PARSE g -trace.c:2468 parse_value_p make_float PRODUCE g -trace.c:2762 trace_source_record make_int PRODUCE g -trace.c:2771 trace_source_record make_int PRODUCE g -trace.c:2795 trace_source_replay VAL_FLOAT TEST g -trace.c:2795 trace_source_replay VAL_INT TEST g -trace.c:2804 trace_source_replay VAL_INT TEST g -trace.c:2806 trace_source_replay slot_f64_value READ g -trace.c:2813 trace_source_replay slot_int_value READ g +trace.c:1580 obs_cfg_sync number RAW g +trace.c:1581 obs_cfg_sync eigs_num_text FORMAT g +trace.c:1581 obs_cfg_sync number RAW g +trace.c:1581 obs_cfg_sync number RAW g +trace.c:1582 obs_cfg_sync number RAW g +trace.c:1583 obs_cfg_sync eigs_num_text FORMAT g +trace.c:1583 obs_cfg_sync number RAW g +trace.c:1583 obs_cfg_sync number RAW g +trace.c:1584 obs_cfg_sync number RAW g +trace.c:1585 obs_cfg_sync eigs_num_text FORMAT g +trace.c:1585 obs_cfg_sync number RAW g +trace.c:1585 obs_cfg_sync number RAW g +trace.c:1586 obs_cfg_sync number RAW g +trace.c:1588 obs_cfg_sync eigs_num_text FORMAT g +trace.c:1588 obs_cfg_sync number RAW g +trace.c:1588 obs_cfg_sync number RAW g +trace.c:1589 obs_cfg_sync number RAW g +trace.c:1932 #define TK_NUM_ VAL_FLOAT DATA g +trace.c:1932 #define TK_NUM_ VAL_INT DATA g +trace.c:2044 kinds_text VAL_FLOAT DATA g +trace.c:2044 kinds_text VAL_INT DATA g +trace.c:2045 kinds_text VAL_FLOAT DATA g +trace.c:2354 parse_value_p strtod PARSE g +trace.c:2460 parse_value_p make_int PRODUCE g +trace.c:2463 parse_value_p strtod PARSE g +trace.c:2473 parse_value_p make_float PRODUCE g +trace.c:2767 trace_source_record make_int PRODUCE g +trace.c:2776 trace_source_record make_int PRODUCE g +trace.c:2800 trace_source_replay VAL_FLOAT TEST g +trace.c:2800 trace_source_replay VAL_INT TEST g +trace.c:2809 trace_source_replay VAL_INT TEST g +trace.c:2811 trace_source_replay slot_f64_value READ g +trace.c:2818 trace_source_replay slot_int_value READ g +trace.c:2987 tape_float_text eigs_num_text FORMAT g trace.c:3007 write_value_ptr VAL_F64_RAW RAW g trace.c:3007 write_value_ptr VAL_FLOAT CASE g trace.c:3008 write_value_ptr VAL_I64_RAW RAW g @@ -2499,6 +2517,11 @@ trace.c:3146 write_value_ptr_full VAL_FLOAT CASE g trace.c:3148 write_value_ptr_full VAL_F64_RAW RAW g trace.c:3152 write_value_ptr_full VAL_INT CASE g trace.c:3154 write_value_ptr_full VAL_I64_RAW RAW g +trace.c:3194 write_value_ptr_full number RAW g +trace.c:3195 write_value_ptr_full eigs_num_text FORMAT g +trace.c:3195 write_value_ptr_full number RAW g +trace.c:3195 write_value_ptr_full number RAW g +trace.c:3196 write_value_ptr_full number RAW g value_slot.h:84 slot_is_f64 slot_is_f64 TEST a value_slot.h:90 slot_is_smi slot_is_smi TEST a value_slot.h:101 #define SLOT_F64_RAW SLOT_F64_RAW RAW b diff --git a/src/trace.c b/src/trace.c index a7eebd059..c402f4a0a 100644 --- a/src/trace.c +++ b/src/trace.c @@ -1577,11 +1577,16 @@ static void obs_cfg_sync(void) { * %.17g fields in one call could silently truncate the record. */ emit_tag("O"); tp_puts("cfg "); - tp_printf("%.17g ", binding->obs_dh_zero); - tp_printf("%.17g ", binding->obs_dh_small); - tp_printf("%.17g ", binding->obs_h_low); + char number[32]; + eigs_num_text(number, sizeof number, binding->obs_dh_zero); + tp_printf("%s ", number); + eigs_num_text(number, sizeof number, binding->obs_dh_small); + tp_printf("%s ", number); + eigs_num_text(number, sizeof number, binding->obs_h_low); + tp_printf("%s ", number); tp_printf("%d ", binding->obs_window); - tp_printf("%.17g\n", binding->obs_scale); + eigs_num_text(number, sizeof number, binding->obs_scale); + tp_printf("%s\n", number); } /* `set_observer_window of ["x", n]` — the per-binding override, recorded at @@ -2976,15 +2981,10 @@ static void write_string(const char *s) { tp_putc('"'); } -/* Tape float spelling is independent of ordinary display (N6, R1.7). The - * point/exponent is the v8 kind marker: integral floats, including negative - * zero, must never replay as ints. %.17g preserves the exact double bits. */ +/* N6/T1: the point/exponent is the v8 float-kind marker. The shared + * shortest writer retains it for every integral float, including -0.0. */ static void tape_float_text(char *buf, size_t nbuf, double n) { - snprintf(buf, nbuf, "%.17g", n); - if (isfinite(n) && !strchr(buf, '.') && !strchr(buf, 'e') && !strchr(buf, 'E')) { - size_t used = strlen(buf); - if (used + 2 < nbuf) memcpy(buf + used, ".0", 3); - } + eigs_num_text(buf, nbuf, n); } static void write_float(double n) { @@ -3191,7 +3191,9 @@ static void write_value_ptr_full(Value *v, int *budget) { int n = v->data.buffer.count; for (int i = 0; i < n && *budget > 0; i++) { if (i) wf_puts(", ", budget); - wf_printf(budget, "%.17g", v->data.buffer.data[i]); + char number[32]; + eigs_num_text(number, sizeof number, v->data.buffer.data[i]); + wf_printf(budget, "%s", number); } wf_putc(']', budget); break; From 4d83f1e8aaf193e877e4a591c3bb0741469688e5 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 25 Oct 2026 11:22:26 -0500 Subject: [PATCH 182/188] fix(compiler): deduplicate float constants by binary64 bits R1.7-D4 preserves signed-zero constant keys in hash and equality. Direct probe8/8 checks green;13 R1.7 programs51/51 tier observations green. Dedup-by-value plant belongs to final plant train. Release0 warnings. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- changes/changed/1758-number-text.md | 2 +- docs/design/phase2-inventory.txt | 46 ++++++++++++++--------------- src/chunk.c | 15 +++++----- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/changes/changed/1758-number-text.md b/changes/changed/1758-number-text.md index e29ad5b6b..12a1d034c 100644 --- a/changes/changed/1758-number-text.md +++ b/changes/changed/1758-number-text.md @@ -1 +1 @@ -- Float text now uses Python-style shortest round-trip spelling across display, f-strings and JSON (N6), preserving integral float `.0` and signed zero. Integer text remains exact. Store records and SQL parameters use the same writer, fixing dropped digits (#1762). Trace number records use the same spelling without a tape format version change (T1). +- Float text now uses Python-style shortest round-trip spelling across display, f-strings and JSON (N6), preserving integral float `.0` and signed zero. Integer text remains exact. Store records and SQL parameters use the same writer, fixing dropped digits (#1762). Trace number records use the same spelling without a tape format version change (T1). Constant dedup preserves binary64 bits, including distinct signed zeros. diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index 9f14c6dcd..d5748e868 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1400,31 +1400,31 @@ builtins_tensor.c:2479 tensor_load_record_verdict make_int PRODUCE c builtins_tensor.c:2498 builtin_tensor_load VAL_INT TEST a builtins_tensor.c:2499 builtin_tensor_load VAL_INT TEST a builtins_tensor.c:2573 builtin_tensor_load num_guard_named GUARD c -chunk.c:194 const_hash_value VAL_FLOAT TEST f -chunk.c:195 const_hash_value VAL_F64_RAW RAW f -chunk.c:204 const_hash_value VAL_INT TEST f -chunk.c:205 const_hash_value VAL_I64_RAW RAW f -chunk.c:220 const_equal VAL_FLOAT TEST f -chunk.c:220 const_equal VAL_FLOAT TEST f -chunk.c:221 const_equal VAL_F64_RAW RAW f -chunk.c:221 const_equal VAL_F64_RAW RAW f -chunk.c:222 const_equal VAL_INT TEST f -chunk.c:222 const_equal VAL_INT TEST f -chunk.c:223 const_equal VAL_I64_RAW RAW f -chunk.c:223 const_equal VAL_I64_RAW RAW f -chunk.c:243 const_dedup_grow val_is_number TEST a -chunk.c:252 chunk_add_constant_ex val_is_number TEST a -chunk.c:431 chunk_disassemble VAL_FLOAT TEST e -chunk.c:432 chunk_disassemble number RAW e -chunk.c:433 chunk_disassemble VAL_F64_RAW RAW e -chunk.c:433 chunk_disassemble eigs_num_text FORMAT e -chunk.c:433 chunk_disassemble number RAW e +chunk.c:193 const_hash_value VAL_FLOAT TEST f +chunk.c:194 const_hash_value VAL_F64_RAW RAW f +chunk.c:202 const_hash_value VAL_INT TEST f +chunk.c:203 const_hash_value VAL_I64_RAW RAW f +chunk.c:218 const_equal VAL_FLOAT TEST f +chunk.c:218 const_equal VAL_FLOAT TEST f +chunk.c:220 const_equal VAL_F64_RAW RAW f +chunk.c:220 const_equal VAL_F64_RAW RAW f +chunk.c:223 const_equal VAL_INT TEST f +chunk.c:223 const_equal VAL_INT TEST f +chunk.c:224 const_equal VAL_I64_RAW RAW f +chunk.c:224 const_equal VAL_I64_RAW RAW f +chunk.c:244 const_dedup_grow val_is_number TEST a +chunk.c:253 chunk_add_constant_ex val_is_number TEST a +chunk.c:432 chunk_disassemble VAL_FLOAT TEST e chunk.c:433 chunk_disassemble number RAW e +chunk.c:434 chunk_disassemble VAL_F64_RAW RAW e +chunk.c:434 chunk_disassemble eigs_num_text FORMAT e +chunk.c:434 chunk_disassemble number RAW e chunk.c:434 chunk_disassemble number RAW e -chunk.c:436 chunk_disassemble VAL_INT TEST e -chunk.c:437 chunk_disassemble VAL_I64_RAW RAW e -chunk.c:803 chunk_verify_impl VAL_INT TEST a -chunk.c:1110 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a +chunk.c:435 chunk_disassemble number RAW e +chunk.c:437 chunk_disassemble VAL_INT TEST e +chunk.c:438 chunk_disassemble VAL_I64_RAW RAW e +chunk.c:804 chunk_verify_impl VAL_INT TEST a +chunk.c:1111 chunk_scan_leaf_accessor/OP_CONST VAL_FLOAT TEST a compiler.c:583 add_num_constant make_float PRODUCE c compiler.c:590 add_int_constant make_int PRODUCE c compiler.c:599 literal_index_u16 data.number RAW b diff --git a/src/chunk.c b/src/chunk.c index 4f8030a22..95777e217 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -186,14 +186,12 @@ void chunk_patch_jump(EigsChunk *chunk, int offset) { /* ---- Constant pool ---- */ /* ---- Constant-pool dedup index (#341) ---- - * Equality is EXACTLY the old linear scan's tests, so pools stay - * byte-identical (the AOT oracle depends on that): NaN never equals - * itself (each NaN appends), and -0.0 merges with +0.0 (they hash the - * same and compare ==). Only numeric and string constants are deduped; numeric kinds stay distinct. */ + * N6 compares float identities by binary64 bits, retaining signed zero + * and NaN payloads. Integers and strings keep their existing value keys; + * numeric kinds stay distinct. */ static uint32_t const_hash_value(const Value *v) { if (v->type == VAL_FLOAT) { double d = VAL_F64_RAW(v); - if (d == 0.0) d = 0.0; /* fold -0.0 into +0.0, matching == */ uint64_t bits; memcpy(&bits, &d, sizeof bits); bits ^= bits >> 33; @@ -217,8 +215,11 @@ static uint32_t const_hash_value(const Value *v) { } static int const_equal(const Value *a, const Value *b) { - if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) - return VAL_F64_RAW(a) == VAL_F64_RAW(b); + if (a->type == VAL_FLOAT && b->type == VAL_FLOAT) { + /* N6: constant identity preserves signed zero and every double bit. */ + double av = VAL_F64_RAW(a), bv = VAL_F64_RAW(b); + return memcmp(&av, &bv, sizeof av) == 0; + } if (a->type == VAL_INT && b->type == VAL_INT) return VAL_I64_RAW(a) == VAL_I64_RAW(b); if (a->type == VAL_STR && b->type == VAL_STR) From 20f9d86c21276ddc8d1a1ebf027f8756360afd68 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Sun, 25 Oct 2026 11:25:04 -0500 Subject: [PATCH 183/188] docs(numbers): record R1.7 oracles, rulings and exact diff evidence Record D2 seven-probe/six-amendment boundary, D3 measured two invariants and11change rows, D4 direct constant-pool witness; all51 final MAP tier observations green. N6 shortest writer and N14/T1 sites covered by actual C/ASan/freestanding/fulltrain gates. Corpus retains full raw/comparer evidence without changing counts or normalizing differences;12 ownership/capture helpercontrols green. Cost comparison remains byte-strict by default; N6 opt-in calibrated6positive/15negativecontrols. Consumer candidate-call census16repos recorded. Final acceptance counts appended after complete train. Continuation 3 gate maintenance: apply main PR #1970's exact comment and unset EIGS_TREE_LOCK_HELD after ROOT in tools/make_lock_check.sh. Entire script blob matches #1970: c0afa514af52c1dcf2e71e2e043598e63bed85d6. Train #2 under make inherited the recursive-lock bypass and failed case 1, 0/8 cases passed. The selftest now clears it; case 3 still sets it explicitly. Requested public selftest rows in /tmp/es-r17-checkpoints, actual rc=0: make-lock selftest: 8/8 passed calibration: cases=54 as-expected=54 unexpected=0 All six clean-apply/tree/manifest checkpoint proofs and refreshed bundle extraction recorded in continue3-checkpoint-proof.json. The post-check amendment changes commit metadata only; tested trees are identical. Source fingerprint: 596b197d7775d094297d85265323f5ee14b8c8df73d76287843f612fa3c97152 Final acceptance counts: phase2-check: tier=off examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0; tier=default examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0; tier=osr examined=111 rows tag_fail=111 branch_pass=111 vacuous=0 tag_timeout=0 tag_signal=0; tier=trace examined=105 rows tag_fail=105 branch_pass=105 vacuous=0 tag_timeout=0 tag_signal=0; phase2-check: PASS phase2-ci: phase2-check: PASS; phase2-lib-diff: range=[-3, 110] modules=78 importable=66 functions=889 via_reexport=95 no_params=24 calls=281423 examined=281423 unexamined=0 both_ok=124575 both_raise=156668 improved=0; phase2-lib-diff: N4 source_functions=28 exported_functions=19 calls=4631 both_ok=2500 changed_functions=11; phase2-lib-diff: listed_functions=13 undeclared=0 stale=0 PASS; phase2-ci: PASS (through=R1.7) full-release-make-test: RESULTS: 4606/4606 passed, 0 failed, 10 skipped extensions-suite: RESULTS: 4850/4850 passed, 0 failed, 5 skipped lib-diff: phase2-lib-diff: range=[-3, 110] modules=78 importable=66 functions=889 via_reexport=95 no_params=24 calls=281423 examined=281423 unexamined=0 both_ok=124575 both_raise=156668 improved=0; phase2-lib-diff: N4 source_functions=28 exported_functions=19 calls=4631 both_ok=2500 changed_functions=11; phase2-lib-diff: listed_functions=13 undeclared=0 stale=0 PASS corpus-adjudication: Corpus adjudicated: 54 differences traced to R1.7 behavior/registration; sole expected runaway timeout; no other crash/timeout. replay-diff: replay_diff: OK (267 programs record+replay; 27 at the documented boundary; 0 nondeterministic; 1 ledgered) jit-diff: jit_diff: OBS examined=783 denied=13; jit_diff: OK (267 programs x {jit, osr} vs the interpreter; suite-env completed=16; OBS examined=783 denied=13; 32 arms adjudicated; 2 ledgered) cost-measure: phase2-cost: source=codspeed.yml workloads=15 tiers=2 undeclared_max=+0.3% declarations=30 stale_below_max=0.5 logs=/tmp/phase2-cost-rul4mqfr; phase2-cost: output_compare=n6-text (exact values/bits, exact integer digits, Python repr); phase2-cost: n6-text workload=tests/bench_idxset.eigs tier=jit changed_tokens=1; phase2-cost: n6-text workload=tests/bench_idxset.eigs tier=off changed_tokens=1; phase2-cost: workloads=15 rows=30 over_declared_max=0 stale_declarations=0 PASS Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KC99CmwatKssQYggkBCgwF --- docs/design/phase2-numbers.md | 34 +++++++++++++++++- tests/phase2/MAP.md | 2 +- tools/make_lock_check.sh | 6 ++++ tools/phase2_corpus_diff.sh | 67 +++++++++++++++++++++++++++++++++-- 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/docs/design/phase2-numbers.md b/docs/design/phase2-numbers.md index 8ad18bc1a..66651cc51 100644 --- a/docs/design/phase2-numbers.md +++ b/docs/design/phase2-numbers.md @@ -2519,7 +2519,7 @@ failing on zero rows: | R1.6f | 3 | R1.6f-D1 shared store handle refusals; R1.6d-D1 net_send byte refusals; mechanical: per-builtin table and the `gate.N5.net-byte-boundary` actual-client socketpair fixture (R1.6f-D2; compiled and executed here and at every later `--through`) | | R1.6g | 5 | per-builtin table, including the new N9 rows | | R1.6z | 0 | mechanical: bridge-token deletion compile and final full table | -| R1.7 | 12 | `gate.N14.db-param-exact` | +| R1.7 | 13 (11 change rows, 2 invariant controls) | `gate.N14.db-param-exact`, `gate.N6.const-dedup-bits` (R1.7-D3/D4) | | R1.8 | 0 | `gate.N7.embed-int` (the embed smoke test), the executed doc fences (suite [89]/[90]), the LSP and lint suite sections | | R2.1 | 0 | mechanical: the C slot test's NaN-payload rows and plant 2 (no program can make a NaN before R2.2) | | R2.2 | 9 | | @@ -3217,3 +3217,35 @@ source `make_int_defs=0 outside_writers=0`; slot matrix `examined=33 calls=165 matrix_cells=396 arm_rows=32 failures=0`. The changelog fragment check exited 0 after all fourteen malformed fragment bullets were repaired. No push or CI run is claimed by these local results. + +### R1.7 rulings and executable text oracle + +R1.7-D2 permits only the mechanical N6 float-text re-render of seven frozen +probes. `tools/phase2_float_amend.py` checks numeric positions and double bits, +source-bound live kinds, exact integer spellings and every other byte. Six +probes change; json_path already has the N6 spelling. Accepted SHA amendments +and earlier authorities are recorded in `tests/phase2/builtins_changes.md`. + +R1.7-D3 distinguishes CHANGE rows from `[R1.7, invariant]` controls. Actual +b6f9db38 already printed the D1 boundary literal with 15..17 round-trip digits; +printing it directly still passes. D1 and exact int text are invariants. +T1 adds 0.1 as a discriminating shortest-text witness. Every change is base-red +and every invariant base-green. Invariants run all declared branch tiers; +the older v0.46 anchor predates their already-landed contract. + +R1.7-D4 keeps the signed-zero program and adds the actual constant-pool C +probe through `tools/phase2_readers.sh`: distinct indices and memcmp-exact +stored signed-zero doubles. A complete dedup-by-value plant restores both +zero-normalizing hash keys and numeric equality, and must fail that probe. + +The actual shared writer is also checked by `tests/phase2/num_text.c`, Python +repr comparisons over binary64 patterns, and the same production function +linked to mini_fmt/mini_strtod. The runtime retains its inherited default +round-to-nearest floating-point environment assumption. + +Cost comparisons opt in to `tools/phase2_cost.sh --n6-text`: finite value bits +and exact integer digits stay equal, changed float tokens must be Python repr, +and nonnumeric bytes/positions stay exact. The default mode stays byte strict. +This cost-only comparison cannot establish a legacy unadorned token's source +kind; the semantic gates and D2 live kind witnesses do. Corpus diffs remain +exact and are attributed individually from observed evidence. diff --git a/tests/phase2/MAP.md b/tests/phase2/MAP.md index 48a35b578..44395067d 100644 --- a/tests/phase2/MAP.md +++ b/tests/phase2/MAP.md @@ -16,7 +16,7 @@ design doc) runs every row: default JIT). The leaf evaluator is off under trace, so the `trace` tier is the leaf differential: a row must print the same in it as in the others. -Every mapped row must FAIL on the tag and PASS on the branch in every tier, +Every change row must FAIL on the tag and PASS on the branch in every tier, and its witness must hold on the branch (design §9.1), or it is VACUOUS. `phase2_check.sh --through ` checks only the rows whose `[Rn]` has landed by that commit (a row tagged `[Ra/Rb]` lands with the later); R1.1, diff --git a/tools/make_lock_check.sh b/tools/make_lock_check.sh index 91fe08622..c0afa514a 100755 --- a/tools/make_lock_check.sh +++ b/tools/make_lock_check.sh @@ -8,6 +8,12 @@ set -u } ROOT=$(cd "$(dirname "$0")/.." && pwd) +# This test controls the tree lock itself. Run from inside a make recipe (for +# example `make precheck`, whose selftests reach this row), it would inherit +# EIGS_TREE_LOCK_HELD=1, which the Makefile exports so that recursive makes +# skip the lock; every make it starts would then run unlocked and case 1 would +# fail. Case 3 sets the flag explicitly for the one make that needs it. +unset EIGS_TREE_LOCK_HELD if ! command -v flock >/dev/null 2>&1; then echo "make-lock selftest: SKIP: flock is unavailable" exit 0 diff --git a/tools/phase2_corpus_diff.sh b/tools/phase2_corpus_diff.sh index aab1e6eab..73da1121e 100755 --- a/tools/phase2_corpus_diff.sh +++ b/tools/phase2_corpus_diff.sh @@ -96,6 +96,11 @@ # paths, for the calibration (tools/phase2_check.sh --calibrate). A restricted # run prints `corpus-diff: RESTRICTED ...` instead of a verdict and exits 3: # it can never pass for the whole corpus. +# PHASE2_DIFF_EVIDENCE_DIR optionally names an absent or empty task-owned +# directory. Every DIFF keeps all relevant runs' complete comparer files +# (.out/.err/.rc) AND unmodified process bytes (.rawout/.rawerr), plus its +# exact diagnostic. Replay differences also keep the tape. No verdict or +# counter depends on the contents of the evidence; retention errors are loud. set -u [ $# -eq 2 ] || { echo "usage: tools/phase2_corpus_diff.sh "; exit 2; } abspath() { (cd "$(dirname "$1")" && printf '%s/%s\n' "$(pwd -P)" "$(basename "$1")"); } @@ -115,6 +120,58 @@ TMP=$(mktemp -d "${TMPDIR:-/tmp}/eigs-corpus-diff.XXXXXX") || exit 2 DONE=0 trap 'rc=$?; [ "$DONE" = 1 ] || echo "corpus-diff: FAIL: exited ($rc) before a verdict, at: $BASH_COMMAND"; rm -rf "$TMP"' EXIT +# ---- retained DIFF evidence (optional; never normalise these copies) ------ +EVIDENCE_DIR=${PHASE2_DIFF_EVIDENCE_DIR:-} +evidence_fail() { echo "corpus-diff: FAIL: evidence: $*" >&2; return 1; } +evidence_init() { + [ -n "$EVIDENCE_DIR" ] || return 0 + local contents + [ ! -L "$EVIDENCE_DIR" ] || { evidence_fail "directory is a symlink: $EVIDENCE_DIR"; return 1; } + mkdir -p "$EVIDENCE_DIR" || { evidence_fail "cannot create directory: $EVIDENCE_DIR"; return 1; } + contents=$(find "$EVIDENCE_DIR" -mindepth 1 -maxdepth 1 -print -quit) \ + || { evidence_fail "cannot inspect directory: $EVIDENCE_DIR"; return 1; } + [ -z "$contents" ] || { evidence_fail "directory is not empty: $EVIDENCE_DIR"; return 1; } + # Noclobber makes two callers racing to claim the same empty directory fail. + (set -C; : > "$EVIDENCE_DIR/.phase2-corpus-evidence") 2>/dev/null \ + || { evidence_fail "directory claim collision: $EVIDENCE_DIR"; return 1; } + EVIDENCE_DIR=$(cd "$EVIDENCE_DIR" && pwd -P) \ + || { evidence_fail 'cannot resolve directory'; return 1; } + printf 'path\tverdict\tarms\n' > "$EVIDENCE_DIR/index.tsv" \ + || { evidence_fail 'cannot create index'; return 1; } +} +retain_diff() { + [ -n "$EVIDENCE_DIR" ] || return 0 + local rel="$1" verdict="$2" diagnostic="$3" row arm suffix source + shift 3 + case "$rel" in tests/*.eigs) ;; *) evidence_fail "unsafe row path: $rel"; return 1 ;; esac + case "/$rel/" in */../*|*/./*|*//* ) evidence_fail "unsafe row path: $rel"; return 1 ;; esac + [ "$#" -gt 0 ] || { evidence_fail "no run arms: $rel"; return 1; } + row="$EVIDENCE_DIR/$rel" + mkdir -p "$(dirname "$row")" || { evidence_fail "cannot create row parent: $rel"; return 1; } + mkdir "$row" 2>/dev/null || { evidence_fail "row collision: $rel"; return 1; } + printf '%s\n' "$diagnostic" > "$row/verdict.txt" \ + || { evidence_fail "cannot write diagnostic: $rel"; return 1; } + for arm in "$@"; do + case "$arm" in b1|b2|r1|r2|t0|p1|p2|q1) ;; *) evidence_fail "unknown run arm: $arm"; return 1 ;; esac + for suffix in out err rc rawout rawerr; do + source="$TMP/$arm.$suffix" + [ -f "$source" ] || { evidence_fail "missing run file: $rel $arm.$suffix"; return 1; } + # Keep both the already-normalised comparer inputs and raw captures. + cp "$source" "$row/$arm.$suffix" && cmp -s "$source" "$row/$arm.$suffix" \ + || { evidence_fail "copy failed: $rel $arm.$suffix"; return 1; } + done + done + if [ "$verdict" = DIFF-under-replay ]; then + [ -s "$TMP/tape" ] || { evidence_fail "missing replay tape: $rel"; return 1; } + cp "$TMP/tape" "$row/tape" && cmp -s "$TMP/tape" "$row/tape" \ + || { evidence_fail "tape copy failed: $rel"; return 1; } + fi + printf '%s\t%s\t%s\n' "$rel" "$verdict" "$*" >> "$EVIDENCE_DIR/index.tsv" \ + || { evidence_fail "cannot index row: $rel"; return 1; } + echo "corpus-diff: retained $verdict evidence: $row" +} +evidence_init || { DONE=1; exit 2; } + # ---- the seed pin -------------------------------------------------------- cat > "$TMP/seedpin.c" <<'CSRC' #define _GNU_SOURCE @@ -333,6 +390,8 @@ while IFS= read -r rel; do ndiff=$((ndiff + 1)) echo "$rel (changed; the baseline cannot complete it: rc $rb1/$rb2)" >> "$TMP/diffs" echo ".. $examined/$listed $rel DIFF $(took)s" + retain_diff "$rel" DIFF-BEHAVIOUR "DIFF-BEHAVIOUR $rel (changed; the baseline cannot complete it: rc $rb1/$rb2)" b1 b2 r1 r2 \ + || { DONE=1; exit 2; } else [ "$branch_only" = MODIFIED ] && modified_failed=$((modified_failed + 1)) || new_failed=$((new_failed + 1)) echo ".. $examined/$listed $rel $branch_only-FAIL rc=$rr $(took)s" @@ -377,7 +436,9 @@ while IFS= read -r rel; do echo "$rel" >> "$TMP/diffs" echo ".. $examined/$listed $rel DIFF $(took)s" if same "$TMP/b1" "$TMP/r1"; then wrong=r2; else wrong=r1; fi - echo "DIFF $rel: the baseline is deterministic (two runs agree); branch run $wrong differs: rc baseline=$rb1 branch=$(cat "$TMP/$wrong.rc")" + diff_diagnostic="DIFF $rel: the baseline is deterministic (two runs agree); branch run $wrong differs: rc baseline=$rb1 branch=$(cat "$TMP/$wrong.rc")" + echo "$diff_diagnostic" + retain_diff "$rel" DIFF "$diff_diagnostic" b1 b2 r1 r2 || { DONE=1; exit 2; } show_diff "$TMP/b1" "$TMP/$wrong" [ "$urand" = 1 ] && echo "$rel DIFF" >> "$TMP/urandom" continue @@ -390,7 +451,9 @@ while IFS= read -r rel; do ndiff=$((ndiff + 1)); verdict=DIFF-under-replay echo "$rel (under replay)" >> "$TMP/diffs" echo ".. $examined/$listed $rel DIFF-under-replay $(took)s" - echo "DIFF $rel: replaying the baseline's tape, rc baseline=$(cat "$TMP/p1.rc") branch=$(cat "$TMP/q1.rc")" + diff_diagnostic="DIFF $rel: replaying the baseline's tape, rc baseline=$(cat "$TMP/p1.rc") branch=$(cat "$TMP/q1.rc")" + echo "$diff_diagnostic" + retain_diff "$rel" DIFF-under-replay "$diff_diagnostic" b1 b2 r1 r2 t0 p1 p2 q1 || { DONE=1; exit 2; } show_diff "$TMP/p1" "$TMP/q1" else nondet=$((nondet + 1)); echo "$rel" >> "$TMP/nondet"; verdict=nondet From e84be0654e0df5429020cdc5941c51f4722e880a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 26 Oct 2026 00:27:31 -0500 Subject: [PATCH 184/188] test(observer): amend CI corpus goldens for N6 (#1758) N6 float-kind text only: D2/D6 check_pair proved 19 changed lines / 21 float tokens across seven programs; binary64 bits, runtime kinds before/after and every other byte match. Source-bound probes preserve the original program output. Observer corpus red: 7 match, 7 diverge (rc=1); green: 14 match, 0 diverge (rc=0). Evidence: r1-7-ff/corpus-proof.json. --- .../golden/EigenScript__container_observer.out | 4 ++-- .../observer_corpus/golden/EigenScript__idioms.out | 4 ++-- .../golden/EigenScript__numerical.out | 4 ++-- .../golden/EigenScript__structural_observer.out | 4 ++-- tests/observer_corpus/golden/dynamics__physics.out | 6 +++--- tests/observer_corpus/golden/dynamics__solve.out | 2 +- .../golden/iLambdaAi__test_interrogative_spec.out | 14 +++++++------- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/observer_corpus/golden/EigenScript__container_observer.out b/tests/observer_corpus/golden/EigenScript__container_observer.out index c3d3cc9a5..cee618b7c 100644 --- a/tests/observer_corpus/golden/EigenScript__container_observer.out +++ b/tests/observer_corpus/golden/EigenScript__container_observer.out @@ -8,9 +8,9 @@ 2.877443751081734 3.377443751081734 3.584962500721156 -2 2 stable +2.0 2.0 stable 2.584962500721156 0.5849625007211561 stable -3 0.4150374992788439 diverging +3.0 0.4150374992788439 diverging 3.321928094887362 0.3219280948873622 diverging 3.584962500721156 0.2630344058337939 diverging 3.807354922057604 0.2223924213364481 diverging diff --git a/tests/observer_corpus/golden/EigenScript__idioms.out b/tests/observer_corpus/golden/EigenScript__idioms.out index b65985233..177d1b76e 100644 --- a/tests/observer_corpus/golden/EigenScript__idioms.out +++ b/tests/observer_corpus/golden/EigenScript__idioms.out @@ -8,7 +8,7 @@ Sum of positives: 26 (5 values) 10 / 3 = 3.3333333333333335 Warning: division by zero, returning 0 15 / 0 = 0 - 20 / 4 = 5 + 20 / 4 = 5.0 Warning: division by zero, returning 0 0 / 0 = 0 100 / 7 = 14.285714285714286 @@ -34,7 +34,7 @@ GOOD (prefixed 'cs_total' is safe): --- calling conventions --- double of 7: 14 -lerp of [0, 100, 0.75]: 75 +lerp of [0, 100, 0.75]: 75.0 timestamp of null: 1712419200 --- early exit pattern --- diff --git a/tests/observer_corpus/golden/EigenScript__numerical.out b/tests/observer_corpus/golden/EigenScript__numerical.out index 9d46132e0..a7afafcfa 100644 --- a/tests/observer_corpus/golden/EigenScript__numerical.out +++ b/tests/observer_corpus/golden/EigenScript__numerical.out @@ -1,7 +1,7 @@ --- Newton's Method: Square Roots --- sqrt(2) = 1.414213562373095 -sqrt(9) = 3 -sqrt(144) = 12 +sqrt(9) = 3.0 +sqrt(144) = 12.0 sqrt(2.5) = 1.5811388300841895 --- Bisection Method: x^3 - x - 2 = 0 --- diff --git a/tests/observer_corpus/golden/EigenScript__structural_observer.out b/tests/observer_corpus/golden/EigenScript__structural_observer.out index 0abb0d3cd..2e0d0a7b8 100644 --- a/tests/observer_corpus/golden/EigenScript__structural_observer.out +++ b/tests/observer_corpus/golden/EigenScript__structural_observer.out @@ -2,8 +2,8 @@ equilibrium moving ["moving", 0.7219280948873623, -0.19636773916712724, -0.08170416594551044] 3.479597728084419e-06 -4 -1 +4.0 +1.0 1.191829090169325e-06 3.4366397314414046e-06 3.0014538431203897 diff --git a/tests/observer_corpus/golden/dynamics__physics.out b/tests/observer_corpus/golden/dynamics__physics.out index 5521d2dee..c332878fe 100644 --- a/tests/observer_corpus/golden/dynamics__physics.out +++ b/tests/observer_corpus/golden/dynamics__physics.out @@ -3,11 +3,11 @@ observe ENERGY (Lyapunov) vs DISPLACEMENT (oscillation); flags = regime visited zeta | E:osc conv div grew | x:osc conv div | reading -0.05 | E:Y - - Y | x:Y - - | DIVERGES (energy grew) - 0 | E:Y - - - | x:Y - - | x OSCILLATES, energy settles + 0.0 | E:Y - - - | x:Y - - | x OSCILLATES, energy settles 0.1 | E:- - - - | x:Y - - | x OSCILLATES, energy settles 0.4 | E:- Y - - | x:Y Y - | x OSCILLATES, energy settles - 1 | E:- Y - - | x:- Y - | settles - 2 | E:- Y - - | x:- - - | settles + 1.0 | E:- Y - - | x:- Y - | settles + 2.0 | E:- Y - - | x:- - - | settles the gem is the zeta=0 row: energy conserved -> never converges, while x oscillates. Same system, opposite verdict, set by what the observer watches. diff --git a/tests/observer_corpus/golden/dynamics__solve.out b/tests/observer_corpus/golden/dynamics__solve.out index 9a3f2aa3d..0cab89b3a 100644 --- a/tests/observer_corpus/golden/dynamics__solve.out +++ b/tests/observer_corpus/golden/dynamics__solve.out @@ -7,7 +7,7 @@ Jacobi Ax=b -> Gauss-Seidel Ax=b -> 21 iters (fresh values -> fewer than Jacobi) -Power iteration dominant eigenvalue -> 2 (14 iters, expect ~2) +Power iteration dominant eigenvalue -> 2.0 (14 iters, expect ~2) PageRank stationary distribution -> (48 iters) diff --git a/tests/observer_corpus/golden/iLambdaAi__test_interrogative_spec.out b/tests/observer_corpus/golden/iLambdaAi__test_interrogative_spec.out index 0af5af719..3ca5da4e3 100644 --- a/tests/observer_corpus/golden/iLambdaAi__test_interrogative_spec.out +++ b/tests/observer_corpus/golden/iLambdaAi__test_interrogative_spec.out @@ -6,11 +6,11 @@ Verifies each interrogative matches LLVM IR semantics EXPECT: 42 --- WHAT: list length --- -5 +5.0 EXPECT: 5 --- WHAT: string length --- -5 +5.0 EXPECT: 5 --- WHAT: computed value --- @@ -26,11 +26,11 @@ counter EXPECT: counter --- WHEN: temporal step --- -1 +1.0 EXPECT: 1 --- WHEN: after multiple assignments --- -3 +3.0 EXPECT: 3 --- WHERE: entropy (spatial) --- @@ -39,15 +39,15 @@ WHERE returns entropy (number >= 0): --- WHY: gradient (dH/dt) --- WHY returns gradient (number): -0 +0.0 --- HOW: stability (0-1) --- HOW returns stability (0-1 range): -1 +1.0 --- ARITHMETIC COMPOSITION --- Arithmetic on interrogatives works: -102 +102.0 --- ASSIGNMENT THEN INTERROGATIVE --- 256 From 5adf9e56a421898e0a9841be1e5ebc7748c341f6 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 26 Oct 2026 00:33:40 -0500 Subject: [PATCH 185/188] test(tsan): expect N6 float text from replay workers (#1758) N6: both workers sum 3000 taped random=0.5 draws, so their exact 1500 results are floats and print 1500.0. Preserve the exact two-worker byte check and all race/rc checks. Actual local gate red rc=1 at the replay row, green rc=0; built with make tsan and every invocation uses setarch -R. See r1-7-ff/tsan-before-a1.log and tsan-after-a1.log for counts. Actual TSan gate counts: before 61 passed / 1 failed (rc=1); after 62 passed / 0 failed (rc=0). Literal-match correction: use grep -F so the N6 decimal points are literal bytes. The previous regex accepts a=1500x0 b=1500y0 (rc=0); corrected command accepts the exact output and rejects wildcard, wrong-value and old-kind controls (positive=1 / rejected=3). Actual make tsan + full setarch -R gate on final source: 62 passed / 0 failed, rc=0. --- tests/test_tsan.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_tsan.sh b/tests/test_tsan.sh index fbd9409d3..2136aa195 100755 --- a/tests/test_tsan.sh +++ b/tests/test_tsan.sh @@ -312,7 +312,8 @@ if [ -f "$RP_EIGS" ]; then elif [ "$LAST_RC" -eq 124 ]; then echo " FAIL: replay-workers HUNG" FAIL=$((FAIL + 1)) - elif [ "$LAST_RC" -eq 0 ] && grep -qx 'a=1500 b=1500' \ + # N6: random draws and their sums are floats, including integral sums. + elif [ "$LAST_RC" -eq 0 ] && grep -Fxq 'a=1500.0 b=1500.0' \ "$TESTS_DIR/../build/tsan_replay_mt.out"; then echo " PASS: replay-workers causal values, TSan-clean"; PASS=$((PASS + 1)) else From 6bf51c6f75518343114c52c90560b57c579f527a Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 26 Oct 2026 00:46:04 -0500 Subject: [PATCH 186/188] fix(numbers): bound N6 decimal scratch for amalgamation (#1758) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit N6: uint64 significand (20 digits), e, signed int32 exponent (11 bytes), NUL require up to 33 bytes by the format types; use 40. The reported CI warning is at -O1; this machine GCC 13.3 runs the unmodified CI script at rc=0 (7/0), so local baseline warning reproduction is unavailable. cc alone in a fresh directory at -O0, -O1 and -O2 now yields zero warnings, 8 passed / 0 failed (rc=0). The script now checks all three levels with -Wall -Wextra; runtime number text is unchanged. Continuation 1 precheck fix: Prefix this commit's one-line changelog fragment with "- " so the fragment parser recognizes it. Reproduced the original docs-claims and changelog checks at rc=1. On the corrected final source, PRECHECK_BASE=20f9d86c21276ddc8d1a1ebf027f8756360afd68 make precheck: 19 passed / 0 failed / 0 skipped, rc=0; docs-claims: OK — PATHS 285, FLAGS 47, MAKE TARGETS 52, NAMES 527, DOC ENROLMENT 12, rc=0; changelog: examined 24 changed path(s) against 20f9d86c21276ddc8d1a1ebf027f8756360afd68; 2 fragment(s) added; cut=0, rc=0. Actual logs and source-bound receipts: continuation1-precheck, continuation1-docs-after, continuation1-changelog-after in r1-7-ff/. --- changes/fixed/1758-number-text-amalgamation.md | 1 + src/eigenscript.c | 3 ++- tests/test_amalgamation.sh | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 changes/fixed/1758-number-text-amalgamation.md diff --git a/changes/fixed/1758-number-text-amalgamation.md b/changes/fixed/1758-number-text-amalgamation.md new file mode 100644 index 000000000..ce32dd20d --- /dev/null +++ b/changes/fixed/1758-number-text-amalgamation.md @@ -0,0 +1 @@ +- Size N6 float-renderer scratch text for the complete unsigned significand and signed exponent format, keeping the two-file amalgamation warning-free at every tested optimization level. diff --git a/src/eigenscript.c b/src/eigenscript.c index 4fc4ffdba..bc7203827 100644 --- a/src/eigenscript.c +++ b/src/eigenscript.c @@ -3556,7 +3556,8 @@ void eigs_num_text(char *buf, size_t nbuf, double n) { candidate_scale--; } if (candidate == 0) continue; - char decimal[32]; + /* uint64 digits + e + signed int32 exponent + NUL: at most 33. */ + char decimal[40]; snprintf(decimal, sizeof decimal, "%llue%+d", (unsigned long long)candidate, candidate_scale); if (strtod(decimal, NULL) == magnitude) { diff --git a/tests/test_amalgamation.sh b/tests/test_amalgamation.sh index f417ca205..5476b4bd2 100755 --- a/tests/test_amalgamation.sh +++ b/tests/test_amalgamation.sh @@ -45,8 +45,8 @@ else fi # Embedders also use debug and lightly optimized builds (#1775). A successful -# compiler exit alone does not reject warnings at either optimization level. -for opt in 0 1; do +# compiler exit alone does not reject warnings at all three optimization levels. +for opt in 0 1 2; do if ( cd "$WORK" && LC_ALL=C "$CC" -Wall -Wextra $WERROR_FLAGS -O"$opt" \ -c eigenscript_all.c -o "amalgamation-O$opt.o" ) >"$WORK/O$opt.err" 2>&1; then if grep -q 'warning:' "$WORK/O$opt.err"; then From f7191b7e3f9bd00f433ef224f8342f43f01e1fec Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 26 Oct 2026 00:58:09 -0500 Subject: [PATCH 187/188] fix(sort): preserve equal elements on every platform (#1758) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Orchestrator sort ruling / principle Determinism is a guarantee with a stated boundary: sort and sort_by are stable. Replace list_sort libc qsort with a stable bottom-up merge, borrowing scratch slots without reference changes. sort_by already has an original-index tie-break; retain it. Document both contracts in BUILTINS, SPEC, COMPARISON, README and llms. New 257-element tests check mixed boxed-int/float ties, signed zero, strings, sort_by record identities, input mutation and key-call count. Actual regression suite: 10 passed / 0 failed; boxed containers: 10 checks. Forced quicksort without the stable merge fails sort and the original boxed order; removing sort_by tiebreak fails its record-order checks; restoring the real merge and tiebreak passes under that same forced quicksort. Freestanding runtime linked with actual mini-libc qsort passes, with equal qsort/eigs_qsort symbol addresses; mini-libc differential green. Counts and rc in r1-7-ff receipts. Refresh the generated LSP builtin description from the stable-sort comment (bash tools/gen_lsp_builtin_index.sh rc=0, regeneration is idempotent). This is the only generated-header delta; inventory counts remain unchanged. Continuation 1 precheck fix: Begin the SPEC sort sentence with "`sort` sorts" so the preceding output ending in 15 is not parsed as a builtin count; preserve both stable-order guarantees. The suggested "The builtin" still fails because the detector permits two intervening words after the number. Prefix this commit's one-line changelog fragment with "- ". Reproduced the original docs-claims and changelog checks at rc=1. On the corrected final source, PRECHECK_BASE=20f9d86c21276ddc8d1a1ebf027f8756360afd68 make precheck: 19 passed / 0 failed / 0 skipped, rc=0; docs-claims: OK — PATHS 285, FLAGS 47, MAKE TARGETS 52, NAMES 527, DOC ENROLMENT 12, rc=0; changelog: examined 24 changed path(s) against 20f9d86c21276ddc8d1a1ebf027f8756360afd68; 2 fragment(s) added; cut=0, rc=0. Actual logs and source-bound receipts: continuation1-precheck, continuation1-docs-after, continuation1-changelog-after in r1-7-ff/. --- README.md | 3 ++ changes/fixed/1758-stable-sort.md | 1 + docs/BUILTINS.md | 4 +-- docs/COMPARISON.md | 3 ++ docs/SPEC.md | 3 ++ docs/design/phase2-inventory.txt | 16 ++++----- docs/llms.txt | 3 ++ src/builtins.c | 2 +- src/container.h | 27 +++++++++++++-- src/lsp_builtin_index.h | 2 +- tests/sections/0ft-stable-sort-1758.sh | 3 ++ tests/test_sort_stable.eigs | 46 ++++++++++++++++++++++++++ 12 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 changes/fixed/1758-stable-sort.md create mode 100644 tests/sections/0ft-stable-sort-1758.sh create mode 100644 tests/test_sort_stable.eigs diff --git a/README.md b/README.md index c48fbd163..f4442d4d9 100644 --- a/README.md +++ b/README.md @@ -569,6 +569,9 @@ next operation after a raise. int64 before sending them as text (N14, B6). The executed loopback example is `tests/phase2/builtins/builtins/http_post.eigs`. +Builtin `sort` sorts a list in place; `sort_by` returns a new list using numeric keys. +Both are stable on every platform: equal elements or keys keep their input order. + ## Standard Library Pure EigenScript libraries under `lib/`: diff --git a/changes/fixed/1758-stable-sort.md b/changes/fixed/1758-stable-sort.md new file mode 100644 index 000000000..c04ba30db --- /dev/null +++ b/changes/fixed/1758-stable-sort.md @@ -0,0 +1 @@ +- `sort` now preserves the input order of equal elements on every platform, including mixed int/float ties. Both `sort` and `sort_by` guarantee stable ordering (the #1758 R1.7 fix-forward sort ruling). diff --git a/docs/BUILTINS.md b/docs/BUILTINS.md index 663b8f700..521d37a69 100644 --- a/docs/BUILTINS.md +++ b/docs/BUILTINS.md @@ -107,13 +107,13 @@ tokens, and raises `value` naming any integer token outside int64. | `list_slice` | `list_slice of [list, start, end]` | New list with the elements of [start, end) — dual of `copy_into`. Negative indices count from the end, like `[]`; bounds then clamp to [0, len]. `start >= end` gives `[]`. Clamped integer bounds remain valid. Integer positions, lengths and counts accept integral floats; fractions or values outside the C int range raise `value` (N5). | | `num_copy` | `num_copy of value` | Create an independent numeric copy, preserving int/float kind and every int64 bit | | `hex` | `hex of n` or `hex of [n, nibbles]` | Exact uppercase hex digits for any non-negative int64. Value and optional nibble count follow N5; fractions raise, integral floats convert. Width clamps to 0..16, never truncating digits. | -| `sort` | `sort of list` | Sort an all-number or all-string list in-place (numeric / lexicographic). Mixed or non-scalar elements raise — use `sort_by` for records. Returns the list. A non-list argument raises by default; under `EIGS_STRICT=0` it is handed back unchanged (#971). | +| `sort` | `sort of list` | Stably sort an all-number or all-string list in-place (numeric / lexicographic); equal elements keep their input order on every platform. Mixed or non-scalar elements raise — use `sort_by` for records. Returns the list. A non-list argument raises by default; under `EIGS_STRICT=0` it is handed back unchanged (#971). | | `list_truncate` | `list_truncate of [list, new_len]` | Shrink list in-place to new_len items. No-op if new_len >= length. Returns the list. Integer positions, lengths and counts accept integral floats; fractions or values outside the C int range raise `value` (N5). | | `list_remove_at` | `list_remove_at of [list, index]` | Remove element at index, shift tail down (mutates). No-op if out of bounds. Returns the list. Integer positions, lengths and counts accept integral floats; fractions or values outside the C int range raise `value` (N5). | | `list_insert_at` | `list_insert_at of [list, index, value]` | Insert value at index, shift tail up (mutates) — dual of `list_remove_at`. `index == len` appends; any other out-of-bounds index is a no-op. Returns the list. Integer positions, lengths and counts accept integral floats; fractions or values outside the C int range raise `value` (N5). | | `list_index_of` | `list_index_of of [list, value]` | First structural match index as an int, or int -1 when absent; exact numeric equality (N2). | | `list_contains` | `list_contains of [list, value]` | `true` if any element structurally equals `value`, else `false` — the list counterpart of the string-only `contains` | -| `sort_by` | `sort_by of [list, key_fn]` | Sort list by numeric keys from key_fn (qsort, O(n log n), stable). Returns a new sorted list | +| `sort_by` | `sort_by of [list, key_fn]` | Stably sort list by numeric keys from key_fn, evaluated once per element; equal keys keep their input order on every platform. Returns a new sorted list | | `dispatch` | `dispatch of [table, key, arg]` | Index list `table` by numeric `key` and call the resulting function with `arg` — a jump table (mirrors the `OP_DISPATCH` fast path). `key` must be a number. An ordinary builtin, not a special form: a user binding of the name wins (#459 — the fast path steps aside for any unit that rebinds `dispatch`, references `eval`, or compiles against an env where it is already rebound), and the parenthesized `dispatch of ([t, k, a])` form is one argument per #355/#405 | | `fill` | `fill of [count, value]` | Construct a list of repeated values. Integer positions, lengths and counts accept integral floats; fractions or values outside the C int range raise `value` (N5). | diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index e1fb7c47d..9120e85f5 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -365,6 +365,9 @@ print of (c of null) 2 ``` +Builtin `sort` sorts a list in place; `sort_by` returns a new list using numeric keys. +Both are stable on every platform: equal elements or keys keep their input order. + ## Lists: map / filter / comprehension Python: diff --git a/docs/SPEC.md b/docs/SPEC.md index 5ce98b553..c5a3b7f66 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -1283,6 +1283,9 @@ print of (apply of [add5, 10]) 15 ``` +`sort` sorts a list in place; `sort_by` returns a new list using numeric keys. +Both are stable on every platform: equal elements or keys keep their input order. + `sort_by` is a builtin; `map` and `filter` come from the standard library (`lib/list.eigs`): diff --git a/docs/design/phase2-inventory.txt b/docs/design/phase2-inventory.txt index d5748e868..d6659bf11 100644 --- a/docs/design/phase2-inventory.txt +++ b/docs/design/phase2-inventory.txt @@ -1756,14 +1756,14 @@ eigenscript.c:3431 values_equal_impl VAL_I64_RAW RAW f eigenscript.c:3431 values_equal_impl VAL_I64_RAW RAW f eigenscript.c:3431 values_equal_impl VAL_INT CASE f eigenscript.c:3501 eigs_num_text eigs_num_text FORMAT e -eigenscript.c:3562 eigs_num_text strtod PARSE e -eigenscript.c:3617 value_to_string VAL_FLOAT CASE e -eigenscript.c:3618 value_to_string VAL_F64_RAW RAW e -eigenscript.c:3618 value_to_string eigs_num_text FORMAT e -eigenscript.c:3621 value_to_string VAL_INT CASE e -eigenscript.c:3622 value_to_string VAL_I64_RAW RAW e -eigenscript.c:4923 gc_value_is_node VAL_FLOAT CASE a -eigenscript.c:4924 gc_value_is_node VAL_INT CASE a +eigenscript.c:3563 eigs_num_text strtod PARSE e +eigenscript.c:3618 value_to_string VAL_FLOAT CASE e +eigenscript.c:3619 value_to_string VAL_F64_RAW RAW e +eigenscript.c:3619 value_to_string eigs_num_text FORMAT e +eigenscript.c:3622 value_to_string VAL_INT CASE e +eigenscript.c:3623 value_to_string VAL_I64_RAW RAW e +eigenscript.c:4924 gc_value_is_node VAL_FLOAT CASE a +eigenscript.c:4925 gc_value_is_node VAL_INT CASE a eigenscript.h:196 number RAW b eigenscript.h:214 AST_NUM DATA a eigenscript.h:240 number RAW b diff --git a/docs/llms.txt b/docs/llms.txt index 900374e0f..191f20f8c 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -24,6 +24,9 @@ print of (fround of 0.1) > are where that fails. When unsure, generate, then run the validation ladder at > the end. +Builtin `sort` sorts a list in place; `sort_by` returns a new list using numeric keys. +Both are stable on every platform: equal elements or keys keep their input order. + ## Calls use `of`, never `f(x)` Hosted release includes lazy graphics. The server profile adds HTTP, raw TCP, diff --git a/src/builtins.c b/src/builtins.c index 02315d21e..e74b10cec 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -6091,7 +6091,7 @@ Value* builtin_sort_by(Value *arg) { return result; } -/* sort of list — in-place qsort of an all-number or all-string list. +/* sort of list — stable in-place sort of an all-number or all-string list. * Anything else raises (#368): the old comparator returned 0 for any * non-numeric pair, so sorting a list of records silently no-oped — * with libc-dependent element order on top (qsort gives no stability diff --git a/src/container.h b/src/container.h index 5cf46b184..9dbac8b42 100644 --- a/src/container.h +++ b/src/container.h @@ -419,9 +419,32 @@ static inline void list_move(Value *list, int dst, int src, int n) { static inline void dict_value_move(Value *dict, int dst, int src, int n) { memmove(&dict->data.dict.vals[dst], &dict->data.dict.vals[src], (size_t)n * sizeof(EigsSlot)); } -/* The comparator receives `const EigsSlot *` element pointers. */ +/* Stable bottom-up mergesort: libc qsort has no tie-order guarantee. + * The comparator receives `const EigsSlot *` element pointers. Scratch + * slots borrow the list's references; only their order changes. #1758. */ static inline void list_sort(Value *list, int (*cmp)(const void *, const void *)) { - qsort(list->data.list.items, (size_t)list->data.list.count, sizeof(EigsSlot), cmp); + size_t n = (size_t)list->data.list.count; + if (n < 2) return; + EigsSlot *scratch = xmalloc(n * sizeof(EigsSlot)); + EigsSlot *src = list->data.list.items, *dst = scratch; + for (size_t width = 1; width < n; width *= 2) { + for (size_t lo = 0; lo < n; lo += 2 * width) { + size_t mid = lo + width < n ? lo + width : n; + size_t hi = lo + 2 * width < n ? lo + 2 * width : n; + size_t i = lo, j = mid, k = lo; + while (i < mid && j < hi) { + /* Left wins equality, preserving the original tie order. */ + if (cmp(&src[j], &src[i]) < 0) dst[k++] = src[j++]; + else dst[k++] = src[i++]; + } + while (i < mid) dst[k++] = src[i++]; + while (j < hi) dst[k++] = src[j++]; + } + EigsSlot *tmp = src; src = dst; dst = tmp; + } + if (src != list->data.list.items) + memcpy(list->data.list.items, src, n * sizeof(EigsSlot)); + free(scratch); } /* Raw storage is confined to bulk allocation/movement/destruction code. */ diff --git a/src/lsp_builtin_index.h b/src/lsp_builtin_index.h index 1cf5d14e4..a3b63b5bb 100644 --- a/src/lsp_builtin_index.h +++ b/src/lsp_builtin_index.h @@ -291,7 +291,7 @@ static const char *builtin_docs[][2] = { {"sign_extend", "sign_extend of [val, bits] — sign-extend val from given bit width."}, {"sin", "sin — builtin; see docs/BUILTINS.md"}, {"softmax", "softmax — builtin; see docs/BUILTINS.md"}, - {"sort", "sort of list — in-place qsort of an all-number or all-string list."}, + {"sort", "sort of list — stable in-place sort of an all-number or all-string list."}, {"sort_by", "sort_by of [list, key_fn] — sort list by numeric keys from key_fn."}, {"spawn", "spawn — builtin; see docs/BUILTINS.md"}, {"split", "split — builtin; see docs/BUILTINS.md"}, diff --git a/tests/sections/0ft-stable-sort-1758.sh b/tests/sections/0ft-stable-sort-1758.sh new file mode 100644 index 000000000..c2a295727 --- /dev/null +++ b/tests/sections/0ft-stable-sort-1758.sh @@ -0,0 +1,3 @@ +echo "[0ft] Stable sort across platforms (#1758)" +check_eigs_suite "stable sort and sort_by ties" test_sort_stable.eigs "All tests passed." +echo "" diff --git a/tests/test_sort_stable.eigs b/tests/test_sort_stable.eigs new file mode 100644 index 000000000..72b35648e --- /dev/null +++ b/tests/test_sort_stable.eigs @@ -0,0 +1,46 @@ +# #1758 sort ruling: tie order is observable in numeric kinds and signed zero. +load_file of "lib/test.eigs" +xs is [] +want is [] +for i in range of 257: + local group is (i * 7) % 5 + local value is 140737488355328 + group + if i % 3 == 0: + value is value + 0.0 + append of [xs, value] +for group in range of 5: + for value in xs: + if value == 140737488355328 + group: + append of [want, value] +result is sort of xs +assert_eq of [str of result, str of want, "sort keeps mixed int/float ties in input order"] +assert_eq of [str of xs, str of want, "sort mutates its input"] + +zs is [0.0, -0.0, 0, -0.0, 0.0, 0] +assert_eq of [str of (sort of zs), "[0.0, -0.0, 0, -0.0, 0.0, 0]", "sort preserves signed-zero ties"] +assert_eq of [str of (sort of ["b", "a", "a", "b"]), "[\"a\", \"a\", \"b\", \"b\"]", "sort strings"] +assert_eq of [str of (sort of ([])), "[]", "sort empty"] +assert_eq of [str of (sort of ([3])), "[3]", "sort singleton"] + +records is [] +expected is [] +for i in range of 257: + local key is (i * 7) % 5 + if i % 3 == 0: + key is key + 0.0 + append of [records, [key, i]] +for key in range of 5: + for record in records: + if record[0] == key: + append of [expected, record] +calls is 0 +define key_of(record) as: + calls is calls + 1 + return record[0] +unchanged is str of records +sorted is sort_by of [records, key_of] +assert_eq of [str of sorted, str of expected, "sort_by keeps many mixed-key ties in input order"] +assert_eq of [str of records, unchanged, "sort_by leaves its input intact"] +assert_eq of [calls, 257, "sort_by evaluates each key exactly once"] +assert_eq of [str of (sort_by of [records, (v) => 1]), unchanged, "sort_by all equal keys"] +test_summary of null From f406359cb4d141c5a8a85dba1a5302f670791561 Mon Sep 17 00:00:00 2001 From: InauguralPhysicist Date: Mon, 26 Oct 2026 01:03:08 -0500 Subject: [PATCH 188/188] fix(observer-oracle): compare N6 printed counts by exact value (#1758) N6: when returns an integral float and prints 11.0. Parse printed indices/counts using exact Decimal value, requiring finite integral values; no float rounding, truncation or tolerance. All runtime values retain check_value binary64/NaN/signed-zero checks; labels, tier witnesses and floor are unchanged. Actual parser calibration: complete positive transcript accepted; 6 wrong/fractional/nonfinite/malformed count plants rejected; exact int64 and value/sign controls green. Actual CI lane before rc=1 (issue1891_row63), after rc=0 (all floor verdicts checked, 0 lost). Actual oracle lane: floor 1872 verdicts checked / 0 lost, rc=0. Count calibration: 1 complete positive transcript, 6 rejected counter plants, 5 exact representation controls and 3 value/sign controls, rc=0. --- tools/observer_oracle/score.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tools/observer_oracle/score.py b/tools/observer_oracle/score.py index 9cdae5db7..59a04c000 100644 --- a/tools/observer_oracle/score.py +++ b/tools/observer_oracle/score.py @@ -72,6 +72,7 @@ refused floor, an internal exception). """ import contextlib +from decimal import Decimal, InvalidOperation import fcntl import hashlib import json @@ -297,6 +298,21 @@ def run(binary, prog, env): return p.returncode, p.stdout.splitlines(), errors, p.stderr, hot.group(0) if hot else "" +def printed_count(token): + """Parse a printed count by exact value, including N6's integral floats. + + Decimal avoids both truncating a fractional count and rounding large ints + through binary64. Runtime values still use check_value's bitwise oracle. + """ + try: + value = Decimal(token) + if value.is_finite() and value == value.to_integral_value(): + return int(value) + except (InvalidOperation, ValueError, OverflowError): + pass + raise HarnessError(f"non-integral printed count {token!r}") + + def parse_run(row, cks, form, rc, lines, errors, xs, ys): rid = row["id"] if rc != 0 or errors or not lines or lines[-1] != f"ROW_DONE {rid}": @@ -306,23 +322,23 @@ def parse_run(row, cks, form, rc, lines, errors, xs, ys): for ln in lines[:-1]: f = ln.split() if len(f) == 3 and f[0] in vals: - i = int(f[1]) + i = printed_count(f[1]) if i != last[f[0]] + 1: raise HarnessError(f"{rid}: {f[0]} line {i} out of order after {last[f[0]]}") last[f[0]], vals[f[0]][i] = i, f[2] continue if len(f) == 4 and f[0] == "S" and f[1] in vals and f[3] in ("true", "false"): - signs[(f[1], int(f[2]))] = f[3] == "true" + signs[(f[1], printed_count(f[2]))] = f[3] == "true" continue if len(f) != 9 + (ys is not None) or f[0] != "CK": raise HarnessError(f"{rid}: unexpected output line {ln!r}") - at = int(f[1]) + at = printed_count(f[1]) if at in got: raise HarnessError(f"{rid}: duplicate checkpoint {at}") if form == "straight" and (last["V"] != at or (ys is not None and last["Y"] != at)): raise HarnessError(f"{rid}: checkpoint {at} read after value {last['V']}:" " a read must follow the assignment of x_at") - if any(w != str(at + 1) for w in f[8:]): + if any(printed_count(w) != at + 1 for w in f[8:]): raise HarnessError(f"{rid}: checkpoint {at} read after {f[8:]} assignments," f" not {at + 1}: a read must fall between x_at and x_{at + 1}") if any(b not in ("true", "false") for b in f[2:8]):