Skip to content

Commit 1339a7c

Browse files
olwangclaude
andcommitted
feat(native-jit): collection Float value helpers (MapInsertFloat, DequePush*Float)
Item #2 of the remaining-issues list: collection element-type breadth for Float VALUES, riding the float-arg helper ABI. Three clean HostCall mirrors of ListPushFloat: - MapInsertFloat: insert a Float value into an Int-keyed Map<Int, Float>. - DequePushBackFloat / DequePushFrontFloat: push a Float onto a Deque<Float>. Each: vm-jit macro row + Fn type + struct field + heap_effect(MutatesInput) set + test noop; reg_vm host impl (journaled write of VmValue::Float, bails on a wrong- value-type collection) + wiring; translate value-type-flows-in-inference + helper selection by float(value) across both whole-function and OSR lowering arms (int_or_free keeps the Int/unconstrained path). Deliberately deferred (documented as the demand tail): float-KEYED collections (Set<Float>, SortedSet/SortedMap with Float keys) need float-key hashing/ordering with NaN semantics; the Map/Deque READS (MatchMapGetFloat, Deque pop) need a new value-typed JitInstr / Option result. The mechanical write pattern here applies directly when those are added. Verify (Docker dev): differential 33/0, runtime 397/0 (new jit_acceptance_runs_float_map_and_deque_helpers runs natively), vm-jit 83/0, reg_vm lib 31/0 default, default+native builds and clippy clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6fdcfd8 commit 1339a7c

4 files changed

Lines changed: 231 additions & 22 deletions

File tree

crates/rsscript/src/reg_vm/mod.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3585,6 +3585,7 @@ fn jit_host_helpers() -> vm_jit::HostHelpers {
35853585
bytes_len: rss_jit_bytes_len,
35863586
bytes_slice: rss_jit_bytes_slice,
35873587
map_insert_int: rss_jit_map_insert_int,
3588+
map_insert_float: rss_jit_map_insert_float,
35883589
map_get_int: rss_jit_map_get_int,
35893590
map_get_match_int: rss_jit_map_get_match_int,
35903591
map_get_match_found: rss_jit_map_get_match_found,
@@ -3606,7 +3607,9 @@ fn jit_host_helpers() -> vm_jit::HostHelpers {
36063607
deque_len: rss_jit_deque_len,
36073608
deque_is_empty: rss_jit_deque_is_empty,
36083609
deque_push_back_int: rss_jit_deque_push_back_int,
3610+
deque_push_back_float: rss_jit_deque_push_back_float,
36093611
deque_push_front_int: rss_jit_deque_push_front_int,
3612+
deque_push_front_float: rss_jit_deque_push_front_float,
36103613
deque_pop_front_int: rss_jit_deque_pop_front_int,
36113614
deque_pop_back_int: rss_jit_deque_pop_back_int,
36123615
}
@@ -4621,6 +4624,36 @@ fn rss_jit_map_insert_int_with_ctx(ctx: JitHostCallCtx, handle: i64, key: i64, v
46214624
}
46224625
}
46234626

4627+
#[cfg(feature = "native-jit")]
4628+
extern "C" fn rss_jit_map_insert_float(
4629+
_ctx: vm_jit::HostCtx,
4630+
handle: i64,
4631+
key: i64,
4632+
value: f64,
4633+
) -> i64 {
4634+
let Some(_ctx) = JitHostCallCtx::from_token(_ctx) else {
4635+
vm_jit::signal_bail();
4636+
return 0;
4637+
};
4638+
rss_jit_map_insert_float_with_ctx(_ctx, handle, key, value)
4639+
}
4640+
4641+
/// Insert a `Float` value into an Int-keyed map — the value-side mirror of
4642+
/// `rss_jit_map_insert_int`. A bad handle bails out-of-band.
4643+
#[cfg(feature = "native-jit")]
4644+
fn rss_jit_map_insert_float_with_ctx(ctx: JitHostCallCtx, handle: i64, key: i64, value: f64) -> i64 {
4645+
match ctx.with_journaled_map_write(handle, |map| {
4646+
map.insert(jit_int_key(key), VmValue::Float(value));
4647+
Some(0)
4648+
}) {
4649+
Some(value) => value,
4650+
None => {
4651+
vm_jit::signal_bail();
4652+
0
4653+
}
4654+
}
4655+
}
4656+
46244657
#[cfg(feature = "native-jit")]
46254658
extern "C" fn rss_jit_map_get_int(_ctx: vm_jit::HostCtx, handle: i64, key: i64) -> i64 {
46264659
let Some(_ctx) = JitHostCallCtx::from_token(_ctx) else {
@@ -5111,6 +5144,29 @@ fn rss_jit_deque_push_back_int_with_ctx(ctx: JitHostCallCtx, handle: i64, value:
51115144
}
51125145
}
51135146

5147+
#[cfg(feature = "native-jit")]
5148+
extern "C" fn rss_jit_deque_push_back_float(_ctx: vm_jit::HostCtx, handle: i64, value: f64) -> i64 {
5149+
let Some(_ctx) = JitHostCallCtx::from_token(_ctx) else {
5150+
vm_jit::signal_bail();
5151+
return 0;
5152+
};
5153+
rss_jit_deque_push_back_float_with_ctx(_ctx, handle, value)
5154+
}
5155+
5156+
#[cfg(feature = "native-jit")]
5157+
fn rss_jit_deque_push_back_float_with_ctx(ctx: JitHostCallCtx, handle: i64, value: f64) -> i64 {
5158+
match ctx.with_journaled_deque_write(handle, |deque| {
5159+
deque.push_back(VmValue::Float(value));
5160+
Some(0)
5161+
}) {
5162+
Some(value) => value,
5163+
None => {
5164+
vm_jit::signal_bail();
5165+
0
5166+
}
5167+
}
5168+
}
5169+
51145170
#[cfg(feature = "native-jit")]
51155171
extern "C" fn rss_jit_deque_push_front_int(_ctx: vm_jit::HostCtx, handle: i64, value: i64) -> i64 {
51165172
let Some(_ctx) = JitHostCallCtx::from_token(_ctx) else {
@@ -5134,6 +5190,29 @@ fn rss_jit_deque_push_front_int_with_ctx(ctx: JitHostCallCtx, handle: i64, value
51345190
}
51355191
}
51365192

5193+
#[cfg(feature = "native-jit")]
5194+
extern "C" fn rss_jit_deque_push_front_float(_ctx: vm_jit::HostCtx, handle: i64, value: f64) -> i64 {
5195+
let Some(_ctx) = JitHostCallCtx::from_token(_ctx) else {
5196+
vm_jit::signal_bail();
5197+
return 0;
5198+
};
5199+
rss_jit_deque_push_front_float_with_ctx(_ctx, handle, value)
5200+
}
5201+
5202+
#[cfg(feature = "native-jit")]
5203+
fn rss_jit_deque_push_front_float_with_ctx(ctx: JitHostCallCtx, handle: i64, value: f64) -> i64 {
5204+
match ctx.with_journaled_deque_write(handle, |deque| {
5205+
deque.push_front(VmValue::Float(value));
5206+
Some(0)
5207+
}) {
5208+
Some(value) => value,
5209+
None => {
5210+
vm_jit::signal_bail();
5211+
0
5212+
}
5213+
}
5214+
}
5215+
51375216
#[cfg(feature = "native-jit")]
51385217
fn jit_deque_pop_int(
51395218
ctx: JitHostCallCtx,

crates/rsscript/src/reg_vm/native/translate.rs

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -469,11 +469,13 @@ pub(in crate::reg_vm) fn translate_to_native_jit_with_calls(
469469
dst,
470470
map,
471471
key,
472-
value,
472+
value: _,
473473
} => {
474+
// The value type flows from its definition (Int or Float);
475+
// lowering picks MapInsertInt/MapInsertFloat, and a wrong-value-type
476+
// map bails at the helper.
474477
native_set_ty(ty, *map, NativeTy::Handle, c)
475478
&& native_set_ty(ty, *key, NativeTy::Int, c)
476-
&& native_set_ty(ty, *value, NativeTy::Int, c)
477479
&& native_set_ty(ty, *dst, NativeTy::Int, c)
478480
}
479481
RegInstr::SetInsert { dst, set, value } => {
@@ -497,10 +499,10 @@ pub(in crate::reg_vm) fn translate_to_native_jit_with_calls(
497499
&& native_set_ty(ty, *value, NativeTy::Int, c)
498500
&& native_set_ty(ty, *dst, NativeTy::Int, c)
499501
}
500-
RegInstr::DequePushBack { dst, deque, value }
501-
| RegInstr::DequePushFront { dst, deque, value } => {
502+
RegInstr::DequePushBack { dst, deque, value: _ }
503+
| RegInstr::DequePushFront { dst, deque, value: _ } => {
504+
// The value type flows (Int or Float); lowering picks the helper.
502505
native_set_ty(ty, *deque, NativeTy::Handle, c)
503-
&& native_set_ty(ty, *value, NativeTy::Int, c)
504506
&& native_set_ty(ty, *dst, NativeTy::Int, c)
505507
}
506508
RegInstr::DequePopFront { dst, deque } | RegInstr::DequePopBack { dst, deque } => {
@@ -1431,9 +1433,14 @@ pub(in crate::reg_vm) fn translate_to_native_jit_with_calls(
14311433
key,
14321434
value,
14331435
} => {
1434-
require(handle_reg(*map) && int(*key) && int(*value) && int(*dst))?;
1436+
require(handle_reg(*map) && int(*key) && int(*dst) && (int_or_free(*value) || float(*value)))?;
1437+
let helper = if float(*value) {
1438+
vm_jit::HostHelper::MapInsertFloat
1439+
} else {
1440+
vm_jit::HostHelper::MapInsertInt
1441+
};
14351442
JitInstr::HostCall {
1436-
helper: vm_jit::HostHelper::MapInsertInt,
1443+
helper,
14371444
dst: r(*dst),
14381445
args: vec![
14391446
vm_jit::HostArg::Reg(r(*map)),
@@ -1482,9 +1489,14 @@ pub(in crate::reg_vm) fn translate_to_native_jit_with_calls(
14821489
}
14831490
}
14841491
RegInstr::DequePushBack { dst, deque, value } => {
1485-
require(handle_reg(*deque) && int(*value) && int(*dst))?;
1492+
require(handle_reg(*deque) && int(*dst) && (int_or_free(*value) || float(*value)))?;
1493+
let helper = if float(*value) {
1494+
vm_jit::HostHelper::DequePushBackFloat
1495+
} else {
1496+
vm_jit::HostHelper::DequePushBackInt
1497+
};
14861498
JitInstr::HostCall {
1487-
helper: vm_jit::HostHelper::DequePushBackInt,
1499+
helper,
14881500
dst: r(*dst),
14891501
args: vec![
14901502
vm_jit::HostArg::Reg(r(*deque)),
@@ -1493,9 +1505,14 @@ pub(in crate::reg_vm) fn translate_to_native_jit_with_calls(
14931505
}
14941506
}
14951507
RegInstr::DequePushFront { dst, deque, value } => {
1496-
require(handle_reg(*deque) && int(*value) && int(*dst))?;
1508+
require(handle_reg(*deque) && int(*dst) && (int_or_free(*value) || float(*value)))?;
1509+
let helper = if float(*value) {
1510+
vm_jit::HostHelper::DequePushFrontFloat
1511+
} else {
1512+
vm_jit::HostHelper::DequePushFrontInt
1513+
};
14971514
JitInstr::HostCall {
1498-
helper: vm_jit::HostHelper::DequePushFrontInt,
1515+
helper,
14991516
dst: r(*dst),
15001517
args: vec![
15011518
vm_jit::HostArg::Reg(r(*deque)),
@@ -3184,11 +3201,13 @@ fn translate_osr_loop_inner(
31843201
dst,
31853202
map,
31863203
key,
3187-
value,
3204+
value: _,
31883205
} => {
3206+
// The value type flows from its definition (Int or Float);
3207+
// lowering picks MapInsertInt/MapInsertFloat, and a wrong-value-type
3208+
// map bails at the helper.
31893209
native_set_ty(ty, *map, NativeTy::Handle, c)
31903210
&& native_set_ty(ty, *key, NativeTy::Int, c)
3191-
&& native_set_ty(ty, *value, NativeTy::Int, c)
31923211
&& native_set_ty(ty, *dst, NativeTy::Int, c)
31933212
}
31943213
RegInstr::SetInsert { dst, set, value } => {
@@ -3212,10 +3231,10 @@ fn translate_osr_loop_inner(
32123231
&& native_set_ty(ty, *value, NativeTy::Int, c)
32133232
&& native_set_ty(ty, *dst, NativeTy::Int, c)
32143233
}
3215-
RegInstr::DequePushBack { dst, deque, value }
3216-
| RegInstr::DequePushFront { dst, deque, value } => {
3234+
RegInstr::DequePushBack { dst, deque, value: _ }
3235+
| RegInstr::DequePushFront { dst, deque, value: _ } => {
3236+
// The value type flows (Int or Float); lowering picks the helper.
32173237
native_set_ty(ty, *deque, NativeTy::Handle, c)
3218-
&& native_set_ty(ty, *value, NativeTy::Int, c)
32193238
&& native_set_ty(ty, *dst, NativeTy::Int, c)
32203239
}
32213240
RegInstr::DequePopFront { dst, deque } | RegInstr::DequePopBack { dst, deque } => {
@@ -4121,9 +4140,14 @@ fn translate_osr_loop_inner(
41214140
key,
41224141
value,
41234142
} => {
4124-
require(handle_reg(*map) && int(*key) && int(*value) && int(*dst))?;
4143+
require(handle_reg(*map) && int(*key) && int(*dst) && (int_or_free(*value) || float(*value)))?;
4144+
let helper = if float(*value) {
4145+
vm_jit::HostHelper::MapInsertFloat
4146+
} else {
4147+
vm_jit::HostHelper::MapInsertInt
4148+
};
41254149
JitInstr::HostCall {
4126-
helper: vm_jit::HostHelper::MapInsertInt,
4150+
helper,
41274151
dst: r(*dst),
41284152
args: vec![
41294153
vm_jit::HostArg::Reg(r(*map)),
@@ -4172,9 +4196,14 @@ fn translate_osr_loop_inner(
41724196
}
41734197
}
41744198
RegInstr::DequePushBack { dst, deque, value } => {
4175-
require(handle_reg(*deque) && int(*value) && int(*dst))?;
4199+
require(handle_reg(*deque) && int(*dst) && (int_or_free(*value) || float(*value)))?;
4200+
let helper = if float(*value) {
4201+
vm_jit::HostHelper::DequePushBackFloat
4202+
} else {
4203+
vm_jit::HostHelper::DequePushBackInt
4204+
};
41764205
JitInstr::HostCall {
4177-
helper: vm_jit::HostHelper::DequePushBackInt,
4206+
helper,
41784207
dst: r(*dst),
41794208
args: vec![
41804209
vm_jit::HostArg::Reg(r(*deque)),
@@ -4183,9 +4212,14 @@ fn translate_osr_loop_inner(
41834212
}
41844213
}
41854214
RegInstr::DequePushFront { dst, deque, value } => {
4186-
require(handle_reg(*deque) && int(*value) && int(*dst))?;
4215+
require(handle_reg(*deque) && int(*dst) && (int_or_free(*value) || float(*value)))?;
4216+
let helper = if float(*value) {
4217+
vm_jit::HostHelper::DequePushFrontFloat
4218+
} else {
4219+
vm_jit::HostHelper::DequePushFrontInt
4220+
};
41874221
JitInstr::HostCall {
4188-
helper: vm_jit::HostHelper::DequePushFrontInt,
4222+
helper,
41894223
dst: r(*dst),
41904224
args: vec![
41914225
vm_jit::HostArg::Reg(r(*deque)),

crates/rsscript/tests/jit_acceptance.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,54 @@ fn main() -> Unit {
415415
);
416416
}
417417

418+
/// Phase 4 (collection element-type breadth): inserting a `Float` value into a
419+
/// `Map<Int, Float>` and pushing a `Float` onto a `Deque<Float>`, both through `mut`
420+
/// parameters, lower to the new `MapInsertFloat` / `DequePushBackFloat` helpers
421+
/// (value-side counterparts enabled by the float-arg helper ABI). Backends must
422+
/// agree with the interpreter and the loop must run natively.
423+
#[cfg(feature = "native-jit")]
424+
#[test]
425+
fn jit_acceptance_runs_float_map_and_deque_helpers() {
426+
let source = "\
427+
fn fill(m: mut Map<Int, Float>, d: mut Deque<Float>, n: Int) -> Int {
428+
let mut i = 0
429+
while i < n {
430+
Map.insert<Int, Float>(map: mut m, key: read i, value: read 1.5)
431+
Deque.push_back<Float>(deque: mut d, value: read 2.5)
432+
i = i + 1
433+
}
434+
return 0
435+
}
436+
437+
fn main() -> Unit {
438+
let mut m = Map<Int, Float>.new()
439+
let mut d = Deque<Float>.new()
440+
let r = fill(m: mut m, d: mut d, n: read 4)
441+
let mut total = 0.0
442+
match Map.get<Int, Float>(map: read m, key: read 2) {
443+
Some(v) => { total = total + v }
444+
None => { total = total }
445+
}
446+
match Deque.pop_front<Float>(deque: mut d) {
447+
Some(v) => { total = total + v }
448+
None => { total = total }
449+
}
450+
Log.write(message: read Float.to_string(value: read total))
451+
return Unit
452+
}
453+
";
454+
let file = "jit-accept-float-map-deque.rss";
455+
assert_fast_jit_backends_agree(file, source);
456+
let exe = rsscript::reg_vm_compile_source(file, source).expect("compile");
457+
let (_out, stats) = exe
458+
.eval_main_with_args_native_with_stats(std::iter::empty::<String>())
459+
.expect("native run");
460+
assert!(
461+
stats.native_calls > 0,
462+
"the Float map-insert / deque-push loop should run natively: {stats:?}",
463+
);
464+
}
465+
418466
#[test]
419467
fn jit_acceptance_runs_float_parameter_loop() {
420468
let source = "\

0 commit comments

Comments
 (0)