YJIT: Add codegen for Float arithmetics (#9774)

* YJIT: Add codegen for Float arithmetics

* Add Flonum and Fixnum tests
This commit is contained in:
Takashi Kokubun 2024-01-31 09:58:47 -08:00 committed by GitHub
parent cc9bbbdd80
commit 09427f51a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 200 additions and 0 deletions

View File

@ -2484,6 +2484,16 @@ assert_equal '[true, false, true, false]', %q{
[is_odd(123), is_odd(456), is_odd(bignum), is_odd(bignum+1)]
}
# Flonum and Flonum
assert_equal '[2.0, 0.0, 1.0, 4.0]', %q{
[1.0 + 1.0, 1.0 - 1.0, 1.0 * 1.0, 8.0 / 2.0]
}
# Flonum and Fixnum
assert_equal '[2.0, 0.0, 1.0, 4.0]', %q{
[1.0 + 1, 1.0 - 1, 1.0 * 1, 8.0 / 2]
}
# Call to static and dynamic symbol
assert_equal 'bar', %q{
def to_string(obj)

View File

@ -217,6 +217,10 @@ fn main() {
// From internal/numeric.h
.allowlist_function("rb_fix_aref")
.allowlist_function("rb_float_plus")
.allowlist_function("rb_float_minus")
.allowlist_function("rb_float_mul")
.allowlist_function("rb_float_div")
// From internal/string.h
.allowlist_function("rb_ec_str_resurrect")

View File

@ -4992,6 +4992,182 @@ fn jit_rb_int_aref(
true
}
fn jit_rb_float_plus(
jit: &mut JITState,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
_ci: *const rb_callinfo,
_cme: *const rb_callable_method_entry_t,
_block: Option<BlockHandler>,
_argc: i32,
_known_recv_class: *const VALUE,
) -> bool {
// Guard obj is Fixnum or Flonum to avoid rb_funcall on rb_num_coerce_bin
let comptime_obj = jit.peek_at_stack(&asm.ctx, 0);
if comptime_obj.fixnum_p() || comptime_obj.flonum_p() {
let obj = asm.stack_opnd(0);
jit_guard_known_klass(
jit,
asm,
ocb,
comptime_obj.class_of(),
obj,
obj.into(),
comptime_obj,
SEND_MAX_DEPTH,
Counter::guard_send_not_fixnum_or_flonum,
);
} else {
return false;
}
// Save the PC and SP because the callee may allocate Float on heap
jit_prepare_routine_call(jit, asm);
asm_comment!(asm, "Float#+");
let obj = asm.stack_opnd(0);
let recv = asm.stack_opnd(1);
let ret = asm.ccall(rb_float_plus as *const u8, vec![recv, obj]);
asm.stack_pop(2); // Keep recv during ccall for GC
let ret_opnd = asm.stack_push(Type::Unknown); // Flonum or heap Float
asm.mov(ret_opnd, ret);
true
}
fn jit_rb_float_minus(
jit: &mut JITState,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
_ci: *const rb_callinfo,
_cme: *const rb_callable_method_entry_t,
_block: Option<BlockHandler>,
_argc: i32,
_known_recv_class: *const VALUE,
) -> bool {
// Guard obj is Fixnum or Flonum to avoid rb_funcall on rb_num_coerce_bin
let comptime_obj = jit.peek_at_stack(&asm.ctx, 0);
if comptime_obj.fixnum_p() || comptime_obj.flonum_p() {
let obj = asm.stack_opnd(0);
jit_guard_known_klass(
jit,
asm,
ocb,
comptime_obj.class_of(),
obj,
obj.into(),
comptime_obj,
SEND_MAX_DEPTH,
Counter::guard_send_not_fixnum_or_flonum,
);
} else {
return false;
}
// Save the PC and SP because the callee may allocate Float on heap
jit_prepare_routine_call(jit, asm);
asm_comment!(asm, "Float#-");
let obj = asm.stack_opnd(0);
let recv = asm.stack_opnd(1);
let ret = asm.ccall(rb_float_minus as *const u8, vec![recv, obj]);
asm.stack_pop(2); // Keep recv during ccall for GC
let ret_opnd = asm.stack_push(Type::Unknown); // Flonum or heap Float
asm.mov(ret_opnd, ret);
true
}
fn jit_rb_float_mul(
jit: &mut JITState,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
_ci: *const rb_callinfo,
_cme: *const rb_callable_method_entry_t,
_block: Option<BlockHandler>,
_argc: i32,
_known_recv_class: *const VALUE,
) -> bool {
// Guard obj is Fixnum or Flonum to avoid rb_funcall on rb_num_coerce_bin
let comptime_obj = jit.peek_at_stack(&asm.ctx, 0);
if comptime_obj.fixnum_p() || comptime_obj.flonum_p() {
let obj = asm.stack_opnd(0);
jit_guard_known_klass(
jit,
asm,
ocb,
comptime_obj.class_of(),
obj,
obj.into(),
comptime_obj,
SEND_MAX_DEPTH,
Counter::guard_send_not_fixnum_or_flonum,
);
} else {
return false;
}
// Save the PC and SP because the callee may allocate Float on heap
jit_prepare_routine_call(jit, asm);
asm_comment!(asm, "Float#*");
let obj = asm.stack_opnd(0);
let recv = asm.stack_opnd(1);
let ret = asm.ccall(rb_float_mul as *const u8, vec![recv, obj]);
asm.stack_pop(2); // Keep recv during ccall for GC
let ret_opnd = asm.stack_push(Type::Unknown); // Flonum or heap Float
asm.mov(ret_opnd, ret);
true
}
fn jit_rb_float_div(
jit: &mut JITState,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
_ci: *const rb_callinfo,
_cme: *const rb_callable_method_entry_t,
_block: Option<BlockHandler>,
_argc: i32,
_known_recv_class: *const VALUE,
) -> bool {
// Guard obj is Fixnum or Flonum to avoid rb_funcall on rb_num_coerce_bin
let comptime_obj = jit.peek_at_stack(&asm.ctx, 0);
if comptime_obj.fixnum_p() || comptime_obj.flonum_p() {
let obj = asm.stack_opnd(0);
jit_guard_known_klass(
jit,
asm,
ocb,
comptime_obj.class_of(),
obj,
obj.into(),
comptime_obj,
SEND_MAX_DEPTH,
Counter::guard_send_not_fixnum_or_flonum,
);
} else {
return false;
}
// Save the PC and SP because the callee may allocate Float on heap
jit_prepare_routine_call(jit, asm);
asm_comment!(asm, "Float#/");
let obj = asm.stack_opnd(0);
let recv = asm.stack_opnd(1);
let ret = asm.ccall(rb_float_div as *const u8, vec![recv, obj]);
asm.stack_pop(2); // Keep recv during ccall for GC
let ret_opnd = asm.stack_push(Type::Unknown); // Flonum or heap Float
asm.mov(ret_opnd, ret);
true
}
/// If string is frozen, duplicate it to get a non-frozen string. Otherwise, return it.
fn jit_rb_str_uplus(
jit: &mut JITState,
@ -9179,6 +9355,11 @@ pub fn yjit_reg_method_codegen_fns() {
yjit_reg_method(rb_cInteger, "^", jit_rb_int_xor);
yjit_reg_method(rb_cInteger, "[]", jit_rb_int_aref);
yjit_reg_method(rb_cFloat, "+", jit_rb_float_plus);
yjit_reg_method(rb_cFloat, "-", jit_rb_float_minus);
yjit_reg_method(rb_cFloat, "*", jit_rb_float_mul);
yjit_reg_method(rb_cFloat, "/", jit_rb_float_div);
yjit_reg_method(rb_cString, "empty?", jit_rb_str_empty_p);
yjit_reg_method(rb_cString, "to_s", jit_rb_str_to_s);
yjit_reg_method(rb_cString, "to_str", jit_rb_str_to_s);

View File

@ -1030,6 +1030,10 @@ extern "C" {
) -> ::std::os::raw::c_int;
pub fn rb_insn_len(insn: VALUE) -> ::std::os::raw::c_int;
pub fn rb_vm_insn_decode(encoded: VALUE) -> ::std::os::raw::c_int;
pub fn rb_float_plus(x: VALUE, y: VALUE) -> VALUE;
pub fn rb_float_minus(x: VALUE, y: VALUE) -> VALUE;
pub fn rb_float_mul(x: VALUE, y: VALUE) -> VALUE;
pub fn rb_float_div(x: VALUE, y: VALUE) -> VALUE;
pub fn rb_fix_aref(fix: VALUE, idx: VALUE) -> VALUE;
pub fn rb_vm_insn_addr2opcode(addr: *const ::std::os::raw::c_void) -> ::std::os::raw::c_int;
pub fn rb_iseq_line_no(iseq: *const rb_iseq_t, pos: usize) -> ::std::os::raw::c_uint;

View File

@ -437,6 +437,7 @@ make_counters! {
guard_send_instance_of_class_mismatch,
guard_send_interrupted,
guard_send_not_fixnums,
guard_send_not_fixnum_or_flonum,
guard_send_not_string,
guard_send_respond_to_mid_mismatch,