From 957e3d482f745c5e47af4519a464c93587191564 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 28 Dec 2021 14:15:22 +0100 Subject: [PATCH] Short circuit logical operator to constant if possible If the left-hand side of a logical operator is a constant that causes the right-hand side to be short-circuited the right-hand side can be discarded even if it is not constant. In this case replace the expression by a constant. E.g. * `0 && expr` will be replaced by a constant 0. * `1 || expr` will be replaced by a constant 1. * `0 -> expr` will be replaced by a constant 1. Note that it is not possible to replace the expression by a constant if only the right-hand side is a constant, even when the value of the expression is constant. The left side still has to be evaluated for side effects. E.g. it is known at elaboration that `a++ && 0` will yield 0, but the increment on `a` has to be executed regardless. Signed-off-by: Lars-Peter Clausen --- eval_tree.cc | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/eval_tree.cc b/eval_tree.cc index 8811f30e7..c4110cd6f 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -811,6 +811,36 @@ NetEConst* NetEBLogic::eval_arguments_(const NetExpr*l, const NetExpr*r) const const NetEConst*lc = dynamic_cast(l); const NetEConst*rc = dynamic_cast(r); + + // If the left side is constant and the right side is short circuited + // replace the expression with a constant + if (rc == 0 && lc != 0) { + verinum v = lc->value(); + verinum::V res = verinum::Vx; + switch (op_) { + case 'a': // Logical AND (&&) + if (v.is_zero()) + res = verinum::V0; + break; + case 'o': // Logical OR (||) + if (! v.is_zero() && v.is_defined()) + res = verinum::V1; + break; + case 'q': // Logical implication (->) + if (v.is_zero()) + res = verinum::V1; + break; + default: + break; + } + if (res != verinum::Vx) { + NetEConst*tmp = new NetEConst(verinum(res, 1)); + ivl_assert(*this, tmp); + eval_debug(this, tmp, false); + return tmp; + } + } + if (lc == 0 || rc == 0) return 0; verinum::V lv = verinum::V0;