in checker/src/abstract_value.rs [3669:3723]
fn multiply(&self, other: Rc<AbstractValue>) -> Rc<AbstractValue> {
// [x * c] -> c * x
if !self.is_compile_time_constant() && other.is_compile_time_constant() {
// Normalize multiply expressions so that if only one of the operands is a constant, it is
// always the left operand.
return other.multiply(self.clone());
}
if let Expression::CompileTimeConstant(c1) = &self.expression {
match c1 {
// [0 * y] -> 0
ConstantDomain::I128(0) | ConstantDomain::U128(0) => {
return self.clone();
}
// [1 * y] -> y
ConstantDomain::I128(1) | ConstantDomain::U128(1) => {
return other;
}
ConstantDomain::I128(..) | ConstantDomain::U128(..) => match &other.expression {
// [c * (x + y)] -> (c * x) + (c * y)
Expression::Add { left: x, right: y } => {
let unsimplified_size =
self.expression_size.saturating_add(other.expression_size);
let cx_cy = self.multiply(x.clone()).addition(self.multiply(y.clone()));
if !cx_cy.is_bottom() && cx_cy.expression_size < unsimplified_size {
return cx_cy;
}
}
// [c1 * (c2 * y)] -> (c1 * c2) * y
Expression::Mul { left: x, right: y } if x.is_compile_time_constant() => {
return self.multiply(x.clone()).multiply(y.clone());
}
_ => {}
},
_ => {
// [c1 * (x / c2)] -> x / (c2 / c1) if c2 > c1 && c2 % c1 == 0
if let Expression::Div { left: x, right } = &other.expression {
if let Expression::CompileTimeConstant(c2) = &right.expression {
if let (ConstantDomain::U128(c1), ConstantDomain::U128(c2)) = (c1, c2) {
if c2 > c1 && c2 % c1 == 0 {
let c2_div_c1: Rc<AbstractValue> = Rc::new((c2 / c1).into());
return x.divide(c2_div_c1);
}
}
}
}
}
}
}
self.try_to_constant_fold_and_distribute_binary_op(
other,
ConstantDomain::mul,
Self::multiply,
|l, r| AbstractValue::make_binary(l, r, |left, right| Expression::Mul { left, right }),
)
}