use vyre::ir::AtomicOp;
use vyre::Error;
pub fn apply(
op: AtomicOp,
old: u32,
expected: Option<u32>,
value: u32,
) -> Result<(u32, u32), vyre::Error> {
match op {
AtomicOp::Add => Ok(atomic_add(old, value)),
AtomicOp::Or => Ok(atomic_or(old, value)),
AtomicOp::And => Ok(atomic_and(old, value)),
AtomicOp::Xor => Ok(atomic_xor(old, value)),
AtomicOp::Min => Ok(atomic_min(old, value)),
AtomicOp::Max => Ok(atomic_max(old, value)),
AtomicOp::Exchange => Ok(atomic_exchange(old, value)),
AtomicOp::CompareExchange => atomic_compare_exchange(old, expected, value),
AtomicOp::LruUpdate => Ok(atomic_lru_update(old, value)),
_ => Err(Error::interp(format!(
"unsupported atomic op `{op:?}` reached the reference interpreter. Fix: define sequential semantics before constructing this AtomicOp."
))),
}
}
pub fn atomic_add(old: u32, value: u32) -> (u32, u32) {
(old, old.wrapping_add(value))
}
pub fn atomic_or(old: u32, value: u32) -> (u32, u32) {
(old, old | value)
}
pub fn atomic_and(old: u32, value: u32) -> (u32, u32) {
(old, old & value)
}
pub fn atomic_xor(old: u32, value: u32) -> (u32, u32) {
(old, old ^ value)
}
pub fn atomic_min(old: u32, value: u32) -> (u32, u32) {
(old, old.min(value))
}
pub fn atomic_max(old: u32, value: u32) -> (u32, u32) {
(old, old.max(value))
}
pub fn atomic_exchange(old: u32, value: u32) -> (u32, u32) {
(old, value)
}
pub fn atomic_lru_update(old: u32, value: u32) -> (u32, u32) {
(old, old.max(value))
}
pub fn atomic_compare_exchange(
old: u32,
expected: Option<u32>,
value: u32,
) -> Result<(u32, u32), vyre::Error> {
let Some(expected) = expected else {
return Err(Error::interp(
"compare-exchange atomic is missing expected value. Fix: set Expr::Atomic.expected.",
));
};
let new = if old == expected { value } else { old };
Ok((old, new))
}