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)
|
: 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()
|
PEBShift::~PEBShift()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
47
PExpr.h
47
PExpr.h
|
|
@ -535,18 +535,51 @@ class PEBLogic : public PEBinary {
|
||||||
NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
|
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:
|
public:
|
||||||
explicit PEBShift(char op, PExpr*l, PExpr*r);
|
explicit PEBShift(char op, PExpr*l, PExpr*r);
|
||||||
~PEBShift();
|
~PEBShift();
|
||||||
|
|
||||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
NetExpr*elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
|
||||||
unsigned min, unsigned lval,
|
int expr_wid) const;
|
||||||
ivl_variable_type_t&expr_type,
|
|
||||||
bool&flag);
|
|
||||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
|
||||||
int expr_width, bool sys_task_arg) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
84
elab_expr.cc
84
elab_expr.cc
|
|
@ -177,6 +177,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
|
||||||
case 'G': // >= Should be handled by PEBComp
|
case 'G': // >= Should be handled by PEBComp
|
||||||
case 'n': // != Should be handled by PEBComp
|
case 'n': // != 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);
|
ivl_assert(*this, 0);
|
||||||
default:
|
default:
|
||||||
if (wid_left > min)
|
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);
|
tmp = elaborate_expr_base_div_(des, lp, rp, expr_wid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l': // <<
|
case 'l':
|
||||||
tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid);
|
case 'r':
|
||||||
break;
|
case 'R':
|
||||||
|
cerr << get_fileline() << ": internal error: "
|
||||||
case 'r': // >>
|
<< "Elaboration of " << human_readable_op(op_)
|
||||||
case 'R': // >>>
|
<< " Should have been handled in NetEBShift::elaborate."
|
||||||
tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid);
|
<< endl;
|
||||||
break;
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
|
||||||
case '^':
|
case '^':
|
||||||
case '&':
|
case '&':
|
||||||
|
|
@ -861,12 +863,12 @@ NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope,
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned PEBShift::test_width(Design*des, NetScope*scope,
|
unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope,
|
||||||
unsigned min, unsigned lval,
|
unsigned min, unsigned lval,
|
||||||
ivl_variable_type_t&expr_type__,
|
ivl_variable_type_t&expr_type__,
|
||||||
bool&unsized_flag)
|
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
|
// The right expression is self-determined and has no impact
|
||||||
// on the expression size that is generated.
|
// on the expression size that is generated.
|
||||||
|
|
@ -876,12 +878,15 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope,
|
||||||
if (wid_left < lval)
|
if (wid_left < lval)
|
||||||
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;
|
wid_left = integer_width;
|
||||||
|
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
cerr << get_fileline() << ": debug: "
|
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
|
<< " is padded to compiler integer width=" << wid_left
|
||||||
<< endl;
|
<< 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);
|
unsigned wid_right = right_->test_width(des, scope, 0, 0, rtype, rflag);
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
cerr << get_fileline() << ": debug: "
|
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
|
<< "returns wid=" << wid_right << ", type=" << rtype
|
||||||
<< ", flag=" << rflag << endl;
|
<< ", flag=" << rflag << endl;
|
||||||
|
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope,
|
NetExpr*PEBLeftWidth::elaborate_expr(Design*des, NetScope*scope,
|
||||||
int expr_wid, bool sys_task_arg) const
|
int expr_wid, bool sys_task_arg) const
|
||||||
{
|
{
|
||||||
assert(left_);
|
assert(left_);
|
||||||
assert(right_);
|
assert(right_);
|
||||||
|
|
||||||
NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, false);
|
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);
|
NetExpr*rp = right_->elaborate_expr(des, scope, -1, false);
|
||||||
if ((lp == 0) || (rp == 0)) {
|
if ((lp == 0) || (rp == 0)) {
|
||||||
delete lp;
|
delete lp;
|
||||||
|
|
@ -918,7 +931,48 @@ NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope,
|
||||||
return 0;
|
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;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,20 @@ NetExpr*PEBComp::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||||
return tmp;
|
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*PEBLogic::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
NetExpr*lp = left_->elaborate_pexpr(des, scope);
|
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; // Logical right shift
|
||||||
case 'R': type = ">>>"; break; // Arithmetic right shift
|
case 'R': type = ">>>"; break; // Arithmetic right shift
|
||||||
|
|
||||||
|
case 'p': type = "**"; break; // Power
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue