use crate::decompiler::ir::{BinOp, Literal, UnaryOp};
use super::super::form::SsaExpr;
pub(super) fn as_literal(expr: &SsaExpr) -> Option<Literal> {
if let SsaExpr::Literal(l) = expr {
Some(l.clone())
} else {
None
}
}
pub(super) fn fold_binary(op: BinOp, a: &Literal, b: &Literal) -> Option<Literal> {
let (Literal::Int(x), Literal::Int(y)) = (a, b) else {
return None;
};
let (x, y) = (*x, *y);
Some(match op {
BinOp::Add => Literal::Int(x.wrapping_add(y)),
BinOp::Sub => Literal::Int(x.wrapping_sub(y)),
BinOp::Mul => Literal::Int(x.wrapping_mul(y)),
BinOp::Div => {
if y == 0 {
return None;
}
Literal::Int(x.wrapping_div(y))
}
BinOp::Mod => {
if y == 0 {
return None;
}
Literal::Int(x.wrapping_rem(y))
}
BinOp::Pow => (0..y)
.take(1024)
.try_fold(1i64, |acc, _| acc.checked_mul(x))
.map(Literal::Int)?,
BinOp::And => Literal::Int(x & y),
BinOp::Or => Literal::Int(x | y),
BinOp::Xor => Literal::Int(x ^ y),
BinOp::Shl => Literal::Int(x.wrapping_shl((y & 63) as u32)),
BinOp::Shr => Literal::Int(x.wrapping_shr((y & 63) as u32)),
BinOp::Eq => Literal::Bool(x == y),
BinOp::Ne => Literal::Bool(x != y),
BinOp::Lt => Literal::Bool(x < y),
BinOp::Le => Literal::Bool(x <= y),
BinOp::Gt => Literal::Bool(x > y),
BinOp::Ge => Literal::Bool(x >= y),
BinOp::LogicalAnd => Literal::Bool(x != 0 && y != 0),
BinOp::LogicalOr => Literal::Bool(x != 0 || y != 0),
})
}
pub(super) fn fold_unary(op: UnaryOp, a: &Literal) -> Option<Literal> {
let Literal::Int(x) = a else {
return None;
};
Some(match op {
UnaryOp::Neg => Literal::Int(x.wrapping_neg()),
UnaryOp::Not => Literal::Int(!x),
UnaryOp::Abs => Literal::Int(x.wrapping_abs()),
UnaryOp::Inc => Literal::Int(x.wrapping_add(1)),
UnaryOp::Dec => Literal::Int(x.wrapping_sub(1)),
UnaryOp::Sign => Literal::Int(x.signum()),
UnaryOp::LogicalNot => Literal::Bool(*x == 0),
})
}