ruby-changes:73299
From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 01:08:04 +0900 (JST)
Subject: [ruby-changes:73299] be730cdae5 (master): AArch64 Ruby immediates (https://github.com/Shopify/ruby/pull/400)
https://git.ruby-lang.org/ruby.git/commit/?id=be730cdae5 From be730cdae5ac54a5ffd167983c3dffe50a055901 Mon Sep 17 00:00:00 2001 From: Kevin Newton <kddnewton@g...> Date: Thu, 11 Aug 2022 15:46:13 -0400 Subject: AArch64 Ruby immediates (https://github.com/Shopify/ruby/pull/400) --- yjit/src/backend/arm64/mod.rs | 66 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index 2cd893923a..64136bfdd2 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -187,16 +187,25 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L187 let mut iterator = self.into_draining_iter(); while let Some((index, insn)) = iterator.next_mapped() { - let opnds = match insn.op { - Op::Load => insn.opnds, - _ => insn.opnds.into_iter().map(|opnd| { - if let Opnd::Value(_) = opnd { - asm.load(opnd) - } else { - opnd - } - }).collect() - }; + // Here we're going to map the operands of the instruction to load + // any Opnd::Value operands into registers if they are heap objects + // such that only the Op::Load instruction needs to handle that + // case. If the values aren't heap objects then we'll treat them as + // if they were just unsigned integer. + let opnds: Vec<Opnd> = insn.opnds.into_iter().map(|opnd| { + match opnd { + Opnd::Value(value) => { + if value.special_const_p() { + Opnd::UImm(value.as_u64()) + } else if insn.op == Op::Load { + opnd + } else { + asm.load(opnd) + } + }, + _ => opnd + } + }).collect(); match insn.op { Op::Add => { @@ -652,6 +661,11 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L661 ldur(cb, insn.out.into(), insn.opnds[0].into()); }, Opnd::Value(value) => { + // We dont need to check if it's a special const + // here because we only allow these operands to hit + // this point if they're not a special const. + assert!(!value.special_const_p()); + // This assumes only load instructions can contain // references to GC'd Value operands. If the value // being loaded is a heap object, we'll report that @@ -660,10 +674,8 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L674 b(cb, A64Opnd::new_imm(1 + (SIZEOF_VALUE as i64) / 4)); cb.write_bytes(&value.as_u64().to_le_bytes()); - if !value.special_const_p() { - let ptr_offset: u32 = (cb.get_write_pos() as u32) - (SIZEOF_VALUE as u32); - gc_offsets.push(ptr_offset); - } + let ptr_offset: u32 = (cb.get_write_pos() as u32) - (SIZEOF_VALUE as u32); + gc_offsets.push(ptr_offset); }, Opnd::None => { unreachable!("Attempted to load from None operand"); @@ -985,6 +997,32 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L997 assert_eq!(16, cb.get_write_pos()); } + #[test] + fn test_emit_load_value_immediate() { + let (mut asm, mut cb) = setup_asm(); + + let opnd = asm.load(Opnd::Value(Qnil)); + asm.store(Opnd::mem(64, SP, 0), opnd); + asm.compile_with_num_regs(&mut cb, 1); + + // Assert that only two instructions were written since the value is an + // immediate. + assert_eq!(8, cb.get_write_pos()); + } + + #[test] + fn test_emit_load_value_non_immediate() { + let (mut asm, mut cb) = setup_asm(); + + let opnd = asm.load(Opnd::Value(VALUE(0xCAFECAFECAFE0000))); + asm.store(Opnd::mem(64, SP, 0), opnd); + asm.compile_with_num_regs(&mut cb, 1); + + // Assert that five instructions were written since the value is not an + // immediate and needs to be loaded into a register. + assert_eq!(20, cb.get_write_pos()); + } + #[test] fn test_emit_or() { let (mut asm, mut cb) = setup_asm(); -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/