Merge remote-tracking branch 'origin/main' into expect-fx-codegen

This commit is contained in:
Folkert 2022-08-23 16:28:21 +02:00
commit a22e04361c
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
222 changed files with 10039 additions and 1945 deletions

View file

@ -440,7 +440,39 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
_src1: AArch64GeneralReg,
_src2: AArch64GeneralReg,
) {
todo!("register multiplication for AArch64");
todo!("register signed multiplication for AArch64");
}
fn umul_reg64_reg64_reg64<'a, ASM, CC>(
_buf: &mut Vec<'a, u8>,
_storage_manager: &mut StorageManager<'a, AArch64GeneralReg, AArch64FloatReg, ASM, CC>,
_dst: AArch64GeneralReg,
_src1: AArch64GeneralReg,
_src2: AArch64GeneralReg,
) where
ASM: Assembler<AArch64GeneralReg, AArch64FloatReg>,
CC: CallConv<AArch64GeneralReg, AArch64FloatReg, ASM>,
{
todo!("register unsigned multiplication for AArch64");
}
#[inline(always)]
fn mul_freg32_freg32_freg32(
_buf: &mut Vec<'_, u8>,
_dst: AArch64FloatReg,
_src1: AArch64FloatReg,
_src2: AArch64FloatReg,
) {
todo!("multiplication for floats for AArch64");
}
#[inline(always)]
fn mul_freg64_freg64_freg64(
_buf: &mut Vec<'_, u8>,
_dst: AArch64FloatReg,
_src1: AArch64FloatReg,
_src2: AArch64FloatReg,
) {
todo!("multiplication for floats for AArch64");
}
#[inline(always)]

View file

@ -21,7 +21,7 @@ mod disassembler_test_macro;
pub(crate) mod storage;
pub(crate) mod x86_64;
use storage::StorageManager;
use storage::{RegStorage, StorageManager};
const REFCOUNT_ONE: u64 = i64::MIN as u64;
// TODO: on all number functions double check and deal with over/underflow.
@ -210,12 +210,33 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
fn mov_stack32_reg64(buf: &mut Vec<'_, u8>, offset: i32, src: GeneralReg);
fn neg_reg64_reg64(buf: &mut Vec<'_, u8>, dst: GeneralReg, src: GeneralReg);
fn mul_freg32_freg32_freg32(
buf: &mut Vec<'_, u8>,
dst: FloatReg,
src1: FloatReg,
src2: FloatReg,
);
fn mul_freg64_freg64_freg64(
buf: &mut Vec<'_, u8>,
dst: FloatReg,
src1: FloatReg,
src2: FloatReg,
);
fn imul_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>,
dst: GeneralReg,
src1: GeneralReg,
src2: GeneralReg,
);
fn umul_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, GeneralReg, FloatReg, ASM, CC>,
dst: GeneralReg,
src1: GeneralReg,
src2: GeneralReg,
) where
ASM: Assembler<GeneralReg, FloatReg>,
CC: CallConv<GeneralReg, FloatReg, ASM>;
fn sub_reg64_reg64_imm32(buf: &mut Vec<'_, u8>, dst: GeneralReg, src1: GeneralReg, imm32: i32);
fn sub_reg64_reg64_reg64(
@ -339,6 +360,19 @@ pub fn new_backend_64bit<
}
}
macro_rules! quadword_and_smaller {
() => {
IntWidth::I64
| IntWidth::U64
| IntWidth::I32
| IntWidth::U32
| IntWidth::I16
| IntWidth::U16
| IntWidth::I8
| IntWidth::U8
};
}
impl<
'a,
GeneralReg: RegTrait,
@ -699,16 +733,7 @@ impl<
fn build_num_add(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>) {
match layout {
Layout::Builtin(Builtin::Int(
IntWidth::I64
| IntWidth::U64
| IntWidth::I32
| IntWidth::U32
| IntWidth::I16
| IntWidth::U16
| IntWidth::I8
| IntWidth::U8,
)) => {
Layout::Builtin(Builtin::Int(quadword_and_smaller!())) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
@ -736,7 +761,9 @@ impl<
fn build_num_mul(&mut self, dst: &Symbol, src1: &Symbol, src2: &Symbol, layout: &Layout<'a>) {
match layout {
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
Layout::Builtin(Builtin::Int(
IntWidth::I64 | IntWidth::I32 | IntWidth::I16 | IntWidth::I8,
)) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
@ -746,6 +773,37 @@ impl<
.load_to_general_reg(&mut self.buf, src2);
ASM::imul_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
Layout::Builtin(Builtin::Int(
IntWidth::U64 | IntWidth::U32 | IntWidth::U16 | IntWidth::U8,
)) => {
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::umul_reg64_reg64_reg64(
&mut self.buf,
&mut self.storage_manager,
dst_reg,
src1_reg,
src2_reg,
);
}
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::mul_freg64_freg64_freg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
Layout::Builtin(Builtin::Float(FloatWidth::F32)) => {
let dst_reg = self.storage_manager.claim_float_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::mul_freg32_freg32_freg32(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
x => todo!("NumMul: layout, {:?}", x),
}
}

View file

@ -22,7 +22,7 @@ use StackStorage::*;
use Storage::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum RegStorage<GeneralReg: RegTrait, FloatReg: RegTrait> {
pub enum RegStorage<GeneralReg: RegTrait, FloatReg: RegTrait> {
General(GeneralReg),
Float(FloatReg),
}
@ -756,7 +756,7 @@ impl<
#[allow(dead_code)]
/// Ensures that a register is free. If it is not free, data will be moved to make it free.
fn ensure_reg_free(
pub fn ensure_reg_free(
&mut self,
buf: &mut Vec<'a, u8>,
wanted_reg: RegStorage<GeneralReg, FloatReg>,

View file

@ -1009,6 +1009,58 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
imul_reg64_reg64(buf, dst, src2);
}
fn umul_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
dst: X86_64GeneralReg,
src1: X86_64GeneralReg,
src2: X86_64GeneralReg,
) where
ASM: Assembler<X86_64GeneralReg, X86_64FloatReg>,
CC: CallConv<X86_64GeneralReg, X86_64FloatReg, ASM>,
{
use crate::generic64::RegStorage;
storage_manager.ensure_reg_free(buf, RegStorage::General(X86_64GeneralReg::RAX));
storage_manager.ensure_reg_free(buf, RegStorage::General(X86_64GeneralReg::RDX));
mov_reg64_reg64(buf, X86_64GeneralReg::RAX, src1);
mul_reg64_reg64(buf, src2);
mov_reg64_reg64(buf, dst, X86_64GeneralReg::RAX);
}
fn mul_freg32_freg32_freg32(
buf: &mut Vec<'_, u8>,
dst: X86_64FloatReg,
src1: X86_64FloatReg,
src2: X86_64FloatReg,
) {
if dst == src1 {
mulss_freg32_freg32(buf, dst, src2);
} else if dst == src2 {
mulss_freg32_freg32(buf, dst, src1);
} else {
movss_freg32_freg32(buf, dst, src1);
mulss_freg32_freg32(buf, dst, src2);
}
}
#[inline(always)]
fn mul_freg64_freg64_freg64(
buf: &mut Vec<'_, u8>,
dst: X86_64FloatReg,
src1: X86_64FloatReg,
src2: X86_64FloatReg,
) {
if dst == src1 {
mulsd_freg64_freg64(buf, dst, src2);
} else if dst == src2 {
mulsd_freg64_freg64(buf, dst, src1);
} else {
movsd_freg64_freg64(buf, dst, src1);
mulsd_freg64_freg64(buf, dst, src2);
}
}
#[inline(always)]
fn jmp_imm32(buf: &mut Vec<'_, u8>, offset: i32) -> usize {
jmp_imm32(buf, offset);
@ -1280,12 +1332,25 @@ impl X86_64Assembler {
}
}
const REX: u8 = 0x40;
const REX_W: u8 = REX | 0x8;
// see https://wiki.osdev.org/X86-64_Instruction_Encoding#Encoding
/// If set, 64-bit operand size is used
const REX_PREFIX_W: u8 = 0b1000;
/// Extension to the MODRM.reg
const REX_PREFIX_R: u8 = 0b0100;
#[allow(unused)]
/// Extension to the SIB.index field
const REX_PREFIX_X: u8 = 0b0010;
/// Extension to the MODRM.rm
const REX_PREFIX_B: u8 = 0b0001;
/// Wide REX
const REX_W: u8 = REX | REX_PREFIX_W;
#[inline(always)]
fn add_rm_extension<T: RegTrait>(reg: T, byte: u8) -> u8 {
if reg.value() > 7 {
byte | 1
byte | REX_PREFIX_B
} else {
byte
}
@ -1299,7 +1364,7 @@ fn add_opcode_extension(reg: X86_64GeneralReg, byte: u8) -> u8 {
#[inline(always)]
fn add_reg_extension<T: RegTrait>(reg: T, byte: u8) -> u8 {
if reg.value() > 7 {
byte | 4
byte | REX_PREFIX_R
} else {
byte
}
@ -1396,6 +1461,46 @@ fn addss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64Fl
}
}
/// `MULSD xmm1,xmm2/m64` -> Multiply the low double-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)]
fn mulsd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
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;
if dst_high || src_high {
buf.extend(&[
0xF2,
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
0x0F,
0x59,
0xC0 | (dst_mod << 3) | (src_mod),
])
} else {
buf.extend(&[0xF2, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
}
}
/// `ADDSS xmm1,xmm2/m64` -> Add the low single-precision floating-point value from xmm2/mem to xmm1 and store the result in xmm1.
#[inline(always)]
fn mulss_freg32_freg32(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
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;
if dst_high || src_high {
buf.extend(&[
0xF3,
0x40 | ((dst_high as u8) << 2) | (src_high as u8),
0x0F,
0x59,
0xC0 | (dst_mod << 3) | (src_mod),
])
} else {
buf.extend(&[0xF3, 0x0F, 0x59, 0xC0 | (dst_mod << 3) | (src_mod)])
}
}
#[inline(always)]
fn andpd_freg64_freg64(buf: &mut Vec<'_, u8>, dst: X86_64FloatReg, src: X86_64FloatReg) {
let dst_high = dst as u8 > 7;
@ -1465,6 +1570,19 @@ fn imul_reg64_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, src: X86_64Gen
extended_binop_reg64_reg64(0x0F, 0xAF, buf, src, dst);
}
/// `MUL r/m64` -> Unsigned Multiply r/m64 to r64.
#[inline(always)]
fn mul_reg64_reg64(buf: &mut Vec<'_, u8>, src: X86_64GeneralReg) {
let mut rex = REX_W;
rex = add_reg_extension(src, rex);
if src.value() > 7 {
rex |= REX_PREFIX_B;
}
buf.extend(&[rex, 0xF7, 0b1110_0000 | (src as u8 % 8)]);
}
/// Jump near, relative, RIP = RIP + 32-bit displacement sign extended to 64-bits.
#[inline(always)]
fn jmp_imm32(buf: &mut Vec<'_, u8>, imm: i32) {
@ -2086,6 +2204,35 @@ mod tests {
);
}
#[test]
fn test_mul_reg64_reg64() {
disassembler_test!(
mul_reg64_reg64,
|reg| format!("mul {}", reg),
ALL_GENERAL_REGS
);
}
#[test]
fn test_mulsd_freg64_freg64() {
disassembler_test!(
mulsd_freg64_freg64,
|reg1, reg2| format!("mulsd {}, {}", reg1, reg2),
ALL_FLOAT_REGS,
ALL_FLOAT_REGS
);
}
#[test]
fn test_mulss_freg32_freg32() {
disassembler_test!(
mulss_freg32_freg32,
|reg1, reg2| format!("mulss {}, {}", reg1, reg2),
ALL_FLOAT_REGS,
ALL_FLOAT_REGS
);
}
#[test]
fn test_jmp_imm32() {
const INST_SIZE: i32 = 5;

View file

@ -1,5 +1,5 @@
#![warn(clippy::dbg_macro)]
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
#![allow(clippy::large_enum_variant, clippy::upper_case_acronyms)]
use bumpalo::{collections::Vec, Bump};

View file

@ -172,7 +172,7 @@ fn build_object<'a, B: Backend<'a>>(
let arena = backend.env().arena;
/*
// Commented out because we couldn't figure out how to get it to work on mac - see https://github.com/rtfeldman/roc/pull/1323
// Commented out because we couldn't figure out how to get it to work on mac - see https://github.com/roc-lang/roc/pull/1323
let comment = output.add_section(vec![], b".comment".to_vec(), SectionKind::OtherString);
output.append_section_data(
comment,