Skip to content

Commit 50cd34c

Browse files
authored
ZJIT: Add Insn:: ArrayArefFixnum to accelerate Array#[] (ruby#14717)
* ZJIT: Add Insn:: ArrayArefFixnum to accelerate Array#[] * ZJIT: Use result from GuardType in ArrayArefFixnum * ZJIT: Unbox index for aref_fixnum * ZJIT: Change condition and add ArrayArefFixnum test * ZJIT: Fix ArrayArefFixnum display for InsnPrinter * ZJIT: Change insta test
1 parent 17a5a5e commit 50cd34c

File tree

5 files changed

+72
-0
lines changed

5 files changed

+72
-0
lines changed

test/ruby/test_zjit.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,14 @@ def test = [1,2,3]
11531153
}
11541154
end
11551155

1156+
def test_array_fixnum_aref
1157+
assert_compiles '3', %q{
1158+
def test(x) = [1,2,3][x]
1159+
test(2)
1160+
test(2)
1161+
}, call_threshold: 2, insns: [:opt_aref]
1162+
end
1163+
11561164
def test_new_range_inclusive
11571165
assert_compiles '1..5', %q{
11581166
def test(a, b) = a..b

zjit/bindgen/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ fn main() {
125125
.allowlist_function("rb_ary_unshift_m")
126126
.allowlist_function("rb_ec_ary_new_from_values")
127127
.allowlist_function("rb_ary_tmp_new_from_values")
128+
.allowlist_function("rb_ary_entry")
128129
.allowlist_function("rb_class_attached_object")
129130
.allowlist_function("rb_singleton_class")
130131
.allowlist_function("rb_define_class")

zjit/src/codegen.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
355355
Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
356356
Insn::NewRangeFixnum { low, high, flag, state } => gen_new_range_fixnum(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
357357
Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)),
358+
Insn::ArrayArefFixnum { array, index, .. } => gen_aref_fixnum(asm, opnd!(array), opnd!(index)),
358359
Insn::ObjectAlloc { val, state } => gen_object_alloc(jit, asm, opnd!(val), &function.frame_state(*state)),
359360
&Insn::ObjectAllocClass { class, state } => gen_object_alloc_class(asm, class, &function.frame_state(state)),
360361
Insn::StringCopy { val, chilled, state } => gen_string_copy(asm, opnd!(val), *chilled, &function.frame_state(*state)),
@@ -1241,6 +1242,16 @@ fn gen_new_array(
12411242
new_array
12421243
}
12431244

1245+
/// Compile array access (array[index])
1246+
fn gen_aref_fixnum(
1247+
asm: &mut Assembler,
1248+
array: Opnd,
1249+
index: Opnd,
1250+
) -> lir::Opnd {
1251+
let unboxed_idx = asm.rshift(index, Opnd::UImm(1));
1252+
asm_ccall!(asm, rb_ary_entry, array, unboxed_idx)
1253+
}
1254+
12441255
/// Compile a new hash instruction
12451256
fn gen_new_hash(
12461257
jit: &mut JITState,

zjit/src/cruby_bindings.inc.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/src/hir.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ pub enum Insn {
577577
ArrayExtend { left: InsnId, right: InsnId, state: InsnId },
578578
/// Push `val` onto `array`, where `array` is already `Array`.
579579
ArrayPush { array: InsnId, val: InsnId, state: InsnId },
580+
ArrayArefFixnum { array: InsnId, index: InsnId },
580581

581582
HashDup { val: InsnId, state: InsnId },
582583

@@ -888,6 +889,10 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
888889
}
889890
Ok(())
890891
}
892+
Insn::ArrayArefFixnum { array, index, .. } => {
893+
write!(f, "ArrayArefFixnum {array}, {index}")?;
894+
Ok(())
895+
}
891896
Insn::NewHash { elements, .. } => {
892897
write!(f, "NewHash")?;
893898
let mut prefix = " ";
@@ -1579,6 +1584,7 @@ impl Function {
15791584
&NewHash { ref elements, state } => NewHash { elements: find_vec!(elements), state: find!(state) },
15801585
&NewRange { low, high, flag, state } => NewRange { low: find!(low), high: find!(high), flag, state: find!(state) },
15811586
&NewRangeFixnum { low, high, flag, state } => NewRangeFixnum { low: find!(low), high: find!(high), flag, state: find!(state) },
1587+
&ArrayArefFixnum { array, index } => ArrayArefFixnum { array: find!(array), index: find!(index) },
15821588
&ArrayMax { ref elements, state } => ArrayMax { elements: find_vec!(elements), state: find!(state) },
15831589
&SetGlobal { id, val, state } => SetGlobal { id, val: find!(val), state },
15841590
&GetIvar { self_val, id, state } => GetIvar { self_val: find!(self_val), id, state },
@@ -1664,6 +1670,7 @@ impl Function {
16641670
Insn::ToRegexp { .. } => types::RegexpExact,
16651671
Insn::NewArray { .. } => types::ArrayExact,
16661672
Insn::ArrayDup { .. } => types::ArrayExact,
1673+
Insn::ArrayArefFixnum { .. } => types::BasicObject,
16671674
Insn::NewHash { .. } => types::HashExact,
16681675
Insn::HashDup { .. } => types::HashExact,
16691676
Insn::NewRange { .. } => types::RangeExact,
@@ -1969,6 +1976,16 @@ impl Function {
19691976
}
19701977
}
19711978
}
1979+
if self.type_of(idx_val).is_subtype(types::Fixnum) {
1980+
self.push_insn(block, Insn::PatchPoint { invariant: Invariant::BOPRedefined { klass: ARRAY_REDEFINED_OP_FLAG, bop: BOP_AREF }, state });
1981+
let fixnum_idx = self.push_insn(block, Insn::GuardType { val: idx_val, guard_type: types::Fixnum, state });
1982+
let result = self.push_insn(block, Insn::ArrayArefFixnum {
1983+
array: self_val,
1984+
index: fixnum_idx,
1985+
});
1986+
self.make_equal_to(orig_insn_id, result);
1987+
return;
1988+
}
19721989
}
19731990
self.push_insn_id(block, orig_insn_id);
19741991
}
@@ -2687,6 +2704,10 @@ impl Function {
26872704
worklist.push_back(val);
26882705
worklist.push_back(state);
26892706
}
2707+
&Insn::ArrayArefFixnum { array, index } => {
2708+
worklist.push_back(array);
2709+
worklist.push_back(index);
2710+
}
26902711
&Insn::Send { recv, ref args, state, .. }
26912712
| &Insn::SendForward { recv, ref args, state, .. }
26922713
| &Insn::SendWithoutBlock { recv, ref args, state, .. }
@@ -12564,4 +12585,34 @@ mod opt_tests {
1256412585
Return v23
1256512586
");
1256612587
}
12588+
12589+
#[test]
12590+
fn test_array_aref_fixnum() {
12591+
eval("
12592+
def test
12593+
arr = [1, 2, 3]
12594+
arr[0]
12595+
end
12596+
");
12597+
assert_snapshot!(hir_string("test"), @r"
12598+
fn test@<compiled>:3:
12599+
bb0():
12600+
EntryPoint interpreter
12601+
v1:BasicObject = LoadSelf
12602+
v2:NilClass = Const Value(nil)
12603+
Jump bb2(v1, v2)
12604+
bb1(v5:BasicObject):
12605+
EntryPoint JIT(0)
12606+
v6:NilClass = Const Value(nil)
12607+
Jump bb2(v5, v6)
12608+
bb2(v8:BasicObject, v9:NilClass):
12609+
v13:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
12610+
v15:ArrayExact = ArrayDup v13
12611+
v18:Fixnum[0] = Const Value(0)
12612+
PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_AREF)
12613+
v30:BasicObject = ArrayArefFixnum v15, v18
12614+
CheckInterrupts
12615+
Return v30
12616+
");
12617+
}
1256712618
}

0 commit comments

Comments
 (0)