use core::ptr::NonNull;
use alloc::vec::Vec;
use cranelift_bitset::ScalarBitSet;
use cranelift_bitset::scalar::ScalarBitSetStorage;
use crate::imms::*;
use crate::opcode::*;
use crate::regs::*;
pub type Result<T, E = DecodingError> = core::result::Result<T, E>;
pub enum DecodingError {
UnexpectedEof {
position: usize,
},
InvalidOpcode {
position: usize,
code: u8,
},
InvalidExtendedOpcode {
position: usize,
code: u16,
},
InvalidReg {
position: usize,
reg: u8,
},
}
impl core::fmt::Debug for DecodingError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(self, f)
}
}
impl core::fmt::Display for DecodingError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::UnexpectedEof { position } => {
write!(f, "unexpected end-of-file at bytecode offset {position:#x}")
}
Self::InvalidOpcode { position, code } => {
write!(
f,
"found invalid opcode {code:#x} at bytecode offset {position:#x}"
)
}
Self::InvalidExtendedOpcode { position, code } => {
write!(
f,
"found invalid opcode {code:#x} at bytecode offset {position:#x}"
)
}
Self::InvalidReg { position, reg } => {
write!(
f,
"found invalid register {reg:#x} at bytecode offset {position:#x}"
)
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecodingError {}
pub trait BytecodeStream: Copy {
type Error;
fn unexpected_eof(&self) -> Self::Error;
fn invalid_opcode(&self, code: u8) -> Self::Error;
fn invalid_extended_opcode(&self, code: u16) -> Self::Error;
fn invalid_reg(&self, reg: u8) -> Self::Error;
fn read<const N: usize>(&mut self) -> Result<[u8; N], Self::Error>;
}
#[derive(Clone, Copy, Debug)]
pub struct SafeBytecodeStream<'a> {
bytecode: &'a [u8],
position: usize,
}
impl<'a> SafeBytecodeStream<'a> {
pub fn new(bytecode: &'a [u8]) -> Self {
Self {
bytecode,
position: 0,
}
}
pub fn position(&self) -> usize {
self.position
}
pub fn as_slice(&self) -> &[u8] {
&self.bytecode
}
}
impl BytecodeStream for SafeBytecodeStream<'_> {
fn read<const N: usize>(&mut self) -> Result<[u8; N], Self::Error> {
let (bytes, rest) = self
.bytecode
.split_first_chunk()
.ok_or_else(|| self.unexpected_eof())?;
self.bytecode = rest;
self.position += N;
Ok(*bytes)
}
type Error = DecodingError;
fn unexpected_eof(&self) -> Self::Error {
DecodingError::UnexpectedEof {
position: self.position,
}
}
fn invalid_opcode(&self, code: u8) -> Self::Error {
DecodingError::InvalidOpcode {
position: self.position - 1,
code,
}
}
fn invalid_extended_opcode(&self, code: u16) -> Self::Error {
DecodingError::InvalidExtendedOpcode {
position: self.position,
code,
}
}
fn invalid_reg(&self, reg: u8) -> Self::Error {
DecodingError::InvalidReg {
position: self.position,
reg,
}
}
}
#[derive(Debug)]
pub enum Uninhabited {}
#[derive(Clone, Copy, Debug)]
pub struct UnsafeBytecodeStream(NonNull<u8>);
impl UnsafeBytecodeStream {
pub unsafe fn new(pc: NonNull<u8>) -> Self {
UnsafeBytecodeStream(pc)
}
pub unsafe fn offset(&self, offset: isize) -> Self {
UnsafeBytecodeStream(unsafe { NonNull::new_unchecked(self.0.as_ptr().offset(offset)) })
}
pub fn as_ptr(&self) -> NonNull<u8> {
self.0
}
}
impl BytecodeStream for UnsafeBytecodeStream {
fn read<const N: usize>(&mut self) -> Result<[u8; N], Self::Error> {
let bytes = unsafe { self.0.cast::<[u8; N]>().as_ptr().read() };
self.0 = unsafe { NonNull::new_unchecked(self.0.as_ptr().add(N)) };
Ok(bytes)
}
type Error = Uninhabited;
fn unexpected_eof(&self) -> Self::Error {
unsafe { crate::unreachable_unchecked() }
}
fn invalid_opcode(&self, _code: u8) -> Self::Error {
unsafe { crate::unreachable_unchecked() }
}
fn invalid_extended_opcode(&self, _code: u16) -> Self::Error {
unsafe { crate::unreachable_unchecked() }
}
fn invalid_reg(&self, _reg: u8) -> Self::Error {
unsafe { crate::unreachable_unchecked() }
}
}
pub trait Decode: Sized {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream;
}
impl Decode for u8 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
bytecode.read::<1>().map(|a| a[0])
}
}
impl Decode for u16 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(u16::from_le_bytes(bytecode.read()?))
}
}
impl Decode for u32 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(u32::from_le_bytes(bytecode.read()?))
}
}
impl Decode for u64 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(u64::from_le_bytes(bytecode.read()?))
}
}
impl Decode for u128 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(u128::from_le_bytes(bytecode.read()?))
}
}
impl Decode for i8 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
bytecode.read::<1>().map(|a| a[0] as i8)
}
}
impl Decode for i16 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(i16::from_le_bytes(bytecode.read()?))
}
}
impl Decode for i32 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(i32::from_le_bytes(bytecode.read()?))
}
}
impl Decode for i64 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(i64::from_le_bytes(bytecode.read()?))
}
}
impl Decode for i128 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(i128::from_le_bytes(bytecode.read()?))
}
}
impl Decode for XReg {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
let byte = u8::decode(bytecode)?;
XReg::new(byte).ok_or_else(|| bytecode.invalid_reg(byte))
}
}
impl Decode for FReg {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
let byte = u8::decode(bytecode)?;
FReg::new(byte).ok_or_else(|| bytecode.invalid_reg(byte))
}
}
impl Decode for VReg {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
let byte = u8::decode(bytecode)?;
VReg::new(byte).ok_or_else(|| bytecode.invalid_reg(byte))
}
}
impl Decode for PcRelOffset {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
i32::decode(bytecode).map(|x| Self::from(x))
}
}
impl Decode for Opcode {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
let byte = u8::decode(bytecode)?;
match Opcode::new(byte) {
Some(v) => Ok(v),
None => Err(bytecode.invalid_opcode(byte)),
}
}
}
impl Decode for ExtendedOpcode {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
let word = u16::decode(bytecode)?;
match ExtendedOpcode::new(word) {
Some(v) => Ok(v),
None => Err(bytecode.invalid_extended_opcode(word)),
}
}
}
impl<D: Reg, S1: Reg, S2: Reg> Decode for BinaryOperands<D, S1, S2> {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
u16::decode(bytecode).map(|bits| Self::from_bits(bits))
}
}
impl<D: Reg, S1: Reg> Decode for BinaryOperands<D, S1, U6> {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
u16::decode(bytecode).map(|bits| Self::from_bits(bits))
}
}
impl<S: Decode + ScalarBitSetStorage> Decode for ScalarBitSet<S> {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
S::decode(bytecode).map(ScalarBitSet::from)
}
}
impl<R: Reg + Decode> Decode for UpperRegSet<R> {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
ScalarBitSet::decode(bytecode).map(Self::from)
}
}
impl Decode for AddrO32 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(AddrO32 {
addr: XReg::decode(bytecode)?,
offset: i32::decode(bytecode)?,
})
}
}
impl Decode for AddrZ {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(AddrZ {
addr: XReg::decode(bytecode)?,
offset: i32::decode(bytecode)?,
})
}
}
impl Decode for AddrG32 {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(AddrG32::from_bits(u32::decode(bytecode)?))
}
}
impl Decode for AddrG32Bne {
fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
where
T: BytecodeStream,
{
Ok(AddrG32Bne::from_bits(u32::decode(bytecode)?))
}
}
#[derive(Default)]
pub struct Decoder {
_private: (),
}
impl Decoder {
pub fn new() -> Self {
Self::default()
}
pub fn decode_all<'a, V>(visitor: &mut V) -> Result<Vec<V::Return>>
where
V: OpVisitor<BytecodeStream = SafeBytecodeStream<'a>> + ExtendedOpVisitor,
{
let mut decoder = Decoder::new();
let mut results = Vec::new();
while !visitor.bytecode().as_slice().is_empty() {
results.push(decoder.decode_one(visitor)?);
}
Ok(results)
}
}
pub struct SequencedVisitor<'a, F, V1, V2> {
join: F,
v1: &'a mut V1,
v2: &'a mut V2,
}
impl<'a, F, V1, V2> SequencedVisitor<'a, F, V1, V2> {
pub fn new(join: F, v1: &'a mut V1, v2: &'a mut V2) -> Self {
SequencedVisitor { join, v1, v2 }
}
}
macro_rules! define_decoder {
(
$(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( {
$(
$( #[$field_attr:meta] )*
$field:ident : $field_ty:ty
),*
} )? ;
)*
) => {
impl Decoder {
#[inline(always)]
pub fn decode_one<V>(
&mut self,
visitor: &mut V,
) -> Result<V::Return, <V::BytecodeStream as BytecodeStream>::Error>
where
V: OpVisitor + ExtendedOpVisitor,
{
visitor.before_visit();
let byte = u8::decode(visitor.bytecode())?;
let opcode = Opcode::new(byte).ok_or_else(|| {
visitor.bytecode().invalid_opcode(byte)
})?;
match opcode {
$(
Opcode::$name => {
$(
$(
let $field = <$field_ty>::decode(
visitor.bytecode(),
)?;
)*
)?
let ret = visitor.$snake_name($( $( $field ),* )?);
visitor.after_visit();
Ok(ret)
},
)*
Opcode::ExtendedOp => {
decode_one_extended(visitor)
}
}
}
}
pub trait OpVisitor {
type BytecodeStream: BytecodeStream;
fn bytecode(&mut self) -> &mut Self::BytecodeStream;
type Return;
fn before_visit(&mut self) {}
fn after_visit(&mut self) {}
$(
$( #[$attr] )*
fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return;
)*
}
impl<F, T, V1, V2> OpVisitor for SequencedVisitor<'_, F, V1, V2>
where
F: FnMut(V1::Return, V2::Return) -> T,
V1: OpVisitor,
V2: OpVisitor<BytecodeStream = V1::BytecodeStream>,
{
type BytecodeStream = V1::BytecodeStream;
fn bytecode(&mut self) -> &mut Self::BytecodeStream {
self.v1.bytecode()
}
type Return = T;
fn before_visit(&mut self) {
self.v1.before_visit();
self.v2.before_visit();
}
fn after_visit(&mut self) {
*self.v2.bytecode() = *self.v1.bytecode();
self.v1.after_visit();
self.v2.after_visit();
}
$(
$( #[$attr] )*
fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
let a = self.v1.$snake_name( $( $( $field , )* )? );
let b = self.v2.$snake_name( $( $( $field , )* )? );
(self.join)(a, b)
}
)*
}
};
}
for_each_op!(define_decoder);
macro_rules! define_extended_decoder {
(
$(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( {
$(
$( #[$field_attr:meta] )*
$field:ident : $field_ty:ty
),*
} )? ;
)*
) => {
pub trait ExtendedOpVisitor: OpVisitor {
$(
$( #[$attr] )*
fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return;
)*
}
fn decode_one_extended<V>(
visitor: &mut V,
) -> Result<V::Return, <V::BytecodeStream as BytecodeStream>::Error>
where
V: ExtendedOpVisitor,
{
let code = u16::decode(visitor.bytecode())?;
let opcode = ExtendedOpcode::new(code).ok_or_else(|| {
visitor.bytecode().invalid_extended_opcode(code)
})?;
match opcode {
$(
ExtendedOpcode::$name => {
$(
$(
let $field = <$field_ty>::decode(
visitor.bytecode(),
)?;
)*
)?
let ret = visitor.$snake_name($( $( $field ),* )?);
visitor.after_visit();
Ok(ret)
}
)*
}
}
impl<F, T, V1, V2> ExtendedOpVisitor for SequencedVisitor<'_, F, V1, V2>
where
F: FnMut(V1::Return, V2::Return) -> T,
V1: ExtendedOpVisitor,
V2: ExtendedOpVisitor<BytecodeStream = V1::BytecodeStream>,
{
$(
$( #[$attr] )*
fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
let a = self.v1.$snake_name( $( $( $field , )* )? );
let b = self.v2.$snake_name( $( $( $field , )* )? );
(self.join)(a, b)
}
)*
}
};
}
for_each_extended_op!(define_extended_decoder);
pub mod operands {
use super::*;
macro_rules! define_operands_decoder {
(
$(
$( #[$attr:meta] )*
$snake_name:ident = $name:ident $( {
$(
$( #[$field_attr:meta] )*
$field:ident : $field_ty:ty
),*
} )? ;
)*
) => {
$(
#[allow(unused_variables, reason = "macro-generated")]
#[expect(missing_docs, reason = "macro-generated")]
pub fn $snake_name<T: BytecodeStream>(pc: &mut T) -> Result<($($($field_ty,)*)?), T::Error> {
Ok((($($((<$field_ty>::decode(pc))?,)*)?)))
}
)*
};
}
for_each_op!(define_operands_decoder);
pub fn extended<T: BytecodeStream>(pc: &mut T) -> Result<(ExtendedOpcode,), T::Error> {
Ok((ExtendedOpcode::decode(pc)?,))
}
for_each_extended_op!(define_operands_decoder);
}