ruby-changes:73193
From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 01:00:04 +0900 (JST)
Subject: [ruby-changes:73193] 0da253e72c (master): Port print_int to the new backend (https://github.com/Shopify/ruby/pull/321)
https://git.ruby-lang.org/ruby.git/commit/?id=0da253e72c From 0da253e72cc80c1dbf8517f5217b59a64ec0f44e Mon Sep 17 00:00:00 2001 From: Kevin Newton <kddnewton@g...> Date: Fri, 15 Jul 2022 16:14:55 -0400 Subject: Port print_int to the new backend (https://github.com/Shopify/ruby/pull/321) * Port print_int to the new backend * Tests for print_int and print_str --- yjit/src/asm/arm64/inst/load.rs | 42 +++++++++++---- yjit/src/asm/arm64/inst/mod.rs | 2 + yjit/src/asm/arm64/inst/sbfm.rs | 77 ++++++++++++++++++++++++++++ yjit/src/asm/arm64/mod.rs | 40 +++++++++++++++ yjit/src/asm/arm64/opnd.rs | 64 +++++++++++------------ yjit/src/backend/arm64/mod.rs | 28 ++++++++++ yjit/src/backend/ir.rs | 5 ++ yjit/src/backend/x86_64/mod.rs | 4 ++ yjit/src/utils.rs | 110 +++++++++++++++++++++++----------------- 9 files changed, 284 insertions(+), 88 deletions(-) create mode 100644 yjit/src/asm/arm64/inst/sbfm.rs diff --git a/yjit/src/asm/arm64/inst/load.rs b/yjit/src/asm/arm64/inst/load.rs index 727dad52f7..b64a6a96ac 100644 --- a/yjit/src/asm/arm64/inst/load.rs +++ b/yjit/src/asm/arm64/inst/load.rs @@ -4,6 +4,12 @@ enum Size { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load.rs#L4 Size64 = 0b11, } +/// The operation to perform for this instruction. +enum Opc { + LDUR = 0b01, + LDURSW = 0b10 +} + /// A convenience function so that we can convert the number of bits of an /// register operand directly into an Sf enum variant. impl From<u8> for Size { @@ -22,8 +28,8 @@ impl From<u8> for Size { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load.rs#L28 /// LDUR /// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+ /// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 | -/// | 1 1 1 0 0 0 0 1 0 0 0 | -/// | size. imm9.......................... rn.............. rt.............. | +/// | 1 1 1 0 0 0 0 0 0 | +/// | size. opc.. imm9.......................... rn.............. rt.............. | /// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+ /// pub struct Load { @@ -36,6 +42,9 @@ pub struct Load { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load.rs#L42 /// The optional signed immediate byte offset from the base register. imm9: i16, + /// The operation to perform for this instruction. + opc: Opc, + /// The size of the operands being operated on. size: Size } @@ -44,12 +53,13 @@ impl Load { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load.rs#L53 /// LDUR (load register, unscaled) /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDUR--Load-Register--unscaled--?lang=en pub fn ldur(rt: u8, rn: u8, imm9: i16, num_bits: u8) -> Self { - Self { - rt, - rn, - imm9, - size: num_bits.into() - } + Self { rt, rn, imm9, opc: Opc::LDUR, size: num_bits.into() } + } + + /// LDURSW (load register, unscaled, signed) + /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDURSW--Load-Register-Signed-Word--unscaled--?lang=en + pub fn ldursw(rt: u8, rn: u8, imm9: i16) -> Self { + Self { rt, rn, imm9, opc: Opc::LDURSW, size: Size::Size32 } } } @@ -65,7 +75,7 @@ impl From<Load> for u32 { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load.rs#L75 | ((inst.size as u32) << 30) | (0b11 << 28) | (FAMILY << 25) - | (1 << 22) + | ((inst.opc as u32) << 22) | (imm9 << 12) | ((inst.rn as u32) << 5) | (inst.rt as u32) @@ -97,4 +107,18 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load.rs#L107 let result: u32 = inst.into(); assert_eq!(0xf847b020, result); } + + #[test] + fn test_ldursw() { + let inst = Load::ldursw(0, 1, 0); + let result: u32 = inst.into(); + assert_eq!(0xb8800020, result); + } + + #[test] + fn test_ldursw_with_imm() { + let inst = Load::ldursw(0, 1, 123); + let result: u32 = inst.into(); + assert_eq!(0xb887b020, result); + } } diff --git a/yjit/src/asm/arm64/inst/mod.rs b/yjit/src/asm/arm64/inst/mod.rs index 752ee64aa3..5d4d252d93 100644 --- a/yjit/src/asm/arm64/inst/mod.rs +++ b/yjit/src/asm/arm64/inst/mod.rs @@ -15,6 +15,7 @@ mod logical_reg; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L15 mod mov; mod nop; mod pc_rel; +mod sbfm; mod shift_imm; mod store; mod sys_reg; @@ -33,6 +34,7 @@ pub use logical_reg::LogicalReg; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/mod.rs#L34 pub use mov::Mov; pub use nop::Nop; pub use pc_rel::PCRelative; +pub use sbfm::SBFM; pub use shift_imm::ShiftImm; pub use store::Store; pub use sys_reg::SysReg; diff --git a/yjit/src/asm/arm64/inst/sbfm.rs b/yjit/src/asm/arm64/inst/sbfm.rs new file mode 100644 index 0000000000..4fbb567ed0 --- /dev/null +++ b/yjit/src/asm/arm64/inst/sbfm.rs @@ -0,0 +1,77 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/sbfm.rs#L1 +use super::super::arg::Sf; + +/// The struct that represents an A64 signed bitfield move instruction that can +/// be encoded. +/// +/// SBFM +/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+ +/// | 31 30 29 28 | 27 26 25 24 | 23 22 21 20 | 19 18 17 16 | 15 14 13 12 | 11 10 09 08 | 07 06 05 04 | 03 02 01 00 | +/// | 0 0 1 0 0 1 1 0 | +/// | sf N immr............... imms............... rn.............. rd.............. | +/// +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+ +/// +pub struct SBFM { + /// The number for the general-purpose register to load the value into. + rd: u8, + + /// The number for the general-purpose register to copy from. + rn: u8, + + /// The leftmost bit number to be moved from the source. + imms: u8, + + // The right rotate amount. + immr: u8, + + /// Whether or not this is a 64-bit operation. + n: bool, + + /// The size of this operation. + sf: Sf +} + +impl SBFM { + /// SXTW + /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/SXTW--Sign-Extend-Word--an-alias-of-SBFM-?lang=en + pub fn sxtw(rd: u8, rn: u8) -> Self { + Self { rd, rn, immr: 0, imms: 31, n: true, sf: Sf::Sf64 } + } +} + +/// https://developer.arm.com/documentation/ddi0602/2022-03/Index-by-Encoding/Data-Processing----Immediate?lang=en#bitfield +const FAMILY: u32 = 0b1001; + +impl From<SBFM> for u32 { + /// Convert an instruction into a 32-bit value. + fn from(inst: SBFM) -> Self { + 0 + | ((inst.sf as u32) << 31) + | (FAMILY << 25) + | (1 << 24) + | ((inst.n as u32) << 22) + | ((inst.immr as u32) << 16) + | ((inst.imms as u32) << 10) + | ((inst.rn as u32) << 5) + | inst.rd as u32 + } +} + +impl From<SBFM> for [u8; 4] { + /// Convert an instruction into a 4 byte array. + fn from(inst: SBFM) -> [u8; 4] { + let result: u32 = inst.into(); + result.to_le_bytes() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sxtw() { + let inst = SBFM::sxtw(0, 1); + let result: u32 = inst.into(); + assert_eq!(0x93407c20, result); + } +} diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs index ca69b33d9e..6eebccaa61 100644 --- a/yjit/src/asm/arm64/mod.rs +++ b/yjit/src/asm/arm64/mod.rs @@ -321,6 +321,21 @@ pub fn ldur(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L321 cb.write_bytes(&bytes); } +/// LDURSW - load a 32-bit memory address into a register and sign-extend it +pub fn ldursw(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) { + let bytes: [u8; 4] = match (rt, rn) { + (A64Opnd::Reg(rt), A64Opnd::Mem(rn)) => { + assert!(rt.num_bits == rn.num_bits, "Expected registers to be the same size"); + assert!(imm_fits_bits(rn.disp.into(), 9), "Expected displacement to be 9 bits or less"); + + Load::ldursw(rt.reg_no, rn.base_reg_no, rn.disp as i16).into() + }, + _ => panic!("Invalid operand combination to ldursw instruction.") + }; + + cb.write_bytes(&bytes); +} + /// LSL - logical shift left a register by an immediate pub fn lsl(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, shift: A64Opnd) { let bytes: [u8; 4] = match (rd, rn, shift) { @@ -558,6 +573,21 @@ pub fn subs(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L573 cb.write_bytes(&bytes); } +/// SXTW - sign extend a 32-bit register into a 64-bit register +pub fn sxtw(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd) { + let bytes: [u8; 4] = match (rd, rn) { + (A64Opnd::Reg(rd), A64Opnd::Reg(rn)) => { + assert_eq!(rd.num_bits, 64, "rd must be 64-bits wide."); + assert_eq!(rn.num_bits, 32, "rn must be 32-bits wide."); + + SBFM::sxtw(rd.reg_no, rn.reg_no).into() + }, + _ => panic!("Invalid operand combination to sxtw instruction."), + }; + + cb.write_bytes(&bytes); +} + /// RET - unconditionally return to a location in a register, defaults to X30 pub fn ret(cb: &mu (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/