summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--insns.def1
-rw-r--r--zjit/src/cruby_bindings.inc.rs7
-rw-r--r--zjit/src/cruby_methods.rs12
-rw-r--r--zjit/src/hir.rs76
-rw-r--r--zjit/src/profile.rs1
5 files changed, 94 insertions, 3 deletions
diff --git a/insns.def b/insns.def
index 69a8210d7d..8225d1ccea 100644
--- a/insns.def
+++ b/insns.def
@@ -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) };