ruby-changes:73286
From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 01:07:54 +0900 (JST)
Subject: [ruby-changes:73286] 7f4ab24f2b (master): Op::Xor for backend IR (https://github.com/Shopify/ruby/pull/397)
https://git.ruby-lang.org/ruby.git/commit/?id=7f4ab24f2b From 7f4ab24f2b99c87874a5540a55026ea5a3d43d3e Mon Sep 17 00:00:00 2001 From: Kevin Newton <kddnewton@g...> Date: Thu, 11 Aug 2022 08:32:06 -0400 Subject: Op::Xor for backend IR (https://github.com/Shopify/ruby/pull/397) --- yjit/src/asm/arm64/inst/logical_imm.rs | 16 ++++++++++++++++ yjit/src/asm/arm64/inst/logical_reg.rs | 16 ++++++++++++++++ yjit/src/asm/arm64/mod.rs | 32 ++++++++++++++++++++++++++++++++ yjit/src/backend/arm64/mod.rs | 15 ++++++++++++++- yjit/src/backend/ir.rs | 5 +++++ yjit/src/backend/x86_64/mod.rs | 6 +++++- 6 files changed, 88 insertions(+), 2 deletions(-) diff --git a/yjit/src/asm/arm64/inst/logical_imm.rs b/yjit/src/asm/arm64/inst/logical_imm.rs index 13865697f6..73eec8b37c 100644 --- a/yjit/src/asm/arm64/inst/logical_imm.rs +++ b/yjit/src/asm/arm64/inst/logical_imm.rs @@ -8,6 +8,9 @@ enum Opc { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/logical_imm.rs#L8 /// The ORR operation. Orr = 0b01, + /// The EOR operation. + Eor = 0b10, + /// The ANDS operation. Ands = 0b11 } @@ -52,6 +55,12 @@ impl LogicalImm { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/logical_imm.rs#L55 Self { rd, rn, imm, opc: Opc::Ands, sf: num_bits.into() } } + /// EOR (bitmask immediate) + /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/EOR--immediate---Bitwise-Exclusive-OR--immediate-- + pub fn eor(rd: u8, rn: u8, imm: BitmaskImmediate, num_bits: u8) -> Self { + Self { rd, rn, imm, opc: Opc::Eor, sf: num_bits.into() } + } + /// MOV (bitmask immediate) /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/MOV--bitmask-immediate---Move--bitmask-immediate---an-alias-of-ORR--immediate--?lang=en pub fn mov(rd: u8, imm: BitmaskImmediate, num_bits: u8) -> Self { @@ -115,6 +124,13 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/logical_imm.rs#L124 assert_eq!(0xf2400820, result); } + #[test] + fn test_eor() { + let inst = LogicalImm::eor(0, 1, 7.try_into().unwrap(), 64); + let result: u32 = inst.into(); + assert_eq!(0xd2400820, result); + } + #[test] fn test_mov() { let inst = LogicalImm::mov(0, 0x5555555555555555.try_into().unwrap(), 64); diff --git a/yjit/src/asm/arm64/inst/logical_reg.rs b/yjit/src/asm/arm64/inst/logical_reg.rs index 5d7954c587..83230ac5b2 100644 --- a/yjit/src/asm/arm64/inst/logical_reg.rs +++ b/yjit/src/asm/arm64/inst/logical_reg.rs @@ -25,6 +25,9 @@ enum Opc { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/logical_reg.rs#L25 /// The ORR operation. Orr = 0b01, + /// The EOR operation. + Eor = 0b10, + /// The ANDS operation. Ands = 0b11 } @@ -78,6 +81,12 @@ impl LogicalReg { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/logical_reg.rs#L81 Self { rd, rn, imm6: 0, rm, n: N::No, shift: Shift::LSL, opc: Opc::Ands, sf: num_bits.into() } } + /// EOR (shifted register) + /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/EOR--shifted-register---Bitwise-Exclusive-OR--shifted-register-- + pub fn eor(rd: u8, rn: u8, rm: u8, num_bits: u8) -> Self { + Self { rd, rn, imm6: 0, rm, n: N::No, shift: Shift::LSL, opc: Opc::Eor, sf: num_bits.into() } + } + /// MOV (register) /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/MOV--register---Move--register---an-alias-of-ORR--shifted-register--?lang=en pub fn mov(rd: u8, rm: u8, num_bits: u8) -> Self { @@ -156,6 +165,13 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/logical_reg.rs#L165 assert_eq!(0xea020020, result); } + #[test] + fn test_eor() { + let inst = LogicalReg::eor(0, 1, 2, 64); + let result: u32 = inst.into(); + assert_eq!(0xca020020, result); + } + #[test] fn test_mov() { let inst = LogicalReg::mov(0, 1, 64); diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs index 93b44dba4b..e5ba2f81ea 100644 --- a/yjit/src/asm/arm64/mod.rs +++ b/yjit/src/asm/arm64/mod.rs @@ -309,6 +309,28 @@ pub fn csel(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd, cond: u8) https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L309 cb.write_bytes(&bytes); } +/// EOR - perform a bitwise XOR of rn and rm, put the result in rd, don't update flags +pub fn eor(cb: &mut CodeBlock, rd: A64Opnd, rn: A64Opnd, rm: A64Opnd) { + let bytes: [u8; 4] = match (rd, rn, rm) { + (A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::Reg(rm)) => { + assert!( + rd.num_bits == rn.num_bits && rn.num_bits == rm.num_bits, + "All operands must be of the same size." + ); + + LogicalReg::eor(rd.reg_no, rn.reg_no, rm.reg_no, rd.num_bits).into() + }, + (A64Opnd::Reg(rd), A64Opnd::Reg(rn), A64Opnd::UImm(imm)) => { + assert!(rd.num_bits == rn.num_bits, "rd and rn must be of the same size."); + + LogicalImm::eor(rd.reg_no, rn.reg_no, imm.try_into().unwrap(), rd.num_bits).into() + }, + _ => panic!("Invalid operand combination to eor instruction."), + }; + + cb.write_bytes(&bytes); +} + /// LDADDAL - atomic add with acquire and release semantics pub fn ldaddal(cb: &mut CodeBlock, rs: A64Opnd, rt: A64Opnd, rn: A64Opnd) { let bytes: [u8; 4] = match (rs, rt, rn) { @@ -1023,6 +1045,16 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L1045 check_bytes("6a018c9a", |cb| csel(cb, X10, X11, X12, Condition::EQ)); } + #[test] + fn test_eor_register() { + check_bytes("6a010cca", |cb| eor(cb, X10, X11, X12)); + } + + #[test] + fn test_eor_immediate() { + check_bytes("6a0940d2", |cb| eor(cb, X10, X11, A64Opnd::new_uimm(7))); + } + #[test] fn test_ldaddal() { check_bytes("8b01eaf8", |cb| ldaddal(cb, X10, X11, X12)); diff --git a/yjit/src/backend/arm64/mod.rs b/yjit/src/backend/arm64/mod.rs index 440c4368c5..2cd893923a 100644 --- a/yjit/src/backend/arm64/mod.rs +++ b/yjit/src/backend/arm64/mod.rs @@ -216,7 +216,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L216 } } }, - Op::And | Op::Or => { + Op::And | Op::Or | Op::Xor => { match (opnds[0], opnds[1]) { (Opnd::Reg(_), Opnd::Reg(_)) => { asm.push_insn(insn.op, vec![opnds[0], opnds[1]], insn.target, insn.text, insn.pos_marker); @@ -615,6 +615,9 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L615 Op::Or => { orr(cb, insn.out.into(), insn.opnds[0].into(), insn.opnds[1].into()); }, + Op::Xor => { + eor(cb, insn.out.into(), insn.opnds[0].into(), insn.opnds[1].into()); + }, Op::Not => { mvn(cb, insn.out.into(), insn.opnds[0].into()); }, @@ -1084,6 +1087,16 @@ mod tests { https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/arm64/mod.rs#L1087 assert_eq!(8, cb.get_write_pos()); } + #[test] + fn test_emit_xor() { + let (mut asm, mut cb) = setup_asm(); + + let opnd = asm.xor(Opnd::Reg(X0_REG), Opnd::Reg(X1_REG)); + asm.store(Opnd::mem(64, Opnd::Reg(X2_REG), 0), opnd); + + asm.compile_with_num_regs(&mut cb, 1); + } + #[test] #[cfg(feature = "disasm")] fn test_simple_disasm() -> std::result::Result<(), capstone::Error> { diff --git a/yjit/src/backend/ir.rs b/yjit/src/backend/ir.rs index 2dfb859fe9..ef8cd5e872 100644 --- a/yjit/src/backend/ir.rs +++ b/yjit/src/backend/ir.rs @@ -63,6 +63,10 @@ pub enum Op https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L63 // binary OR operation. Or, + // This is the same as the OP_ADD instruction, except that it performs the + // binary XOR operation. + Xor, + // 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. @@ -992,6 +996,7 @@ def_push_2_opnd!(add, Op::Add); https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/ir.rs#L996 def_push_2_opnd!(sub, Op::Sub); def_push_2_opnd!(and, Op::And); def_push_2_opnd!(or, Op::Or); +def_push_2_opnd!(xor, Op::Xor); def_push_1_opnd!(not, Op::Not); def_push_2_opnd!(lshift, Op::LShift); def_push_2_opnd!(rshift, Op::RShift); diff --git a/yjit/src/backend/x86_64/mod.rs b/yjit/src/backend/x86_64/mod.rs index 417474ee68..d474c9fe59 100644 --- a/yjit/src/backend/x86_64/mod.rs +++ b/yjit/src/backend/x86_64/mod.rs @@ -139,7 +139,7 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L139 }).collect(); match insn.op { - Op::Add | Op::Sub | Op::And | Op::Cmp | Op::Or | Op::Test => { + Op::Add | Op::Sub | Op::And | Op::Cmp | Op::Or | Op::Test | Op::Xor => { let (opnd0, opnd1) = match (insn.opnds[0], insn.opnds[1]) { (Opnd::Mem(_), Opnd::Mem(_)) => { (asm.load(opnds[0]), asm.load(opnds[1])) @@ -328,6 +328,10 @@ impl Assembler https://github.com/ruby/ruby/blob/trunk/yjit/src/backend/x86_64/mod.rs#L328 or(cb, insn.opnds[0].into(), insn.opnds[1].into()); }, + Op::Xor => { + xor(cb, insn.opnds[0].into(), insn.opnds[1].into()); + }, + Op::Not => { not(cb, insn.opn (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/