YJIT: Fix getconstant exits after opt_ltlt fusion (#10903)
Co-authored-by: Alan Wu <alansi.xingwu@shopify.com>
This commit is contained in:
parent
a8c1ef6a60
commit
a2147eb694
@ -4813,6 +4813,15 @@ assert_equal [0x80000000000, 'a+', :ok].inspect, %q{
|
|||||||
tests
|
tests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# test integer left shift fusion followed by opt_getconstant_path
|
||||||
|
assert_equal '33', %q{
|
||||||
|
def test(a)
|
||||||
|
(a << 5) | (Object; a)
|
||||||
|
end
|
||||||
|
|
||||||
|
test(1)
|
||||||
|
}
|
||||||
|
|
||||||
# test String#stebyte with arguments that need conversion
|
# test String#stebyte with arguments that need conversion
|
||||||
assert_equal "abc", %q{
|
assert_equal "abc", %q{
|
||||||
str = +"a00"
|
str = +"a00"
|
||||||
|
@ -30,7 +30,6 @@ pub use crate::virtualmem::CodePtr;
|
|||||||
/// Status returned by code generation functions
|
/// Status returned by code generation functions
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
enum CodegenStatus {
|
enum CodegenStatus {
|
||||||
SkipNextInsn,
|
|
||||||
KeepCompiling,
|
KeepCompiling,
|
||||||
EndBlock,
|
EndBlock,
|
||||||
}
|
}
|
||||||
@ -197,6 +196,13 @@ impl JITState {
|
|||||||
self.insn_idx + insn_len(self.get_opcode()) as u16
|
self.insn_idx + insn_len(self.get_opcode()) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the index of the next instruction of the next instruction
|
||||||
|
fn next_next_insn_idx(&self) -> u16 {
|
||||||
|
let next_pc = unsafe { rb_iseq_pc_at_idx(self.iseq, self.next_insn_idx().into()) };
|
||||||
|
let next_opcode: usize = unsafe { rb_iseq_opcode_at_pc(self.iseq, next_pc) }.try_into().unwrap();
|
||||||
|
self.next_insn_idx() + insn_len(next_opcode) as u16
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we are compiling the instruction at the stub PC
|
// Check if we are compiling the instruction at the stub PC
|
||||||
// Meaning we are compiling the instruction that is next to execute
|
// Meaning we are compiling the instruction that is next to execute
|
||||||
pub fn at_current_insn(&self) -> bool {
|
pub fn at_current_insn(&self) -> bool {
|
||||||
@ -1098,7 +1104,16 @@ fn jump_to_next_insn(
|
|||||||
jit: &mut JITState,
|
jit: &mut JITState,
|
||||||
asm: &mut Assembler,
|
asm: &mut Assembler,
|
||||||
ocb: &mut OutlinedCb,
|
ocb: &mut OutlinedCb,
|
||||||
) -> Option<()> {
|
) -> Option<CodegenStatus> {
|
||||||
|
end_block_with_jump(jit, asm, ocb, jit.next_insn_idx())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_block_with_jump(
|
||||||
|
jit: &mut JITState,
|
||||||
|
asm: &mut Assembler,
|
||||||
|
ocb: &mut OutlinedCb,
|
||||||
|
continuation_insn_idx: u16,
|
||||||
|
) -> Option<CodegenStatus> {
|
||||||
// Reset the depth since in current usages we only ever jump to
|
// Reset the depth since in current usages we only ever jump to
|
||||||
// chain_depth > 0 from the same instruction.
|
// chain_depth > 0 from the same instruction.
|
||||||
let mut reset_depth = asm.ctx;
|
let mut reset_depth = asm.ctx;
|
||||||
@ -1106,20 +1121,20 @@ fn jump_to_next_insn(
|
|||||||
|
|
||||||
let jump_block = BlockId {
|
let jump_block = BlockId {
|
||||||
iseq: jit.iseq,
|
iseq: jit.iseq,
|
||||||
idx: jit.next_insn_idx(),
|
idx: continuation_insn_idx,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We are at the end of the current instruction. Record the boundary.
|
// We are at the end of the current instruction. Record the boundary.
|
||||||
if jit.record_boundary_patch_point {
|
if jit.record_boundary_patch_point {
|
||||||
jit.record_boundary_patch_point = false;
|
jit.record_boundary_patch_point = false;
|
||||||
let exit_pc = unsafe { jit.pc.offset(insn_len(jit.opcode).try_into().unwrap()) };
|
let exit_pc = unsafe { rb_iseq_pc_at_idx(jit.iseq, continuation_insn_idx.into())};
|
||||||
let exit_pos = gen_outlined_exit(exit_pc, &reset_depth, ocb);
|
let exit_pos = gen_outlined_exit(exit_pc, &reset_depth, ocb);
|
||||||
record_global_inval_patch(asm, exit_pos?);
|
record_global_inval_patch(asm, exit_pos?);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the jump instruction
|
// Generate the jump instruction
|
||||||
gen_direct_jump(jit, &reset_depth, jump_block, asm);
|
gen_direct_jump(jit, &reset_depth, jump_block, asm);
|
||||||
Some(())
|
Some(EndBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile a sequence of bytecode instructions for a given basic block version.
|
// Compile a sequence of bytecode instructions for a given basic block version.
|
||||||
@ -1283,13 +1298,6 @@ pub fn gen_single_block(
|
|||||||
// Move to the next instruction to compile
|
// Move to the next instruction to compile
|
||||||
insn_idx += insn_len(opcode) as u16;
|
insn_idx += insn_len(opcode) as u16;
|
||||||
|
|
||||||
// Move past next instruction when instructed
|
|
||||||
if status == Some(SkipNextInsn) {
|
|
||||||
let next_pc = unsafe { rb_iseq_pc_at_idx(iseq, insn_idx.into()) };
|
|
||||||
let next_opcode: usize = unsafe { rb_iseq_opcode_at_pc(iseq, next_pc) }.try_into().unwrap();
|
|
||||||
insn_idx += insn_len(next_opcode) as u16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the instruction terminates this block
|
// If the instruction terminates this block
|
||||||
if status == Some(EndBlock) {
|
if status == Some(EndBlock) {
|
||||||
break;
|
break;
|
||||||
@ -1519,7 +1527,7 @@ fn fuse_putobject_opt_ltlt(
|
|||||||
|
|
||||||
asm.stack_pop(1);
|
asm.stack_pop(1);
|
||||||
fixnum_left_shift_body(asm, lhs, shift_amt as u64);
|
fixnum_left_shift_body(asm, lhs, shift_amt as u64);
|
||||||
return Some(SkipNextInsn);
|
return end_block_with_jump(jit, asm, ocb, jit.next_next_insn_idx());
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user