SeaLang/src/asm/amd64.rs
2024-09-02 16:03:12 +02:00

451 lines
12 KiB
Rust

#![allow(unused)]
#[allow(non_camel_case_types)]
pub enum Mnemonic {
/// add with carry
/// two operands
adc,
/// integer add
/// two operands
add,
/// signed multiply
/// two operands
imul,
/// two operands
mov,
/// multiply
/// two operands
mul,
/// one operand
pop,
/// one operand
push,
ret,
/// subtract
/// two operands
sub,
jmp,
/// swap registers
/// two operands
xchg,
/// interrupt
int,
/// bitwise shift left
/// two operands
shl,
/// bitwise shift right
/// two operands
shr,
/// arithmetic bitwise shift left
/// two operands
sal,
/// arithmetic bitwise shift right
/// two operands
sar,
// pseudo instructions
/// one operand
alloca,
}
#[allow(non_camel_case_types)]
#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
#[repr(u8)]
pub enum Register {
rax,eax,ax,al,ah,
rbx,ebx,bx,bl,bh,
rcx,ecx,cx,cl,ch,
rdx,edx,dx,dl,dh,
rsi,esi,si,sil,
rdi,edi,di,dil,
rsp,esp,sp,spl,
rbp,ebp,bp,bpl,
r8,r8d,r8w,r8b,
r9,r9d,r9w,r9b,
r10,r10d,r10w,r10b,
r11,r11d,r11w,r11b,
r12,r12d,r12w,r12b,
r13,r13d,r13w,r13b,
r14,r14d,r14w,r14b,
r15,r15d,r15w,r15b,
rip,eip,ip,__ipl,
st0,st1,st2,st3,st4,st5,st6,st7,
mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7,
xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,
xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15,
ymm0,ymm1,ymm2,ymm3,ymm4,ymm5,ymm6,ymm7,
ymm8,ymm9,ymm10,ymm11,ymm12,ymm13,ymm14,ymm15,
// zmm0,zmm1,zmm2,zmm3,zmm4,zmm5,zmm6,zmm7,
// zmm8,zmm9,zmm10,zmm11,zmm12,zmm13,zmm14,zmm15,
}
impl core::fmt::Display for Register {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
Register::rax => "rax",
Register::eax => "eax",
Register::ax => "ax",
Register::al => "al",
Register::ah => "ah",
Register::rbx => "rbx",
Register::ebx => "ebx",
Register::bx => "bx",
Register::bl => "bl",
Register::bh => "bh",
Register::rcx => "rcx",
Register::ecx => "ecx",
Register::cx => "cx",
Register::cl => "cl",
Register::ch => "ch",
Register::rdx => "rdx",
Register::edx => "edx",
Register::dx => "dx",
Register::dl => "dl",
Register::dh => "dh",
Register::rsi => "rsi",
Register::esi => "esi",
Register::si => "si",
Register::sil => "sil",
Register::rdi => "rdi",
Register::edi => "edi",
Register::di => "di",
Register::dil => "dil",
Register::rsp => "rsp",
Register::esp => "esp",
Register::sp => "sp",
Register::spl => "spl",
Register::rbp => "rbp",
Register::ebp => "ebp",
Register::bp => "bp",
Register::bpl => "bpl",
Register::r8 => "r8",
Register::r8d => "r8d",
Register::r8w => "r8w",
Register::r8b => "r8b",
Register::r9 => "r9",
Register::r9d => "r9d",
Register::r9w => "r9w",
Register::r9b => "r9b",
Register::r10 => "r10",
Register::r10d => "r10d",
Register::r10w => "r10w",
Register::r10b => "r10b",
Register::r11 => "r11",
Register::r11d => "r11d",
Register::r11w => "r11w",
Register::r11b => "r11b",
Register::r12 => "r12",
Register::r12d => "r12d",
Register::r12w => "r12w",
Register::r12b => "r12b",
Register::r13 => "r13",
Register::r13d => "r13d",
Register::r13w => "r13w",
Register::r13b => "r13b",
Register::r14 => "r14",
Register::r14d => "r14d",
Register::r14w => "r14w",
Register::r14b => "r14b",
Register::r15 => "r15",
Register::r15d => "r15d",
Register::r15w => "r15w",
Register::r15b => "r15b",
Register::rip => "rip",
Register::eip => "eip",
Register::ip => "ip",
Register::__ipl => "__ipl",
Register::st0 => "st0",
Register::st1 => "st1",
Register::st2 => "st2",
Register::st3 => "st3",
Register::st4 => "st4",
Register::st5 => "st5",
Register::st6 => "st6",
Register::st7 => "st7",
Register::mm0 => "mm0",
Register::mm1 => "mm1",
Register::mm2 => "mm2",
Register::mm3 => "mm3",
Register::mm4 => "mm4",
Register::mm5 => "mm5",
Register::mm6 => "mm6",
Register::mm7 => "mm7",
Register::xmm0 => "xmm0",
Register::xmm1 => "xmm1",
Register::xmm2 => "xmm2",
Register::xmm3 => "xmm3",
Register::xmm4 => "xmm4",
Register::xmm5 => "xmm5",
Register::xmm6 => "xmm6",
Register::xmm7 => "xmm7",
Register::xmm8 => "xmm8",
Register::xmm9 => "xmm9",
Register::xmm10 => "xmm10",
Register::xmm11 => "xmm11",
Register::xmm12 => "xmm12",
Register::xmm13 => "xmm13",
Register::xmm14 => "xmm14",
Register::xmm15 => "xmm15",
Register::ymm0 => "ymm0",
Register::ymm1 => "ymm1",
Register::ymm2 => "ymm2",
Register::ymm3 => "ymm3",
Register::ymm4 => "ymm4",
Register::ymm5 => "ymm5",
Register::ymm6 => "ymm6",
Register::ymm7 => "ymm7",
Register::ymm8 => "ymm8",
Register::ymm9 => "ymm9",
Register::ymm10 => "ymm10",
Register::ymm11 => "ymm11",
Register::ymm12 => "ymm12",
Register::ymm13 => "ymm13",
Register::ymm14 => "ymm14",
Register::ymm15 => "ymm15",
};
write!(f, "{name}")
}
}
impl Register {
const fn bit_size(self) -> u32 {
use Register::*;
match self {
ah | bh | ch | dh | al | bl | cl | dl | sil | dil | spl | bpl | r8b | r9b | r10b
| r11b | r12b | r13b | r14b | r15b => 8,
ax | bx | cx | dx | si | di | sp | bp | ip | r8w | r9w | r10w | r11w | r12w | r13w
| r14w | r15w => 16,
eax | ebx | ecx | edx | esi | edi | esp | ebp | eip | r8d | r9d | r10d | r11d
| r12d | r13d | r14d | r15d => 32,
rax | rbx | rcx | rdx | rsi | rdi | rsp | rbp | rip | r8 | r9 | r10 | r11 | r12
| r13 | r14 | r15 => 64,
mm0 | mm1 | mm2 | mm3 | mm4 | mm5 | mm6 | mm7 => 64,
st0 | st1 | st2 | st3 | st4 | st5 | st6 | st7 => 80,
xmm0 | xmm1 | xmm2 | xmm3 | xmm4 | xmm5 | xmm6 | xmm7 | xmm8 | xmm9 | xmm10 | xmm11
| xmm12 | xmm13 | xmm14 | xmm15 => 128,
ymm0 | ymm1 | ymm2 | ymm3 | ymm4 | ymm5 | ymm6 | ymm7 | ymm8 | ymm9 | ymm10 | ymm11
| ymm12 | ymm13 | ymm14 | ymm15 => 256,
_ => unreachable!(),
}
}
pub const fn byte_size(self) -> u32 {
self.bit_size().div_ceil(8)
}
pub const fn parent_reg(self) -> Self {
use Register::*;
match self {
rax | eax | ax | ah | al => rax,
rbx | ebx | bx | bh | bl => rbx,
rcx | ecx | cx | ch | cl => rcx,
rdx | edx | dx | dh | dl => rdx,
rsi | esi | si | sil => rsi,
rdi | edi | di | dil => rdi,
rsp | esp | sp | spl => rsp,
rbp | ebp | bp | bpl => rbp,
rip | eip | ip => rip,
r8 | r8d | r8w | r8b => r8,
r9 | r9d | r9w | r9b => r9,
r10 | r10d | r10w | r10b => r10,
r11 | r11d | r11w | r11b => r11,
r12 | r12d | r12w | r12b => r12,
r13 | r13d | r13w | r13b => r13,
r14 | r14d | r14w | r14b => r14,
r15 | r15d | r15w | r15b => r15,
reg => reg,
}
}
const fn from_u8(val: u8) -> Self {
unsafe { *(&val as *const u8 as *const Self) }
}
pub const fn into_qword(self) -> Self {
Self::from_u8(self.parent_reg() as u8)
}
pub const fn into_dword(self) -> Self {
Self::from_u8(self.parent_reg() as u8 + 1)
}
pub const fn into_word(self) -> Self {
Self::from_u8(self.parent_reg() as u8 + 2)
}
pub const fn into_byte(self) -> Self {
Self::from_u8(self.parent_reg() as u8 + 3)
}
fn into_bitsize(self, size: u32) -> Self {
assert!(self < Self::__ipl);
match size {
8 => self.into_byte(),
16 => self.into_word(),
32 => self.into_dword(),
64 => self.into_qword(),
_ => panic!("unsupported bitsize {size}"),
}
}
pub fn into_bytesize(self, size: u32) -> Self {
self.into_bitsize(size * 8)
}
pub const SYSV_CALLEE_SAVED: [Register; 5] = {
use Register::*;
[r12, r13, r14, r15, rbx]
};
pub const SYSV_SCRATCH_GPRS: [Register; 8] = {
use Register::*;
[rax, rsi, rdx, rcx, r8, r9, r10, r11]
};
pub const GPR: [Register; 14] = {
use Register::*;
[
rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15,
]
};
pub const SYSV_ARG_GPR: [Register; 6] = {
use Register::*;
[rdi, rsi, rdx, rcx, r8, r9]
};
pub const SYSV_ARG_SSE: [Register; 8] = {
use Register::*;
[xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7]
};
pub const SSE: [Register; 16] = {
use Register::*;
[
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13,
xmm14, xmm15,
]
};
pub const fn is_gp(self) -> bool {
use Register::*;
match self {
rax | eax | ax | ah | al | rbx | ebx | bx | bh | bl | rcx | ecx | cx | ch | cl
| rdx | edx | dx | dh | dl | rsi | esi | si | sil | rdi | edi | di | dil | r8 | r8d
| r8w | r8b | r9 | r9d | r9w | r9b | r10 | r10d | r10w | r10b | r11 | r11d | r11w
| r11b | r12 | r12d | r12w | r12b | r13 | r13d | r13w | r13b | r14 | r14d | r14w
| r14b | r15 | r15d | r15w | r15b => true,
_ => false,
}
}
pub const fn is_sse(self) -> bool {
use Register::*;
match self {
xmm0 | xmm1 | xmm2 | xmm3 | xmm4 | xmm5 | xmm6 | xmm7 | xmm8 | xmm9 | xmm10 | xmm11
| xmm12 | xmm13 | xmm14 | xmm15 | ymm0 | ymm1 | ymm2 | ymm3 | ymm4 | ymm5 | ymm6
| ymm7 | ymm8 | ymm9 | ymm10 | ymm11 | ymm12 | ymm13 | ymm14 | ymm15 => true,
_ => false,
}
}
}
pub enum Operands {
One(Operand),
Two(Operand, Operand),
Three(Operand, Operand, Operand),
}
#[allow(non_camel_case_types)]
pub enum Operand {
imm8(u8),
imm16(u16),
imm32(u32),
imm64(u64),
reg8(u32),
reg16(u32),
reg32(u32),
reg64(u32),
mem8(u32),
mem16(u32),
mem32(u32),
mem64(u32),
moffset64(u64),
}
impl Operand {
pub fn imm8(i: u8) -> Self {
Operand::imm8(i)
}
pub fn imm16(i: u16) -> Self {
Operand::imm16(i)
}
pub fn imm32(i: u32) -> Self {
Operand::imm32(i)
}
pub fn imm64(i: u64) -> Self {
Operand::imm64(i)
}
pub fn reg8(i: u32) -> Self {
Operand::reg8(i)
}
pub fn reg16(i: u32) -> Self {
Operand::reg16(i)
}
pub fn reg32(i: u32) -> Self {
Operand::reg32(i)
}
pub fn reg64(i: u32) -> Self {
Operand::reg64(i)
}
pub fn mem8(i: u32) -> Self {
Operand::mem8(i)
}
pub fn mem16(i: u32) -> Self {
Operand::mem16(i)
}
pub fn mem32(i: u32) -> Self {
Operand::mem32(i)
}
pub fn mem64(i: u32) -> Self {
Operand::mem64(i)
}
pub fn moffset64(i: u64) -> Self {
Operand::moffset64(i)
}
}
pub enum Imm {
Byte(u8),
Word(u16),
DWord(u32),
/// only allowed for `mov`
QWord(u64),
}
/// r := register, m := memory, i := immediate
#[allow(non_camel_case_types)]
pub enum Payload {
rr(Register, Register),
rm,
ri,
r(Register),
m,
i,
}