This commit is contained in:
2026-06-16 23:55:47 -04:00
parent d66f8f02b7
commit 113f3d4d9c
11 changed files with 344 additions and 282 deletions
+33 -28
View File
@@ -23,10 +23,9 @@ impl Code {
if dst.incompatible(&src) {
return Err("incompatible registers due to rex".into());
}
let width = dst.width();
self.prefix16(width);
self.rex(width, src, 0, dst);
self.bytes.push(0x88 | width.not8());
self.prefix16(dst);
self.rex(dst, src, 0, dst);
self.bytes.push(0x88 | dst.not8());
self.modrm(src, dst);
}
RegImmMem::Imm(src) => {
@@ -56,7 +55,7 @@ impl Code {
if dst.high() && src.reg.gt8() {
return Err("registers incompatible (REX)".into());
}
self.prefix32(&src)?;
self.prefix32(src)?;
self.prefix16(dst);
self.rex(dst, dst, 0, src);
self.bytes.push(0x8a | dst.not8());
@@ -71,7 +70,7 @@ impl Code {
if src.high() && dst.reg.gt8() {
return Err("registers incompatible (REX)".into());
}
self.prefix32(&dst)?;
self.prefix32(dst)?;
self.prefix16(src);
self.rex(dst, src, 0, dst);
self.bytes.push(0x88 | src.not8());
@@ -90,7 +89,7 @@ impl Code {
if src_width > dst.width {
return Err("source cannot fit in destination".into());
}
self.prefix32(&dst)?;
self.prefix32(dst)?;
self.prefix16(encode_width);
self.rex(dst, 0, 0, dst);
self.bytes.push(0xc6 | encode_width.not8());
@@ -172,39 +171,42 @@ impl Code {
self.bytes.push(0xc3);
}
fn add_sub(&mut self, dst: Reg, src: impl Into<Imm>, ext: u8) -> ERes {
fn add_sub(&mut self, dst: impl RegMem_, src: impl Into<Imm>, ext: u8) -> ERes {
let mut src = src.into();
let mut width = src.width_signed()?;
let mut imm_width = src.width_signed()?;
let dst_width = dst.width().min(Width::B32);
self.prefix16(dst_width);
self.rex(dst, 0, 0, dst);
if width > dst_width {
width = src.width_unsigned()?;
if dst.width() == Width::B64 || width > dst_width {
if imm_width > dst_width {
imm_width = src.width_unsigned()?;
if dst.width() == Width::B64 || imm_width > dst_width {
return Err("immediate overflow".into());
}
src = src.reinterpret(dst_width);
width = src.width_signed()?;
imm_width = src.width_signed()?;
}
if dst.width() == Width::B8 {
self.bytes.push(0x80);
} else if width == Width::B8 {
self.bytes.push(0x83);
let code = if dst.width() == Width::B8 {
0x80
} else if imm_width == Width::B8 {
0x83
} else {
self.bytes.push(0x81);
width = dst_width;
}
imm_width = dst_width;
0x81
};
self.prefix32(dst)?;
self.prefix16(dst_width);
self.rex(dst, 0, 0, dst);
self.bytes.push(code);
self.modrm(ext, dst);
self.imm(src, width);
self.imm(src, imm_width);
Ok(())
}
pub fn add(&mut self, dst: Reg, src: impl Into<Imm>) -> ERes {
self.add_sub(dst, src, 0)
pub fn add(&mut self, dst: impl Into<RegMem>, src: impl Into<Imm>) -> ERes {
match dst.into() {
RegMem::Reg(dst) => self.add_sub(dst, src, 0),
RegMem::Mem(dst) => self.add_sub(dst, src, 0),
}
}
pub fn sub(&mut self, dst: Reg, src: impl Into<Imm>) -> ERes {
@@ -217,7 +219,10 @@ impl Code {
}
}
fn prefix32(&mut self, mem: &Mem) -> Result<(), CompilerMsg> {
fn prefix32(&mut self, mem: impl MaybeMem) -> Result<(), CompilerMsg> {
let Some(mem) = mem.mem() else {
return Ok(());
};
match mem.reg.width() {
Width::B8 | Width::B16 => return Err("invalid register width".into()),
Width::B32 => self.bytes.push(0x67),