fn multiply()

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 }),
        )
    }