use core::fmt;
use super::entity::{Block, CondCode, StackSlot, Symbol};
use crate::regs::{PReg, Reg};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Scale {
X1,
X2,
X4,
X8,
}
impl Scale {
#[inline]
#[must_use]
pub const fn factor(self) -> u8 {
match self {
Scale::X1 => 1,
Scale::X2 => 2,
Scale::X4 => 4,
Scale::X8 => 8,
}
}
}
const NO_REG: u32 = u32::MAX;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Mem {
base: u32,
index: u32,
disp: i32,
scale: Scale,
}
impl Mem {
#[inline]
#[must_use]
pub fn base(base: Reg) -> Mem {
Mem {
base: reg_bits(base),
index: NO_REG,
disp: 0,
scale: Scale::X1,
}
}
#[inline]
#[must_use]
pub const fn absolute(disp: i32) -> Mem {
Mem {
base: NO_REG,
index: NO_REG,
disp,
scale: Scale::X1,
}
}
#[inline]
#[must_use]
pub fn with_index(self, index: Reg, scale: Scale) -> Mem {
Mem {
index: reg_bits(index),
scale,
..self
}
}
#[inline]
pub(crate) fn with_base(self, base: Reg) -> Mem {
Mem {
base: reg_bits(base),
..self
}
}
#[inline]
#[must_use]
pub const fn with_disp(self, disp: i32) -> Mem {
Mem { disp, ..self }
}
#[inline]
#[must_use]
pub fn base_reg(&self) -> Option<Reg> {
bits_reg(self.base)
}
#[inline]
#[must_use]
pub fn index_reg(&self) -> Option<(Reg, Scale)> {
bits_reg(self.index).map(|r| (r, self.scale))
}
#[inline]
#[must_use]
pub const fn disp(&self) -> i32 {
self.disp
}
pub(crate) fn regs(&self) -> impl Iterator<Item = Reg> {
self.base_reg()
.into_iter()
.chain(self.index_reg().map(|(r, _)| r))
}
}
fn reg_bits(r: Reg) -> u32 {
match (r.as_phys(), r.as_virt()) {
(Some(p), _) => p.index() as u32,
(_, Some(v)) => (v.index() as u32) | (1 << 31),
_ => NO_REG,
}
}
fn bits_reg(bits: u32) -> Option<Reg> {
if bits == NO_REG {
None
} else if bits & (1 << 31) != 0 {
Some(Reg::from(crate::regs::VReg::from_index(bits & !(1 << 31))))
} else {
Some(Reg::from(PReg::from_index(bits as u8)))
}
}
impl fmt::Debug for Mem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mem")
.field("base", &self.base_reg())
.field("index", &self.index_reg())
.field("disp", &self.disp)
.finish()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct BlockCall {
block: Block,
start: u32,
len: u32,
}
impl BlockCall {
pub(crate) const fn new(block: Block, start: u32, len: u32) -> BlockCall {
BlockCall { block, start, len }
}
#[inline]
#[must_use]
pub const fn block(&self) -> Block {
self.block
}
#[inline]
#[must_use]
pub const fn len(&self) -> usize {
self.len as usize
}
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub(crate) const fn range(&self) -> core::ops::Range<usize> {
self.start as usize..self.start as usize + self.len as usize
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Operand {
Reg(Reg),
Imm(i64),
Mem(Mem),
Slot {
slot: StackSlot,
offset: i32,
},
Symbol(Symbol),
Cond(CondCode),
Block(BlockCall),
}
impl Operand {
#[inline]
#[must_use]
pub const fn slot(slot: StackSlot) -> Operand {
Operand::Slot { slot, offset: 0 }
}
#[inline]
#[must_use]
pub const fn reg(&self) -> Option<Reg> {
match self {
Operand::Reg(r) => Some(*r),
_ => None,
}
}
#[inline]
#[must_use]
pub const fn is_mem(&self) -> bool {
matches!(self, Operand::Mem(_) | Operand::Slot { .. })
}
}
impl From<Reg> for Operand {
#[inline]
fn from(r: Reg) -> Operand {
Operand::Reg(r)
}
}
impl From<PReg> for Operand {
#[inline]
fn from(r: PReg) -> Operand {
Operand::Reg(r.into())
}
}
impl From<Mem> for Operand {
#[inline]
fn from(m: Mem) -> Operand {
Operand::Mem(m)
}
}
impl From<CondCode> for Operand {
#[inline]
fn from(c: CondCode) -> Operand {
Operand::Cond(c)
}
}
impl From<BlockCall> for Operand {
#[inline]
fn from(b: BlockCall) -> Operand {
Operand::Block(b)
}
}
impl From<Symbol> for Operand {
#[inline]
fn from(s: Symbol) -> Operand {
Operand::Symbol(s)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ImplicitKind {
Use,
Def,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Implicit {
pub reg: PReg,
pub kind: ImplicitKind,
}