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 <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2023-06-16 06:44:56 -07:00
parent 872ccd32c4
commit 17229f99c9
4 changed files with 57 additions and 30 deletions

View File

@ -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<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(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<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(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<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(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<const NetEConst*>(l);
const NetEConst*rc = dynamic_cast<const NetEConst*>(r);

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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;
};