use crate::{Register, RegisterUnderlyingType, RoundingControl, RoundingControlUnderlyingType};
use core::{fmt, mem};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[allow(dead_code)]
pub(crate) enum MemoryOperandSize {
None,
Byte,
Word,
Dword,
Qword,
Tbyte,
Fword,
Xword,
Yword,
Zword,
}
#[rustfmt::skip]
static GEN_DEBUG_MEMORY_OPERAND_SIZE: [&str; 10] = [
"None",
"Byte",
"Word",
"Dword",
"Qword",
"Tbyte",
"Fword",
"Xword",
"Yword",
"Zword",
];
impl fmt::Debug for MemoryOperandSize {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", GEN_DEBUG_MEMORY_OPERAND_SIZE[*self as usize])
}
}
impl Default for MemoryOperandSize {
#[must_use]
#[inline]
fn default() -> Self {
MemoryOperandSize::None
}
}
struct CodeAsmOpStateFlags1;
impl CodeAsmOpStateFlags1 {
pub const NONE: u8 = 0;
pub const SEGMENT_SHIFT: u8 = 0;
pub const SEGMENT_MASK: u8 = 7;
pub const SIZE_SHIFT: u8 = 3;
pub const SIZE_MASK: u8 = 0xF;
pub const BROADCAST: u8 = 0x80;
}
struct CodeAsmOpStateFlags2;
impl CodeAsmOpStateFlags2 {
pub const NONE: u8 = 0;
pub const OP_MASK_SHIFT: u8 = 0;
pub const OP_MASK_MASK: u8 = 7;
pub const ROUNDING_CONTROL_SHIFT: u8 = 3;
pub const ROUNDING_CONTROL_MASK: u8 = 7;
pub const ZEROING_MASKING: u8 = 0x40;
pub const SUPPRESS_ALL_EXCEPTIONS: u8 = 0x80;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct CodeAsmOpState {
flags1: u8, flags2: u8, }
impl CodeAsmOpState {
#[must_use]
#[inline]
pub const fn new() -> Self {
Self { flags1: CodeAsmOpStateFlags1::NONE, flags2: CodeAsmOpStateFlags2::NONE }
}
#[must_use]
#[inline]
pub fn is_default(&self) -> bool {
(self.flags1 | self.flags2) == 0
}
#[must_use]
pub fn merge(&self, other: CodeAsmOpState) -> Self {
const FLAGS1_KEEP: u8 = CodeAsmOpStateFlags1::BROADCAST;
const FLAGS2_KEEP: u8 = (CodeAsmOpStateFlags2::OP_MASK_MASK << CodeAsmOpStateFlags2::OP_MASK_SHIFT)
| CodeAsmOpStateFlags2::SUPPRESS_ALL_EXCEPTIONS
| CodeAsmOpStateFlags2::ZEROING_MASKING;
const _: () = assert!(CodeAsmOpStateFlags2::OP_MASK_MASK == 7);
let mut flags1 = (self.flags1 | other.flags1) & FLAGS1_KEEP;
let mut flags2 = (self.flags2 | other.flags2) & FLAGS2_KEEP;
macro_rules! copy_bits {
($flags_name:ident, $mask:expr, $shift:expr) => {{
const BITS: u8 = $mask << $shift;
let bits = if (self.$flags_name & BITS) != 0 { self.$flags_name } else { other.$flags_name };
$flags_name |= bits & BITS;
}};
}
copy_bits!(flags1, CodeAsmOpStateFlags1::SEGMENT_MASK, CodeAsmOpStateFlags1::SEGMENT_SHIFT);
copy_bits!(flags1, CodeAsmOpStateFlags1::SIZE_MASK, CodeAsmOpStateFlags1::SIZE_SHIFT);
copy_bits!(flags2, CodeAsmOpStateFlags2::ROUNDING_CONTROL_MASK, CodeAsmOpStateFlags2::ROUNDING_CONTROL_SHIFT);
Self { flags1, flags2 }
}
#[must_use]
#[inline]
#[allow(trivial_numeric_casts)]
pub fn size(&self) -> MemoryOperandSize {
unsafe { mem::transmute((self.flags1 >> CodeAsmOpStateFlags1::SIZE_SHIFT) & CodeAsmOpStateFlags1::SIZE_MASK) }
}
#[inline]
pub fn ptr(&mut self, size: MemoryOperandSize) {
self.flags1 = (self.flags1 & !((CodeAsmOpStateFlags1::SIZE_MASK << CodeAsmOpStateFlags1::SIZE_SHIFT) | CodeAsmOpStateFlags1::BROADCAST))
| ((size as u8) << CodeAsmOpStateFlags1::SIZE_SHIFT);
}
#[inline]
pub fn bcst(&mut self, size: MemoryOperandSize) {
self.flags1 = (self.flags1 & !(CodeAsmOpStateFlags1::SIZE_MASK << CodeAsmOpStateFlags1::SIZE_SHIFT))
| (((size as u8) << CodeAsmOpStateFlags1::SIZE_SHIFT) | CodeAsmOpStateFlags1::BROADCAST);
}
#[must_use]
#[inline]
#[allow(trivial_numeric_casts)]
pub fn segment(&self) -> Register {
let number = ((self.flags1 >> CodeAsmOpStateFlags1::SEGMENT_SHIFT) & CodeAsmOpStateFlags1::SEGMENT_MASK).wrapping_sub(1);
const _: () = assert!(Register::ES as u32 + 1 == Register::CS as u32);
const _: () = assert!(Register::ES as u32 + 2 == Register::SS as u32);
const _: () = assert!(Register::ES as u32 + 3 == Register::DS as u32);
const _: () = assert!(Register::ES as u32 + 4 == Register::FS as u32);
const _: () = assert!(Register::ES as u32 + 5 == Register::GS as u32);
if number < 6 {
unsafe { mem::transmute(Register::ES as RegisterUnderlyingType + number as RegisterUnderlyingType) }
} else {
Register::None
}
}
#[inline]
fn set_segment(&mut self, number: u8) {
self.flags1 = (self.flags1 & !(CodeAsmOpStateFlags1::SEGMENT_MASK << CodeAsmOpStateFlags1::SEGMENT_SHIFT))
| (number << CodeAsmOpStateFlags1::SEGMENT_SHIFT);
}
#[inline]
pub fn set_es(&mut self) {
self.set_segment(1);
}
#[inline]
pub fn set_cs(&mut self) {
self.set_segment(2);
}
#[inline]
pub fn set_ss(&mut self) {
self.set_segment(3);
}
#[inline]
pub fn set_ds(&mut self) {
self.set_segment(4);
}
#[inline]
pub fn set_fs(&mut self) {
self.set_segment(5);
}
#[inline]
pub fn set_gs(&mut self) {
self.set_segment(6);
}
#[must_use]
#[inline]
#[allow(trivial_numeric_casts)]
pub fn op_mask(&self) -> Register {
let number = (self.flags2 >> CodeAsmOpStateFlags2::OP_MASK_SHIFT) & CodeAsmOpStateFlags2::OP_MASK_MASK;
const _: () = assert!(CodeAsmOpStateFlags2::OP_MASK_MASK == 7);
if number == 0 {
Register::None
} else {
const _: () = assert!(Register::K0 as u32 + 1 == Register::K1 as u32);
const _: () = assert!(Register::K0 as u32 + 2 == Register::K2 as u32);
const _: () = assert!(Register::K0 as u32 + 3 == Register::K3 as u32);
const _: () = assert!(Register::K0 as u32 + 4 == Register::K4 as u32);
const _: () = assert!(Register::K0 as u32 + 5 == Register::K5 as u32);
const _: () = assert!(Register::K0 as u32 + 6 == Register::K6 as u32);
const _: () = assert!(Register::K0 as u32 + 7 == Register::K7 as u32);
unsafe { mem::transmute(Register::K0 as RegisterUnderlyingType + number as RegisterUnderlyingType) }
}
}
#[inline]
fn set_op_mask(&mut self, number: u8) {
self.flags2 = (self.flags2 & !(CodeAsmOpStateFlags2::OP_MASK_MASK << CodeAsmOpStateFlags2::OP_MASK_SHIFT))
| (number << CodeAsmOpStateFlags2::OP_MASK_SHIFT);
}
#[inline]
pub fn set_k1(&mut self) {
self.set_op_mask(1);
}
#[inline]
pub fn set_k2(&mut self) {
self.set_op_mask(2);
}
#[inline]
pub fn set_k3(&mut self) {
self.set_op_mask(3);
}
#[inline]
pub fn set_k4(&mut self) {
self.set_op_mask(4);
}
#[inline]
pub fn set_k5(&mut self) {
self.set_op_mask(5);
}
#[inline]
pub fn set_k6(&mut self) {
self.set_op_mask(6);
}
#[inline]
pub fn set_k7(&mut self) {
self.set_op_mask(7);
}
#[must_use]
#[inline]
#[allow(trivial_numeric_casts)]
pub fn rounding_control(&self) -> RoundingControl {
let number = (self.flags2 >> CodeAsmOpStateFlags2::ROUNDING_CONTROL_SHIFT) & CodeAsmOpStateFlags2::ROUNDING_CONTROL_MASK;
unsafe { mem::transmute(number as RoundingControlUnderlyingType) }
}
#[inline]
fn set_rounding_control(&mut self, rc: RoundingControl) {
self.flags2 = (self.flags2 & !(CodeAsmOpStateFlags2::ROUNDING_CONTROL_MASK << CodeAsmOpStateFlags2::ROUNDING_CONTROL_SHIFT))
| ((rc as u8) << CodeAsmOpStateFlags2::ROUNDING_CONTROL_SHIFT);
}
#[inline]
pub fn rn_sae(&mut self) {
self.set_rounding_control(RoundingControl::RoundToNearest);
}
#[inline]
pub fn rd_sae(&mut self) {
self.set_rounding_control(RoundingControl::RoundDown);
}
#[inline]
pub fn ru_sae(&mut self) {
self.set_rounding_control(RoundingControl::RoundUp);
}
#[inline]
pub fn rz_sae(&mut self) {
self.set_rounding_control(RoundingControl::RoundTowardZero);
}
#[must_use]
#[inline]
pub fn is_broadcast(&self) -> bool {
(self.flags1 & CodeAsmOpStateFlags1::BROADCAST) != 0
}
#[must_use]
#[inline]
pub fn suppress_all_exceptions(&self) -> bool {
(self.flags2 & CodeAsmOpStateFlags2::SUPPRESS_ALL_EXCEPTIONS) != 0
}
#[inline]
pub fn set_suppress_all_exceptions(&mut self) {
self.flags2 |= CodeAsmOpStateFlags2::SUPPRESS_ALL_EXCEPTIONS;
}
#[must_use]
#[inline]
pub fn zeroing_masking(&self) -> bool {
(self.flags2 & CodeAsmOpStateFlags2::ZEROING_MASKING) != 0
}
#[inline]
pub fn set_zeroing_masking(&mut self) {
self.flags2 |= CodeAsmOpStateFlags2::ZEROING_MASKING;
}
}