From 17229f99c98eeb0a282dc232eda1a7cdc2012024 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 16 Jun 2023 06:44:56 -0700 Subject: [PATCH] Make result of binary operations 2-state if inputs are 2-state The are many binary operations where if the two operands are 2-state the result is guaranteed to be 2-state. This is true for all arithmetic operation with the exception of division where division by 0 will always result in 'x even if the inputs are both 2-state. The same is true for all binary bitwise operators as well as the binary logical operators. Having the expression type be 2-state avoids some unnecessary %cast2 instructions that would otherwise get inserted when assigning the result to a 2-state variable. E.g without this change the following will result in ``` int a, b, c; b = a + b; ``` will result in ``` %load/vec4 ...; %load/vec4 ...; %add; %cast2; %store/vec4 ...; ``` For binary comparison operators this is already handled. Signed-off-by: Lars-Peter Clausen --- eval_tree.cc | 8 ++++---- net_expr.cc | 55 +++++++++++++++++++++++++++------------------------- netlist.cc | 18 +++++++++++++++++ netlist.h | 6 ++++++ 4 files changed, 57 insertions(+), 30 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index e55305a51..991d1c685 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -807,7 +807,7 @@ NetEConst* NetEBLogic::eval_arguments_(const NetExpr*l, const NetExpr*r) const { // NetEBLogic arguments should have already been reduced so real is not possible. ivl_assert(*this, (l->expr_type() != IVL_VT_REAL) && (r->expr_type() != IVL_VT_REAL)); - ivl_assert(*this, expr_type() == IVL_VT_LOGIC); + ivl_assert(*this, expr_type() == IVL_VT_LOGIC || expr_type() == IVL_VT_BOOL); const NetEConst*lc = dynamic_cast(l); const NetEConst*rc = dynamic_cast(r); @@ -943,7 +943,7 @@ NetExpr* NetEBMinMax::eval_tree_real_(const NetExpr*l, const NetExpr*r) const NetExpr* NetEBMinMax::eval_arguments_(const NetExpr*l, const NetExpr*r) const { if (expr_type() == IVL_VT_REAL) return eval_tree_real_(l,r); - ivl_assert(*this, expr_type() == IVL_VT_LOGIC); + ivl_assert(*this, expr_type() == IVL_VT_LOGIC || expr_type() == IVL_VT_BOOL); const NetEConst*lc = dynamic_cast(l); const NetEConst*rc = dynamic_cast(r); @@ -996,7 +996,7 @@ NetExpr* NetEBMult::eval_tree_real_(const NetExpr*l, const NetExpr*r) const NetExpr* NetEBMult::eval_arguments_(const NetExpr*l, const NetExpr*r) const { if (expr_type() == IVL_VT_REAL) return eval_tree_real_(l,r); - ivl_assert(*this, expr_type() == IVL_VT_LOGIC); + ivl_assert(*this, expr_type() == IVL_VT_LOGIC || expr_type() == IVL_VT_BOOL); const NetEConst*lc = dynamic_cast(l); const NetEConst*rc = dynamic_cast(r); @@ -1034,7 +1034,7 @@ NetExpr* NetEBPow::eval_tree_real_(const NetExpr*l, const NetExpr*r) const NetExpr* NetEBPow::eval_arguments_(const NetExpr*l, const NetExpr*r) const { if (expr_type() == IVL_VT_REAL) return eval_tree_real_(l,r); - ivl_assert(*this, expr_type() == IVL_VT_LOGIC); + ivl_assert(*this, expr_type() == IVL_VT_LOGIC || expr_type() == IVL_VT_BOOL); const NetEConst*lc = dynamic_cast(l); const NetEConst*rc = dynamic_cast(r); diff --git a/net_expr.cc b/net_expr.cc index e398fa42b..22c6228d5 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -111,15 +111,23 @@ NetEBAdd::~NetEBAdd() { } + +static ivl_variable_type_t arith_expr_type(const NetExpr *l, const NetExpr *r) +{ + if (l->expr_type() == IVL_VT_REAL || + r->expr_type() == IVL_VT_REAL) + return IVL_VT_REAL; + + if (l->expr_type() == IVL_VT_LOGIC || + r->expr_type() == IVL_VT_LOGIC) + return IVL_VT_LOGIC; + + return IVL_VT_BOOL; +} + ivl_variable_type_t NetEBAdd::expr_type() const { - if (left_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - - if (right_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - - return IVL_VT_LOGIC; + return arith_expr_type(left_, right_); } /* @@ -171,6 +179,8 @@ ivl_variable_type_t NetEBDiv::expr_type() const if (right_->expr_type() == IVL_VT_REAL) return IVL_VT_REAL; + // div is always 4-state, even if both inputs are 2-state because division + // by 0 can yield 'x return IVL_VT_LOGIC; } @@ -185,12 +195,7 @@ NetEBMinMax::~NetEBMinMax() ivl_variable_type_t NetEBMinMax::expr_type() const { - if (left_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - if (right_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - - return IVL_VT_LOGIC; + return arith_expr_type(left_, right_); } NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag) @@ -204,13 +209,7 @@ NetEBMult::~NetEBMult() ivl_variable_type_t NetEBMult::expr_type() const { - if (left_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - - if (right_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - - return IVL_VT_LOGIC; + return arith_expr_type(left_, right_); } NetEBPow::NetEBPow(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag) @@ -224,12 +223,7 @@ NetEBPow::~NetEBPow() ivl_variable_type_t NetEBPow::expr_type() const { - if (right_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - if (left_->expr_type() == IVL_VT_REAL) - return IVL_VT_REAL; - - return IVL_VT_LOGIC; + return arith_expr_type(left_, right_); } NetEBShift::NetEBShift(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag) @@ -246,6 +240,15 @@ bool NetEBShift::has_width() const return left_->has_width(); } +ivl_variable_type_t NetEBShift::expr_type() const +{ + if (left_->expr_type() == IVL_VT_LOGIC || + right_->expr_type() == IVL_VT_LOGIC) + return IVL_VT_LOGIC; + + return IVL_VT_BOOL; +} + NetEConcat::NetEConcat(unsigned cnt, unsigned r, ivl_variable_type_t vt) : parms_(cnt), repeat_(r), expr_type_(vt) { diff --git a/netlist.cc b/netlist.cc index b1daa0b95..d5dc8d717 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2257,6 +2257,15 @@ NetEBBits::~NetEBBits() { } +ivl_variable_type_t NetEBBits::expr_type() const +{ + if (left_->expr_type() == IVL_VT_LOGIC || + right_->expr_type() == IVL_VT_LOGIC) + return IVL_VT_LOGIC; + + return IVL_VT_BOOL; +} + NetEBinary::NetEBinary(char op__, NetExpr*l, NetExpr*r, unsigned wid, bool signed_flag) : op_(op__), left_(l), right_(r) { @@ -2284,6 +2293,15 @@ NetEBLogic::~NetEBLogic() { } +ivl_variable_type_t NetEBLogic::expr_type() const +{ + if (left_->expr_type() == IVL_VT_LOGIC || + right_->expr_type() == IVL_VT_LOGIC) + return IVL_VT_LOGIC; + + return IVL_VT_BOOL; +} + NetEConst::NetEConst(const verinum&val) : NetExpr(val.len()), value_(val) { diff --git a/netlist.h b/netlist.h index c479bcbac..85814c1d3 100644 --- a/netlist.h +++ b/netlist.h @@ -4248,6 +4248,8 @@ class NetEBBits : public NetEBinary { virtual NetEBBits* dup_expr() const; virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); + ivl_variable_type_t expr_type() const override; + private: NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const; }; @@ -4309,6 +4311,8 @@ class NetEBLogic : public NetEBinary { virtual NetEBLogic* dup_expr() const; virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); + ivl_variable_type_t expr_type() const override; + private: NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const; }; @@ -4392,6 +4396,8 @@ class NetEBShift : public NetEBinary { virtual NetEBShift* dup_expr() const; virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); + ivl_variable_type_t expr_type() const override; + private: NetEConst* eval_arguments_(const NetExpr*l, const NetExpr*r) const; };