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:
Stephen Williams 2008-11-28 14:40:25 -08:00
parent 69726a56b0
commit 82143edf2c
6 changed files with 145 additions and 25 deletions

View File

@ -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
View File

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

View File

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

View File

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

View File

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

View File

@ -929,7 +929,7 @@ expression
$$ = tmp;
}
| expression K_POW expression
{ PEBinary*tmp = new PEBinary('p', $1, $3);
{ PEBinary*tmp = new PEBPower('p', $1, $3);
FILE_NAME(tmp, @2);
$$ = tmp;
}