give immediates a sign & fix stuff
This commit is contained in:
+37
-88
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user