diff options
| -rw-r--r-- | insns.def | 1 | ||||
| -rw-r--r-- | zjit/src/cruby_bindings.inc.rs | 7 | ||||
| -rw-r--r-- | zjit/src/cruby_methods.rs | 12 | ||||
| -rw-r--r-- | zjit/src/hir.rs | 76 | ||||
| -rw-r--r-- | zjit/src/profile.rs | 1 |
5 files changed, 94 insertions, 3 deletions
@@ -1598,6 +1598,7 @@ opt_succ (CALL_DATA cd) (VALUE recv) (VALUE val) +// attr bool zjit_profile = true; { val = vm_opt_succ(recv); diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 17cda12a0b..ffaafed5ff 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -702,9 +702,10 @@ pub const YARVINSN_zjit_opt_aset: ruby_vminsn_type = 237; pub const YARVINSN_zjit_opt_length: ruby_vminsn_type = 238; pub const YARVINSN_zjit_opt_size: ruby_vminsn_type = 239; pub const YARVINSN_zjit_opt_empty_p: ruby_vminsn_type = 240; -pub const YARVINSN_zjit_opt_not: ruby_vminsn_type = 241; -pub const YARVINSN_zjit_opt_regexpmatch2: ruby_vminsn_type = 242; -pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 243; +pub const YARVINSN_zjit_opt_succ: ruby_vminsn_type = 241; +pub const YARVINSN_zjit_opt_not: ruby_vminsn_type = 242; +pub const YARVINSN_zjit_opt_regexpmatch2: ruby_vminsn_type = 243; +pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 244; pub type ruby_vminsn_type = u32; pub type rb_iseq_callback = ::std::option::Option< unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void), diff --git a/zjit/src/cruby_methods.rs b/zjit/src/cruby_methods.rs index 0da7b07ad4..11496f7b98 100644 --- a/zjit/src/cruby_methods.rs +++ b/zjit/src/cruby_methods.rs @@ -206,6 +206,7 @@ pub fn init() -> Annotations { annotate!(rb_cBasicObject, "==", types::BoolExact, no_gc, leaf, elidable); annotate!(rb_cBasicObject, "!", types::BoolExact, no_gc, leaf, elidable); annotate!(rb_cBasicObject, "initialize", types::NilClass, no_gc, leaf, elidable); + annotate!(rb_cInteger, "succ", inline_integer_succ); annotate!(rb_cString, "to_s", inline_string_to_s); let thread_singleton = unsafe { rb_singleton_class(rb_cThread) }; annotate!(thread_singleton, "current", types::BasicObject, no_gc, leaf); @@ -270,3 +271,14 @@ fn inline_string_getbyte(fun: &mut hir::Function, block: hir::BlockId, recv: hir } None } + +fn inline_integer_succ(fun: &mut hir::Function, block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> { + if !args.is_empty() { return None; } + if fun.likely_a(recv, types::Fixnum, state) { + let left = fun.coerce_to(block, recv, types::Fixnum, state); + let right = fun.push_insn(block, hir::Insn::Const { val: hir::Const::Value(VALUE::fixnum_from_usize(1)) }); + let result = fun.push_insn(block, hir::Insn::FixnumAdd { left, right, state }); + return Some(result); + } + None +} diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs index f7df493d4a..a87a416e9e 100644 --- a/zjit/src/hir.rs +++ b/zjit/src/hir.rs @@ -13193,4 +13193,80 @@ mod opt_tests { Return v20 "); } + + #[test] + fn test_inline_integer_succ_with_fixnum() { + eval(" + def test(x) = x.succ + test(4) + "); + assert_contains_opcode("test", YARVINSN_opt_succ); + assert_snapshot!(hir_string("test"), @r" + fn test@<compiled>:2: + bb0(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 + Jump bb2(v1, v2) + bb1(v5:BasicObject, v6:BasicObject): + EntryPoint JIT(0) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:BasicObject): + PatchPoint MethodRedefined(Integer@0x1000, succ@0x1008, cme:0x1010) + v24:Fixnum = GuardType v9, Fixnum + v25:Fixnum[1] = Const Value(1) + v26:Fixnum = FixnumAdd v24, v25 + CheckInterrupts + Return v26 + "); + } + + #[test] + fn test_dont_inline_integer_succ_with_bignum() { + eval(" + def test(x) = x.succ + test(4 << 70) + "); + assert_contains_opcode("test", YARVINSN_opt_succ); + assert_snapshot!(hir_string("test"), @r" + fn test@<compiled>:2: + bb0(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:BasicObject = GetLocal l0, SP@4 + Jump bb2(v1, v2) + bb1(v5:BasicObject, v6:BasicObject): + EntryPoint JIT(0) + Jump bb2(v5, v6) + bb2(v8:BasicObject, v9:BasicObject): + PatchPoint MethodRedefined(Integer@0x1000, succ@0x1008, cme:0x1010) + v24:Integer = GuardType v9, Integer + v25:BasicObject = CCallWithFrame succ@0x1038, v24 + CheckInterrupts + Return v25 + "); + } + + #[test] + fn test_dont_inline_integer_succ_with_args() { + eval(" + def test = 4.succ 1 + "); + assert_snapshot!(hir_string("test"), @r" + fn test@<compiled>:2: + bb0(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + Jump bb2(v1) + bb1(v4:BasicObject): + EntryPoint JIT(0) + Jump bb2(v4) + bb2(v6:BasicObject): + v10:Fixnum[4] = Const Value(4) + v11:Fixnum[1] = Const Value(1) + v13:BasicObject = SendWithoutBlock v10, :succ, v11 + CheckInterrupts + Return v13 + "); + } } diff --git a/zjit/src/profile.rs b/zjit/src/profile.rs index e7db47142b..e935ec9731 100644 --- a/zjit/src/profile.rs +++ b/zjit/src/profile.rs @@ -82,6 +82,7 @@ fn profile_insn(bare_opcode: ruby_vminsn_type, ec: EcPtr) { YARVINSN_objtostring => profile_operands(profiler, profile, 1), YARVINSN_opt_length => profile_operands(profiler, profile, 1), YARVINSN_opt_size => profile_operands(profiler, profile, 1), + YARVINSN_opt_succ => profile_operands(profiler, profile, 1), YARVINSN_opt_send_without_block => { let cd: *const rb_call_data = profiler.insn_opnd(0).as_ptr(); let argc = unsafe { vm_ci_argc((*cd).ci) }; |
