mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Add immediate addition and subtraction for AArch46
This commit is contained in:
parent
f9d571ebc2
commit
be979b4218
3 changed files with 108 additions and 21 deletions
|
@ -147,12 +147,11 @@ impl CallConv<AArch64GPReg> for AArch64Call {
|
|||
requested_stack_size.checked_add(8 * saved_regs.len() as i32 + offset as i32)
|
||||
{
|
||||
if aligned_stack_size > 0 {
|
||||
// TODO deal with sizes over imm12.
|
||||
sub_reg64_reg64_imm12(
|
||||
AArch64Assembler::sub_reg64_reg64_imm32(
|
||||
buf,
|
||||
AArch64GPReg::ZRSP,
|
||||
AArch64GPReg::ZRSP,
|
||||
aligned_stack_size as u16,
|
||||
aligned_stack_size,
|
||||
);
|
||||
|
||||
// All the following stores could be optimized by using `STP` to store pairs.
|
||||
|
@ -196,12 +195,11 @@ impl CallConv<AArch64GPReg> for AArch64Call {
|
|||
offset -= 8;
|
||||
AArch64Assembler::mov_reg64_stack32(buf, *reg, offset);
|
||||
}
|
||||
// TODO deal with sizes over imm12.
|
||||
add_reg64_reg64_imm12(
|
||||
AArch64Assembler::add_reg64_reg64_imm32(
|
||||
buf,
|
||||
AArch64GPReg::ZRSP,
|
||||
AArch64GPReg::ZRSP,
|
||||
aligned_stack_size as u16,
|
||||
aligned_stack_size,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
|
@ -209,6 +207,29 @@ impl CallConv<AArch64GPReg> for AArch64Call {
|
|||
}
|
||||
|
||||
impl Assembler<AArch64GPReg> for AArch64Assembler {
|
||||
#[inline(always)]
|
||||
fn abs_reg64_reg64<'a>(_buf: &mut Vec<'a, u8>, _dst: AArch64GPReg, _src: AArch64GPReg) {
|
||||
unimplemented!("abs_reg64_reg64 is not yet implement for AArch64");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_reg64_reg64_imm32<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
dst: AArch64GPReg,
|
||||
src: AArch64GPReg,
|
||||
imm32: i32,
|
||||
) {
|
||||
if imm32 < 0 {
|
||||
unimplemented!("immediate addition with values less than 0 are not yet implemented");
|
||||
} else if imm32 < 0xFFF {
|
||||
add_reg64_reg64_imm12(buf, dst, src, imm32 as u16);
|
||||
} else {
|
||||
unimplemented!(
|
||||
"immediate additions with values greater than 12bits are not yet implemented"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_reg64_reg64_reg64<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
|
@ -267,8 +288,23 @@ impl Assembler<AArch64GPReg> for AArch64Assembler {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn abs_reg64_reg64<'a>(_buf: &mut Vec<'a, u8>, _dst: AArch64GPReg, _src: AArch64GPReg) {
|
||||
unimplemented!("abs_reg64_reg64 is not yet implement for AArch64");
|
||||
fn sub_reg64_reg64_imm32<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
dst: AArch64GPReg,
|
||||
src: AArch64GPReg,
|
||||
imm32: i32,
|
||||
) {
|
||||
if imm32 < 0 {
|
||||
unimplemented!(
|
||||
"immediate subtractions with values less than 0 are not yet implemented"
|
||||
);
|
||||
} else if imm32 < 0xFFF {
|
||||
sub_reg64_reg64_imm12(buf, dst, src, imm32 as u16);
|
||||
} else {
|
||||
unimplemented!(
|
||||
"immediate subtractions with values greater than 12bits are not yet implemented"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -277,6 +313,8 @@ impl Assembler<AArch64GPReg> for AArch64Assembler {
|
|||
}
|
||||
}
|
||||
|
||||
impl AArch64Assembler {}
|
||||
|
||||
/// AArch64Instruction, maps all instructions to an enum.
|
||||
/// Decoding the function should be cheap because we will always inline.
|
||||
/// All of the operations should resolved by constants, leave just some bit manipulation.
|
||||
|
|
|
@ -43,12 +43,14 @@ pub trait CallConv<GPReg: GPRegTrait> {
|
|||
/// Generally, I prefer explicit sources, as opposed to dst being one of the sources. Ex: `x = x + y` would be `add x, x, y` instead of `add x, y`.
|
||||
/// dst should always come before sources.
|
||||
pub trait Assembler<GPReg: GPRegTrait> {
|
||||
fn abs_reg64_reg64<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, src: GPReg);
|
||||
fn add_reg64_reg64_imm32<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, src1: GPReg, imm32: i32);
|
||||
fn add_reg64_reg64_reg64<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, src1: GPReg, src2: GPReg);
|
||||
fn mov_reg64_imm64<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, imm: i64);
|
||||
fn mov_reg64_reg64<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, src: GPReg);
|
||||
fn mov_reg64_stack32<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, offset: i32);
|
||||
fn mov_stack32_reg64<'a>(buf: &mut Vec<'a, u8>, offset: i32, src: GPReg);
|
||||
fn abs_reg64_reg64<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, src: GPReg);
|
||||
fn sub_reg64_reg64_imm32<'a>(buf: &mut Vec<'a, u8>, dst: GPReg, src1: GPReg, imm32: i32);
|
||||
fn ret<'a>(buf: &mut Vec<'a, u8>);
|
||||
}
|
||||
|
||||
|
|
|
@ -179,11 +179,11 @@ fn x86_64_generic_setup_stack<'a>(
|
|||
requested_stack_size: i32,
|
||||
) -> Result<i32, String> {
|
||||
if !leaf_function {
|
||||
push_reg64(buf, X86_64GPReg::RBP);
|
||||
X86_64Assembler::push_reg64(buf, X86_64GPReg::RBP);
|
||||
X86_64Assembler::mov_reg64_reg64(buf, X86_64GPReg::RBP, X86_64GPReg::RSP);
|
||||
}
|
||||
for reg in saved_regs {
|
||||
push_reg64(buf, *reg);
|
||||
X86_64Assembler::push_reg64(buf, *reg);
|
||||
}
|
||||
|
||||
// full size is upcast to i64 to make sure we don't overflow here.
|
||||
|
@ -200,8 +200,12 @@ fn x86_64_generic_setup_stack<'a>(
|
|||
};
|
||||
if let Some(aligned_stack_size) = requested_stack_size.checked_add(offset as i32) {
|
||||
if aligned_stack_size > 0 {
|
||||
// TODO: move this call to one using X86_64Assembler.
|
||||
sub_reg64_imm32(buf, X86_64GPReg::RSP, aligned_stack_size);
|
||||
X86_64Assembler::sub_reg64_reg64_imm32(
|
||||
buf,
|
||||
X86_64GPReg::RSP,
|
||||
X86_64GPReg::RSP,
|
||||
aligned_stack_size,
|
||||
);
|
||||
Ok(aligned_stack_size)
|
||||
} else {
|
||||
Ok(0)
|
||||
|
@ -219,15 +223,19 @@ fn x86_64_generic_cleanup_stack<'a>(
|
|||
aligned_stack_size: i32,
|
||||
) -> Result<(), String> {
|
||||
if aligned_stack_size > 0 {
|
||||
// TODO: move this call to one using X86_64Assembler.
|
||||
add_reg64_imm32(buf, X86_64GPReg::RSP, aligned_stack_size);
|
||||
X86_64Assembler::add_reg64_reg64_imm32(
|
||||
buf,
|
||||
X86_64GPReg::RSP,
|
||||
X86_64GPReg::RSP,
|
||||
aligned_stack_size,
|
||||
);
|
||||
}
|
||||
for reg in saved_regs.iter().rev() {
|
||||
pop_reg64(buf, *reg);
|
||||
X86_64Assembler::pop_reg64(buf, *reg);
|
||||
}
|
||||
if !leaf_function {
|
||||
X86_64Assembler::mov_reg64_reg64(buf, X86_64GPReg::RSP, X86_64GPReg::RBP);
|
||||
pop_reg64(buf, X86_64GPReg::RBP);
|
||||
X86_64Assembler::pop_reg64(buf, X86_64GPReg::RBP);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -236,6 +244,26 @@ impl Assembler<X86_64GPReg> for X86_64Assembler {
|
|||
// These functions should map to the raw assembly functions below.
|
||||
// In some cases, that means you can just directly call one of the direct assembly functions.
|
||||
#[inline(always)]
|
||||
fn abs_reg64_reg64<'a>(buf: &mut Vec<'a, u8>, dst: X86_64GPReg, src: X86_64GPReg) {
|
||||
mov_reg64_reg64(buf, dst, src);
|
||||
neg_reg64(buf, dst);
|
||||
cmovl_reg64_reg64(buf, dst, src);
|
||||
}
|
||||
#[inline(always)]
|
||||
fn add_reg64_reg64_imm32<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
dst: X86_64GPReg,
|
||||
src1: X86_64GPReg,
|
||||
imm32: i32,
|
||||
) {
|
||||
if dst == src1 {
|
||||
add_reg64_imm32(buf, dst, imm32);
|
||||
} else {
|
||||
mov_reg64_reg64(buf, dst, src1);
|
||||
add_reg64_imm32(buf, dst, imm32);
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn add_reg64_reg64_reg64<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
dst: X86_64GPReg,
|
||||
|
@ -268,10 +296,18 @@ impl Assembler<X86_64GPReg> for X86_64Assembler {
|
|||
mov_stack32_reg64(buf, offset, src);
|
||||
}
|
||||
#[inline(always)]
|
||||
fn abs_reg64_reg64<'a>(buf: &mut Vec<'a, u8>, dst: X86_64GPReg, src: X86_64GPReg) {
|
||||
mov_reg64_reg64(buf, dst, src);
|
||||
neg_reg64(buf, dst);
|
||||
cmovl_reg64_reg64(buf, dst, src);
|
||||
fn sub_reg64_reg64_imm32<'a>(
|
||||
buf: &mut Vec<'a, u8>,
|
||||
dst: X86_64GPReg,
|
||||
src1: X86_64GPReg,
|
||||
imm32: i32,
|
||||
) {
|
||||
if dst == src1 {
|
||||
sub_reg64_imm32(buf, dst, imm32);
|
||||
} else {
|
||||
mov_reg64_reg64(buf, dst, src1);
|
||||
sub_reg64_imm32(buf, dst, imm32);
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn ret<'a>(buf: &mut Vec<'a, u8>) {
|
||||
|
@ -279,6 +315,17 @@ impl Assembler<X86_64GPReg> for X86_64Assembler {
|
|||
}
|
||||
}
|
||||
|
||||
impl X86_64Assembler {
|
||||
#[inline(always)]
|
||||
fn pop_reg64<'a>(buf: &mut Vec<'a, u8>, reg: X86_64GPReg) {
|
||||
pop_reg64(buf, reg);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn push_reg64<'a>(buf: &mut Vec<'a, u8>, reg: X86_64GPReg) {
|
||||
push_reg64(buf, reg);
|
||||
}
|
||||
}
|
||||
const REX: u8 = 0x40;
|
||||
const REX_W: u8 = REX + 0x8;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue