Rework shift and power PExpr nodes for their special needs.
The power (**) and shift operators are different from other binary operators because their expression width calculations rely only on their left operand, with their right operand self-determined. Get the handling of these operators out of the PEBinary base class to prevent confusion.
This commit is contained in:
parent
69726a56b0
commit
82143edf2c
20
PExpr.cc
20
PExpr.cc
|
|
@ -95,11 +95,29 @@ PEBLogic::~PEBLogic()
|
|||
{
|
||||
}
|
||||
|
||||
PEBShift::PEBShift(char op, PExpr*l, PExpr*r)
|
||||
PEBLeftWidth::PEBLeftWidth(char op, PExpr*l, PExpr*r)
|
||||
: PEBinary(op, l, r)
|
||||
{
|
||||
}
|
||||
|
||||
PEBLeftWidth::~PEBLeftWidth()
|
||||
{
|
||||
}
|
||||
|
||||
PEBPower::PEBPower(char op, PExpr*l, PExpr*r)
|
||||
: PEBLeftWidth(op, l, r)
|
||||
{
|
||||
}
|
||||
|
||||
PEBPower::~PEBPower()
|
||||
{
|
||||
}
|
||||
|
||||
PEBShift::PEBShift(char op, PExpr*l, PExpr*r)
|
||||
: PEBLeftWidth(op, l, r)
|
||||
{
|
||||
}
|
||||
|
||||
PEBShift::~PEBShift()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
47
PExpr.h
47
PExpr.h
|
|
@ -535,18 +535,51 @@ class PEBLogic : public PEBinary {
|
|||
NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
||||
};
|
||||
|
||||
class PEBShift : public PEBinary {
|
||||
/*
|
||||
* A couple of the binary operands have a special sub-expression rule
|
||||
* where the expression width is carried entirely by the left
|
||||
* expression, and the right operand is self-determined.
|
||||
*/
|
||||
class PEBLeftWidth : public PEBinary {
|
||||
|
||||
public:
|
||||
explicit PEBLeftWidth(char op, PExpr*l, PExpr*r);
|
||||
~PEBLeftWidth() =0;
|
||||
|
||||
virtual NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const =0;
|
||||
|
||||
protected:
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
|
||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*scope) const;
|
||||
|
||||
};
|
||||
|
||||
class PEBPower : public PEBLeftWidth {
|
||||
|
||||
public:
|
||||
explicit PEBPower(char op, PExpr*l, PExpr*r);
|
||||
~PEBPower();
|
||||
|
||||
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const;
|
||||
};
|
||||
|
||||
class PEBShift : public PEBLeftWidth {
|
||||
|
||||
public:
|
||||
explicit PEBShift(char op, PExpr*l, PExpr*r);
|
||||
~PEBShift();
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type,
|
||||
bool&flag);
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
int expr_width, bool sys_task_arg) const;
|
||||
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
86
elab_expr.cc
86
elab_expr.cc
|
|
@ -177,6 +177,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
|
|||
case 'G': // >= Should be handled by PEBComp
|
||||
case 'n': // != Should be handled by PEBComp
|
||||
case 'N': // !== Should be handled by PEBComp
|
||||
case 'p': // ** should be handled by PEBPower
|
||||
ivl_assert(*this, 0);
|
||||
default:
|
||||
if (wid_left > min)
|
||||
|
|
@ -315,14 +316,15 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
|
|||
tmp = elaborate_expr_base_div_(des, lp, rp, expr_wid);
|
||||
break;
|
||||
|
||||
case 'l': // <<
|
||||
tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid);
|
||||
break;
|
||||
|
||||
case 'r': // >>
|
||||
case 'R': // >>>
|
||||
tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid);
|
||||
break;
|
||||
case 'l':
|
||||
case 'r':
|
||||
case 'R':
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Elaboration of " << human_readable_op(op_)
|
||||
<< " Should have been handled in NetEBShift::elaborate."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
|
||||
case '^':
|
||||
case '&':
|
||||
|
|
@ -861,12 +863,12 @@ NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope,
|
|||
return tmp;
|
||||
}
|
||||
|
||||
unsigned PEBShift::test_width(Design*des, NetScope*scope,
|
||||
unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
ivl_variable_type_t&expr_type__,
|
||||
bool&unsized_flag)
|
||||
{
|
||||
unsigned wid_left = left_->test_width(des,scope,min, 0, expr_type__, unsized_flag);
|
||||
unsigned wid_left = left_->test_width(des,scope,min, lval, expr_type__, unsized_flag);
|
||||
|
||||
// The right expression is self-determined and has no impact
|
||||
// on the expression size that is generated.
|
||||
|
|
@ -876,12 +878,15 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope,
|
|||
if (wid_left < lval)
|
||||
wid_left = lval;
|
||||
|
||||
if (unsized_flag && wid_left < integer_width) {
|
||||
if (unsized_flag
|
||||
&& type_is_vectorable(expr_type__)
|
||||
&& wid_left > 0
|
||||
&& wid_left < integer_width) {
|
||||
wid_left = integer_width;
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Test width of unsized left shift"
|
||||
<< "Test width of unsized " << human_readable_op(op_)
|
||||
<< " is padded to compiler integer width=" << wid_left
|
||||
<< endl;
|
||||
}
|
||||
|
|
@ -897,20 +902,28 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope,
|
|||
unsigned wid_right = right_->test_width(des, scope, 0, 0, rtype, rflag);
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Test width of shift amount of shift expression "
|
||||
<< "Test width of exponent of " << op_ << " expression "
|
||||
<< "returns wid=" << wid_right << ", type=" << rtype
|
||||
<< ", flag=" << rflag << endl;
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool sys_task_arg) const
|
||||
NetExpr*PEBLeftWidth::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool sys_task_arg) const
|
||||
{
|
||||
assert(left_);
|
||||
assert(right_);
|
||||
|
||||
NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, false);
|
||||
if (expr_wid > 0 && lp->expr_width() < (unsigned)expr_wid) {
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Pad left operand of " << human_readable_op(op_)
|
||||
<< " to " << expr_wid << "." << endl;
|
||||
lp = pad_to_width(lp, expr_wid, *this);
|
||||
}
|
||||
|
||||
NetExpr*rp = right_->elaborate_expr(des, scope, -1, false);
|
||||
if ((lp == 0) || (rp == 0)) {
|
||||
delete lp;
|
||||
|
|
@ -918,7 +931,48 @@ NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid);
|
||||
eval_expr(lp);
|
||||
eval_expr(rp);
|
||||
|
||||
return elaborate_expr_leaf(des, lp, rp, expr_wid);
|
||||
}
|
||||
|
||||
NetExpr*PEBPower::elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: elaborate expression "
|
||||
<< *this << " expr_wid=" << expr_wid << endl;
|
||||
}
|
||||
|
||||
NetExpr*tmp = new NetEBPow(op_, lp, rp);
|
||||
tmp->set_line(*this);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr*PEBShift::elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||
int expr_wid) const
|
||||
{
|
||||
NetExpr*tmp = 0;
|
||||
|
||||
switch (op_) {
|
||||
case 'l':
|
||||
tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid);
|
||||
break;
|
||||
|
||||
case 'r': // >>
|
||||
case 'R': // >>>
|
||||
tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid);
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Unexpected opcode " << human_readable_op(op_)
|
||||
<< " in PEBShift::elaborate_expr_leaf." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,20 @@ NetExpr*PEBComp::elaborate_pexpr(Design*des, NetScope*scope) const
|
|||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr*PEBLeftWidth::elaborate_pexpr (Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*lp = left_->elaborate_pexpr(des, scope);
|
||||
NetExpr*rp = right_->elaborate_pexpr(des, scope);
|
||||
if ((lp == 0) || (rp == 0)) {
|
||||
delete lp;
|
||||
delete rp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*tmp = elaborate_expr_leaf(des, lp, rp, -2);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr*PEBLogic::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*lp = left_->elaborate_pexpr(des, scope);
|
||||
|
|
|
|||
|
|
@ -405,6 +405,7 @@ const char *human_readable_op(const char op)
|
|||
case 'r': type = ">>"; break; // Logical right shift
|
||||
case 'R': type = ">>>"; break; // Arithmetic right shift
|
||||
|
||||
case 'p': type = "**"; break; // Power
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue