use crate::{Error, SlotSpan};
use core::{
fmt::{Debug, Formatter},
marker::PhantomData,
};
/// A generic register type.
pub struct Reg<T> {
/// Tells the compiler that `T` is not used within.
marker: PhantomData<fn() -> T>,
}
impl<T> Copy for Reg<T> {}
impl<T> Clone for Reg<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Default for Reg<T> {
#[inline]
fn default() -> Self {
Self {
marker: PhantomData,
}
}
}
mod marker {
/// Marker for the integer GPR register.
pub enum Int {}
/// Marker for the `f32` register.
pub enum F32 {}
/// Marker for the `f64` register.
pub enum F64 {}
}
/// The general purpose (integer) register.
pub type Ireg = Reg<marker::Int>;
impl Debug for Ireg {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str("Ireg")
}
}
/// The `f32` register.
pub type Freg32 = Reg<marker::F32>;
impl Debug for Freg32 {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str("Freg32")
}
}
/// The `f64` register.
pub type Freg64 = Reg<marker::F64>;
impl Debug for Freg64 {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str("Freg64")
}
}
/// An [`Op::BranchTableSpan`](crate::Op::BranchTableSpan) branching target.
#[derive(Debug, Copy, Clone)]
pub struct BranchTableTarget {
/// The result stack slots of the branch target.
pub results: SlotSpan,
/// The offset to branch to for the target.
pub offset: BranchOffset,
}
impl BranchTableTarget {
/// Creates a new [`BranchTableTarget`] for `results` and `offset`.
pub fn new(results: SlotSpan, offset: BranchOffset) -> Self {
Self { results, offset }
}
}
/// Error that may occur upon converting values to [`Address`] and [`Offset16`].
#[derive(Debug, Copy, Clone)]
pub struct OutOfBoundsConst;
/// The sign of a value.
#[derive(Debug)]
pub struct Sign<T> {
/// Whether the sign value is positive.
pub(crate) is_positive: bool,
/// Required for the Rust compiler.
marker: PhantomData<fn() -> T>,
}
impl<T> Clone for Sign<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Sign<T> {}
impl<T> PartialEq for Sign<T> {
fn eq(&self, other: &Self) -> bool {
self.is_positive == other.is_positive
}
}
impl<T> Eq for Sign<T> {}
impl<T> Sign<T> {
/// Create a new typed [`Sign`] with the given value.
pub(crate) fn new(is_positive: bool) -> Self {
Self {
is_positive,
marker: PhantomData,
}
}
/// Creates a new typed [`Sign`] that has positive polarity.
pub fn pos() -> Self {
Self::new(true)
}
/// Creates a new typed [`Sign`] that has negative polarity.
pub fn neg() -> Self {
Self::new(false)
}
/// Returns `true` if [`Sign`] is positive.
pub(crate) fn is_positive(self) -> bool {
self.is_positive
}
}
macro_rules! impl_sign_for {
( $($ty:ty),* $(,)? ) => {
$(
impl From<$ty> for Sign<$ty> {
fn from(value: $ty) -> Self {
Self::new(value.is_sign_positive())
}
}
impl From<Sign<$ty>> for $ty {
fn from(sign: Sign<$ty>) -> Self {
match sign.is_positive {
true => 1.0,
false => -1.0,
}
}
}
)*
};
}
impl_sign_for!(f32, f64);
/// A signed offset for branch instructions.
///
/// This defines how much the instruction pointer is offset
/// upon taking the respective branch.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BranchOffset(i32);
impl From<i32> for BranchOffset {
fn from(index: i32) -> Self {
Self(index)
}
}
impl From<BranchOffset> for i32 {
fn from(offset: BranchOffset) -> Self {
offset.0
}
}
impl BranchOffset {
/// Returns `true` if [`Self`] is an offset for a backward branch.
pub fn is_backwards(&self) -> bool {
self.0.is_negative()
}
/// Returns `true` if [`Self`] is an offset for a forward branch.
pub fn is_forwards(&self) -> bool {
self.0.is_positive()
}
/// Returns `true` if the [`BranchOffset`] has been initialized.
pub fn is_init(self) -> bool {
self.0 != 0
}
/// Creates an uninitialized [`BranchOffset`].
pub fn uninit() -> Self {
Self(0)
}
/// Initializes the [`BranchOffset`] with a proper value.
///
/// # Panics
///
/// - If the [`BranchOffset`] have already been initialized.
/// - If the given [`BranchOffset`] is not properly initialized.
pub fn init(&mut self, valid_offset: BranchOffset) {
assert!(valid_offset.is_init());
assert!(!self.is_init());
*self = valid_offset;
}
}
/// The accumulated fuel to execute a block via [`Op::ConsumeFuel`].
///
/// [`Op::ConsumeFuel`]: crate::Op::ConsumeFuel
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct BlockFuel(u64);
impl From<u64> for BlockFuel {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<BlockFuel> for u64 {
fn from(value: BlockFuel) -> Self {
value.0
}
}
impl BlockFuel {
/// Bump the fuel by `amount` if possible.
///
/// # Errors
///
/// If the new fuel amount after this operation is out of bounds.
pub fn bump_by(&mut self, amount: u64) -> Result<(), Error> {
self.0 = u64::from(*self)
.checked_add(amount)
.ok_or(Error::BlockFuelOutOfBounds)?;
Ok(())
}
}
/// A 64-bit memory address used for some load and store instructions.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Address(u64);
impl TryFrom<u64> for Address {
type Error = OutOfBoundsConst;
fn try_from(address: u64) -> Result<Self, OutOfBoundsConst> {
if usize::try_from(address).is_err() {
return Err(OutOfBoundsConst);
};
Ok(Self(address))
}
}
impl From<Address> for usize {
fn from(address: Address) -> Self {
// Note: no checks are needed since we statically ensured that
// `Address32` can be safely and losslessly cast to `usize`.
debug_assert!(usize::try_from(address.0).is_ok());
address.0 as usize
}
}
impl From<Address> for u64 {
fn from(address: Address) -> Self {
address.0
}
}
/// A 16-bit encoded load or store address offset.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(transparent)]
pub struct Offset16(u16);
impl TryFrom<u64> for Offset16 {
type Error = OutOfBoundsConst;
fn try_from(address: u64) -> Result<Self, Self::Error> {
<u16>::try_from(address)
.map(Self)
.map_err(|_| OutOfBoundsConst)
}
}
impl From<u16> for Offset16 {
fn from(offset: u16) -> Self {
Self(offset)
}
}
impl From<Offset16> for u16 {
fn from(offset: Offset16) -> Self {
offset.0
}
}
use crate::;
use ;
/// A generic register type.
/// The general purpose (integer) register.
pub type Ireg = ;
/// The `f32` register.
pub type Freg32 = ;
/// The `f64` register.
pub type Freg64 = ;
/// An [`Op::BranchTableSpan`](crate::Op::BranchTableSpan) branching target.
/// Error that may occur upon converting values to [`Address`] and [`Offset16`].
;
/// The sign of a value.
}
}
)*
};
}
impl_sign_for!;
/// A signed offset for branch instructions.
///
/// This defines how much the instruction pointer is offset
/// upon taking the respective branch.
;
/// The accumulated fuel to execute a block via [`Op::ConsumeFuel`].
///
/// [`Op::ConsumeFuel`]: crate::Op::ConsumeFuel
;
/// A 64-bit memory address used for some load and store instructions.
;
/// A 16-bit encoded load or store address offset.
;