use std::fmt;
use il::*;
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum Expression {
Scalar(Scalar),
Constant(Constant),
Add(Box<Expression>, Box<Expression>),
Sub(Box<Expression>, Box<Expression>),
Mul(Box<Expression>, Box<Expression>),
Divu(Box<Expression>, Box<Expression>),
Modu(Box<Expression>, Box<Expression>),
Divs(Box<Expression>, Box<Expression>),
Mods(Box<Expression>, Box<Expression>),
And(Box<Expression>, Box<Expression>),
Or(Box<Expression>, Box<Expression>),
Xor(Box<Expression>, Box<Expression>),
Shl(Box<Expression>, Box<Expression>),
Shr(Box<Expression>, Box<Expression>),
Cmpeq(Box<Expression>, Box<Expression>),
Cmpneq(Box<Expression>, Box<Expression>),
Cmplts(Box<Expression>, Box<Expression>),
Cmpltu(Box<Expression>, Box<Expression>),
Zext(usize, Box<Expression>),
Sext(usize, Box<Expression>),
Trun(usize, Box<Expression>),
}
impl Expression {
pub fn bits(&self) -> usize {
match *self {
Expression::Scalar(ref scalar) => scalar.bits(),
Expression::Constant(ref constant) => constant.bits(),
Expression::Add(ref lhs, _) |
Expression::Sub(ref lhs, _) |
Expression::Mul(ref lhs, _) |
Expression::Divu(ref lhs, _) |
Expression::Modu(ref lhs, _) |
Expression::Divs(ref lhs, _) |
Expression::Mods(ref lhs, _) |
Expression::And(ref lhs, _) |
Expression::Or(ref lhs, _) |
Expression::Xor(ref lhs, _) |
Expression::Shl(ref lhs, _) |
Expression::Shr(ref lhs, _) => lhs.bits(),
Expression::Cmpeq(_, _) |
Expression::Cmpneq(_, _) |
Expression::Cmplts(_, _) |
Expression::Cmpltu(_, _) => 1,
Expression::Zext(bits, _) |
Expression::Sext(bits, _) |
Expression::Trun(bits, _) => bits
}
}
fn ensure_sort(lhs: &Expression, rhs: &Expression, no_flags: bool) -> Result<()> {
if lhs.bits() != rhs.bits()
|| (no_flags && lhs.bits() == 0) {
Err(ErrorKind::Sort.into())
}
else {
Ok(())
}
}
pub fn scalars(&self) -> Vec<&Scalar> {
let mut scalars: Vec<&Scalar> = Vec::new();
match *self {
Expression::Scalar(ref scalar) => {
scalars.push(scalar)
}
Expression::Constant(_) => {}
Expression::Add(ref lhs, ref rhs) |
Expression::Sub(ref lhs, ref rhs) |
Expression::Mul(ref lhs, ref rhs) |
Expression::Divu(ref lhs, ref rhs) |
Expression::Modu(ref lhs, ref rhs) |
Expression::Divs(ref lhs, ref rhs) |
Expression::Mods(ref lhs, ref rhs) |
Expression::And(ref lhs, ref rhs) |
Expression::Or(ref lhs, ref rhs) |
Expression::Xor(ref lhs, ref rhs) |
Expression::Shl(ref lhs, ref rhs) |
Expression::Shr(ref lhs, ref rhs) |
Expression::Cmpeq(ref lhs, ref rhs) |
Expression::Cmpneq(ref lhs, ref rhs) |
Expression::Cmplts(ref lhs, ref rhs) |
Expression::Cmpltu(ref lhs, ref rhs) => {
scalars.append(&mut lhs.scalars());
scalars.append(&mut rhs.scalars());
},
Expression::Zext(_, ref rhs) |
Expression::Sext(_, ref rhs) |
Expression::Trun(_, ref rhs) => {
scalars.append(&mut rhs.scalars());
}
}
scalars
}
pub fn scalars_mut(&mut self) -> Vec<&mut Scalar> {
let mut scalars: Vec<&mut Scalar> = Vec::new();
match *self {
Expression::Scalar(ref mut scalar) => {
scalars.push(scalar)
}
Expression::Constant(_) => {}
Expression::Add(ref mut lhs, ref mut rhs) |
Expression::Sub(ref mut lhs, ref mut rhs) |
Expression::Mul(ref mut lhs, ref mut rhs) |
Expression::Divu(ref mut lhs, ref mut rhs) |
Expression::Modu(ref mut lhs, ref mut rhs) |
Expression::Divs(ref mut lhs, ref mut rhs) |
Expression::Mods(ref mut lhs, ref mut rhs) |
Expression::And(ref mut lhs, ref mut rhs) |
Expression::Or(ref mut lhs, ref mut rhs) |
Expression::Xor(ref mut lhs, ref mut rhs) |
Expression::Shl(ref mut lhs, ref mut rhs) |
Expression::Shr(ref mut lhs, ref mut rhs) |
Expression::Cmpeq(ref mut lhs, ref mut rhs) |
Expression::Cmpneq(ref mut lhs, ref mut rhs) |
Expression::Cmplts(ref mut lhs, ref mut rhs) |
Expression::Cmpltu(ref mut lhs, ref mut rhs) => {
scalars.append(&mut lhs.scalars_mut());
scalars.append(&mut rhs.scalars_mut());
},
Expression::Zext(_, ref mut rhs) |
Expression::Sext(_, ref mut rhs) |
Expression::Trun(_, ref mut rhs) => {
scalars.append(&mut rhs.scalars_mut());
}
}
scalars
}
pub fn scalar(scalar: Scalar) -> Expression {
Expression::Scalar(scalar)
}
pub fn constant(constant: Constant) -> Expression {
Expression::Constant(constant)
}
pub fn add(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Add(Box::new(lhs), Box::new(rhs)))
}
pub fn sub(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Sub(Box::new(lhs), Box::new(rhs)))
}
pub fn mul(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Mul(Box::new(lhs), Box::new(rhs)))
}
pub fn divu(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Divu(Box::new(lhs), Box::new(rhs)))
}
pub fn modu(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Modu(Box::new(lhs), Box::new(rhs)))
}
pub fn divs(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Divs(Box::new(lhs), Box::new(rhs)))
}
pub fn mods(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Mods(Box::new(lhs), Box::new(rhs)))
}
pub fn and(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::And(Box::new(lhs), Box::new(rhs)))
}
pub fn or(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Or(Box::new(lhs), Box::new(rhs)))
}
pub fn xor(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Xor(Box::new(lhs), Box::new(rhs)))
}
pub fn shl(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Shl(Box::new(lhs), Box::new(rhs)))
}
pub fn shr(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, true));
Ok(Expression::Shr(Box::new(lhs), Box::new(rhs)))
}
pub fn cmpeq(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, false));
Ok(Expression::Cmpeq(Box::new(lhs), Box::new(rhs)))
}
pub fn cmpneq(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, false));
Ok(Expression::Cmpneq(Box::new(lhs), Box::new(rhs)))
}
pub fn cmpltu(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, false));
Ok(Expression::Cmpltu(Box::new(lhs), Box::new(rhs)))
}
pub fn cmplts(lhs: Expression, rhs: Expression) -> Result<Expression> {
try!(Expression::ensure_sort(&lhs, &rhs, false));
Ok(Expression::Cmplts(Box::new(lhs), Box::new(rhs)))
}
pub fn zext(bits: usize, src: Expression) -> Result<Expression> {
if src.bits() >= bits || src.bits() == 0 {
return Err(ErrorKind::Sort.into());
}
Ok(Expression::Zext(bits, Box::new(src)))
}
pub fn sext(bits: usize, src: Expression) -> Result<Expression> {
if src.bits() >= bits || src.bits() == 0 {
return Err(ErrorKind::Sort.into());
}
Ok(Expression::Sext(bits, Box::new(src)))
}
pub fn trun(bits: usize, src: Expression) -> Result<Expression> {
if src.bits() <= bits || src.bits() == 0 {
return Err(ErrorKind::Sort.into());
}
Ok(Expression::Trun(bits, Box::new(src)))
}
}
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Expression::Scalar(ref s) => s.fmt(f),
Expression::Constant(ref c) => c.fmt(f),
Expression::Add(ref lhs, ref rhs) =>
write!(f, "({} + {})", lhs, rhs),
Expression::Sub(ref lhs, ref rhs) =>
write!(f, "({} - {})", lhs, rhs),
Expression::Mul(ref lhs, ref rhs) =>
write!(f, "({} * {})", lhs, rhs),
Expression::Divu(ref lhs, ref rhs) =>
write!(f, "({} /u {})", lhs, rhs),
Expression::Modu(ref lhs, ref rhs) =>
write!(f, "({} %u {})", lhs, rhs),
Expression::Divs(ref lhs, ref rhs) =>
write!(f, "({} /s {})", lhs, rhs),
Expression::Mods(ref lhs, ref rhs) =>
write!(f, "({} %s {})", lhs, rhs),
Expression::And(ref lhs, ref rhs) =>
write!(f, "({} & {})", lhs, rhs),
Expression::Or(ref lhs, ref rhs) =>
write!(f, "({} | {})", lhs, rhs),
Expression::Xor(ref lhs, ref rhs) =>
write!(f, "({} ^ {})", lhs, rhs),
Expression::Shl(ref lhs, ref rhs) =>
write!(f, "({} << {})", lhs, rhs),
Expression::Shr(ref lhs, ref rhs) =>
write!(f, "({} >> {})", lhs, rhs),
Expression::Cmpeq(ref lhs, ref rhs) =>
write!(f, "({} == {})", lhs, rhs),
Expression::Cmpneq(ref lhs, ref rhs) =>
write!(f, "({} != {})", lhs, rhs),
Expression::Cmplts(ref lhs, ref rhs) =>
write!(f, "({} <s {})", lhs, rhs),
Expression::Cmpltu(ref lhs, ref rhs) =>
write!(f, "({} <u {})", lhs, rhs),
Expression::Zext(ref bits, ref src) =>
write!(f, "zext.{}({})", bits, src),
Expression::Sext(ref bits, ref src) =>
write!(f, "sext.{}({})", bits, src),
Expression::Trun(ref bits, ref src) =>
write!(f, "trun.{}({})", bits, src),
}
}
}