summaryrefslogtreecommitdiff
path: root/yjit
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2022-08-11 08:32:06 -0400
committerTakashi Kokubun <takashikkbn@gmail.com>2022-08-29 08:47:10 -0700
commit7f4ab24f2b99c87874a5540a55026ea5a3d43d3e (patch)
tree9430ef0ce2828c5f4621d2f4f2ce4735612f9ad6 /yjit
parent4d811d7a2b92d110e3e70cb77e5f499acfa7112a (diff)
Op::Xor for backend IR (https://github.com/Shopify/ruby/pull/397)
Diffstat (limited to 'yjit')
-rw-r--r--yjit/src/asm/arm64/inst/logical_imm.rs16
-rw-r--r--yjit/src/asm/arm64/inst/logical_reg.rs16
-rw-r--r--yjit/src/asm/arm64/mod.rs32
-rw-r--r--yjit/src/backend/arm64/mod.rs15
-rw-r--r--yjit/src/backend/ir.rs5
-rw-r--r--yjit/src/backend/x86_64/mod.rs6
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 {
/// The ORR operation.
Orr = 0b01,
+ /// The EOR operation.
+ Eor = 0b10,
+
/// The ANDS operation.
Ands = 0b11
}
@@ -52,6 +55,12 @@ impl LogicalImm {
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 {
@@ -116,6 +125,13 @@ mod tests {
}
#[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);
let result: u32 = inst.into();
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 {
/// The ORR operation.
Orr = 0b01,
+ /// The EOR operation.
+ Eor = 0b10,
+
/// The ANDS operation.
Ands = 0b11
}
@@ -78,6 +81,12 @@ impl LogicalReg {
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 {
@@ -157,6 +166,13 @@ mod tests {
}
#[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);
let result: u32 = inst.into();
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)
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) {
@@ -1024,6 +1046,16 @@ mod tests {
}
#[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
}
}
},
- 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
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());
},
@@ -1085,6 +1088,16 @@ mod tests {
}
#[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> {
// Test drive Capstone with simple input
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
// 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);
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
}).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
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.opnds[0].into())
},