ruby-changes:73131
From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:55:16 +0900 (JST)
Subject: [ruby-changes:73131] 0000984fed (master): Port over putnil, putobject, and gen_leave()
https://git.ruby-lang.org/ruby.git/commit/?id=0000984fed From 0000984fed1be885ad51845477f4e475d1b07fab Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Thu, 9 Jun 2022 16:29:55 -0400 Subject: Port over putnil, putobject, and gen_leave() * Remove x86-64 dependency from codegen.rs * Port over putnil and putobject * Port over gen_leave() * Complete port of gen_leave() * Fix bug in x86 instruction splitting --- yjit/src/asm/x86_64/mod.rs | 2 +- yjit/src/backend/ir.rs | 148 +++++++++-------------------- yjit/src/backend/x86_64/mod.rs | 34 ++++--- yjit/src/codegen.rs | 205 +++++++++++++++++++++-------------------- 4 files changed, 168 insertions(+), 221 deletions(-) diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index fdfac82f92..399c2e8c7e 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -245,7 +245,7 @@ pub const R13B: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 8, reg_type: RegType:: https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/x86_64/mod.rs#L245 pub const R14B: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 8, reg_type: RegType::GP, reg_no: 14 }); pub const R15B: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 8, reg_type: RegType::GP, reg_no: 15 }); -// C argument registers +// C argument registers on this platform pub const C_ARG_REGS: [X86Opnd; 6] = [RDI, RSI, RDX, RCX, R8, R9]; //=========================================================================== diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index 63bf85f3a0..a077eb1945 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -6,7 +6,7 @@ use std::fmt; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L6 use std::convert::From; use crate::cruby::{VALUE}; use crate::virtualmem::{CodePtr}; -use crate::asm::{CodeBlock}; +use crate::asm::{CodeBlock, uimm_num_bits, imm_num_bits}; use crate::asm::x86_64::{X86Opnd, X86Imm, X86UImm, X86Reg, X86Mem, RegType}; use crate::core::{Context, Type, TempMapping}; use crate::codegen::{JITState}; @@ -21,6 +21,9 @@ pub const EC: Opnd = _EC; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L21 pub const CFP: Opnd = _CFP; pub const SP: Opnd = _SP; +pub const C_ARG_OPNDS: [Opnd; 6] = _C_ARG_OPNDS; +pub const C_RET_OPND: Opnd = _C_RET_OPND; + /// Instruction opcodes #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Op @@ -77,6 +80,9 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L80 // Compare two operands Cmp, + // Unconditional jump which takes an address operand + JmpOpnd, + // Low-level conditional jump instructions Jbe, Je, @@ -92,110 +98,8 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L98 // C function return CRet, - /* - // The following are conditional jump instructions. They all accept as their - // first operand an EIR_LABEL_NAME, which is used as the target of the jump. - // - // The OP_JUMP_EQ instruction accepts two additional operands, to be - // compared for equality. If they're equal, then the generated code jumps to - // the target label. If they're not, then it continues on to the next - // instruction. - JumpEq, - - // The OP_JUMP_NE instruction is very similar to the OP_JUMP_EQ instruction, - // except it compares for inequality instead. - JumpNe, - - // Checks the overflow flag and conditionally jumps to the target if it is - // currently set. - JumpOvf, - - // A low-level call instruction for calling a function by a pointer. It - // accepts one operand of type EIR_IMM that should be a pointer to the - // function. Usually this is done by first casting the function to a void*, - // as in: ir_const_ptr((void *)&my_function)). - Call, - - // Calls a function by a pointer and returns an operand that contains the - // result of the function. Accepts as its operands a pointer to a function - // of type EIR_IMM (usually generated from ir_const_ptr) and a variable - // number of arguments to the function being called. - // - // This is the higher-level instruction that should be used when you want to - // call a function with arguments, as opposed to OP_CALL which is - // lower-level and just calls a function without moving arguments into - // registers for you. - CCall, - - // Returns from the function being generated immediately. This is different - // from OP_RETVAL in that it does nothing with the return value register - // (whatever is in there is what will get returned). Accepts no operands. - Ret, - - // First, moves a value into the return value register. Then, returns from - // the generated function. Accepts as its only operand the value that should - // be returned from the generated function. - RetVal, - - // A conditional move instruction that should be preceeded at some point by - // an OP_CMP instruction that would have set the requisite comparison flags. - // Accepts 2 operands, both of which are expected to be of the EIR_REG type. - // - // If the comparison indicates the left compared value is greater than or - // equal to the right compared value, then the conditional move is executed, - // otherwise we just continue on to the next instruction. - // - // This is considered a low-level instruction, and the OP_SELECT_* variants - // should be preferred if possible. - CMovGE, - - // The same as OP_CMOV_GE, except the comparison is greater than. - CMovGT, - - // The same as OP_CMOV_GE, except the comparison is less than or equal. - CMovLE, - - // The same as OP_CMOV_GE, except the comparison is less than. - CMovLT, - - // Selects between two different values based on a comparison of two other - // values. Accepts 4 operands. The first two are the basis of the - // comparison. The second two are the "then" case and the "else" case. You - // can effectively think of this instruction as a ternary operation, where - // the first two values are being compared. - // - // OP_SELECT_GE performs the described ternary using a greater than or equal - // comparison, that is if the first operand is greater than or equal to the - // second operand. - SelectGE, - - // The same as OP_SELECT_GE, except the comparison is greater than. - SelectGT, - - // The same as OP_SELECT_GE, except the comparison is less than or equal. - SelectLE, - - // The same as OP_SELECT_GE, except the comparison is less than. - SelectLT, - - // For later: - // These encode Ruby true/false semantics - // Can be used to enable op fusion of Ruby compare + branch. - // OP_JUMP_TRUE, // (opnd, target) - // OP_JUMP_FALSE, // (opnd, target) - - // For later: - // OP_GUARD_HEAP, // (opnd, target) - // OP_GUARD_IMM, // (opnd, target) - // OP_GUARD_FIXNUM, // (opnd, target) - - // For later: - // OP_COUNTER_INC, (counter_name) - - // For later: - // OP_LEA, - // OP_TEST, - */ + // Trigger a debugger breakpoint + Breakpoint, } // Memory location @@ -256,6 +160,12 @@ impl Opnd https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L160 } } +impl From<usize> for Opnd { + fn from(value: usize) -> Self { + Opnd::UImm(value.try_into().unwrap()) + } +} + impl From<VALUE> for Opnd { fn from(value: VALUE) -> Self { let VALUE(uimm) = value; @@ -522,6 +432,18 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L432 let opnd1 = asm.load(opnds[1]); asm.push_insn(op, vec![opnds[0], opnd1], None); }, + + [Opnd::Mem(_), Opnd::UImm(val)] => { + if uimm_num_bits(*val) > 32 { + let opnd1 = asm.load(opnds[1]); + asm.push_insn(op, vec![opnds[0], opnd1], None); + } + else + { + asm.push_insn(op, opnds, target); + } + }, + _ => { asm.push_insn(op, opnds, target); } @@ -609,7 +531,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L531 // C return values need to be mapped to the C return register if op == Op::CCall { - out_reg = Opnd::Reg(take_reg(&mut pool, ®s, &RET_REG)) + out_reg = Opnd::Reg(take_reg(&mut pool, ®s, &C_RET_REG)) } // If this instruction's first operand maps to a register and @@ -689,6 +611,18 @@ macro_rules! def_push_jcc { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L611 }; } +macro_rules! def_push_0_opnd_no_out { + ($op_name:ident, $opcode:expr) => { + impl Assembler + { + pub fn $op_name(&mut self) + { + self.push_insn($opcode, vec![], None); + } + } + }; +} + macro_rules! def_push_1_opnd { ($op_name:ident, $opcode:expr) => { impl Assembler @@ -737,6 +671,7 @@ macro_rules! def_push_2_opnd_no_out { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L671 }; } +def_push_1_opnd_no_out!(jmp_opnd, Op::JmpOpnd); def_push_jcc!(je, Op::Je); def_push_jcc!(jbe, Op::Jbe); def_push_jcc!(jnz, Op::Jnz); @@ -752,6 +687,7 @@ def_push_2_opnd_no_out!(store, Op::Store); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L687 def_push_2_opnd_no_out!(mov, Op::Mov); def_push_2_opnd_no_out!(cmp, Op::Cmp); def_push_2_opnd_no_out!(test, Op::Test); +def_push_0_opnd_no_out!(breakpoint, Op::Breakpoint); // NOTE: these methods are temporary and will likely m (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/