[前][次][番号順一覧][スレッド一覧]

ruby-changes:73231

From: Maxime <ko1@a...>
Date: Tue, 30 Aug 2022 01:03:28 +0900 (JST)
Subject: [ruby-changes:73231] 45da697450 (master): Push first pass at SSA IR sketch

https://git.ruby-lang.org/ruby.git/commit/?id=45da697450

From 45da6974500070872a2b20fafe2b50bc1dce1052 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Mon, 1 Aug 2022 16:12:51 -0400
Subject: Push first pass at SSA IR sketch

---
 yjit/src/backend/ir.rs     |    1 -
 yjit/src/backend/ir_ssa.rs | 1165 ++++++++++++++++++++++++++++++++++++++++++++
 yjit/src/backend/mod.rs    |    1 +
 yjit/src/lib.rs            |    3 -
 4 files changed, 1166 insertions(+), 4 deletions(-)
 create mode 100644 yjit/src/backend/ir_ssa.rs

diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs
index ce82161693..45d4378eb4 100644
--- a/yjit/src/backend/ir.rs
+++ b/yjit/src/backend/ir.rs
@@ -8,7 +8,6 @@ use crate::cruby::{VALUE}; https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L8
 use crate::virtualmem::{CodePtr};
 use crate::asm::{CodeBlock, uimm_num_bits, imm_num_bits};
 use crate::core::{Context, Type, TempMapping};
-use crate::codegen::{JITState};
 
 #[cfg(target_arch = "x86_64")]
 use crate::backend::x86_64::*;
diff --git a/yjit/src/backend/ir_ssa.rs b/yjit/src/backend/ir_ssa.rs
new file mode 100644
index 0000000000..49974b90b7
--- /dev/null
+++ b/yjit/src/backend/ir_ssa.rs
@@ -0,0 +1,1165 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir_ssa.rs#L1
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_imports)]
+
+use std::fmt;
+use std::convert::From;
+use crate::cruby::{VALUE};
+use crate::virtualmem::{CodePtr};
+use crate::asm::{CodeBlock, uimm_num_bits, imm_num_bits};
+use crate::core::{Context, Type, TempMapping};
+
+/*
+#[cfg(target_arch = "x86_64")]
+use crate::backend::x86_64::*;
+
+#[cfg(target_arch = "aarch64")]
+use crate::backend::arm64::*;
+
+
+pub const EC: Opnd = _EC;
+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;
+*/
+
+
+
+// Dummy reg struct
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub struct Reg
+{
+    reg_no: u8,
+    num_bits: u8,
+}
+
+
+
+
+
+
+
+/// 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,
+
+    // Mark a position in the generated code
+    PosMarker,
+
+    // Bake a string directly into the instruction stream.
+    BakeString,
+
+    // 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,
+
+    // A low-level instruction that loads a value into a register and
+    // sign-extends it to a 64-bit value.
+    LoadSExt,
+
+    // Low-level instruction to store a value to memory.
+    Store,
+
+    // Load effective address
+    Lea,
+
+    // Load effective address relative to the current instruction pointer. It
+    // accepts a single signed immediate operand.
+    LeaLabel,
+
+    // A low-level mov instruction. It accepts two operands.
+    Mov,
+
+    // Bitwise AND test instruction
+    Test,
+
+    // Compare two operands
+    Cmp,
+
+    // Unconditional jump to a branch target
+    Jmp,
+
+    // Unconditional jump which takes a reg/mem address operand
+    JmpOpnd,
+
+    // Low-level conditional jump instructions
+    Jbe,
+    Je,
+    Jne,
+    Jz,
+    Jnz,
+    Jo,
+
+    // Conditional select instructions
+    CSelZ,
+    CSelNZ,
+    CSelE,
+    CSelNE,
+    CSelL,
+    CSelLE,
+    CSelG,
+    CSelGE,
+
+    // Push and pop registers to/from the C stack
+    CPush,
+    CPop,
+    CPopInto,
+
+    // Push and pop all of the caller-save registers and the flags to/from the C
+    // stack
+    CPushAll,
+    CPopAll,
+
+    // C function call with N arguments (variadic)
+    CCall,
+
+    // C function return
+    CRet,
+
+    // Atomically increment a counter
+    // Input: memory operand, increment value
+    // Produces no output
+    IncrCounter,
+
+    // Trigger a debugger breakpoint
+    Breakpoint,
+
+    /// Set up the frame stack as necessary per the architecture.
+    FrameSetup,
+
+    /// Tear down the frame stack as necessary per the architecture.
+    FrameTeardown,
+
+    /// Take a specific register. Signal the register allocator to not use it.
+    LiveReg,
+}
+
+/// Instruction idx in an assembler
+/// This is used like a pointer
+type InsnIdx = u32;
+
+/// Instruction operand index
+type OpndIdx = u32;
+
+// Memory operand base
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum MemBase
+{
+    Reg(u8),
+    InsnOut(InsnIdx),
+}
+
+// Memory location
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct Mem
+{
+    // Base register number or instruction index
+    pub(super) base: MemBase,
+
+    // Offset relative to the base pointer
+    pub(super) disp: i32,
+
+    // Size in bits
+    pub(super) num_bits: u8,
+}
+
+impl fmt::Debug for Mem {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "Mem{}[{:?}", self.num_bits, self.base)?;
+        if self.disp != 0 {
+            let sign = if self.disp > 0 { '+' } else { '-' };
+            write!(fmt, " {sign} {}", self.disp)?;
+        }
+
+        write!(fmt, "]")
+    }
+}
+
+/// Operand to an IR instruction
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum Opnd
+{
+    None,               // For insns with no output
+
+    // Immediate Ruby value, may be GC'd, movable
+    Value(VALUE),
+
+    // Output of a preceding instruction in this block
+    InsnOut{ idx: InsnIdx, num_bits: u8 },
+
+    // Low-level operands, for lowering
+    Imm(i64),           // Raw signed immediate
+    UImm(u64),          // Raw unsigned immediate
+    Mem(Mem),           // Memory location
+    Reg(Reg),           // Machine register
+}
+
+impl fmt::Debug for Opnd {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        use Opnd::*;
+        match self {
+            Self::None => write!(fmt, "None"),
+            Value(val) => write!(fmt, "Value({val:?})"),
+            InsnOut { idx, num_bits } => write!(fmt, "Out{num_bits}({idx})"),
+            Imm(signed) => write!(fmt, "{signed:x}_i64"),
+            UImm(unsigned) => write!(fmt, "{unsigned:x}_u64"),
+            // Say Mem and Reg only once
+            Mem(mem) => write!(fmt, "{mem:?}"),
+            Reg(reg) => write!(fmt, "{reg:?}"),
+        }
+    }
+}
+
+impl Opnd
+{
+    /// Convenience constructor for memory operands
+    pub fn mem(num_bits: u8, base: Opnd, disp: i32) -> Self {
+        match base {
+            Opnd::Reg(base_reg) => {
+                assert!(base_reg.num_bits == 64);
+                Opnd::Mem(Mem {
+                    base: MemBase::Reg(base_reg.reg_no),
+                    disp: disp,
+                    num_bits: num_bits,
+                })
+            },
+
+            Opnd::InsnOut{idx, num_bits } => {
+                assert!(num_bits == 64);
+                Opnd::Mem(Mem {
+                    base: MemBase::InsnOut(idx),
+                    disp: disp,
+                    num_bits: num_bits,
+                })
+            },
+
+            _ => unreachable!("memory operand with non-register base")
+        }
+    }
+
+    /// Constructor for constant pointer operand
+    pub fn const_ptr(ptr: *const u8) -> Self {
+        Opnd::UImm(ptr as u64)
+    }
+
+    pub fn is_some(&self) -> bool {
+        match *self {
+            Opnd::None => false,
+            _ => true,
+        }
+    }
+
+    /// Unwrap a register operand
+    pub fn unwrap_reg(&self) -> Reg {
+        match self {
+            Opnd::Reg(reg) => *reg,
+            _ => unreachable!("trying to unwrap {:?} into reg", self)
+        }
+    }
+
+    /// Get the size in bits for register/memory operands
+    pub fn rm_num_bits(&self) -> u8 {
+        match *self {
+            Opnd::Reg(reg) => reg.num_bits,
+            Opnd::Mem(mem) => mem.num_bits,
+            Opnd::InsnOut{ num_bits, .. } => num_bits,
+            _ => unreachable!()
+        }
+    }
+}
+
+impl From<usize> for Opnd {
+    fn from(value: usize) -> Self {
+        Opnd::UImm(value.try_into().unwrap())
+    }
+}
+
+impl From<u64> for Opnd {
+    fn from(value: u64) -> Self {
+        Opnd::UImm(value.try_into().unwrap())
+    }
+}
+
+impl From<i64> for Opnd {
+    fn from(value: i64) -> Self {
+        Opnd::Imm(value)
+    }
+}
+
+impl From<i32> for Opnd {
+    fn from(value: i32) -> Self {
+        Opnd::Imm(value.try_into().unwrap())
+    }
+}
+
+impl From<u32> for Opnd {
+    fn from(value: u32) -> Self {
+        Opnd::UImm(value as u64)
+    }
+}
+
+impl From<VALUE> for Opnd {
+    fn from(value: VALUE) -> Self {
+        let VALUE(uimm) = value;
+        Opnd::UImm(uimm as u64)
+    }
+}
+
+/// Branch target (something that we can jump to)
+/// for branch instructions
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum Target
+{ (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]