use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use crate::arch::Arch;
use crate::encoding::AddressComputation;
use crate::utils::EitherIter;
mod locs;
pub use locs::*;
pub const MAX_PARTS: usize = 32;
pub const PART_NAMES: &[&str] = &[
"a", "b", "c", "d", "e", "f", "g", "h", "j", "k", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
];
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Bit {
Part(usize),
Fixed(u8),
DontCare,
}
impl Bit {
pub fn unwrap_fixed(&self) -> u8 {
match self {
Bit::Fixed(n) => *n,
_ => panic!(),
}
}
pub fn part_index(&self) -> Option<usize> {
match self {
Bit::Part(index) => Some(*index),
_ => None,
}
}
}
impl Debug for Bit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Bit::Part(n) => f.write_str(PART_NAMES[*n]),
Bit::Fixed(v) => write!(f, "{v}"),
Bit::DontCare => f.write_str("_"),
}
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum PartValue {
Valid,
Invalid,
}
impl PartValue {
pub fn is_valid(&self) -> bool {
self == &PartValue::Valid
}
pub fn is_invalid(&self) -> bool {
self == &PartValue::Invalid
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum ImmBitOrder {
Positive(usize),
Negative(usize),
}
impl ImmBitOrder {
pub fn as_offset(&self, source_bit: u64) -> u64 {
match self {
ImmBitOrder::Positive(bit) => source_bit << bit,
ImmBitOrder::Negative(bit) => (!(source_bit << bit)).wrapping_add(1),
}
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum MappingOrBitOrder {
Mapping(Vec<PartValue>),
BitOrder(Vec<ImmBitOrder>),
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum ImmBit {
Is0,
Is1,
Fill,
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct ImmBits(Vec<ImmBit>);
impl ImmBits {
pub fn new(iter: impl Iterator<Item = ImmBit>) -> Self {
Self(iter.collect())
}
pub fn interpret_value(&self, value: u64) -> u64 {
let mut result = 0;
let mut data = value;
for (index, bit) in self.0.iter().enumerate() {
let val = match bit {
ImmBit::Is0 => 0,
ImmBit::Is1 => 1,
ImmBit::Fill => {
let val = data & 1;
data >>= 1;
val
},
};
result |= val << index;
}
result
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = ImmBit> + '_ {
self.0.iter().copied()
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ImmBit> {
self.0.iter_mut()
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(
feature = "schemars",
schemars(bound = "A: schemars::JsonSchema, A::Reg: schemars::JsonSchema")
)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(bound = "")]
pub enum PartMapping<A: Arch> {
Imm {
mapping: Option<MappingOrBitOrder>,
locations: Vec<FlowInputLocation>,
#[serde(default)]
bits: Option<ImmBits>,
},
MemoryComputation {
mapping: Vec<Option<AddressComputation>>,
memory_indexes: Vec<usize>,
},
Register {
mapping: Vec<Option<A::Reg>>,
locations: Vec<FlowValueLocation>,
},
}
impl<A: Arch> PartMapping<A> {
pub fn register_mapping(&self) -> Option<&[Option<A::Reg>]> {
match self {
PartMapping::Register {
mapping, ..
} => Some(mapping),
_ => None,
}
}
pub fn valid_values(&self) -> Option<impl Iterator<Item = usize> + '_> {
match self {
PartMapping::Imm {
mapping: Some(MappingOrBitOrder::Mapping(mapping)),
..
} if mapping.iter().any(PartValue::is_invalid) => Some(EitherIter::Left(EitherIter::Left(
mapping
.iter()
.enumerate()
.filter(|(_, &item)| item == PartValue::Valid)
.map(|(index, _)| index),
))),
PartMapping::MemoryComputation {
mapping, ..
} if mapping.iter().any(Option::is_none) => Some(EitherIter::Left(EitherIter::Right(
mapping
.iter()
.enumerate()
.filter(|(_, &item)| item.is_some())
.map(|(index, _)| index),
))),
PartMapping::Register {
mapping, ..
} if mapping.iter().any(Option::is_none) => Some(EitherIter::Right(
mapping
.iter()
.enumerate()
.filter(|(_, &item)| item.is_some())
.map(|(index, _)| index),
)),
_ => None,
}
}
pub fn first_valid_value(&self) -> u64 {
match self.valid_values() {
Some(mut iter) => iter.next().unwrap() as u64,
None => 0,
}
}
pub fn value_is_valid(&self, val: u64) -> bool {
match self {
PartMapping::Imm {
mapping: Some(MappingOrBitOrder::Mapping(mapping)),
..
} if mapping.iter().any(PartValue::is_invalid) => mapping[val as usize] == PartValue::Valid,
PartMapping::MemoryComputation {
mapping, ..
} if mapping.iter().any(Option::is_none) => mapping[val as usize].is_some(),
PartMapping::Register {
mapping, ..
} if mapping.iter().any(Option::is_none) => mapping[val as usize].is_some(),
_ => true,
}
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(
feature = "schemars",
schemars(bound = "A: schemars::JsonSchema, A::Reg: schemars::JsonSchema")
)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(bound = "")]
pub struct Part<A: Arch> {
pub size: usize,
pub value: u64,
pub mapping: PartMapping<A>,
}
impl<A: Arch> Part<A> {
pub fn size(&self) -> usize {
self.size
}
}