add more adds
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
mod setup;
|
||||
use setup::*;
|
||||
|
||||
#[test]
|
||||
fn mov() {
|
||||
let c = &mut TestCtx::new("mov");
|
||||
|
||||
for dst in regs() {
|
||||
for src in regs() {
|
||||
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
|
||||
}
|
||||
}
|
||||
|
||||
for dst in regs() {
|
||||
for src in mems() {
|
||||
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
|
||||
}
|
||||
}
|
||||
|
||||
for dst in regs() {
|
||||
for src in imms() {
|
||||
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
|
||||
}
|
||||
}
|
||||
|
||||
for dst in mems() {
|
||||
for src in regs() {
|
||||
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
|
||||
}
|
||||
}
|
||||
|
||||
for dst in mems() {
|
||||
for src in imms() {
|
||||
eq(c, format!("mov {dst}, {src}"), |c| c.mov(dst, src));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_sub() {
|
||||
let c = &mut TestCtx::new("add_sub");
|
||||
|
||||
// add
|
||||
for dst in regs() {
|
||||
for src in imms() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
for dst in regs() {
|
||||
for src in regs() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
for dst in mems() {
|
||||
for src in imms() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
// sub
|
||||
for dst in regs() {
|
||||
for src in imms() {
|
||||
eq(c, format!("sub {dst}, {src}"), |c| c.sub(dst, src))
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
-46
@@ -19,11 +19,8 @@ impl Code {
|
||||
if dst.width() != src.width() {
|
||||
return Err("src and dst are not same width".into());
|
||||
}
|
||||
if dst.incompatible(&src) {
|
||||
return Err("incompatible registers due to rex".into());
|
||||
}
|
||||
self.prefix16(dst);
|
||||
self.rex(dst, src, 0, dst);
|
||||
self.rex(dst, src, 0, dst)?;
|
||||
self.bytes.push(0x88 | dst.not8());
|
||||
self.modrm(src, dst);
|
||||
}
|
||||
@@ -42,7 +39,7 @@ impl Code {
|
||||
if src_width <= Width::B32 {
|
||||
dst = dst.lower64();
|
||||
}
|
||||
self.rex(dst, 0, 0, dst);
|
||||
self.rex(dst, 0, 0, dst)?;
|
||||
self.bytes.push(0xb0 | (dst.not8() << 3) | dst.base());
|
||||
self.imm(src, dst.width());
|
||||
}
|
||||
@@ -51,12 +48,9 @@ impl Code {
|
||||
if src.width != dst.width() {
|
||||
return Err("register & memory sizes don't match".into());
|
||||
}
|
||||
if dst.high() && src.reg.gt8() {
|
||||
return Err("registers incompatible (REX)".into());
|
||||
}
|
||||
self.prefix32(src)?;
|
||||
self.prefix16(dst);
|
||||
self.rex(dst, dst, 0, src);
|
||||
self.rex(dst, dst, 0, src)?;
|
||||
self.bytes.push(0x8a | dst.not8());
|
||||
self.modrm(dst, src);
|
||||
}
|
||||
@@ -66,12 +60,9 @@ impl Code {
|
||||
if src.width() != dst.width {
|
||||
return Err("register & memory sizes don't match".into());
|
||||
}
|
||||
if src.high() && dst.reg.gt8() {
|
||||
return Err("registers incompatible (REX)".into());
|
||||
}
|
||||
self.prefix32(dst)?;
|
||||
self.prefix16(src);
|
||||
self.rex(dst, src, 0, dst);
|
||||
self.rex(dst, src, 0, dst)?;
|
||||
self.bytes.push(0x88 | src.not8());
|
||||
self.modrm(src, dst);
|
||||
}
|
||||
@@ -90,7 +81,7 @@ impl Code {
|
||||
}
|
||||
self.prefix32(dst)?;
|
||||
self.prefix16(encode_width);
|
||||
self.rex(dst, 0, 0, dst);
|
||||
self.rex(dst, 0, 0, dst)?;
|
||||
self.bytes.push(0xc6 | encode_width.not8());
|
||||
self.modrm(0, dst);
|
||||
self.imm(src, encode_width);
|
||||
@@ -142,10 +133,11 @@ impl Code {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lea(&mut self, dst: Reg, sym: Symbol) {
|
||||
self.rex(1, dst, 0, 0);
|
||||
pub fn lea(&mut self, dst: Reg, sym: Symbol) -> ERes {
|
||||
self.rex(1, dst, 0, 0)?;
|
||||
self.bytes.push(0x8d);
|
||||
self.modrm(dst, sym);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn int(&mut self, code: u8) {
|
||||
@@ -170,42 +162,68 @@ impl Code {
|
||||
self.bytes.push(0xc3);
|
||||
}
|
||||
|
||||
fn add_sub(&mut self, dst: impl RegMem, src: impl Into<Imm>, ext: u8) -> ERes {
|
||||
let mut src = src.into();
|
||||
let mut imm_width = src.width_signed()?;
|
||||
let dst_width = dst.width().min(Width::B32);
|
||||
|
||||
if imm_width > dst_width {
|
||||
imm_width = src.width_unsigned()?;
|
||||
if dst.width() == Width::B64 || imm_width > dst_width {
|
||||
return Err("immediate overflow".into());
|
||||
fn add_sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>, ext: u8) -> ERes {
|
||||
match src.into() {
|
||||
RegMemImm::Reg(src) => {
|
||||
if src.width() != dst.width() {
|
||||
return Err("incompatible widths".into());
|
||||
}
|
||||
self.prefix32(dst)?;
|
||||
self.prefix16(src);
|
||||
self.rex(dst, src, 0, dst)?;
|
||||
self.bytes.push(src.not8());
|
||||
self.modrm(src, dst);
|
||||
}
|
||||
src = src.reinterpret(dst_width);
|
||||
imm_width = src.width_signed()?;
|
||||
}
|
||||
let code = if dst.width() == Width::B8 {
|
||||
0x80
|
||||
} else if imm_width == Width::B8 {
|
||||
0x83
|
||||
} else {
|
||||
imm_width = dst_width;
|
||||
0x81
|
||||
};
|
||||
RegMemImm::Imm(mut src) => {
|
||||
let mut imm_width = src.width_signed()?;
|
||||
let dst_width = dst.width().min(Width::B32);
|
||||
|
||||
self.prefix32(dst)?;
|
||||
self.prefix16(dst_width);
|
||||
self.rex(dst, 0, 0, dst);
|
||||
self.bytes.push(code);
|
||||
self.modrm(ext, dst);
|
||||
self.imm(src, imm_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);
|
||||
imm_width = src.width_signed()?;
|
||||
}
|
||||
let code = if dst.width() == Width::B8 {
|
||||
0x80
|
||||
} else if imm_width == Width::B8 {
|
||||
0x83
|
||||
} else {
|
||||
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, imm_width);
|
||||
}
|
||||
RegMemImm::Mem(src) => {
|
||||
let RegMemKind::Reg(dst) = dst.kind() else {
|
||||
return Err("cannot add memory to memory".into());
|
||||
};
|
||||
if src.width() != dst.width() {
|
||||
return Err("incompatible widths".into());
|
||||
}
|
||||
self.prefix32(src)?;
|
||||
self.prefix16(dst);
|
||||
self.rex(dst, dst, 0, src)?;
|
||||
self.bytes.push(0x2 | dst.not8());
|
||||
self.modrm(dst, src);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add(&mut self, dst: impl RegMem, src: impl Into<Imm>) -> ERes {
|
||||
pub fn add(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> ERes {
|
||||
self.add_sub(dst, src, 0)
|
||||
}
|
||||
|
||||
pub fn sub(&mut self, dst: impl RegMem, src: impl Into<Imm>) -> ERes {
|
||||
pub fn sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> ERes {
|
||||
self.add_sub(dst, src, 5)
|
||||
}
|
||||
|
||||
@@ -227,10 +245,14 @@ impl Code {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rex(&mut self, w: impl RexW, r: impl RexBit, x: u8, b: impl RexBit) {
|
||||
if w.rexw() || r.rex() || x.rex() || b.rex() | r.req() | b.req() {
|
||||
fn rex(&mut self, w: impl RexW, r: impl RexBit, x: u8, b: impl RexBit) -> ERes {
|
||||
if r.req() && b.req_no() || r.req_no() && b.req() {
|
||||
return Err("registers incompatible (REX)".into());
|
||||
}
|
||||
if w.rexw() || r.rex() || x.rex() || b.rex() || r.req() || b.req() {
|
||||
self.bytes.push(rex(w, r, x, b));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modrm(&mut self, reg: impl ModRMReg, rm: impl ModRMRM) {
|
||||
|
||||
@@ -38,20 +38,40 @@ fn mov() {
|
||||
|
||||
#[test]
|
||||
fn add_sub() {
|
||||
let c = &mut TestCtx::new("mov");
|
||||
let c = &mut TestCtx::new("add_sub");
|
||||
|
||||
// add
|
||||
for dst in regs() {
|
||||
for src in imms() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
for dst in regs() {
|
||||
for src in regs() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
for dst in regs() {
|
||||
for src in mems() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
for dst in mems() {
|
||||
for src in imms() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
for dst in mems() {
|
||||
for src in regs() {
|
||||
eq(c, format!("add {dst}, {src}"), |c| c.add(dst, src))
|
||||
}
|
||||
}
|
||||
|
||||
// sub
|
||||
for dst in regs() {
|
||||
for src in imms() {
|
||||
eq(c, format!("sub {dst}, {src}"), |c| c.sub(dst, src))
|
||||
|
||||
@@ -59,6 +59,7 @@ pub struct TestCtx {
|
||||
changed: bool,
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn eq(
|
||||
ctx: &mut TestCtx,
|
||||
asm: impl AsRef<str>,
|
||||
@@ -102,7 +103,7 @@ fn nasm(input: &str) -> Result<Vec<u8>, String> {
|
||||
let fout = "/tmp/69420nasm_out.o";
|
||||
let input = "result:".to_string() + input;
|
||||
write(fin, input.as_bytes());
|
||||
run(["nasm", "-w+error", "-felf64", fin, &format!("-o{fout}")])?;
|
||||
run(["nasm", "-O1", "-w+error", "-felf64", fin, &format!("-o{fout}")])?;
|
||||
let output = run(["objdump", "--no-addresses", "-dw", "-Mintel", fout])?;
|
||||
let mut iter = output.lines().skip_while(|l| !l.contains("result")).skip(1);
|
||||
let res_line = iter.next().unwrap().trim();
|
||||
|
||||
@@ -196,6 +196,9 @@ pub trait RexBit: Sized {
|
||||
fn req(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn req_no(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl RexBit for u8 {
|
||||
@@ -211,12 +214,18 @@ impl RexBit for Reg {
|
||||
fn req(&self) -> bool {
|
||||
self.gt4() && (self.width() == Width::B8) && !self.high()
|
||||
}
|
||||
fn req_no(&self) -> bool {
|
||||
self.high()
|
||||
}
|
||||
}
|
||||
|
||||
impl RexBit for Mem {
|
||||
fn rex(&self) -> bool {
|
||||
self.reg.rex()
|
||||
}
|
||||
fn req(&self) -> bool {
|
||||
self.reg.gt8()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RexW {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user