Skip to content

Commit d3a4cc2

Browse files
committed
ZJIT: Inline Primitives for Array#each
1 parent 0a47b9b commit d3a4cc2

File tree

4 files changed

+68
-17
lines changed

4 files changed

+68
-17
lines changed

array.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,21 +2695,21 @@ ary_enum_length(VALUE ary, VALUE args, VALUE eobj)
26952695
}
26962696

26972697
// Return true if the index is at or past the end of the array.
2698-
static VALUE
2698+
VALUE
26992699
rb_jit_ary_at_end(rb_execution_context_t *ec, VALUE self, VALUE index)
27002700
{
27012701
return FIX2LONG(index) >= RARRAY_LEN(self) ? Qtrue : Qfalse;
27022702
}
27032703

27042704
// Return the element at the given fixnum index.
2705-
static VALUE
2705+
VALUE
27062706
rb_jit_ary_at(rb_execution_context_t *ec, VALUE self, VALUE index)
27072707
{
27082708
return RARRAY_AREF(self, FIX2LONG(index));
27092709
}
27102710

27112711
// Increment a fixnum by 1.
2712-
static VALUE
2712+
VALUE
27132713
rb_jit_fixnum_inc(rb_execution_context_t *ec, VALUE self, VALUE num)
27142714
{
27152715
return LONG2FIX(FIX2LONG(num) + 1);

zjit/src/cruby_methods.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ use std::ffi::c_void;
1414
use crate::hir_type::{types, Type};
1515
use crate::hir;
1616

17+
// Array iteration builtin functions (defined in array.c)
18+
unsafe extern "C" {
19+
fn rb_jit_ary_at_end(ec: EcPtr, self_: VALUE, index: VALUE) -> VALUE;
20+
fn rb_jit_ary_at(ec: EcPtr, self_: VALUE, index: VALUE) -> VALUE;
21+
fn rb_jit_fixnum_inc(ec: EcPtr, self_: VALUE, num: VALUE) -> VALUE;
22+
}
23+
1724
pub struct Annotations {
1825
cfuncs: HashMap<*mut c_void, FnProperties>,
1926
builtin_funcs: HashMap<*mut c_void, FnProperties>,
@@ -270,6 +277,11 @@ pub fn init() -> Annotations {
270277
annotate_builtin!(rb_cSymbol, "name", types::StringExact);
271278
annotate_builtin!(rb_cSymbol, "to_s", types::StringExact);
272279

280+
// Array iteration builtins (used in with_jit Array#each, map, select, find)
281+
builtin_funcs.insert(rb_jit_fixnum_inc as *mut c_void, FnProperties { inline: inline_fixnum_inc, return_type: types::Fixnum, ..Default::default() });
282+
builtin_funcs.insert(rb_jit_ary_at as *mut c_void, FnProperties { inline: inline_ary_at, ..Default::default() });
283+
builtin_funcs.insert(rb_jit_ary_at_end as *mut c_void, FnProperties { inline: inline_ary_at_end, return_type: types::BoolExact, ..Default::default() });
284+
273285
Annotations {
274286
cfuncs: std::mem::take(cfuncs),
275287
builtin_funcs: std::mem::take(builtin_funcs),
@@ -892,3 +904,33 @@ fn inline_kernel_class(fun: &mut hir::Function, block: hir::BlockId, _recv: hir:
892904
let real_class = unsafe { rb_class_real(recv_class) };
893905
Some(fun.push_insn(block, hir::Insn::Const { val: hir::Const::Value(real_class) }))
894906
}
907+
908+
/// Inline `fixnum_inc(ec, self, num)` implies FixnumAdd(num, 1).
909+
/// num is always a Fixnum (starts at 0 and is incremented by fixnum_inc).
910+
fn inline_fixnum_inc(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
911+
let &[_self, num] = args else { return None; };
912+
let one = fun.push_insn(block, hir::Insn::Const { val: hir::Const::Value(VALUE::fixnum_from_usize(1)) });
913+
let result = fun.push_insn(block, hir::Insn::FixnumAdd { left: num, right: one, state });
914+
Some(result)
915+
}
916+
917+
/// Inline `ary_at(ec, self, index)` implies ArrayAref.
918+
/// Called from Array#each etc. where self is Array and index is in bounds.
919+
fn inline_ary_at(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], _state: hir::InsnId) -> Option<hir::InsnId> {
920+
let &[recv, index] = args else { return None; };
921+
let recv = fun.push_insn(block, hir::Insn::RefineType { val: recv, new_type: types::Array });
922+
let index = fun.push_insn(block, hir::Insn::UnboxFixnum { val: index });
923+
let result = fun.push_insn(block, hir::Insn::ArrayAref { array: recv, index });
924+
Some(result)
925+
}
926+
927+
/// Inline `ary_at_end(ec, self, index)` implies index >= ArrayLength(self).
928+
/// Called from Array#each etc. where self is Array and index is Fixnum.
929+
fn inline_ary_at_end(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
930+
let &[recv, index] = args else { return None; };
931+
let recv = fun.push_insn(block, hir::Insn::RefineType { val: recv, new_type: types::Array });
932+
let length_cint = fun.push_insn(block, hir::Insn::ArrayLength { array: recv });
933+
let length = fun.push_insn(block, hir::Insn::BoxFixnum { val: length_cint, state });
934+
let result = fun.push_insn(block, hir::Insn::FixnumGe { left: index, right: length });
935+
Some(result)
936+
}

zjit/src/hir/opt_tests.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12030,18 +12030,27 @@ mod hir_opt_tests {
1203012030
v28:BasicObject = InvokeBuiltin <inline_expr>, v23
1203112031
CheckInterrupts
1203212032
Return v28
12033-
bb7(v48:BasicObject, v49:BasicObject):
12034-
v52:BasicObject = InvokeBuiltin rb_jit_ary_at_end, v48, v49
12035-
v54:CBool = Test v52
12033+
bb7(v48:BasicObject, v49:Fixnum):
12034+
v83:Array = RefineType v48, Array
12035+
v84:CInt64 = ArrayLength v83
12036+
v85:Fixnum = BoxFixnum v84
12037+
v86:BoolExact = FixnumGe v49, v85
12038+
IncrCounter inline_cfunc_optimized_send_count
12039+
v54:CBool = Test v86
1203612040
IfFalse v54, bb6(v48, v49)
1203712041
CheckInterrupts
1203812042
Return v48
12039-
bb6(v67:BasicObject, v68:BasicObject):
12040-
v72:BasicObject = InvokeBuiltin rb_jit_ary_at, v67, v68
12041-
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
12042-
v78:BasicObject = InvokeBuiltin rb_jit_fixnum_inc, v67, v68
12043+
bb6(v67:BasicObject, v68:Fixnum):
12044+
v88:Array = RefineType v67, Array
12045+
v89:CInt64 = UnboxFixnum v68
12046+
v90:BasicObject = ArrayAref v88, v89
12047+
IncrCounter inline_cfunc_optimized_send_count
12048+
v74:BasicObject = InvokeBlock, v90 # SendFallbackReason: Uncategorized(invokeblock)
12049+
v92:Fixnum[1] = Const Value(1)
12050+
v93:Fixnum = FixnumAdd v68, v92
12051+
IncrCounter inline_cfunc_optimized_send_count
1204312052
PatchPoint NoEPEscape(each)
12044-
Jump bb7(v67, v78)
12053+
Jump bb7(v67, v93)
1204512054
");
1204612055
}
1204712056
}

zjit/src/hir/tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4100,19 +4100,19 @@ pub mod hir_build_tests {
41004100
bb5(v30:BasicObject, v31:NilClass):
41014101
v35:Fixnum[0] = Const Value(0)
41024102
Jump bb7(v30, v35)
4103-
bb7(v48:BasicObject, v49:BasicObject):
4104-
v52:BasicObject = InvokeBuiltin rb_jit_ary_at_end, v48, v49
4103+
bb7(v48:BasicObject, v49:Fixnum):
4104+
v52:BoolExact = InvokeBuiltin rb_jit_ary_at_end, v48, v49
41054105
v54:CBool = Test v52
4106-
v55:Falsy = RefineType v52, Falsy
4106+
v55:FalseClass = RefineType v52, Falsy
41074107
IfFalse v54, bb6(v48, v49)
4108-
v57:Truthy = RefineType v52, Truthy
4108+
v57:TrueClass = RefineType v52, Truthy
41094109
v59:NilClass = Const Value(nil)
41104110
CheckInterrupts
41114111
Return v48
4112-
bb6(v67:BasicObject, v68:BasicObject):
4112+
bb6(v67:BasicObject, v68:Fixnum):
41134113
v72:BasicObject = InvokeBuiltin rb_jit_ary_at, v67, v68
41144114
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
4115-
v78:BasicObject = InvokeBuiltin rb_jit_fixnum_inc, v67, v68
4115+
v78:Fixnum = InvokeBuiltin rb_jit_fixnum_inc, v67, v68
41164116
PatchPoint NoEPEscape(each)
41174117
Jump bb7(v67, v78)
41184118
");

0 commit comments

Comments
 (0)