ruby-changes:73116
From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:53:31 +0900 (JST)
Subject: [ruby-changes:73116] 7c83a904a4 (master): Implement gc offset logic
https://git.ruby-lang.org/ruby.git/commit/?id=7c83a904a4 From 7c83a904a49a8ba3a1b78474a6d51a7a32178a4a Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Wed, 25 May 2022 15:05:54 -0400 Subject: Implement gc offset logic --- yjit/src/asm/x86_64/mod.rs | 2 +- yjit/src/backend/ir.rs | 68 +++++++++++++++++++++++++++--------------- yjit/src/backend/x86_64/mod.rs | 30 ++++++++++++++----- yjit/src/codegen.rs | 62 +++++++++++++++++++++++++++++++------- yjit/src/core.rs | 14 ++++----- 5 files changed, 126 insertions(+), 50 deletions(-) diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index 1f3dfd2e24..1ada5ffbb7 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -214,7 +214,7 @@ pub const AX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType: https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/x86_64/mod.rs#L214 pub const CX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 1 }); pub const DX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 2 }); pub const BX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 3 }); -pub const SP: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 4 }); +//pub const SP: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 4 }); pub const BP: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 5 }); pub const SI: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 6 }); pub const DI: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 16, reg_type: RegType::GP, reg_no: 7 }); diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index 63a0478984..a578564afb 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -9,6 +9,7 @@ use crate::virtualmem::{CodePtr}; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L9 use crate::asm::{CodeBlock}; use crate::asm::x86_64::{X86Opnd, X86Imm, X86UImm, X86Reg, X86Mem, RegType}; use crate::core::{Context, Type, TempMapping}; +use crate::codegen::{JITState}; #[cfg(target_arch = "x86_64")] use crate::backend::x86_64::*; @@ -16,6 +17,10 @@ use crate::backend::x86_64::*; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L17 //#[cfg(target_arch = "aarch64")] //use crate::backend:aarch64::* +pub const EC: Opnd = _EC; +pub const CFP: Opnd = _CFP; +pub const SP: Opnd = _SP; + /// Instruction opcodes #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Op @@ -63,6 +68,9 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L68 // A low-level mov instruction. It accepts two operands. Mov, + // Load effective address + Lea, + // Bitwise AND test instruction Test, @@ -315,7 +323,7 @@ pub struct Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L323 /// Parallel vec with insns /// Index of the last insn using the output of this insn - pub(super) live_ranges: Vec<usize> + pub(super) live_ranges: Vec<usize>, } impl Assembler @@ -323,7 +331,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L331 pub fn new() -> Assembler { Assembler { insns: Vec::default(), - live_ranges: Vec::default() + live_ranges: Vec::default(), } } @@ -608,10 +616,10 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L616 } /// Compile the instructions down to machine code - pub fn compile(self, cb: &mut CodeBlock) + pub fn compile(self, jit: &mut JITState, cb: &mut CodeBlock) { let scratch_regs = Self::get_scratch_regs(); - self.compile_with_regs(cb, scratch_regs); + self.compile_with_regs(jit, cb, scratch_regs); } } @@ -682,6 +690,7 @@ def_push_2_opnd!(sub, Op::Sub); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L690 def_push_2_opnd!(and, Op::And); def_push_1_opnd!(load, Op::Load); def_push_2_opnd_no_out!(mov, Op::Mov); +def_push_2_opnd_no_out!(lea, Op::Lea); def_push_2_opnd_no_out!(cmp, Op::Cmp); def_push_2_opnd_no_out!(test, Op::Test); @@ -690,6 +699,10 @@ def_push_2_opnd_no_out!(test, Op::Test); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L699 // They are just wrappers to convert from X86Opnd into the IR Opnd type impl Context { + pub fn ir_sp_opnd(&mut self, idx: isize) -> Opnd { + self.sp_opnd(idx).into() + } + pub fn ir_stack_opnd(&mut self, idx: i32) -> Opnd { self.stack_opnd(idx).into() } @@ -801,62 +814,71 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L814 assert_eq!(result.insns[5].out, Opnd::Reg(regs[0])); } + fn setup_asm(num_regs: usize) -> (Assembler, JITState, CodeBlock, Vec<Reg>) { + let blockid = BlockId { + iseq: std::ptr::null(), + idx: 0, + }; + let block = Block::new(blockid, &Context::default()); + + let mut regs = Assembler::get_scratch_regs(); + + return ( + Assembler::new(), + JITState::new(&block), + CodeBlock::new_dummy(1024), + regs.drain(0..num_regs).collect() + ); + } + // Test full codegen pipeline #[test] fn test_compile() { - let mut asm = Assembler::new(); - let mut cb = CodeBlock::new_dummy(1024); - let regs = Assembler::get_scratch_regs(); + let (mut asm, mut jit, mut cb, regs) = setup_asm(1); let out = asm.add(Opnd::Reg(regs[0]), Opnd::UImm(2)); asm.add(out, Opnd::UImm(2)); - asm.compile(&mut cb); + asm.compile(&mut jit, &mut cb); } // Test memory-to-memory move #[test] fn test_mov_mem2mem() { - let mut asm = Assembler::new(); - let mut cb = CodeBlock::new_dummy(1024); - let regs = Assembler::get_scratch_regs(); + let (mut asm, mut jit, mut cb, regs) = setup_asm(1); asm.comment("check that comments work too"); asm.mov(Opnd::mem(64, SP, 0), Opnd::mem(64, SP, 8)); - asm.compile_with_regs(&mut cb, vec![regs[0]]); + asm.compile_with_regs(&mut jit, &mut cb, regs); } // Test load of register into new register #[test] fn test_load_reg() { - let mut asm = Assembler::new(); - let mut cb = CodeBlock::new_dummy(1024); - let regs = Assembler::get_scratch_regs(); + let (mut asm, mut jit, mut cb, regs) = setup_asm(1); let out = asm.load(SP); asm.mov(Opnd::mem(64, SP, 0), out); - asm.compile_with_regs(&mut cb, vec![regs[0]]); + asm.compile_with_regs(&mut jit, &mut cb, regs); } // Multiple registers needed and register reuse #[test] fn test_reuse_reg() { - let mut asm = Assembler::new(); - let mut cb = CodeBlock::new_dummy(1024); - let regs = Assembler::get_scratch_regs(); + let (mut asm, mut jit, mut cb, regs) = setup_asm(2); let v0 = asm.add(Opnd::mem(64, SP, 0), Opnd::UImm(1)); let v1 = asm.add(Opnd::mem(64, SP, 8), Opnd::UImm(1)); let v2 = asm.add(v0, Opnd::UImm(1)); asm.add(v0, v2); - asm.compile_with_regs(&mut cb, vec![regs[0], regs[1]]); + asm.compile_with_regs(&mut jit, &mut cb, regs); } #[test] @@ -866,15 +888,13 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L888 { } - let mut asm = Assembler::new(); - let mut cb = CodeBlock::new_dummy(1024); - let regs = Assembler::get_scratch_regs(); + let (mut asm, mut jit, mut cb, regs) = setup_asm(2); asm.ccall( dummy_c_fun as *const u8, vec![Opnd::mem(64, SP, 0), Opnd::UImm(1)] ); - asm.compile_with_regs(&mut cb, vec![regs[0], regs[1]]); + asm.compile_with_regs(&mut jit, &mut cb, regs); } } diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index f6a901f77d..f6ebcc5643 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -4,15 +4,17 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L4 use crate::asm::{CodeBlock}; use crate::asm::x86_64::*; +use crate::codegen::{JITState}; +use crate::cruby::*; use crate::backend::ir::*; // Use the x86 register type for this platform pub type Reg = X86Reg; // Callee-saved registers -pub const CFP: Opnd = Opnd::Reg(R13_REG); -pub const EC: Opnd = Opnd::Reg(R12_REG); -pub const SP: Opnd = Opnd::Reg(RBX_REG); +pub const _CFP: Opnd = Opnd::Reg(R13_REG); +pub const _EC: Opnd = Opnd::Reg(R12_REG); +pub const _SP: Opnd = Opnd::Reg(RBX_REG); // C return value register on this platform pub const RET_REG: Reg = RAX_REG; @@ -91,7 +93,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L93 } // Emit platform-specific machine code - pub fn x86_emit(&self, cb: &mut CodeBlock) + pub fn x86_emit(&mut self, jit: &mut JITState, cb: &mut CodeBlock) { // For each instruction for insn in &self.insns { @@ -107,8 +109,22 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L109 add(cb, insn.opnds[0].into(), insn.opnds[1].into()) }, - Op::Load => mov(cb, insn.out.into(), insn.opnds[0].into()), + //TODO: //Store + + Op::Load => { + mov(cb, insn.out.into(), insn.opnds[0].into()); + + // If the value being loaded is a heapp object + if let Opnd::Value(val) = insn.opnds[0] { + if !val.special_const_p() { + // The pointe (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/