ruby-changes:73106
From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 00:51:26 +0900 (JST)
Subject: [ruby-changes:73106] e9cc17dcc9 (master): Start work on platform-specific codegen
https://git.ruby-lang.org/ruby.git/commit/?id=e9cc17dcc9 From e9cc17dcc9a365d59330b8c37baeafed5d75a519 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Tue, 17 May 2022 17:31:36 -0400 Subject: Start work on platform-specific codegen --- yjit/src/asm/x86_64/mod.rs | 51 ++- yjit/src/backend/ir.rs | 709 ++++++++++++++++++++++++++++++++++++++++ yjit/src/backend/mod.rs | 3 + yjit/src/backend/x86_64/mod.rs | 55 ++++ yjit/src/codegen.rs | 1 - yjit/src/ir.rs | 711 ----------------------------------------- yjit/src/lib.rs | 2 +- 7 files changed, 802 insertions(+), 730 deletions(-) create mode 100644 yjit/src/backend/ir.rs create mode 100644 yjit/src/backend/mod.rs create mode 100644 yjit/src/backend/x86_64/mod.rs delete mode 100644 yjit/src/ir.rs diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index b4ef2e4bf9..0a930ecf60 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -34,7 +34,7 @@ pub enum RegType https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/x86_64/mod.rs#L34 IP, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct X86Reg { // Size in bits @@ -157,22 +157,39 @@ const RBP_REG_NO: u8 = 5; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/x86_64/mod.rs#L157 const R12_REG_NO: u8 = 12; const R13_REG_NO: u8 = 13; -pub const RAX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: RAX_REG_NO }); -pub const RCX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 1 }); -pub const RDX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 2 }); -pub const RBX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 3 }); -pub const RSP: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: RSP_REG_NO }); -pub const RBP: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: RBP_REG_NO }); -pub const RSI: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 6 }); -pub const RDI: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 7 }); -pub const R8: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 8 }); -pub const R9: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 9 }); -pub const R10: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 10 }); -pub const R11: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 11 }); -pub const R12: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: R12_REG_NO }); -pub const R13: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: R13_REG_NO }); -pub const R14: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 14 }); -pub const R15: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 15 }); +pub const RAX_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: RAX_REG_NO }; +pub const RCX_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 1 }; +pub const RDX_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 2 }; +pub const RBX_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 3 }; +pub const RSP_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: RSP_REG_NO }; +pub const RBP_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: RBP_REG_NO }; +pub const RSI_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 6 }; +pub const RDI_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 7 }; +pub const R8_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 8 }; +pub const R9_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 9 }; +pub const R10_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 10 }; +pub const R11_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 11 }; +pub const R12_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: R12_REG_NO }; +pub const R13_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: R13_REG_NO }; +pub const R14_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 14 }; +pub const R15_REG: X86Reg = X86Reg { num_bits: 64, reg_type: RegType::GP, reg_no: 15 }; + +pub const RAX: X86Opnd = X86Opnd::Reg(RAX_REG); +pub const RCX: X86Opnd = X86Opnd::Reg(RCX_REG); +pub const RDX: X86Opnd = X86Opnd::Reg(RDX_REG); +pub const RBX: X86Opnd = X86Opnd::Reg(RBX_REG); +pub const RSP: X86Opnd = X86Opnd::Reg(RSP_REG); +pub const RBP: X86Opnd = X86Opnd::Reg(RBP_REG); +pub const RSI: X86Opnd = X86Opnd::Reg(RSI_REG); +pub const RDI: X86Opnd = X86Opnd::Reg(RDI_REG); +pub const R8: X86Opnd = X86Opnd::Reg(R8_REG); +pub const R9: X86Opnd = X86Opnd::Reg(R9_REG); +pub const R10: X86Opnd = X86Opnd::Reg(R10_REG); +pub const R11: X86Opnd = X86Opnd::Reg(R11_REG); +pub const R12: X86Opnd = X86Opnd::Reg(R12_REG); +pub const R13: X86Opnd = X86Opnd::Reg(R13_REG); +pub const R14: X86Opnd = X86Opnd::Reg(R14_REG); +pub const R15: X86Opnd = X86Opnd::Reg(R15_REG); // 32-bit GP registers pub const EAX: X86Opnd = X86Opnd::Reg(X86Reg { num_bits: 32, reg_type: RegType::GP, reg_no: 0 }); diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs new file mode 100644 index 0000000000..9cff4aeac9 --- /dev/null +++ b/yjit/src/backend/ir.rs @@ -0,0 +1,709 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L1 +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unused_imports)] + +use std::convert::From; +use crate::cruby::{VALUE}; +use crate::virtualmem::{CodePtr}; +use crate::asm::{CodeBlock}; +use crate::asm::x86_64::{X86Opnd, X86Imm, X86UImm, X86Reg, X86Mem, RegType}; +use crate::core::{Context, Type, TempMapping}; + +#[cfg(target_arch = "x86_64")] +use crate::backend::x86_64::*; + +//#[cfg(target_arch = "aarch64")] +//use crate::backend:aarch64::* + +/// Instruction opcodes +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Op +{ + // Add a comment into the IR at the point that this instruction is added. + // It won't have any impact on that actual compiled code. + Comment, + + // Add a label into the IR at the point that this instruction is added. + Label, + + // Add two operands together, and return the result as a new operand. This + // operand can then be used as the operand on another instruction. It + // accepts two operands, which can be of any type + // + // Under the hood when allocating registers, the IR will determine the most + // efficient way to get these values into memory. For example, if both + // operands are immediates, then it will load the first one into a register + // first with a mov instruction and then add them together. If one of them + // is a register, however, it will just perform a single add instruction. + Add, + + // This is the same as the OP_ADD instruction, except for subtraction. + Sub, + + // This is the same as the OP_ADD instruction, except that it performs the + // binary AND operation. + And, + + // Perform the NOT operation on an individual operand, and return the result + // as a new operand. This operand can then be used as the operand on another + // instruction. + Not, + + // + // Low-level instructions + // + + // A low-level instruction that loads a value into a register. + Load, + + // Low-level instruction to store a value to memory. + Store, + + // A low-level mov instruction. It accepts two operands. + Mov, + + // Bitwise AND test instruction + Test, + + // Compare two operands + Cmp, + + // Low-level conditional jump instructions + Jnz, + Jbe, + + /* + // 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. (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/