tests, but at what cost

This commit is contained in:
2026-06-12 05:09:38 -04:00
parent 7004cdbfe2
commit ceebcdc0e3
7 changed files with 288 additions and 57 deletions
+102 -18
View File
@@ -5,33 +5,34 @@ pub struct Reg {
width: Width,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum Width {
B64,
B32,
B16,
B8,
B8 = 0,
B16 = 1,
B32 = 2,
B64 = 3,
}
def_regs! { Reg;
def_regs! {
0b0000 : rax eax ax al,
0b0001 : rcx ecx cx cl,
0b0001 : rcx ecx cx cl !_,
0b0010 : rdx edx dx dl,
0b0011 : rbx ebx bx bl,
0b0100 : rsp esp sp spl norex=ah,
0b0100 : rsp esp sp spl norex=ah !_,
0b0101 : rbp ebp bp bpl norex=ch,
0b0110 : rsi esi si sil norex=dh,
0b0110 : rsi esi si sil norex=dh !_,
0b0111 : rdi edi di dil norex=bh,
0b1000 : r8 r8d r8w r8b,
0b1001 : r9 r9d r9w r9b,
0b1001 : r9 r9d r9w r9b !_,
0b1010 : r10 r10d r10w r10b,
0b1011 : r11 r11d r11w r11b,
0b1100 : r12 r12d r12w r12b,
0b1101 : r13 r13d r13w r13b,
0b1110 : r14 r14d r14w r14b,
0b1111 : r15 r15d r15w r15b,
0b1111 : r15 r15d r15w r15b !_,
}
impl Reg {
@@ -49,16 +50,29 @@ impl Reg {
self.high
}
pub fn val(&self) -> u8 {
self.val
}
pub fn width(&self) -> Width {
self.width
}
/// if self has 64 bit width, changes width to 32 bit
pub fn lower64(&mut self) {
self.width.lower64()
}
pub fn requires_rex(&self) -> bool {
self.gt8()
|| self.width == Width::B64
|| (self.gt4() && self.width == Width::B8 && !self.high)
}
pub fn requires_mem_rex(&self) -> bool {
self.gt8() || (self.gt4() && self.width == Width::B8 && !self.high)
}
pub fn incompatible(&self, other: &Reg) -> bool {
(self.requires_rex() && other.high) || (self.high && other.requires_rex())
}
@@ -77,6 +91,13 @@ impl Width {
Self::B8 { .. } => u8::MAX as u64,
}
}
pub fn lower64(&mut self) {
if matches!(self, Width::B64) {
*self = Width::B32;
}
}
pub const fn bytes(&self) -> usize {
match self {
Self::B64 => 8,
@@ -85,29 +106,75 @@ impl Width {
Self::B8 { .. } => 1,
}
}
pub const fn fit(val: u64) -> Self {
const B8: u64 = 1 << 8;
const B16: u64 = 1 << 16;
const B32: u64 = 1 << 32;
match val {
..B8 => Self::B8,
B8..B16 => Self::B16,
B16..B32 => Self::B32,
B32.. => Self::B64,
}
}
pub const fn fiti(val: u64) -> Self {
match val {
..0x80 => Self::B8,
0x80..0x8000 => Self::B16,
0x8000..0x8000_0000 => Self::B32,
0x8000_0000.. => Self::B64,
}
}
/// greater than 8 bits
pub const fn gt8(&self) -> bool {
!matches!(self, Self::B8)
}
}
macro_rules! filter {
($($filtered:ident)*; ! $_:tt $($item:ident)*; $($rest:tt)*) => {
filter!($($filtered)* $($item)*; $($rest)*)
};
($($filtered:ident)*; $($item:ident)*; $($rest:tt)*) => {
filter!($($filtered)*; $($rest)*)
};
($($filtered:ident)*;) => {
[$($filtered, )*]
};
}
use filter;
macro_rules! def_regs {
($Struct: ident; $($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)?,)*) => {
($($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => {
$(
#[allow(non_upper_case_globals)]
pub const $B64: $Struct = $Struct::new($val, Width::B64, false);
pub const $B64: Reg = Reg::new($val, Width::B64, false);
#[allow(non_upper_case_globals)]
pub const $B32: $Struct = $Struct::new($val, Width::B32, false);
pub const $B32: Reg = Reg::new($val, Width::B32, false);
#[allow(non_upper_case_globals)]
pub const $B16: $Struct = $Struct::new($val, Width::B16, false);
pub const $B16: Reg = Reg::new($val, Width::B16, false);
#[allow(non_upper_case_globals)]
pub const $B8 : $Struct = $Struct::new($val, Width::B8 , false);
pub const $B8 : Reg = Reg::new($val, Width::B8 , false);
$(
#[allow(non_upper_case_globals)]
pub const $B8H: $Struct = $Struct::new($val, Width::B8, true);
pub const $B8H: Reg = Reg::new($val, Width::B8, true);
)?
)*
impl $Struct {
impl Reg {
#[cfg(test)]
pub const ALL: &[Reg] = &[
$( $B64, $B32, $B16, $B8, $($B8H,)? )*
];
#[cfg(test)]
pub const IMPORTANT: &[Reg] = &
filter!(; $($(!$imp)? $B64 $B32 $B16 $B8 $($B8H)?; )* )
;
pub fn parse(s: &str) -> Option<Self> {
Some(match s.to_lowercase().as_str() {
$(
@@ -123,6 +190,23 @@ macro_rules! def_regs {
})
}
}
impl std::fmt::Display for Reg {
#[allow(non_upper_case_globals)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match *self {
$(
$B64 => stringify!($B64),
$B32 => stringify!($B32),
$B16 => stringify!($B16),
$B8 => stringify!($B8),
$(
$B8H => stringify!($B8H),
)?
)*
_ => "UNKNOWN",
})
}
}
};
}