Merge pull request #5041 from thehabbos007/eq

gen_dev x86: misc low-level bool comparison functions
This commit is contained in:
Folkert de Vries 2023-02-20 08:51:11 +01:00 committed by GitHub
commit c6089ebb6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 147 additions and 8 deletions

View file

@ -1102,7 +1102,7 @@ impl<
fn build_eq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
match *arg_layout {
single_register_int_builtins!() => {
single_register_int_builtins!() | Layout::BOOL => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
@ -1117,8 +1117,8 @@ impl<
}
fn build_neq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
match self.layout_interner.get(*arg_layout) {
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
match *arg_layout {
single_register_int_builtins!() | Layout::BOOL => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
@ -1132,6 +1132,55 @@ impl<
}
}
fn build_and(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
match *arg_layout {
Layout::BOOL => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::and_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
x => todo!("And: layout, {:?}", x),
}
}
fn build_or(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
match *arg_layout {
Layout::BOOL => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::or_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
x => todo!("Or: layout, {:?}", x),
}
}
fn build_not(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>) {
match *arg_layout {
Layout::BOOL => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src_reg = self.storage_manager.load_to_general_reg(&mut self.buf, src);
// Not would usually be implemented as `xor src, -1` followed by `and src, 1`
// but since our booleans are represented as `0x101010101010101` currently, we can simply XOR with that
let bool_val = [true as u8; 8];
ASM::mov_reg64_imm64(&mut self.buf, dst_reg, i64::from_ne_bytes(bool_val));
ASM::xor_reg64_reg64_reg64(&mut self.buf, src_reg, src_reg, dst_reg);
ASM::mov_reg64_reg64(&mut self.buf, dst_reg, src_reg);
}
x => todo!("Not: layout, {:?}", x),
}
}
fn build_num_lt(
&mut self,
dst: &Symbol,

View file

@ -623,6 +623,41 @@ trait Backend<'a> {
);
self.build_neq(sym, &args[0], &args[1], &arg_layouts[0])
}
LowLevel::And => {
debug_assert_eq!(2, args.len(), "And: expected to have exactly two argument");
debug_assert_eq!(
arg_layouts[0], arg_layouts[1],
"And: expected all arguments of to have the same layout"
);
debug_assert_eq!(
Layout::BOOL,
*ret_layout,
"And: expected to have return layout of type Bool"
);
self.build_and(sym, &args[0], &args[1], &arg_layouts[0])
}
LowLevel::Or => {
debug_assert_eq!(2, args.len(), "Or: expected to have exactly two argument");
debug_assert_eq!(
arg_layouts[0], arg_layouts[1],
"Or: expected all arguments of to have the same layout"
);
debug_assert_eq!(
Layout::BOOL,
*ret_layout,
"Or: expected to have return layout of type Bool"
);
self.build_or(sym, &args[0], &args[1], &arg_layouts[0])
}
LowLevel::Not => {
debug_assert_eq!(1, args.len(), "Not: expected to have exactly one argument");
debug_assert_eq!(
Layout::BOOL,
*ret_layout,
"Not: expected to have return layout of type Bool"
);
self.build_not(sym, &args[0], &arg_layouts[0])
}
LowLevel::NumLt => {
debug_assert_eq!(
2,
@ -1016,6 +1051,15 @@ trait Backend<'a> {
/// build_neq stores the result of `src1 != src2` into dst.
fn build_neq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>);
/// build_and stores the result of `src1 && src2` into dst.
fn build_and(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>);
/// build_or stores the result of `src1 || src2` into dst.
fn build_or(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>);
/// build_not stores the result of `!src` into dst.
fn build_not(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>);
/// build_num_lt stores the result of `src1 < src2` into dst.
fn build_num_lt(
&mut self,

View file

@ -27,7 +27,7 @@ fn eq_i64() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn neq_i64() {
assert_evals_to!(
indoc!(
@ -61,7 +61,7 @@ fn eq_u64() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn neq_u64() {
assert_evals_to!(
indoc!(
@ -78,7 +78,7 @@ fn neq_u64() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn eq_bool_tag() {
assert_evals_to!(
indoc!(
@ -95,7 +95,7 @@ fn eq_bool_tag() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn neq_bool_tag() {
assert_evals_to!(
indoc!(
@ -111,6 +111,52 @@ fn neq_bool_tag() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn bool_logic() {
assert_evals_to!(
indoc!(
r#"
bool1 = Bool.true
bool2 = Bool.false
bool3 = !bool1
(bool1 && bool2) || bool2 && bool3
"#
),
false,
bool
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn and_bool() {
assert_evals_to!("Bool.true && Bool.true", true, bool);
assert_evals_to!("Bool.true && Bool.false", false, bool);
assert_evals_to!("Bool.false && Bool.true", false, bool);
assert_evals_to!("Bool.false && Bool.false", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn or_bool() {
assert_evals_to!("Bool.true || Bool.true", true, bool);
assert_evals_to!("Bool.true || Bool.false", true, bool);
assert_evals_to!("Bool.false || Bool.true", true, bool);
assert_evals_to!("Bool.false || Bool.false", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn not_bool() {
assert_evals_to!("!Bool.true", false, bool);
assert_evals_to!("!Bool.false", true, bool);
assert_evals_to!("!(!Bool.true)", true, bool);
assert_evals_to!("!(!Bool.false)", false, bool);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn empty_record() {
@ -152,7 +198,7 @@ fn unit() {
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn newtype() {
assert_evals_to!("Identity 42 == Identity 42", true, bool);
assert_evals_to!("Identity 42 != Identity 42", false, bool);