Skip to content

Commit

Permalink
YJIT: Skip defer_compilation for fixnums if possible (#7168)
Browse files Browse the repository at this point in the history
* YJIT: Skip defer_compilation for fixnums if possible

* YJIT: It should be Some(false)

* YJIT: Define two_fixnums_on_stack on Context
  • Loading branch information
k0kubun committed Jan 30, 2023
1 parent e1ffafb commit bc0dc9d
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 77 deletions.
165 changes: 88 additions & 77 deletions yjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,14 @@ fn jit_next_insn_idx(jit: &JITState) -> u32 {

// Check if we are compiling the instruction at the stub PC
// Meaning we are compiling the instruction that is next to execute
fn jit_at_current_insn(jit: &JITState) -> bool {
pub fn jit_at_current_insn(jit: &JITState) -> bool {
let ec_pc: *mut VALUE = unsafe { get_cfp_pc(get_ec_cfp(jit.ec.unwrap())) };
ec_pc == jit.pc
}

// Peek at the nth topmost value on the Ruby stack.
// Returns the topmost value when n == 0.
fn jit_peek_at_stack(jit: &JITState, ctx: &Context, n: isize) -> VALUE {
pub fn jit_peek_at_stack(jit: &JITState, ctx: &Context, n: isize) -> VALUE {
assert!(jit_at_current_insn(jit));
assert!(n < ctx.get_stack_size() as isize);

Expand Down Expand Up @@ -1093,15 +1093,15 @@ fn gen_opt_plus(
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
if !jit_at_current_insn(jit) {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);
let two_fixnums = match ctx.two_fixnums_on_stack(jit) {
Some(two_fixnums) => two_fixnums,
None => {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}
};

if comptime_a.fixnum_p() && comptime_b.fixnum_p() {
if two_fixnums {
// Create a side-exit to fall back to the interpreter
// Note: we generate the side-exit before popping operands from the stack
let side_exit = get_side_exit(jit, ocb, ctx);
Expand Down Expand Up @@ -2622,16 +2622,16 @@ fn gen_fixnum_cmp(
ocb: &mut OutlinedCb,
cmov_op: CmovFn,
) -> CodegenStatus {
// Defer compilation so we can specialize base on a runtime receiver
if !jit_at_current_insn(jit) {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);
let two_fixnums = match ctx.two_fixnums_on_stack(jit) {
Some(two_fixnums) => two_fixnums,
None => {
// Defer compilation so we can specialize based on a runtime receiver
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}
};

if comptime_a.fixnum_p() && comptime_b.fixnum_p() {
if two_fixnums {
// Create a side-exit to fall back to the interpreter
// Note: we generate the side-exit before popping operands from the stack
let side_exit = get_side_exit(jit, ocb, ctx);
Expand Down Expand Up @@ -2698,24 +2698,29 @@ fn gen_opt_gt(
}

// Implements specialized equality for either two fixnum or two strings
// Returns true if code was generated, otherwise false
// Returns None if enough type information isn't available, Some(true)
// if code was generated, otherwise Some(false).
fn gen_equality_specialized(
jit: &mut JITState,
ctx: &mut Context,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
side_exit: Target,
) -> bool {
let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);
) -> Option<bool> {
// Create a side-exit to fall back to the interpreter
let side_exit = get_side_exit(jit, ocb, ctx);

let a_opnd = ctx.stack_opnd(1);
let b_opnd = ctx.stack_opnd(0);

if comptime_a.fixnum_p() && comptime_b.fixnum_p() {
let two_fixnums = match ctx.two_fixnums_on_stack(jit) {
Some(two_fixnums) => two_fixnums,
None => return None,
};

if two_fixnums {
if !assume_bop_not_redefined(jit, ocb, INTEGER_REDEFINED_OP_FLAG, BOP_EQ) {
// if overridden, emit the generic version
return false;
return Some(false);
}

guard_two_fixnums(jit, ctx, asm, ocb, side_exit);
Expand All @@ -2729,13 +2734,19 @@ fn gen_equality_specialized(
let dst = ctx.stack_push(Type::UnknownImm);
asm.mov(dst, val);

true
return Some(true);
}
else if unsafe { comptime_a.class_of() == rb_cString && comptime_b.class_of() == rb_cString }
{

if !jit_at_current_insn(jit) {
return None;
}
let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);

if unsafe { comptime_a.class_of() == rb_cString && comptime_b.class_of() == rb_cString } {
if !assume_bop_not_redefined(jit, ocb, STRING_REDEFINED_OP_FLAG, BOP_EQ) {
// if overridden, emit the generic version
return false;
return Some(false);
}

// Guard that a is a String
Expand Down Expand Up @@ -2792,9 +2803,9 @@ fn gen_equality_specialized(

asm.write_label(ret);

true
Some(true)
} else {
false
Some(false)
}
}

Expand All @@ -2804,16 +2815,16 @@ fn gen_opt_eq(
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
// Defer compilation so we can specialize base on a runtime receiver
if !jit_at_current_insn(jit) {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

// Create a side-exit to fall back to the interpreter
let side_exit = get_side_exit(jit, ocb, ctx);
let specialized = match gen_equality_specialized(jit, ctx, asm, ocb) {
Some(specialized) => specialized,
None => {
// Defer compilation so we can specialize base on a runtime receiver
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}
};

if gen_equality_specialized(jit, ctx, asm, ocb, side_exit) {
if specialized {
jump_to_next_insn(jit, ctx, asm, ocb);
EndBlock
} else {
Expand Down Expand Up @@ -3068,16 +3079,16 @@ fn gen_opt_and(
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
// Defer compilation so we can specialize on a runtime `self`
if !jit_at_current_insn(jit) {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);
let two_fixnums = match ctx.two_fixnums_on_stack(jit) {
Some(two_fixnums) => two_fixnums,
None => {
// Defer compilation so we can specialize on a runtime `self`
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}
};

if comptime_a.fixnum_p() && comptime_b.fixnum_p() {
if two_fixnums {
// Create a side-exit to fall back to the interpreter
// Note: we generate the side-exit before popping operands from the stack
let side_exit = get_side_exit(jit, ocb, ctx);
Expand Down Expand Up @@ -3113,16 +3124,16 @@ fn gen_opt_or(
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
// Defer compilation so we can specialize on a runtime `self`
if !jit_at_current_insn(jit) {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);
let two_fixnums = match ctx.two_fixnums_on_stack(jit) {
Some(two_fixnums) => two_fixnums,
None => {
// Defer compilation so we can specialize on a runtime `self`
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}
};

if comptime_a.fixnum_p() && comptime_b.fixnum_p() {
if two_fixnums {
// Create a side-exit to fall back to the interpreter
// Note: we generate the side-exit before popping operands from the stack
let side_exit = get_side_exit(jit, ocb, ctx);
Expand Down Expand Up @@ -3158,16 +3169,16 @@ fn gen_opt_minus(
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
// Defer compilation so we can specialize on a runtime `self`
if !jit_at_current_insn(jit) {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);
let two_fixnums = match ctx.two_fixnums_on_stack(jit) {
Some(two_fixnums) => two_fixnums,
None => {
// Defer compilation so we can specialize on a runtime `self`
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}
};

if comptime_a.fixnum_p() && comptime_b.fixnum_p() {
if two_fixnums {
// Create a side-exit to fall back to the interpreter
// Note: we generate the side-exit before popping operands from the stack
let side_exit = get_side_exit(jit, ocb, ctx);
Expand Down Expand Up @@ -3225,16 +3236,16 @@ fn gen_opt_mod(
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
// Defer compilation so we can specialize on a runtime `self`
if !jit_at_current_insn(jit) {
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

let comptime_a = jit_peek_at_stack(jit, ctx, 1);
let comptime_b = jit_peek_at_stack(jit, ctx, 0);
let two_fixnums = match ctx.two_fixnums_on_stack(jit) {
Some(two_fixnums) => two_fixnums,
None => {
// Defer compilation so we can specialize on a runtime `self`
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}
};

if comptime_a.fixnum_p() && comptime_b.fixnum_p() {
if two_fixnums {
// Create a side-exit to fall back to the interpreter
// Note: we generate the side-exit before popping operands from the stack
let side_exit = get_side_exit(jit, ocb, ctx);
Expand Down
16 changes: 16 additions & 0 deletions yjit/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,22 @@ impl Context {

return diff;
}

pub fn two_fixnums_on_stack(&self, jit: &mut JITState) -> Option<bool> {
if jit_at_current_insn(jit) {
let comptime_recv = jit_peek_at_stack(jit, self, 1);
let comptime_arg = jit_peek_at_stack(jit, self, 0);
return Some(comptime_recv.fixnum_p() && comptime_arg.fixnum_p());
}

let recv_type = self.get_opnd_type(StackOpnd(1));
let arg_type = self.get_opnd_type(StackOpnd(0));
match (recv_type, arg_type) {
(Type::Fixnum, Type::Fixnum) => Some(true),
(Type::Unknown | Type::UnknownImm, Type::Unknown | Type::UnknownImm) => None,
_ => Some(false),
}
}
}

impl BlockId {
Expand Down

0 comments on commit bc0dc9d

Please sign in to comment.