Skip to content

Commit

Permalink
Refactor YJIT branches to use PosMarker (#333)
Browse files Browse the repository at this point in the history
* Refactor defer_compilation to use PosMarker

* Port gen_direct_jump() to use PosMarker

* Port gen_branch, branchunless

* Port over gen_jump()

* Port over branchif and branchnil

* Fix use od record_boundary_patch_point in jump_to_next_insn
  • Loading branch information
maximecb authored and k0kubun committed Aug 26, 2022
1 parent b2bf39e commit 97bc546
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 127 deletions.
41 changes: 33 additions & 8 deletions bootstraptest/test_yjit_new_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,37 @@ def foo(n)
foo(777)
}

# TODO: progress towards getting branches and calls working
=begin
def foo(n)
if n
n
# branchunless
assert_equal '7', %q{
def foo(n)
if n
7
else
10
end
end
foo(true)
}
assert_equal '10', %q{
def foo(n)
if n
7
else
10
end
end
end
puts foo(0)
=end
foo(false)
}

# branchunless, jump
assert_equal '1', %q{
def foo(n)
if n
v = 0
else
v = 1
end
return 1 + v
end
foo(true)
}
3 changes: 3 additions & 0 deletions yjit/src/backend/arm64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,9 @@ impl Assembler
Op::Je => {
emit_conditional_jump::<{Condition::EQ}>(cb, insn.target.unwrap());
},
Op::Jne => {
emit_conditional_jump::<{Condition::NE}>(cb, insn.target.unwrap());
},
Op::Jbe => {
emit_conditional_jump::<{Condition::LS}>(cb, insn.target.unwrap());
},
Expand Down
2 changes: 2 additions & 0 deletions yjit/src/backend/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ pub enum Op
// Low-level conditional jump instructions
Jbe,
Je,
Jne,
Jz,
Jnz,
Jo,
Expand Down Expand Up @@ -883,6 +884,7 @@ macro_rules! def_push_2_opnd_no_out {
def_push_1_opnd_no_out!(jmp_opnd, Op::JmpOpnd);
def_push_jcc!(jmp, Op::Jmp);
def_push_jcc!(je, Op::Je);
def_push_jcc!(jne, Op::Jne);
def_push_jcc!(jbe, Op::Jbe);
def_push_jcc!(jz, Op::Jz);
def_push_jcc!(jnz, Op::Jnz);
Expand Down
8 changes: 8 additions & 0 deletions yjit/src/backend/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,14 @@ impl Assembler
}
}

Op::Jne => {
match insn.target.unwrap() {
Target::CodePtr(code_ptr) => jne_ptr(cb, code_ptr),
Target::Label(label_idx) => jne_label(cb, label_idx),
_ => unreachable!()
}
}

Op::Jbe => {
match insn.target.unwrap() {
Target::CodePtr(code_ptr) => jbe_ptr(cb, code_ptr),
Expand Down
104 changes: 32 additions & 72 deletions yjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ enum CodegenStatus {
KeepCompiling,
CantCompile,
EndBlock,
DeferCompilation,
}

/// Code generation function signature
Expand Down Expand Up @@ -698,17 +697,10 @@ fn jump_to_next_insn(

// We are at the end of the current instruction. Record the boundary.
if jit.record_boundary_patch_point {
todo!();

/*
let next_insn = unsafe { jit.pc.offset(insn_len(jit.opcode).try_into().unwrap()) };
let exit_pos = gen_exit(next_insn, &reset_depth, ocb.unwrap());
record_global_inval_patch(cb, exit_pos);
let exit_pc = unsafe { jit.pc.offset(insn_len(jit.opcode).try_into().unwrap()) };
let exit_pos = gen_outlined_exit(exit_pc, &reset_depth, ocb);
record_global_inval_patch(asm, exit_pos);
jit.record_boundary_patch_point = false;
*/



}

// Generate the jump instruction
Expand Down Expand Up @@ -752,9 +744,6 @@ pub fn gen_single_block(
// Create a backend assembler instance
let mut asm = Assembler::new();

// Codegen status for the last instruction compiled
let mut status = CantCompile;

// For each instruction to compile
// NOTE: could rewrite this loop with a std::iter::Iterator
while insn_idx < iseq_size {
Expand Down Expand Up @@ -792,7 +781,7 @@ pub fn gen_single_block(
}

// Lookup the codegen function for this instruction
status = CantCompile;
let mut status = CantCompile;
if let Some(gen_fn) = get_gen_fn(VALUE(opcode)) {
// :count-placement:
// Count bytecode instructions that execute in generated code.
Expand Down Expand Up @@ -835,11 +824,6 @@ pub fn gen_single_block(
break;
}

// If we are deferring compilation for this instruction
if status == DeferCompilation {
break;
}

// For now, reset the chain depth after each instruction as only the
// first instruction in the block can concern itself with the depth.
ctx.reset_chain_depth();
Expand Down Expand Up @@ -870,24 +854,9 @@ pub fn gen_single_block(
block.set_end_idx(insn_idx);
}

// If we are deferring compilation for the current instruction
if status == DeferCompilation {
defer_compilation(&jit.block, insn_idx, &ctx, cb, ocb);

// Mark the end position of the block
let mut block = jit.block.borrow_mut();
block.set_end_addr(cb.get_write_ptr());
}



// We currently can't handle cases where the request is for a block that
// doesn't go to the next instruction.
//assert!(!jit.record_boundary_patch_point);




assert!(!jit.record_boundary_patch_point);

// If code for the block doesn't fit, fail
if cb.has_dropped_bytes() || ocb.unwrap().has_dropped_bytes() {
Expand Down Expand Up @@ -1140,7 +1109,8 @@ fn gen_opt_plus(
ocb: &mut OutlinedCb,
) -> CodegenStatus {
if !jit_at_current_insn(jit) {
return DeferCompilation;
defer_compilation(jit, ctx, asm, ocb);
return EndBlock;
}

let comptime_a = jit_peek_at_stack(jit, ctx, 1);
Expand Down Expand Up @@ -3208,47 +3178,48 @@ fn gen_opt_case_dispatch(
KeepCompiling // continue with the next instruction
}
*/

fn gen_branchif_branch(
cb: &mut CodeBlock,
asm: &mut Assembler,
target0: CodePtr,
target1: Option<CodePtr>,
shape: BranchShape,
) {
assert!(target1 != None);
match shape {
BranchShape::Next0 => {
jz_ptr(cb, target1.unwrap());
asm.jz(target1.unwrap().into());
}
BranchShape::Next1 => {
jnz_ptr(cb, target0);
asm.jnz(target0.into());
}
BranchShape::Default => {
jnz_ptr(cb, target0);
jmp_ptr(cb, target1.unwrap());
asm.jnz(target0.into());
asm.jmp(target1.unwrap().into());
}
}
}

fn gen_branchif(
jit: &mut JITState,
ctx: &mut Context,
cb: &mut CodeBlock,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
let jump_offset = jit_get_arg(jit, 0).as_i32();

// Check for interrupts, but only on backward branches that may create loops
if jump_offset < 0 {
let side_exit = get_side_exit(jit, ocb, ctx);
gen_check_ints(cb, side_exit);
gen_check_ints(asm, side_exit);
}

// Test if any bit (outside of the Qnil bit) is on
// RUBY_Qfalse /* ...0000 0000 */
// RUBY_Qnil /* ...0000 1000 */
let val_opnd = ctx.stack_pop(1);
test(cb, val_opnd, imm_opnd(!Qnil.as_i64()));
asm.test(val_opnd, Opnd::Imm(!Qnil.as_i64()));

// Get the branch target instruction offsets
let next_idx = jit_next_insn_idx(jit);
Expand All @@ -3266,7 +3237,7 @@ fn gen_branchif(
gen_branch(
jit,
ctx,
cb,
asm,
ocb,
jump_block,
ctx,
Expand All @@ -3277,7 +3248,6 @@ fn gen_branchif(

EndBlock
}
*/

fn gen_branchunless_branch(
asm: &mut Assembler,
Expand Down Expand Up @@ -3328,18 +3298,11 @@ fn gen_branchunless(
idx: jump_idx.try_into().unwrap(),
};




// TODO: port gen_branch logic
todo!("complete branchunless implementation");

/*
// Generate the branch instructions
gen_branch(
jit,
ctx,
cb,
asm,
ocb,
jump_block,
ctx,
Expand All @@ -3349,46 +3312,42 @@ fn gen_branchunless(
);

EndBlock
*/


}

/*
fn gen_branchnil_branch(
cb: &mut CodeBlock,
asm: &mut Assembler,
target0: CodePtr,
target1: Option<CodePtr>,
shape: BranchShape,
) {
match shape {
BranchShape::Next0 => jne_ptr(cb, target1.unwrap()),
BranchShape::Next1 => je_ptr(cb, target0),
BranchShape::Next0 => asm.jne(target1.unwrap().into()),
BranchShape::Next1 => asm.je(target0.into()),
BranchShape::Default => {
je_ptr(cb, target0);
jmp_ptr(cb, target1.unwrap());
asm.je(target0.into());
asm.jmp(target1.unwrap().into());
}
}
}

fn gen_branchnil(
jit: &mut JITState,
ctx: &mut Context,
cb: &mut CodeBlock,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
let jump_offset = jit_get_arg(jit, 0).as_i32();

// Check for interrupts, but only on backward branches that may create loops
if jump_offset < 0 {
let side_exit = get_side_exit(jit, ocb, ctx);
gen_check_ints(cb, side_exit);
gen_check_ints(asm, side_exit);
}

// Test if the value is Qnil
// RUBY_Qnil /* ...0000 1000 */
let val_opnd = ctx.stack_pop(1);
cmp(cb, val_opnd, uimm_opnd(Qnil.into()));
asm.cmp(val_opnd, Opnd::UImm(Qnil.into()));

// Get the branch target instruction offsets
let next_idx = jit_next_insn_idx(jit) as i32;
Expand All @@ -3406,7 +3365,7 @@ fn gen_branchnil(
gen_branch(
jit,
ctx,
cb,
asm,
ocb,
jump_block,
ctx,
Expand All @@ -3421,15 +3380,15 @@ fn gen_branchnil(
fn gen_jump(
jit: &mut JITState,
ctx: &mut Context,
cb: &mut CodeBlock,
asm: &mut Assembler,
ocb: &mut OutlinedCb,
) -> CodegenStatus {
let jump_offset = jit_get_arg(jit, 0).as_i32();

// Check for interrupts, but only on backward branches that may create loops
if jump_offset < 0 {
let side_exit = get_side_exit(jit, ocb, ctx);
gen_check_ints(cb, side_exit);
gen_check_ints(asm, side_exit);
}

// Get the branch target instruction offsets
Expand All @@ -3440,11 +3399,12 @@ fn gen_jump(
};

// Generate the jump instruction
gen_direct_jump(jit, ctx, jump_block, cb);
gen_direct_jump(jit, ctx, jump_block, asm);

EndBlock
}

/*
/// Guard that self or a stack operand has the same class as `known_klass`, using
/// `sample_instance` to speculate about the shape of the runtime value.
/// FIXNUM and on-heap integers are treated as if they have distinct classes, and
Expand Down Expand Up @@ -6067,11 +6027,11 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
YARVINSN_opt_invokebuiltin_delegate => Some(gen_opt_invokebuiltin_delegate),
YARVINSN_opt_invokebuiltin_delegate_leave => Some(gen_opt_invokebuiltin_delegate),
YARVINSN_opt_case_dispatch => Some(gen_opt_case_dispatch),
*/
YARVINSN_branchif => Some(gen_branchif),
YARVINSN_branchunless => Some(gen_branchunless),
YARVINSN_branchnil => Some(gen_branchnil),
YARVINSN_jump => Some(gen_jump),
*/

//YARVINSN_getblockparamproxy => Some(gen_getblockparamproxy),
//YARVINSN_getblockparam => Some(gen_getblockparam),
Expand Down
Loading

0 comments on commit 97bc546

Please sign in to comment.