mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-02 19:32:17 +00:00
handle all comparison widths
This commit is contained in:
parent
9dd69f6f9c
commit
fdffcc8b36
5 changed files with 283 additions and 110 deletions
|
@ -7,7 +7,7 @@ use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{InLayout, STLayoutInterner};
|
use roc_mono::layout::{InLayout, STLayoutInterner};
|
||||||
|
|
||||||
use super::CompareOperation;
|
use super::{CompareOperation, RegisterWidth};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -854,6 +854,7 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn eq_reg64_reg64_reg64(
|
fn eq_reg64_reg64_reg64(
|
||||||
_buf: &mut Vec<'_, u8>,
|
_buf: &mut Vec<'_, u8>,
|
||||||
|
_register_width: RegisterWidth,
|
||||||
_dst: AArch64GeneralReg,
|
_dst: AArch64GeneralReg,
|
||||||
_src1: AArch64GeneralReg,
|
_src1: AArch64GeneralReg,
|
||||||
_src2: AArch64GeneralReg,
|
_src2: AArch64GeneralReg,
|
||||||
|
@ -864,6 +865,7 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn neq_reg64_reg64_reg64(
|
fn neq_reg64_reg64_reg64(
|
||||||
_buf: &mut Vec<'_, u8>,
|
_buf: &mut Vec<'_, u8>,
|
||||||
|
_register_width: RegisterWidth,
|
||||||
_dst: AArch64GeneralReg,
|
_dst: AArch64GeneralReg,
|
||||||
_src1: AArch64GeneralReg,
|
_src1: AArch64GeneralReg,
|
||||||
_src2: AArch64GeneralReg,
|
_src2: AArch64GeneralReg,
|
||||||
|
@ -871,26 +873,6 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
||||||
todo!("registers non-equality for AArch64");
|
todo!("registers non-equality for AArch64");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn ilt_reg64_reg64_reg64(
|
|
||||||
_buf: &mut Vec<'_, u8>,
|
|
||||||
_dst: AArch64GeneralReg,
|
|
||||||
_src1: AArch64GeneralReg,
|
|
||||||
_src2: AArch64GeneralReg,
|
|
||||||
) {
|
|
||||||
todo!("registers signed less than for AArch64");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn ult_reg64_reg64_reg64(
|
|
||||||
_buf: &mut Vec<'_, u8>,
|
|
||||||
_dst: AArch64GeneralReg,
|
|
||||||
_src1: AArch64GeneralReg,
|
|
||||||
_src2: AArch64GeneralReg,
|
|
||||||
) {
|
|
||||||
todo!("registers unsigned less than for AArch64");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn cmp_freg_freg_reg64(
|
fn cmp_freg_freg_reg64(
|
||||||
_buf: &mut Vec<'_, u8>,
|
_buf: &mut Vec<'_, u8>,
|
||||||
|
@ -903,26 +885,6 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
||||||
todo!("registers float comparison for AArch64");
|
todo!("registers float comparison for AArch64");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn igt_reg64_reg64_reg64(
|
|
||||||
_buf: &mut Vec<'_, u8>,
|
|
||||||
_dst: AArch64GeneralReg,
|
|
||||||
_src1: AArch64GeneralReg,
|
|
||||||
_src2: AArch64GeneralReg,
|
|
||||||
) {
|
|
||||||
todo!("registers signed greater than for AArch64");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn ugt_reg64_reg64_reg64(
|
|
||||||
_buf: &mut Vec<'_, u8>,
|
|
||||||
_dst: AArch64GeneralReg,
|
|
||||||
_src1: AArch64GeneralReg,
|
|
||||||
_src2: AArch64GeneralReg,
|
|
||||||
) {
|
|
||||||
todo!("registers unsigned greater than for AArch64");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn to_float_freg64_reg64(
|
fn to_float_freg64_reg64(
|
||||||
_buf: &mut Vec<'_, u8>,
|
_buf: &mut Vec<'_, u8>,
|
||||||
|
@ -1061,6 +1023,28 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
||||||
fn sqrt_freg32_freg32(_buf: &mut Vec<'_, u8>, _dst: AArch64FloatReg, _src: AArch64FloatReg) {
|
fn sqrt_freg32_freg32(_buf: &mut Vec<'_, u8>, _dst: AArch64FloatReg, _src: AArch64FloatReg) {
|
||||||
todo!("sqrt")
|
todo!("sqrt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn signed_compare_reg64(
|
||||||
|
_buf: &mut Vec<'_, u8>,
|
||||||
|
_register_width: RegisterWidth,
|
||||||
|
_operation: CompareOperation,
|
||||||
|
_dst: AArch64GeneralReg,
|
||||||
|
_src1: AArch64GeneralReg,
|
||||||
|
_src2: AArch64GeneralReg,
|
||||||
|
) {
|
||||||
|
todo!("signed compare")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unsigned_compare_reg64(
|
||||||
|
_buf: &mut Vec<'_, u8>,
|
||||||
|
_register_width: RegisterWidth,
|
||||||
|
_operation: CompareOperation,
|
||||||
|
_dst: AArch64GeneralReg,
|
||||||
|
_src1: AArch64GeneralReg,
|
||||||
|
_src2: AArch64GeneralReg,
|
||||||
|
) {
|
||||||
|
todo!("unsigned compare")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AArch64Assembler {}
|
impl AArch64Assembler {}
|
||||||
|
|
|
@ -27,6 +27,14 @@ use storage::{RegStorage, StorageManager};
|
||||||
|
|
||||||
// TODO: on all number functions double check and deal with over/underflow.
|
// TODO: on all number functions double check and deal with over/underflow.
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum RegisterWidth {
|
||||||
|
W8,
|
||||||
|
W16,
|
||||||
|
W32,
|
||||||
|
W64,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<GeneralReg, FloatReg>>:
|
pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<GeneralReg, FloatReg>>:
|
||||||
Sized + Copy
|
Sized + Copy
|
||||||
{
|
{
|
||||||
|
@ -390,6 +398,7 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
||||||
|
|
||||||
fn eq_reg64_reg64_reg64(
|
fn eq_reg64_reg64_reg64(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
dst: GeneralReg,
|
dst: GeneralReg,
|
||||||
src1: GeneralReg,
|
src1: GeneralReg,
|
||||||
src2: GeneralReg,
|
src2: GeneralReg,
|
||||||
|
@ -397,20 +406,25 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
||||||
|
|
||||||
fn neq_reg64_reg64_reg64(
|
fn neq_reg64_reg64_reg64(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
dst: GeneralReg,
|
dst: GeneralReg,
|
||||||
src1: GeneralReg,
|
src1: GeneralReg,
|
||||||
src2: GeneralReg,
|
src2: GeneralReg,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn ilt_reg64_reg64_reg64(
|
fn signed_compare_reg64(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
|
operation: CompareOperation,
|
||||||
dst: GeneralReg,
|
dst: GeneralReg,
|
||||||
src1: GeneralReg,
|
src1: GeneralReg,
|
||||||
src2: GeneralReg,
|
src2: GeneralReg,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn ult_reg64_reg64_reg64(
|
fn unsigned_compare_reg64(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
|
operation: CompareOperation,
|
||||||
dst: GeneralReg,
|
dst: GeneralReg,
|
||||||
src1: GeneralReg,
|
src1: GeneralReg,
|
||||||
src2: GeneralReg,
|
src2: GeneralReg,
|
||||||
|
@ -425,20 +439,6 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
||||||
operation: CompareOperation,
|
operation: CompareOperation,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn igt_reg64_reg64_reg64(
|
|
||||||
buf: &mut Vec<'_, u8>,
|
|
||||||
dst: GeneralReg,
|
|
||||||
src1: GeneralReg,
|
|
||||||
src2: GeneralReg,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn ugt_reg64_reg64_reg64(
|
|
||||||
buf: &mut Vec<'_, u8>,
|
|
||||||
dst: GeneralReg,
|
|
||||||
src1: GeneralReg,
|
|
||||||
src2: GeneralReg,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn to_float_freg32_reg64(buf: &mut Vec<'_, u8>, dst: FloatReg, src: GeneralReg);
|
fn to_float_freg32_reg64(buf: &mut Vec<'_, u8>, dst: FloatReg, src: GeneralReg);
|
||||||
|
|
||||||
fn to_float_freg64_reg64(buf: &mut Vec<'_, u8>, dst: FloatReg, src: GeneralReg);
|
fn to_float_freg64_reg64(buf: &mut Vec<'_, u8>, dst: FloatReg, src: GeneralReg);
|
||||||
|
@ -1191,6 +1191,14 @@ impl<
|
||||||
fn build_eq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
|
fn build_eq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
|
||||||
match *arg_layout {
|
match *arg_layout {
|
||||||
single_register_int_builtins!() | Layout::BOOL => {
|
single_register_int_builtins!() | Layout::BOOL => {
|
||||||
|
let width = match *arg_layout {
|
||||||
|
Layout::BOOL | Layout::I8 | Layout::U8 => RegisterWidth::W8,
|
||||||
|
Layout::I16 | Layout::U16 => RegisterWidth::W16,
|
||||||
|
Layout::U32 | Layout::I32 => RegisterWidth::W32,
|
||||||
|
Layout::I64 | Layout::U64 => RegisterWidth::W64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
let src1_reg = self
|
let src1_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
|
@ -1198,7 +1206,7 @@ impl<
|
||||||
let src2_reg = self
|
let src2_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.load_to_general_reg(&mut self.buf, src2);
|
.load_to_general_reg(&mut self.buf, src2);
|
||||||
ASM::eq_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
ASM::eq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, src1_reg, src2_reg);
|
||||||
}
|
}
|
||||||
Layout::STR => {
|
Layout::STR => {
|
||||||
// use a zig call
|
// use a zig call
|
||||||
|
@ -1208,7 +1216,17 @@ impl<
|
||||||
&[*src1, *src2],
|
&[*src1, *src2],
|
||||||
&[Layout::STR, Layout::STR],
|
&[Layout::STR, Layout::STR],
|
||||||
&Layout::BOOL,
|
&Layout::BOOL,
|
||||||
)
|
);
|
||||||
|
|
||||||
|
// mask the result; we pass booleans around as 64-bit values, but branch on 0x0 and 0x1.
|
||||||
|
// Zig gives back values where not all of the upper bits are zero, so we must clear them ourselves
|
||||||
|
let tmp = &Symbol::DEV_TMP;
|
||||||
|
let tmp_reg = self.storage_manager.claim_general_reg(&mut self.buf, tmp);
|
||||||
|
ASM::mov_reg64_imm64(&mut self.buf, tmp_reg, true as i64);
|
||||||
|
|
||||||
|
let width = RegisterWidth::W8; // we're comparing booleans
|
||||||
|
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
|
||||||
|
ASM::eq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, dst_reg, tmp_reg);
|
||||||
}
|
}
|
||||||
x => todo!("NumEq: layout, {:?}", x),
|
x => todo!("NumEq: layout, {:?}", x),
|
||||||
}
|
}
|
||||||
|
@ -1217,6 +1235,14 @@ impl<
|
||||||
fn build_neq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
|
fn build_neq(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, arg_layout: &InLayout<'a>) {
|
||||||
match *arg_layout {
|
match *arg_layout {
|
||||||
single_register_int_builtins!() | Layout::BOOL => {
|
single_register_int_builtins!() | Layout::BOOL => {
|
||||||
|
let width = match *arg_layout {
|
||||||
|
Layout::BOOL | Layout::I8 | Layout::U8 => RegisterWidth::W8,
|
||||||
|
Layout::I16 | Layout::U16 => RegisterWidth::W16,
|
||||||
|
Layout::U32 | Layout::I32 => RegisterWidth::W32,
|
||||||
|
Layout::I64 | Layout::U64 => RegisterWidth::W64,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
let src1_reg = self
|
let src1_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
|
@ -1224,7 +1250,7 @@ impl<
|
||||||
let src2_reg = self
|
let src2_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.load_to_general_reg(&mut self.buf, src2);
|
.load_to_general_reg(&mut self.buf, src2);
|
||||||
ASM::neq_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
ASM::neq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, src1_reg, src2_reg);
|
||||||
}
|
}
|
||||||
Layout::STR => {
|
Layout::STR => {
|
||||||
self.build_fn_call(
|
self.build_fn_call(
|
||||||
|
@ -1238,10 +1264,11 @@ impl<
|
||||||
// negate the result
|
// negate the result
|
||||||
let tmp = &Symbol::DEV_TMP;
|
let tmp = &Symbol::DEV_TMP;
|
||||||
let tmp_reg = self.storage_manager.claim_general_reg(&mut self.buf, tmp);
|
let tmp_reg = self.storage_manager.claim_general_reg(&mut self.buf, tmp);
|
||||||
ASM::mov_reg64_imm64(&mut self.buf, tmp_reg, 164);
|
ASM::mov_reg64_imm64(&mut self.buf, tmp_reg, true as i64);
|
||||||
|
|
||||||
|
let width = RegisterWidth::W8; // we're comparing booleans
|
||||||
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
|
||||||
ASM::neq_reg64_reg64_reg64(&mut self.buf, dst_reg, dst_reg, tmp_reg);
|
ASM::neq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, dst_reg, tmp_reg);
|
||||||
}
|
}
|
||||||
x => todo!("NumNeq: layout, {:?}", x),
|
x => todo!("NumNeq: layout, {:?}", x),
|
||||||
}
|
}
|
||||||
|
@ -1280,7 +1307,14 @@ impl<
|
||||||
let src2_reg = self
|
let src2_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.load_to_general_reg(&mut self.buf, src2);
|
.load_to_general_reg(&mut self.buf, src2);
|
||||||
ASM::ilt_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
ASM::signed_compare_reg64(
|
||||||
|
&mut self.buf,
|
||||||
|
RegisterWidth::W64,
|
||||||
|
CompareOperation::LessThan,
|
||||||
|
dst_reg,
|
||||||
|
src1_reg,
|
||||||
|
src2_reg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Int(IntWidth::U64)) => {
|
Layout::Builtin(Builtin::Int(IntWidth::U64)) => {
|
||||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
|
@ -1290,7 +1324,14 @@ impl<
|
||||||
let src2_reg = self
|
let src2_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.load_to_general_reg(&mut self.buf, src2);
|
.load_to_general_reg(&mut self.buf, src2);
|
||||||
ASM::ult_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
ASM::unsigned_compare_reg64(
|
||||||
|
&mut self.buf,
|
||||||
|
RegisterWidth::W64,
|
||||||
|
CompareOperation::LessThan,
|
||||||
|
dst_reg,
|
||||||
|
src1_reg,
|
||||||
|
src2_reg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Float(width)) => {
|
Layout::Builtin(Builtin::Float(width)) => {
|
||||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
|
@ -1326,7 +1367,14 @@ impl<
|
||||||
let src2_reg = self
|
let src2_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.load_to_general_reg(&mut self.buf, src2);
|
.load_to_general_reg(&mut self.buf, src2);
|
||||||
ASM::igt_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
ASM::signed_compare_reg64(
|
||||||
|
&mut self.buf,
|
||||||
|
RegisterWidth::W64,
|
||||||
|
CompareOperation::GreaterThan,
|
||||||
|
dst_reg,
|
||||||
|
src1_reg,
|
||||||
|
src2_reg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Int(IntWidth::U64)) => {
|
Layout::Builtin(Builtin::Int(IntWidth::U64)) => {
|
||||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
|
@ -1336,7 +1384,14 @@ impl<
|
||||||
let src2_reg = self
|
let src2_reg = self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.load_to_general_reg(&mut self.buf, src2);
|
.load_to_general_reg(&mut self.buf, src2);
|
||||||
ASM::ugt_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
ASM::unsigned_compare_reg64(
|
||||||
|
&mut self.buf,
|
||||||
|
RegisterWidth::W64,
|
||||||
|
CompareOperation::GreaterThan,
|
||||||
|
dst_reg,
|
||||||
|
src1_reg,
|
||||||
|
src2_reg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Float(width)) => {
|
Layout::Builtin(Builtin::Float(width)) => {
|
||||||
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
|
||||||
|
|
|
@ -9,7 +9,7 @@ use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{InLayout, Layout, LayoutInterner, STLayoutInterner};
|
use roc_mono::layout::{InLayout, Layout, LayoutInterner, STLayoutInterner};
|
||||||
|
|
||||||
use super::CompareOperation;
|
use super::{CompareOperation, RegisterWidth};
|
||||||
|
|
||||||
// Not sure exactly how I want to represent registers.
|
// Not sure exactly how I want to represent registers.
|
||||||
// If we want max speed, we would likely make them structs that impl the same trait to avoid ifs.
|
// If we want max speed, we would likely make them structs that impl the same trait to avoid ifs.
|
||||||
|
@ -1554,45 +1554,73 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn eq_reg64_reg64_reg64(
|
fn eq_reg64_reg64_reg64(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
dst: X86_64GeneralReg,
|
dst: X86_64GeneralReg,
|
||||||
src1: X86_64GeneralReg,
|
src1: X86_64GeneralReg,
|
||||||
src2: X86_64GeneralReg,
|
src2: X86_64GeneralReg,
|
||||||
) {
|
) {
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
dbg!(register_width);
|
||||||
|
cmp_reg64_reg64(buf, register_width, src1, src2);
|
||||||
sete_reg64(buf, dst);
|
sete_reg64(buf, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn neq_reg64_reg64_reg64(
|
fn neq_reg64_reg64_reg64(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
dst: X86_64GeneralReg,
|
dst: X86_64GeneralReg,
|
||||||
src1: X86_64GeneralReg,
|
src1: X86_64GeneralReg,
|
||||||
src2: X86_64GeneralReg,
|
src2: X86_64GeneralReg,
|
||||||
) {
|
) {
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
dbg!(register_width);
|
||||||
|
cmp_reg64_reg64(buf, register_width, src1, src2);
|
||||||
setne_reg64(buf, dst);
|
setne_reg64(buf, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ilt_reg64_reg64_reg64(
|
fn signed_compare_reg64(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
|
operation: CompareOperation,
|
||||||
dst: X86_64GeneralReg,
|
dst: X86_64GeneralReg,
|
||||||
src1: X86_64GeneralReg,
|
src1: X86_64GeneralReg,
|
||||||
src2: X86_64GeneralReg,
|
src2: X86_64GeneralReg,
|
||||||
) {
|
) {
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
match operation {
|
||||||
setl_reg64(buf, dst);
|
CompareOperation::LessThan => {
|
||||||
|
cmp_reg64_reg64(buf, register_width, src1, src2);
|
||||||
|
setl_reg64(buf, dst);
|
||||||
|
}
|
||||||
|
CompareOperation::LessThanOrEqual => todo!(),
|
||||||
|
CompareOperation::GreaterThan => {
|
||||||
|
cmp_reg64_reg64(buf, register_width, src1, src2);
|
||||||
|
setg_reg64(buf, dst);
|
||||||
|
}
|
||||||
|
CompareOperation::GreaterThanOrEqual => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
fn unsigned_compare_reg64(
|
||||||
fn ult_reg64_reg64_reg64(
|
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
|
operation: CompareOperation,
|
||||||
dst: X86_64GeneralReg,
|
dst: X86_64GeneralReg,
|
||||||
src1: X86_64GeneralReg,
|
src1: X86_64GeneralReg,
|
||||||
src2: X86_64GeneralReg,
|
src2: X86_64GeneralReg,
|
||||||
) {
|
) {
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
match operation {
|
||||||
setb_reg64(buf, dst);
|
CompareOperation::LessThan => {
|
||||||
|
cmp_reg64_reg64(buf, register_width, src1, src2);
|
||||||
|
setb_reg64(buf, dst);
|
||||||
|
}
|
||||||
|
CompareOperation::LessThanOrEqual => todo!(),
|
||||||
|
CompareOperation::GreaterThan => {
|
||||||
|
cmp_reg64_reg64(buf, register_width, src1, src2);
|
||||||
|
seta_reg64(buf, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompareOperation::GreaterThanOrEqual => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -1622,28 +1650,6 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn igt_reg64_reg64_reg64(
|
|
||||||
buf: &mut Vec<'_, u8>,
|
|
||||||
dst: X86_64GeneralReg,
|
|
||||||
src1: X86_64GeneralReg,
|
|
||||||
src2: X86_64GeneralReg,
|
|
||||||
) {
|
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
|
||||||
setg_reg64(buf, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn ugt_reg64_reg64_reg64(
|
|
||||||
buf: &mut Vec<'_, u8>,
|
|
||||||
dst: X86_64GeneralReg,
|
|
||||||
src1: X86_64GeneralReg,
|
|
||||||
src2: X86_64GeneralReg,
|
|
||||||
) {
|
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
|
||||||
seta_reg64(buf, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn to_float_freg32_reg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64GeneralReg) {
|
fn to_float_freg32_reg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64GeneralReg) {
|
||||||
cvtsi2ss_freg64_reg64(buf, dst, src);
|
cvtsi2ss_freg64_reg64(buf, dst, src);
|
||||||
|
@ -1671,7 +1677,7 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
||||||
src1: X86_64GeneralReg,
|
src1: X86_64GeneralReg,
|
||||||
src2: X86_64GeneralReg,
|
src2: X86_64GeneralReg,
|
||||||
) {
|
) {
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
cmp_reg64_reg64(buf, RegisterWidth::W64, src1, src2);
|
||||||
setle_reg64(buf, dst);
|
setle_reg64(buf, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1682,7 +1688,7 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
||||||
src1: X86_64GeneralReg,
|
src1: X86_64GeneralReg,
|
||||||
src2: X86_64GeneralReg,
|
src2: X86_64GeneralReg,
|
||||||
) {
|
) {
|
||||||
cmp_reg64_reg64(buf, src1, src2);
|
cmp_reg64_reg64(buf, RegisterWidth::W64, src1, src2);
|
||||||
setge_reg64(buf, dst);
|
setge_reg64(buf, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1847,6 +1853,50 @@ fn add_reg_extension<T: RegTrait>(reg: T, byte: u8) -> u8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn binop_reg16_reg16(
|
||||||
|
op_code: u8,
|
||||||
|
buf: &mut Vec<'_, u8>,
|
||||||
|
dst: X86_64GeneralReg,
|
||||||
|
src: X86_64GeneralReg,
|
||||||
|
) {
|
||||||
|
let dst_high = dst as u8 > 7;
|
||||||
|
let dst_mod = dst as u8 % 8;
|
||||||
|
let src_high = src as u8 > 7;
|
||||||
|
let src_mod = (src as u8 % 8) << 3;
|
||||||
|
|
||||||
|
if dst_high || src_high {
|
||||||
|
let rex = add_rm_extension(dst, REX);
|
||||||
|
let rex = add_reg_extension(src, rex);
|
||||||
|
|
||||||
|
buf.extend([0x66, rex, op_code, 0xC0 | dst_mod | src_mod])
|
||||||
|
} else {
|
||||||
|
buf.extend([0x66, op_code, 0xC0 | dst_mod | src_mod]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn binop_reg32_reg32(
|
||||||
|
op_code: u8,
|
||||||
|
buf: &mut Vec<'_, u8>,
|
||||||
|
dst: X86_64GeneralReg,
|
||||||
|
src: X86_64GeneralReg,
|
||||||
|
) {
|
||||||
|
let dst_high = dst as u8 > 7;
|
||||||
|
let dst_mod = dst as u8 % 8;
|
||||||
|
let src_high = src as u8 > 7;
|
||||||
|
let src_mod = (src as u8 % 8) << 3;
|
||||||
|
|
||||||
|
if dst_high || src_high {
|
||||||
|
let rex = add_rm_extension(dst, REX);
|
||||||
|
let rex = add_reg_extension(src, rex);
|
||||||
|
|
||||||
|
buf.extend([rex, op_code, 0xC0 | dst_mod | src_mod])
|
||||||
|
} else {
|
||||||
|
buf.extend([op_code, 0xC0 | dst_mod | src_mod]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn binop_reg64_reg64(
|
fn binop_reg64_reg64(
|
||||||
op_code: u8,
|
op_code: u8,
|
||||||
|
@ -2119,8 +2169,18 @@ fn cmp_reg64_imm32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i32) {
|
||||||
|
|
||||||
/// `CMP r/m64,r64` -> Compare r64 to r/m64.
|
/// `CMP r/m64,r64` -> Compare r64 to r/m64.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn cmp_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64GeneralReg) {
|
fn cmp_reg64_reg64(
|
||||||
binop_reg64_reg64(0x39, buf, dst, src);
|
buf: &mut Vec<'_, u8>,
|
||||||
|
register_width: RegisterWidth,
|
||||||
|
dst: X86_64GeneralReg,
|
||||||
|
src: X86_64GeneralReg,
|
||||||
|
) {
|
||||||
|
match register_width {
|
||||||
|
RegisterWidth::W8 => binop_reg64_reg64(0x38, buf, dst, src),
|
||||||
|
RegisterWidth::W16 => binop_reg16_reg16(0x39, buf, dst, src),
|
||||||
|
RegisterWidth::W32 => binop_reg32_reg32(0x39, buf, dst, src),
|
||||||
|
RegisterWidth::W64 => binop_reg64_reg64(0x39, buf, dst, src),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -2419,13 +2479,6 @@ fn mov_base8_offset32_reg8(
|
||||||
buf.extend(offset.to_le_bytes());
|
buf.extend(offset.to_le_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RegisterWidth {
|
|
||||||
W8,
|
|
||||||
W16,
|
|
||||||
W32,
|
|
||||||
W64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn mov_reg_base_offset32(
|
fn mov_reg_base_offset32(
|
||||||
buf: &mut Vec<'_, u8>,
|
buf: &mut Vec<'_, u8>,
|
||||||
|
@ -3671,4 +3724,51 @@ mod tests {
|
||||||
ALL_FLOAT_REGS
|
ALL_FLOAT_REGS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_int_cmp() {
|
||||||
|
disassembler_test!(
|
||||||
|
cmp_reg64_reg64,
|
||||||
|
|_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!(
|
||||||
|
"cmp {}, {}",
|
||||||
|
dst.low_8bits_string(),
|
||||||
|
src.low_8bits_string()
|
||||||
|
),
|
||||||
|
[RegisterWidth::W8],
|
||||||
|
ALL_GENERAL_REGS,
|
||||||
|
ALL_GENERAL_REGS
|
||||||
|
);
|
||||||
|
|
||||||
|
disassembler_test!(
|
||||||
|
cmp_reg64_reg64,
|
||||||
|
|_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!(
|
||||||
|
"cmp {}, {}",
|
||||||
|
dbg!(dst.low_16bits_string()),
|
||||||
|
dbg!(src.low_16bits_string())
|
||||||
|
),
|
||||||
|
[RegisterWidth::W16],
|
||||||
|
ALL_GENERAL_REGS,
|
||||||
|
ALL_GENERAL_REGS
|
||||||
|
);
|
||||||
|
|
||||||
|
disassembler_test!(
|
||||||
|
cmp_reg64_reg64,
|
||||||
|
|_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!(
|
||||||
|
"cmp {}, {}",
|
||||||
|
dbg!(dst.low_32bits_string()),
|
||||||
|
dbg!(src.low_32bits_string())
|
||||||
|
),
|
||||||
|
[RegisterWidth::W32],
|
||||||
|
ALL_GENERAL_REGS,
|
||||||
|
ALL_GENERAL_REGS
|
||||||
|
);
|
||||||
|
|
||||||
|
disassembler_test!(
|
||||||
|
cmp_reg64_reg64,
|
||||||
|
|_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!("cmp {dst}, {src}",),
|
||||||
|
[RegisterWidth::W64],
|
||||||
|
ALL_GENERAL_REGS,
|
||||||
|
ALL_GENERAL_REGS
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,40 @@ use indoc::indoc;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use roc_std::{RocList, RocResult, RocStr};
|
use roc_std::{RocList, RocResult, RocStr};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
|
fn string_eq() {
|
||||||
|
// context: the dev backend did not correctly mask the boolean that zig returns here
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
main : I64
|
||||||
|
main = if "*" == "*" then 123 else 456
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
123,
|
||||||
|
u64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||||
|
fn string_neq() {
|
||||||
|
// context: the dev backend did not correctly mask the boolean that zig returns here
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [main] to "./platform"
|
||||||
|
main : I64
|
||||||
|
main = if "*" != "*" then 123 else 456
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
456,
|
||||||
|
u64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
||||||
fn str_split_empty_delimiter() {
|
fn str_split_empty_delimiter() {
|
||||||
|
|
|
@ -210,7 +210,7 @@ pub fn helper(
|
||||||
let builtins_host_tempfile =
|
let builtins_host_tempfile =
|
||||||
roc_bitcode::host_tempfile().expect("failed to write host builtins object to tempfile");
|
roc_bitcode::host_tempfile().expect("failed to write host builtins object to tempfile");
|
||||||
|
|
||||||
if false {
|
if true {
|
||||||
std::fs::copy(&app_o_file, "/tmp/app.o").unwrap();
|
std::fs::copy(&app_o_file, "/tmp/app.o").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue