diff --git a/compiler/gen_dev/src/generic64/aarch64.rs b/compiler/gen_dev/src/generic64/aarch64.rs index d344be324c..890995c726 100644 --- a/compiler/gen_dev/src/generic64/aarch64.rs +++ b/compiler/gen_dev/src/generic64/aarch64.rs @@ -500,6 +500,16 @@ impl Assembler for AArch64Assembler { unimplemented!("registers non-equality not implemented yet for AArch64"); } + #[inline(always)] + fn lt_reg64_reg64_reg64( + _buf: &mut Vec<'_, u8>, + _dst: AArch64GeneralReg, + _src1: AArch64GeneralReg, + _src2: AArch64GeneralReg, + ) { + unimplemented!("registers less than 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 dbffdcf8f4..b3936857b9 100644 --- a/compiler/gen_dev/src/generic64/mod.rs +++ b/compiler/gen_dev/src/generic64/mod.rs @@ -179,6 +179,13 @@ pub trait Assembler { src2: GeneralReg, ); + fn lt_reg64_reg64_reg64( + buf: &mut Vec<'_, u8>, + dst: GeneralReg, + src1: GeneralReg, + src2: GeneralReg, + ); + fn ret(buf: &mut Vec<'_, u8>); } @@ -868,6 +875,25 @@ impl< } } + fn build_num_lt( + &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::lt_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg); + Ok(()) + } + x => Err(format!("NumLt: 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 b9af105e3c..33aa59d2c4 100644 --- a/compiler/gen_dev/src/generic64/x86_64.rs +++ b/compiler/gen_dev/src/generic64/x86_64.rs @@ -1107,6 +1107,17 @@ impl Assembler for X86_64Assembler { setne_reg64(buf, dst); } + #[inline(always)] + fn lt_reg64_reg64_reg64( + buf: &mut Vec<'_, u8>, + dst: X86_64GeneralReg, + src1: X86_64GeneralReg, + src2: X86_64GeneralReg, + ) { + cmp_reg64_reg64(buf, src1, src2); + setl_reg64(buf, dst); + } + #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { ret(buf); @@ -1498,6 +1509,12 @@ fn setne_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) { set_reg64_help(buf, reg, 0x95); } +/// `SETL r/m64` -> Set byte if less (SF=ΜΈ OF). +#[inline(always)] +fn setl_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) { + set_reg64_help(buf, reg, 0x9c); +} + /// `RET` -> Near return to calling procedure. #[inline(always)] fn ret(buf: &mut Vec<'_, u8>) { @@ -2082,7 +2099,7 @@ mod tests { } #[test] - fn test_sete_reg64() { + fn test_set_reg64_help() { let arena = bumpalo::Bump::new(); let mut buf = bumpalo::vec![in &arena]; @@ -2095,7 +2112,7 @@ mod tests { ], ); buf.clear(); - sete_reg64(&mut buf, reg); + set_reg64_help(&mut buf, reg, 0x94); // sete_reg64 assert_eq!(expected, &buf[..]); // tests for 8 bytes in the output buffer @@ -2120,47 +2137,7 @@ mod tests { ), ] { buf.clear(); - sete_reg64(&mut buf, *reg); - assert_eq!(expected, &buf[..]); - } - } - - #[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); + set_reg64_help(&mut buf, *reg, 0x94); // sete_reg64 assert_eq!(expected, &buf[..]); } } diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index e8dff1d967..a87e2ecdf7 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -433,6 +433,23 @@ where ); self.build_neq(sym, &args[0], &args[1], &arg_layouts[0]) } + LowLevel::NumLt => { + debug_assert_eq!( + 2, + args.len(), + "NumLt: expected to have exactly two argument" + ); + debug_assert_eq!( + arg_layouts[0], arg_layouts[1], + "NumLt: expected all arguments of to have the same layout" + ); + debug_assert_eq!( + Layout::Builtin(Builtin::Int1), + *ret_layout, + "NumLt: expected to have return layout of type I1" + ); + self.build_num_lt(sym, &args[0], &args[1], &arg_layouts[0]) + } LowLevel::NumRound => self.build_fn_call( sym, bitcode::NUM_ROUND[FloatWidth::F64].to_string(), @@ -523,6 +540,15 @@ where arg_layout: &Layout<'a>, ) -> Result<(), String>; + /// build_num_lt stores the result of `src1 < src2` into dst. + fn build_num_lt( + &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 df451c4898..1c283bac43 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -726,6 +726,20 @@ fn gen_int_neq() { ); } +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))] +fn gen_int_less_than() { + assert_evals_to!( + indoc!( + r#" + 4 < 5 + "# + ), + true, + bool + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn gen_dec_eq() {