give immediates a sign & fix stuff

This commit is contained in:
2026-06-12 17:08:42 -04:00
parent e199620856
commit 7280f7b071
7 changed files with 282 additions and 150 deletions
+37 -88
View File
@@ -1,7 +1,5 @@
use crate::backend::Symbol;
use super::*;
use util::*;
use crate::backend::Symbol;
type ERes = Result<(), CompilerMsg>;
@@ -12,30 +10,6 @@ pub struct Code {
pub(super) missing: Vec<(usize, Symbol)>,
}
#[derive(Clone, Copy)]
pub struct Mem {
pub reg: Reg,
pub disp: i32,
pub width: Width,
}
#[derive(Clone, Copy)]
pub enum RegImmMem {
Reg(Reg),
Imm(u64),
Mem(Mem),
}
#[derive(Clone, Copy)]
pub enum RegMem {
Reg(Reg),
Mem(Mem),
}
pub fn mem(reg: Reg, disp: i32, width: Width) -> Mem {
Mem { reg, disp, width }
}
impl Code {
pub fn mov(&mut self, dst: impl Into<RegMem>, src: impl Into<RegImmMem>) -> ERes {
let dst = dst.into();
@@ -58,42 +32,56 @@ impl Code {
self.bytes.push(modrm_regs(src, dst));
}
RegImmMem::Imm(src) => {
let src_width = Width::fit(src);
let src_width = src.width_unsigned()?;
if src_width > dst.width() {
return Err("immediate cannot fit in register".into());
}
self.prefix16(dst);
if src_width <= Width::B32 {
dst.lower64();
if dst.width() == Width::B64 && src_width <= Width::B32 && src.0 < 0 {
self.bytes
.extend([rex(dst.width(), 0, 0, dst), 0xc7, 0xc0 | dst.base()]);
self.imm(src, Width::B32);
} else {
if src_width <= Width::B32 {
dst = dst.lower64();
}
if dst.requires_rex() {
self.bytes.push(rex(dst.width(), 0, 0, dst));
}
let opcode = 0xb0 | ((dst.width().gt8() as u8) << 3);
self.bytes.push(opcode | dst.base());
self.imm(src, dst.width());
}
if dst.requires_rex() {
self.bytes.push(rex(dst.width(), 0, 0, dst));
}
let opcode = 0xb0 | ((dst.width().gt8() as u8) << 3);
self.bytes.push(opcode | dst.base());
self.bytes.extend(&src.to_le_bytes()[..dst.width().bytes()]);
}
RegImmMem::Mem(src) => todo!(),
},
RegMem::Mem(dst) => match src {
RegImmMem::Reg(src) => todo!(),
RegImmMem::Imm(src) => {
let src_width = Width::fit(src);
let encode_width = dst.width.min(Width::B32);
let src_width = if dst.width == Width::B64 {
src.width_signed()
} else {
src.width_unsigned()
}?;
if src_width == Width::B64 {
return Err("cannot move 64 bit immediate into memory".into());
}
if src_width > dst.width {
return Err("source cannot fit in destination".into());
}
match dst.reg.width() {
Width::B8 | Width::B16 => return Err("invalid register width".into()),
Width::B32 => self.bytes.push(0x67),
Width::B64 => (),
}
self.prefix16(src_width);
if dst.reg.requires_mem_rex() {
self.bytes.push(rex(src_width, 0, 0, dst.reg));
self.prefix16(encode_width);
if dst.reg.requires_mem_rex() || dst.width == Width::B64 {
self.bytes.push(rex(dst.width, 0, 0, dst.reg));
}
self.bytes.push(0xc6 | (src_width != Width::B8) as u8);
self.bytes.push(0xc6 | (encode_width != Width::B8) as u8);
self.modrm_regdisp(dst.reg, dst.disp);
self.bytes.extend(&src.to_le_bytes()[..src_width.bytes()]);
self.imm(src, encode_width);
}
RegImmMem::Mem(_) => return Err("cannot move memory to memory".into()),
},
@@ -113,14 +101,14 @@ impl Code {
Width::B16 => {}
_ => return Err("register must be 64 or 16 bit".into()),
},
RegImmMem::Imm(imm) => match Width::fit(imm) {
RegImmMem::Imm(imm) => match imm.width_unsigned()? {
Width::B8 => {
self.bytes.push(0x6a);
self.bytes.push(imm as u8);
self.bytes.push(imm.0 as u8);
}
Width::B16 | Width::B32 => {
self.bytes.push(0x68);
self.bytes.extend((imm as u32).to_le_bytes());
self.bytes.extend((imm.0 as u32).to_le_bytes());
}
Width::B64 => return Err("immediate must be 32 bit or less".into()),
},
@@ -215,6 +203,10 @@ impl Code {
self.missing
.extend(other.missing.iter().map(|&(p, s)| (pos + p, s)));
}
fn imm(&mut self, imm: Imm, width: Width) {
self.bytes.extend(&imm.0.to_le_bytes()[..width.bytes()]);
}
}
pub fn encode(f: impl FnOnce(&mut Code) -> Result<(), CompilerMsg>) -> Result<Code, CompilerMsg> {
@@ -222,46 +214,3 @@ pub fn encode(f: impl FnOnce(&mut Code) -> Result<(), CompilerMsg>) -> Result<Co
f(&mut code)?;
Ok(code)
}
// fromrot
impl From<Reg> for RegImmMem {
fn from(value: Reg) -> Self {
Self::Reg(value)
}
}
impl From<Reg> for RegMem {
fn from(value: Reg) -> Self {
Self::Reg(value)
}
}
impl From<Mem> for RegImmMem {
fn from(value: Mem) -> Self {
Self::Mem(value)
}
}
impl From<Mem> for RegMem {
fn from(value: Mem) -> Self {
Self::Mem(value)
}
}
impl From<u64> for RegImmMem {
fn from(value: u64) -> Self {
Self::Imm(value)
}
}
impl From<i64> for RegImmMem {
fn from(value: i64) -> Self {
Self::Imm(value as u64)
}
}
impl From<i32> for RegImmMem {
fn from(value: i32) -> Self {
Self::Imm(value as u64)
}
}