lots of refactoring

This commit is contained in:
2026-06-11 00:15:09 -04:00
parent bc922a6086
commit ddf63ad817
9 changed files with 345 additions and 160 deletions
+52 -64
View File
@@ -2,6 +2,7 @@ use std::collections::HashMap;
use super::*;
use crate::backend::{LibImport, LinkedProgram, SymImport, SymTable, Symbol};
use util::*;
pub struct Encoder<'a> {
pub data: Vec<u8>,
@@ -71,63 +72,42 @@ fn compile_instr(encoder: &mut Encoder, instr: &BInstr) -> Result<(), CompilerMs
impl Encoder<'_> {
// assembly
pub fn mov(&mut self, dst: RegMode, src: impl Into<RegImmMem>) -> Result<(), CompilerMsg> {
let src = src.into();
let width = dst.width;
if width == BitWidth::B16 {
pub fn movi(&mut self, dst: RegWH, imm: u64) -> Result<(), CompilerMsg> {
if dst.widthh == WidthH::B16 {
self.data.push(0x66);
}
let dst8 = dst.gt8();
let b64 = width == BitWidth::B64;
let b8 = width == BitWidth::B8;
let src8 = if let RegImmMem::Reg(src) = src {
src.gt8()
} else {
false
};
// special 64-bit / register 4-7 indicator
if dst8 || src8 || b64 || (dst.gt4() && !dst.high) {
self.data
.push(0x40 | dst8 as u8 | ((b64 as u8) << 3) | ((src8 as u8) << 2));
if dst.requires_rex() {
self.data.push(rex(dst.widthh, 0, 0, dst));
}
match src {
RegImmMem::Reg(src) => {
if dst.width != src.width {
return Err("src and dst are not the same size".into());
}
self.data.push(0x88 | !b8 as u8);
let modrm = 0b11_000_000 | (src.base() << 3) | dst.base();
self.data.push(modrm);
}
RegImmMem::Imm(imm) => {
if imm > width.max() {
return Err("immediate cannot fit in register".into());
}
self.data.push(0xb0 | ((!b8 as u8) << 3) | dst.base());
self.data.extend(&imm.to_le_bytes()[..width.bytes()]);
}
if imm > dst.widthh.max() {
return Err("immediate cannot fit in register".into());
}
let opcode = 0xb0 | ((dst.widthh.gt8() as u8) << 3);
self.data.push(opcode | dst.base());
self.data.extend(&imm.to_le_bytes()[..dst.widthh.bytes()]);
Ok(())
}
pub fn mem_mov(&mut self, reg: RegMode, offset: u64, val: u64) {
assert!(offset <= u8::MAX as u64);
assert!(val <= u32::MAX as u64);
self.data
.extend([0x48 | ((reg.gt8() as u8) << 2), 0xc7, 0x40 | reg.base()]);
if reg.reg == rsp.reg {
self.data.push(0x24)
pub fn movr(&mut self, dst: RegH, src: RegH, width: Width) {
if width == Width::B16 {
self.data.push(0x66);
}
self.data.push(offset as u8);
self.data.extend((val as u32).to_le_bytes());
if src.requires_rex(width) || dst.requires_rex(width) {
self.data.push(rex(width, src, 0, dst));
}
self.data.push(0x88 | width.gt8() as u8);
self.data.push(modrm_regs(src, dst));
}
pub fn lea(&mut self, dst: RegMode, sym: Symbol) {
self.data.extend([
0x48 | ((dst.gt8() as u8) << 2),
0x8d,
0x05 | (dst.base() << 3),
]);
pub fn movm(&mut self, reg: RegWH, offset: u32, val: u32) {
self.data.extend([rex(1, reg, 0, 0), 0xc7]);
self.modrm_regdisp(reg, offset);
self.data.extend(val.to_le_bytes());
}
pub fn lea(&mut self, dst: RegWH, sym: Symbol) {
self.data
.extend([rex(1, dst, 0, 0), 0x8d, modrm_disp32(dst)]);
self.sym_offset4(sym);
}
@@ -144,7 +124,7 @@ impl Encoder<'_> {
self.sym_offset4(sym);
}
pub fn call_mem(&mut self, sym: Symbol) {
pub fn callm(&mut self, sym: Symbol) {
self.data.extend([0xff, 0x15]);
self.sym_offset4(sym);
}
@@ -153,15 +133,15 @@ impl Encoder<'_> {
self.data.push(0xc3);
}
pub fn push(&mut self, reg: Reg) {
pub fn pushr(&mut self, reg: Reg) {
if reg.gt8() {
self.data.push(0x41);
}
self.data.push(0x50 | reg.base());
}
pub fn push_imm(&mut self, imm: u64) {
const U8: u64 = 2 << 8;
pub fn pushi(&mut self, imm: u32) {
const U8: u32 = 2 << 8;
if let 0..U8 = imm {
self.data.push(0x6a);
self.data.push(imm as u8);
@@ -195,30 +175,38 @@ impl Encoder<'_> {
pub fn asm(&mut self, instr: Instr) -> Result<(), CompilerMsg> {
match instr {
Instr::Mov { dst, src } => self.mov(dst, src)?,
Instr::MemMov { reg, offset, val } => self.mem_mov(reg, offset, val),
Instr::Movr { dst, src, width } => self.movr(dst, src, width),
Instr::Movi { dst, imm } => self.movi(dst, imm)?,
Instr::Movm { reg, offset, val } => self.movm(reg, offset, val),
Instr::Int(code) => self.int(code),
Instr::Syscall => self.syscall(),
Instr::Lea { dst, sym } => self.lea(dst, sym),
Instr::Call(sym) => self.call(sym),
Instr::Callm(sym) => self.callm(sym),
Instr::Ret => self.ret(),
Instr::Push(val) => match val {
RegImm::Reg(reg) => self.push(reg),
RegImm::Imm(imm) => self.push_imm(imm),
},
Instr::Pushr(reg) => self.pushr(reg),
Instr::Pushi(imm) => self.pushi(imm),
Instr::Pop(reg) => self.pop(reg),
Instr::CallMem(sym) => self.call_mem(sym),
Instr::Sub => self.data.extend([0x48, 0x83, 0xec, 0x28]),
}
Ok(())
}
}
/// assumes the next instruction is directly after
fn addr_offset(pos: usize, addr: u64) -> [u8; 4] {
let pos = (pos + 4) as i32;
let offset = addr as i32 - pos;
offset.to_le_bytes()
pub fn modrm_regdisp(&mut self, reg: impl Into<Reg>, disp: u32) {
let reg = reg.into();
let disp8 = disp < u8::MAX as u32;
let mod_ = if disp8 { 0b01 } else { 0b10 };
self.data.push(modrm(mod_, 0, reg.base()));
if reg == rsp.reg {
// SIB
self.data.push(0x24);
}
if disp8 {
self.data.push(disp as u8);
} else {
self.data.extend(disp.to_le_bytes());
}
}
}
impl<'a> Encoder<'a> {