#[derive(Clone, Copy, PartialEq)] pub struct Reg { val: u8, high: bool, width: Width, } #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] #[repr(u8)] pub enum Width { B8 = 0, B16 = 1, B32 = 2, B64 = 3, } def_regs! { 0b0000 : rax eax ax al, 0b0001 : rcx ecx cx cl !_, 0b0010 : rdx edx dx dl, 0b0011 : rbx ebx bx bl, 0b0100 : rsp esp sp spl norex=ah !_, 0b0101 : rbp ebp bp bpl norex=ch, 0b0110 : rsi esi si sil norex=dh !_, 0b0111 : rdi edi di dil norex=bh, 0b1000 : r8 r8d r8w r8b, 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, } impl Reg { pub fn base(&self) -> u8 { self.val & 0b111 } /// checks if register is not one of the first 8 (0-7) pub fn gt8(&self) -> bool { self.val >= 0b1000 } pub fn gt4(&self) -> bool { self.val >= 0b0100 } pub fn width(&self) -> Width { self.width } pub fn not8(&self) -> u8 { self.width.not8() } pub fn high(&self) -> bool { self.high } /// if self has 64 bit width, changes width to 32 bit pub fn lower64(&self) -> Self { let mut new = *self; new.width = new.width.min(Width::B32); new } pub fn requires_rex(&self) -> bool { self.gt8() || self.width == Width::B64 || (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()) } const fn new(val: u8, width: Width, high: bool) -> Self { Self { val, high, width } } } impl Width { pub const fn max_val(&self) -> u64 { match self { Self::B64 => u64::MAX, Self::B32 => u32::MAX as u64, Self::B16 => u16::MAX as u64, Self::B8 { .. } => u8::MAX as u64, } } pub fn min(self, other: Self) -> Self { if self <= other { self } else { other } } pub const fn bytes(&self) -> usize { match self { Self::B64 => 8, Self::B32 => 4, Self::B16 => 2, Self::B8 { .. } => 1, } } /// greater than 8 bits pub const fn not8(&self) -> u8 { !matches!(self, Self::B8) as u8 } } 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 { ($($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => { $( #[allow(non_upper_case_globals)] pub const $B64: Reg = Reg::new($val, Width::B64, false); #[allow(non_upper_case_globals)] pub const $B32: Reg = Reg::new($val, Width::B32, false); #[allow(non_upper_case_globals)] pub const $B16: Reg = Reg::new($val, Width::B16, false); #[allow(non_upper_case_globals)] pub const $B8 : Reg = Reg::new($val, Width::B8 , false); $( #[allow(non_upper_case_globals)] pub const $B8H: Reg = Reg::new($val, Width::B8, true); )? )* 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 { Some(match s.to_lowercase().as_str() { $( stringify!($B64) => $B64, stringify!($B32) => $B32, stringify!($B16) => $B16, stringify!($B8 ) => $B8, $( stringify!($B8H) => $B8H, )? )* _ => return None, }) } } 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", }) } } }; } use def_regs; use crate::arch::x86_64::Imm; impl From for Width { fn from(value: Reg) -> Self { value.width } }