From e064deca760d65865a85002c0308e94e05e2bd0c Mon Sep 17 00:00:00 2001 From: satotake Date: Fri, 19 Nov 2021 16:50:41 +0000 Subject: [PATCH] add x86_64 Int neq support for gen_dev --- compiler/gen_dev/src/generic64/aarch64.rs | 10 ++++ compiler/gen_dev/src/generic64/mod.rs | 26 +++++++++ compiler/gen_dev/src/generic64/x86_64.rs | 71 +++++++++++++++++++++++ compiler/gen_dev/src/lib.rs | 26 +++++++++ compiler/test_gen/src/gen_num.rs | 2 +- 5 files changed, 134 insertions(+), 1 deletion(-) diff --git a/compiler/gen_dev/src/generic64/aarch64.rs b/compiler/gen_dev/src/generic64/aarch64.rs index 908940bf6f..d344be324c 100644 --- a/compiler/gen_dev/src/generic64/aarch64.rs +++ b/compiler/gen_dev/src/generic64/aarch64.rs @@ -490,6 +490,16 @@ impl Assembler for AArch64Assembler { unimplemented!("registers equality not implemented yet for AArch64"); } + #[inline(always)] + fn neq_reg64_reg64_reg64( + _buf: &mut Vec<'_, u8>, + _dst: AArch64GeneralReg, + _src1: AArch64GeneralReg, + _src2: AArch64GeneralReg, + ) { + unimplemented!("registers non-equality not implemented yet for AArch64"); + } + #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { ret_reg64(buf, AArch64GeneralReg::LR) diff --git a/compiler/gen_dev/src/generic64/mod.rs b/compiler/gen_dev/src/generic64/mod.rs index 7fdb8fe688..dbffdcf8f4 100644 --- a/compiler/gen_dev/src/generic64/mod.rs +++ b/compiler/gen_dev/src/generic64/mod.rs @@ -172,6 +172,13 @@ pub trait Assembler { src2: GeneralReg, ); + fn neq_reg64_reg64_reg64( + buf: &mut Vec<'_, u8>, + dst: GeneralReg, + src1: GeneralReg, + src2: GeneralReg, + ); + fn ret(buf: &mut Vec<'_, u8>); } @@ -842,6 +849,25 @@ impl< } } + fn build_neq( + &mut self, + dst: &Symbol, + src1: &Symbol, + src2: &Symbol, + arg_layout: &Layout<'a>, + ) -> Result<(), String> { + match arg_layout { + Layout::Builtin(Builtin::Int64) => { + let dst_reg = self.claim_general_reg(dst)?; + let src1_reg = self.load_to_general_reg(src1)?; + let src2_reg = self.load_to_general_reg(src2)?; + ASM::neq_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg); + Ok(()) + } + x => Err(format!("NumNeq: layout, {:?}, not implemented yet", x)), + } + } + fn create_struct( &mut self, sym: &Symbol, diff --git a/compiler/gen_dev/src/generic64/x86_64.rs b/compiler/gen_dev/src/generic64/x86_64.rs index f79b89c1ad..01518eff84 100644 --- a/compiler/gen_dev/src/generic64/x86_64.rs +++ b/compiler/gen_dev/src/generic64/x86_64.rs @@ -1096,6 +1096,17 @@ impl Assembler for X86_64Assembler { sete_reg64(buf, dst); } + #[inline(always)] + fn neq_reg64_reg64_reg64( + buf: &mut Vec<'_, u8>, + dst: X86_64GeneralReg, + src1: X86_64GeneralReg, + src2: X86_64GeneralReg, + ) { + cmp_reg64_reg64(buf, src1, src2); + setne_reg64(buf, dst); + } + #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { ret(buf); @@ -1475,6 +1486,26 @@ fn sete_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) { and_reg64_imm8(buf, reg, 1); } +/// `SETNE r/m64` -> Set byte if not equal (ZF=0). +#[inline(always)] +fn setne_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) { + // Follow `sete_reg64` implementation. + // Change 94 => 95 + buf.reserve(7); + + let reg_mod = reg as u8 % 8; + use X86_64GeneralReg::*; + match reg { + RAX | RCX | RDX | RBX => buf.extend(&[0x0F, 0x95, 0xC0 + reg_mod]), + RSP | RBP | RSI | RDI => buf.extend(&[REX, 0x0F, 0x95, 0xC0 + reg_mod]), + R8 | R9 | R10 | R11 | R12 | R13 | R14 | R15 => { + buf.extend(&[REX + 1, 0x0F, 0x95, 0xC0 + reg_mod]) + } + } + + and_reg64_imm8(buf, reg, 1); +} + /// `RET` -> Near return to calling procedure. #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { @@ -2074,6 +2105,46 @@ mod tests { } } + #[test] + // follow test_sete_reg64 + // refer it + fn test_setne_reg64() { + let arena = bumpalo::Bump::new(); + let mut buf = bumpalo::vec![in &arena]; + + let (reg, expected) = ( + X86_64GeneralReg::RAX, + [ + 0x0F, 0x95, 0xC0, // SETNE al ; + 0x48, 0x83, 0xE0, 0x01, + ], + ); + buf.clear(); + setne_reg64(&mut buf, reg); + assert_eq!(expected, &buf[..]); + + for (reg, expected) in &[ + ( + X86_64GeneralReg::RSP, + [ + // SETNE spl; + 0x40, 0x0F, 0x95, 0xC4, 0x48, 0x83, 0xE4, 0x01, + ], + ), + ( + X86_64GeneralReg::R15, + [ + // SETNE r15b; + 0x41, 0x0F, 0x95, 0xC7, 0x49, 0x83, 0xE7, 0x01, + ], + ), + ] { + buf.clear(); + setne_reg64(&mut buf, *reg); + assert_eq!(expected, &buf[..]); + } + } + #[test] fn test_ret() { let arena = bumpalo::Bump::new(); diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 185e5d991b..e8dff1d967 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -416,6 +416,23 @@ where ); self.build_eq(sym, &args[0], &args[1], &arg_layouts[0]) } + LowLevel::NotEq => { + debug_assert_eq!( + 2, + args.len(), + "NotEq: expected to have exactly two argument" + ); + debug_assert_eq!( + arg_layouts[0], arg_layouts[1], + "NotEq: expected all arguments of to have the same layout" + ); + debug_assert_eq!( + Layout::Builtin(Builtin::Int1), + *ret_layout, + "NotEq: expected to have return layout of type I1" + ); + self.build_neq(sym, &args[0], &args[1], &arg_layouts[0]) + } LowLevel::NumRound => self.build_fn_call( sym, bitcode::NUM_ROUND[FloatWidth::F64].to_string(), @@ -497,6 +514,15 @@ where arg_layout: &Layout<'a>, ) -> Result<(), String>; + /// build_neq stores the result of `src1 != src2` into dst. + fn build_neq( + &mut self, + dst: &Symbol, + src1: &Symbol, + src2: &Symbol, + arg_layout: &Layout<'a>, + ) -> Result<(), String>; + /// literal_map gets the map from symbol to literal, used for lazy loading and literal folding. fn literal_map(&mut self) -> &mut MutMap>; diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index 149473cef5..df451c4898 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -713,7 +713,7 @@ fn gen_int_eq() { } #[test] -#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] fn gen_int_neq() { assert_evals_to!( indoc!(