ruby-changes:73556
From: Takashi <ko1@a...>
Date: Wed, 14 Sep 2022 23:28:08 +0900 (JST)
Subject: [ruby-changes:73556] 8f37e9c918 (master): YJIT: Add Opnd#with_num_bits to use only 8 bits (#6359)
https://git.ruby-lang.org/ruby.git/commit/?id=8f37e9c918 From 8f37e9c91814357f79911e208ef4d0d56dfa9433 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun <takashikkbn@g...> Date: Wed, 14 Sep 2022 23:27:52 +0900 Subject: YJIT: Add Opnd#with_num_bits to use only 8 bits (#6359) * YJIT: Add Opnd#sub_opnd to use only 8 bits * Add with_num_bits and let arm64_split use it * Add another assertion to with_num_bits * Use only with_num_bits --- yjit/src/asm/arm64/inst/load_store.rs | 14 ++++++++++++++ yjit/src/asm/arm64/mod.rs | 16 ++++++++++++++++ yjit/src/asm/arm64/opnd.rs | 6 ++---- yjit/src/asm/x86_64/mod.rs | 5 +---- yjit/src/backend/arm64/mod.rs | 15 +++++++++++++-- yjit/src/backend/ir.rs | 18 ++++++++++++++---- yjit/src/codegen.rs | 3 +-- 7 files changed, 61 insertions(+), 16 deletions(-) diff --git a/yjit/src/asm/arm64/inst/load_store.rs b/yjit/src/asm/arm64/inst/load_store.rs index ea42f2d17f..e877c6de77 100644 --- a/yjit/src/asm/arm64/inst/load_store.rs +++ b/yjit/src/asm/arm64/inst/load_store.rs @@ -2,6 +2,7 @@ use super::super::arg::truncate_imm; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load_store.rs#L2 /// The size of the operands being operated on. enum Size { + Size8 = 0b00, Size32 = 0b10, Size64 = 0b11, } @@ -81,6 +82,12 @@ impl LoadStore { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load_store.rs#L82 Self { rt, rn, idx: Index::None, imm9, opc: Opc::LDR, size: num_bits.into() } } + /// LDURB (load register, byte, unscaled) + /// https://developer.arm.com/documentation/ddi0596/2021-12/Base-Instructions/LDURB--Load-Register-Byte--unscaled--?lang=en + pub fn ldurb(rt: u8, rn: u8, imm9: i16) -> Self { + Self { rt, rn, idx: Index::None, imm9, opc: Opc::LDR, size: Size::Size8 } + } + /// 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 { @@ -157,6 +164,13 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/load_store.rs#L164 assert_eq!(0xf8400020, result); } + #[test] + fn test_ldurb() { + let inst = LoadStore::ldurb(0, 1, 0); + let result: u32 = inst.into(); + assert_eq!(0x38400020, result); + } + #[test] fn test_ldur_with_imm() { let inst = LoadStore::ldur(0, 1, 123, 64); diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs index 420151c6d1..d97452a045 100644 --- a/yjit/src/asm/arm64/mod.rs +++ b/yjit/src/asm/arm64/mod.rs @@ -507,6 +507,22 @@ pub fn ldur(cb: &mut CodeBlock, rt: A64Opnd, rn: A64Opnd) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L507 cb.write_bytes(&bytes); } +/// LDURB - load a byte from memory, zero-extend it, and write it to a register +pub fn ldurb(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!(rt.num_bits == 8, "Expected registers to have size 8"); + assert!(mem_disp_fits_bits(rn.disp), "Expected displacement to be 9 bits or less"); + + LoadStore::ldurb(rt.reg_no, rn.base_reg_no, rn.disp as i16).into() + }, + _ => panic!("Invalid operands for LDURB") + }; + + 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) { diff --git a/yjit/src/asm/arm64/opnd.rs b/yjit/src/asm/arm64/opnd.rs index c89481fb03..52b2a84637 100644 --- a/yjit/src/asm/arm64/opnd.rs +++ b/yjit/src/asm/arm64/opnd.rs @@ -12,10 +12,8 @@ pub struct A64Reg https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/opnd.rs#L12 } impl A64Reg { - pub fn sub_reg(&self, num_bits: u8) -> Self { - assert!(num_bits == 32 || num_bits == 64); - assert!(num_bits <= self.num_bits); - + pub fn with_num_bits(&self, num_bits: u8) -> Self { + assert!(num_bits == 8 || num_bits == 16 || num_bits == 32 || num_bits == 64); Self { num_bits, reg_no: self.reg_no } } } diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index 3f865b82a5..d310e3bf12 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -89,16 +89,13 @@ pub enum X86Opnd https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/x86_64/mod.rs#L89 } impl X86Reg { - pub fn sub_reg(&self, num_bits: u8) -> Self { + pub fn with_num_bits(&self, num_bits: u8) -> Self { assert!( num_bits == 8 || num_bits == 16 || num_bits == 32 || num_bits == 64 ); - - assert!(num_bits <= self.num_bits); - Self { num_bits, reg_type: self.reg_type, diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index 446332788a..9d19c65114 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -140,7 +140,14 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L140 Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd, Opnd::Mem(_) => { let split_opnd = split_memory_address(asm, opnd); - asm.load(split_opnd) + let out_opnd = asm.load(split_opnd); + // Many Arm insns support only 32-bit or 64-bit operands. asm.load with fewer + // bits zero-extends the value, so it's safe to recognize it as a 32-bit value. + if out_opnd.rm_num_bits() < 32 { + out_opnd.with_num_bits(32).unwrap() + } else { + out_opnd + } }, _ => asm.load(opnd) } @@ -747,7 +754,11 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L754 emit_load_value(cb, out.into(), imm as u64); }, Opnd::Mem(_) => { - ldur(cb, out.into(), opnd.into()); + match opnd.rm_num_bits() { + 64 | 32 => ldur(cb, out.into(), opnd.into()), + 8 => ldurb(cb, out.into(), opnd.into()), + num_bits => panic!("unexpected num_bits: {}", num_bits) + }; }, Opnd::Value(value) => { // We dont need to check if it's a special const diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index ee6499ff64..609ca8eaf4 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -151,6 +151,16 @@ impl Opnd https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L151 } } + pub fn with_num_bits(&self, num_bits: u8) -> Option<Opnd> { + assert!(num_bits == 8 || num_bits == 16 || num_bits == 32 || num_bits == 64); + match *self { + Opnd::Reg(reg) => Some(Opnd::Reg(reg.with_num_bits(num_bits))), + Opnd::Mem(Mem { base, disp, .. }) => Some(Opnd::Mem(Mem { base, disp, num_bits })), + Opnd::InsnOut { idx, .. } => Some(Opnd::InsnOut { idx, num_bits }), + _ => None, + } + } + /// Get the size in bits for register/memory operands. pub fn rm_num_bits(&self) -> u8 { self.num_bits().unwrap() @@ -1052,21 +1062,21 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L1062 // output operand on this instruction because the live range // extends beyond the index of the instruction. let out = insn.out_opnd_mut().unwrap(); - *out = Opnd::Reg(out_reg.unwrap().sub_reg(out_num_bits)); + *out = Opnd::Reg(out_reg.unwrap().with_num_bits(out_num_bits)); } // Replace InsnOut operands by their corresponding register let mut opnd_iter = insn.opnd_iter_mut(); while let Some(opnd) = opnd_iter.next() { match *opnd { - Opnd::InsnOut { idx, .. } => { - *opnd = *asm.insns[idx].out_opnd().unwrap(); + Opnd::InsnOut { idx, num_bits } => { + *opnd = (*asm.insns[idx].out_opnd().unwrap()).with_num_bits(num_bits).unwrap(); }, Opnd::Mem(Mem { base: MemBase::InsnOut(idx), disp, num_bits }) => { let base = MemBase::Reg(asm.insns[idx].out_opnd().unwrap().unwrap_reg().reg_no); *opnd = Opnd::Mem(Mem { base, disp, num_bits }); } - _ => {}, + _ => {}, } } diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 1c48a1b040..ca9ec655d1 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -3477,8 +3477,7 @@ fn jit_guard_known_klass( https://github.com/ruby/ruby/blob/trunk/yjit/src/codegen.rs#L3477 asm.comment("guard object is static symbol"); assert!(RUBY_SPECIAL_SHIFT == 8); - let flag_bits = asm.and(obj_opnd, Opnd::UImm(0xf)); - asm.cmp(flag_bits, Opnd::UImm(RUBY_SYMBOL_FLAG as u64)); + asm.cmp(obj_opnd.with_num_bits(8).unwrap(), Opnd::UImm(RUBY_SYMBOL_FLAG as u64)); jit_chain_guard(JCC_JNE, jit, ctx, asm, ocb, max_chain_depth, side_exit); ctx.upgrade_opnd_type(insn_opnd, Type::ImmSymbol); } -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/