ruby-changes:73212
From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 01:02:57 +0900 (JST)
Subject: [ruby-changes:73212] 70e117d512 (master): Fixes (https://github.com/Shopify/ruby/pull/336)
https://git.ruby-lang.org/ruby.git/commit/?id=70e117d512 From 70e117d512636465d8dc2094b22dd6535602050a Mon Sep 17 00:00:00 2001 From: Kevin Newton <kddnewton@g...> Date: Thu, 21 Jul 2022 16:25:21 -0400 Subject: Fixes (https://github.com/Shopify/ruby/pull/336) * Fix bitmask encoding to u32 * Fix splitting for Op::And to account for bitmask immediate --- yjit/src/asm/arm64/arg/bitmask_imm.rs | 9 +++- yjit/src/backend/arm64/mod.rs | 98 +++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 46 deletions(-) diff --git a/yjit/src/asm/arm64/arg/bitmask_imm.rs b/yjit/src/asm/arm64/arg/bitmask_imm.rs index 847b735eaa..220a7d697e 100644 --- a/yjit/src/asm/arm64/arg/bitmask_imm.rs +++ b/yjit/src/asm/arm64/arg/bitmask_imm.rs @@ -136,7 +136,7 @@ impl From<BitmaskImmediate> for u32 { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/arg/bitmask_imm.rs#L136 fn from(bitmask: BitmaskImmediate) -> Self { 0 | (((bitmask.n as u32) & 1) << 12) - | (bitmask.immr << 6) as u32 + | ((bitmask.immr as u32) << 6) | bitmask.imms as u32 } } @@ -152,6 +152,13 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/arg/bitmask_imm.rs#L152 }); } + #[test] + fn test_negative() { + let bitmask: BitmaskImmediate = (-9_i64 as u64).try_into().unwrap(); + let encoded: u32 = bitmask.into(); + assert_eq!(7998, encoded); + } + #[test] fn test_size_2_minimum() { let bitmask = BitmaskImmediate::try_from(0x5555555555555555); diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index b1f4d63d0f..d3db3877dc 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -81,6 +81,30 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L81 /// have no memory operands. fn arm64_split(mut self) -> Assembler { + fn load_bitmask_immediate(asm: &mut Assembler, opnd: Opnd) -> Opnd { + match opnd { + Opnd::Reg(_) | Opnd::InsnOut { .. } => opnd, + Opnd::Mem(_) => asm.load(opnd), + Opnd::Imm(imm) => { + if imm <= 0 { + asm.load(opnd) + } else if BitmaskImmediate::try_from(imm as u64).is_ok() { + Opnd::UImm(imm as u64) + } else { + asm.load(opnd) + } + }, + Opnd::UImm(uimm) => { + if BitmaskImmediate::try_from(uimm).is_ok() { + opnd + } else { + asm.load(opnd) + } + }, + Opnd::None | Opnd::Value(_) => unreachable!() + } + } + self.forward_pass(|asm, index, op, opnds, target, text, pos_marker| { // Load all Value operands into registers that aren't already a part // of Load instructions. @@ -96,7 +120,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L120 }; match op { - Op::Add | Op::And | Op::Sub => { + Op::Add | Op::Sub => { // Check if one of the operands is a register. If it is, // then we'll make that the first operand. match (opnds[0], opnds[1]) { @@ -115,6 +139,23 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L139 } } }, + Op::And => { + match (opnds[0], opnds[1]) { + (Opnd::Reg(_), Opnd::Reg(_)) => { + asm.and(opnds[0], opnds[1]); + }, + (reg_opnd @ Opnd::Reg(_), other_opnd) | + (other_opnd, reg_opnd @ Opnd::Reg(_)) => { + let opnd1 = load_bitmask_immediate(asm, other_opnd); + asm.and(reg_opnd, opnd1); + }, + _ => { + let opnd0 = asm.load(opnds[0]); + let opnd1 = load_bitmask_immediate(asm, opnds[1]); + asm.and(opnd0, opnd1); + } + } + }, Op::CCall => { assert!(opnds.len() < C_ARG_REGS.len()); @@ -188,29 +229,16 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L229 }; }, Op::Mov => { - // The value that is being moved must be either a register - // or an immediate that can be encoded as a bitmask - // immediate. Otherwise, we'll need to split the move into - // multiple instructions. - let value = match opnds[1] { - Opnd::Reg(_) | Opnd::InsnOut { .. } => opnds[1], - Opnd::Mem(_) | Opnd::Imm(_) => asm.load(opnds[1]), - Opnd::UImm(uimm) => { - if let Ok(encoded) = BitmaskImmediate::try_from(uimm) { - if let Opnd::Mem(_) = opnds[0] { - // If the first operand is a memory operand, - // we're going to transform this into a - // store instruction, so we'll need to load - // this anyway. - asm.load(opnds[1]) - } else { - opnds[1] - } - } else { - asm.load(opnds[1]) - } - }, - _ => unreachable!() + let value = match (opnds[0], opnds[1]) { + // If the first operand is a memory operand, we're going + // to transform this into a store instruction, so we'll + // need to load this anyway. + (Opnd::Mem(_), Opnd::UImm(_)) => asm.load(opnds[1]), + // The value that is being moved must be either a + // register or an immediate that can be encoded as a + // bitmask immediate. Otherwise, we'll need to split the + // move into multiple instructions. + _ => load_bitmask_immediate(asm, opnds[1]) }; // If we're attempting to load into a memory operand, then @@ -253,27 +281,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L281 // unsigned immediate that can be encoded as a bitmask // immediate. If it's not one of those, we'll need to load // it first. - let opnd1 = match opnds[1] { - Opnd::Reg(_) | Opnd::InsnOut { .. } => opnds[1], - Opnd::Mem(_) => asm.load(opnds[1]), - Opnd::Imm(imm) => { - if imm <= 0 { - asm.load(opnds[1]) - } else if BitmaskImmediate::try_from(imm as u64).is_ok() { - Opnd::UImm(imm as u64) - } else { - asm.load(opnds[1]) - } - }, - Opnd::UImm(uimm) => { - if BitmaskImmediate::try_from(uimm).is_ok() { - opnds[1] - } else { - asm.load(opnds[1]) - } - }, - Opnd::None | Opnd::Value(_) => unreachable!() - }; + let opnd1 = load_bitmask_immediate(asm, opnds[1]); asm.test(opnd0, opnd1); }, -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/