Skip to content

Commit f5f1476

Browse files
committed
ZJIT: Inline Primitives for Array#each
1 parent 84d8cc5 commit f5f1476

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
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
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
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 ary_at_end(ec: EcPtr, self_: VALUE, index: VALUE) -> VALUE;
20+
fn ary_at(ec: EcPtr, self_: VALUE, index: VALUE) -> VALUE;
21+
fn 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(fixnum_inc as *mut c_void, FnProperties { inline: inline_fixnum_inc, return_type: types::Fixnum, ..Default::default() });
282+
builtin_funcs.insert(ary_at as *mut c_void, FnProperties { inline: inline_ary_at, ..Default::default() });
283+
builtin_funcs.insert(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),
@@ -888,3 +900,33 @@ fn inline_kernel_class(fun: &mut hir::Function, block: hir::BlockId, _recv: hir:
888900
let real_class = unsafe { rb_class_real(recv_class) };
889901
Some(fun.push_insn(block, hir::Insn::Const { val: hir::Const::Value(real_class) }))
890902
}
903+
904+
/// Inline `fixnum_inc(ec, self, num)` implies FixnumAdd(num, 1).
905+
/// num is always a Fixnum (starts at 0 and is incremented by fixnum_inc).
906+
fn inline_fixnum_inc(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
907+
let &[_self, num] = args else { return None; };
908+
let one = fun.push_insn(block, hir::Insn::Const { val: hir::Const::Value(VALUE::fixnum_from_usize(1)) });
909+
let result = fun.push_insn(block, hir::Insn::FixnumAdd { left: num, right: one, state });
910+
Some(result)
911+
}
912+
913+
/// Inline `ary_at(ec, self, index)` implies ArrayAref.
914+
/// Called from Array#each etc. where self is Array and index is in bounds.
915+
fn inline_ary_at(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], _state: hir::InsnId) -> Option<hir::InsnId> {
916+
let &[recv, index] = args else { return None; };
917+
let recv = fun.push_insn(block, hir::Insn::RefineType { val: recv, new_type: types::Array });
918+
let index = fun.push_insn(block, hir::Insn::UnboxFixnum { val: index });
919+
let result = fun.push_insn(block, hir::Insn::ArrayAref { array: recv, index });
920+
Some(result)
921+
}
922+
923+
/// Inline `ary_at_end(ec, self, index)` implies index >= ArrayLength(self).
924+
/// Called from Array#each etc. where self is Array and index is Fixnum.
925+
fn inline_ary_at_end(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
926+
let &[recv, index] = args else { return None; };
927+
let recv = fun.push_insn(block, hir::Insn::RefineType { val: recv, new_type: types::Array });
928+
let length_cint = fun.push_insn(block, hir::Insn::ArrayLength { array: recv });
929+
let length = fun.push_insn(block, hir::Insn::BoxFixnum { val: length_cint, state });
930+
let result = fun.push_insn(block, hir::Insn::FixnumGe { left: index, right: length });
931+
Some(result)
932+
}

zjit/src/hir/opt_tests.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11913,18 +11913,27 @@ mod hir_opt_tests {
1191311913
v28:BasicObject = InvokeBuiltin <inline_expr>, v23
1191411914
CheckInterrupts
1191511915
Return v28
11916-
bb7(v48:BasicObject, v49:BasicObject):
11917-
v52:BasicObject = InvokeBuiltin ary_at_end, v48, v49
11918-
v54:CBool = Test v52
11916+
bb7(v48:BasicObject, v49:Fixnum):
11917+
v83:Array = RefineType v48, Array
11918+
v84:CInt64 = ArrayLength v83
11919+
v85:Fixnum = BoxFixnum v84
11920+
v86:BoolExact = FixnumGe v49, v85
11921+
IncrCounter inline_cfunc_optimized_send_count
11922+
v54:CBool = Test v86
1191911923
IfFalse v54, bb6(v48, v49)
1192011924
CheckInterrupts
1192111925
Return v48
11922-
bb6(v67:BasicObject, v68:BasicObject):
11923-
v72:BasicObject = InvokeBuiltin ary_at, v67, v68
11924-
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
11925-
v78:BasicObject = InvokeBuiltin fixnum_inc, v67, v68
11926+
bb6(v67:BasicObject, v68:Fixnum):
11927+
v88:Array = RefineType v67, Array
11928+
v89:CInt64 = UnboxFixnum v68
11929+
v90:BasicObject = ArrayAref v88, v89
11930+
IncrCounter inline_cfunc_optimized_send_count
11931+
v74:BasicObject = InvokeBlock, v90 # SendFallbackReason: Uncategorized(invokeblock)
11932+
v92:Fixnum[1] = Const Value(1)
11933+
v93:Fixnum = FixnumAdd v68, v92
11934+
IncrCounter inline_cfunc_optimized_send_count
1192611935
PatchPoint NoEPEscape(each)
11927-
Jump bb7(v67, v78)
11936+
Jump bb7(v67, v93)
1192811937
");
1192911938
}
1193011939
}

zjit/src/hir/tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4073,19 +4073,19 @@ pub mod hir_build_tests {
40734073
bb5(v30:BasicObject, v31:NilClass):
40744074
v35:Fixnum[0] = Const Value(0)
40754075
Jump bb7(v30, v35)
4076-
bb7(v48:BasicObject, v49:BasicObject):
4077-
v52:BasicObject = InvokeBuiltin ary_at_end, v48, v49
4076+
bb7(v48:BasicObject, v49:Fixnum):
4077+
v52:BoolExact = InvokeBuiltin ary_at_end, v48, v49
40784078
v54:CBool = Test v52
4079-
v55:Falsy = RefineType v52, Falsy
4079+
v55:FalseClass = RefineType v52, Falsy
40804080
IfFalse v54, bb6(v48, v49)
4081-
v57:Truthy = RefineType v52, Truthy
4081+
v57:TrueClass = RefineType v52, Truthy
40824082
v59:NilClass = Const Value(nil)
40834083
CheckInterrupts
40844084
Return v48
4085-
bb6(v67:BasicObject, v68:BasicObject):
4085+
bb6(v67:BasicObject, v68:Fixnum):
40864086
v72:BasicObject = InvokeBuiltin ary_at, v67, v68
40874087
v74:BasicObject = InvokeBlock, v72 # SendFallbackReason: Uncategorized(invokeblock)
4088-
v78:BasicObject = InvokeBuiltin fixnum_inc, v67, v68
4088+
v78:Fixnum = InvokeBuiltin fixnum_inc, v67, v68
40894089
PatchPoint NoEPEscape(each)
40904090
Jump bb7(v67, v78)
40914091
");

0 commit comments

Comments
 (0)