Implement increment/decrement statements.

During parse/pform processing, convert increment statements to
the equivalent compressed assignment statement. This is less weird
for elaboration processing and better expresses what is going on.
This commit is contained in:
Stephen Williams 2012-02-19 18:54:58 -08:00
parent 6b4251626b
commit f8e346f108
4 changed files with 109 additions and 36 deletions

View File

@ -509,6 +509,10 @@ class PEUnary : public PExpr {
unsigned flags) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const;
public:
inline char get_op() const { return op_; }
inline PExpr*get_expr() const { return expr_; }
private:
NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const;

97
parse.y
View File

@ -496,7 +496,7 @@ static void current_task_set_statement(vector<Statement*>*s)
%type <pform_name> hierarchy_identifier
%type <expr> assignment_pattern expression expr_primary expr_mintypmax
%type <expr> lpvalue
%type <expr> inc_or_dec_expression lpvalue
%type <expr> branch_probe_expression
%type <expr> delay_value delay_value_simple
%type <exprs> delay1 delay3 delay3_opt delay_value_list
@ -665,6 +665,35 @@ implicit_class_handle /* IEEE1800-2005: A.8.4 */
| K_super
;
/* SystemVerilog adds support for the increment/decrement
expressions, which look like a++, --a, etc. These are primaries
but are in their own rules because they can also be
statements. Note that the operator can only take l-value
expressions. */
inc_or_dec_expression /* IEEE1800-2005: A.4.3 */
: K_INCR lpvalue %prec UNARY_PREC
{ PEUnary*tmp = new PEUnary('I', $2);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| lpvalue K_INCR %prec UNARY_PREC
{ PEUnary*tmp = new PEUnary('i', $1);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| K_DECR lpvalue %prec UNARY_PREC
{ PEUnary*tmp = new PEUnary('D', $2);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| lpvalue K_DECR %prec UNARY_PREC
{ PEUnary*tmp = new PEUnary('d', $1);
FILE_NAME(tmp, @1);
$$ = tmp;
}
;
number : BASED_NUMBER
{ $$ = $1; based_size = 0;}
| DEC_NUMBER
@ -1790,32 +1819,10 @@ branch_probe_expression
expression
: expr_primary
{ $$ = $1; }
| inc_or_dec_expression
{ $$ = $1; }
| '+' expr_primary %prec UNARY_PREC
{ $$ = $2; }
| K_INCR expr_primary %prec UNARY_PREC
{
PEUnary*tmp = new PEUnary('I', $2);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| expr_primary K_INCR %prec UNARY_PREC
{
PEUnary*tmp = new PEUnary('i', $1);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| K_DECR expr_primary %prec UNARY_PREC
{
PEUnary*tmp = new PEUnary('D', $2);
FILE_NAME(tmp, @2);
$$ = tmp;
}
| expr_primary K_DECR %prec UNARY_PREC
{
PEUnary*tmp = new PEUnary('d', $1);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| '-' expr_primary %prec UNARY_PREC
{ PEUnary*tmp = new PEUnary('-', $2);
FILE_NAME(tmp, @2);
@ -4897,7 +4904,7 @@ spec_notifier
;
statement
statement /* This is roughly statement_item in the LRM */
/* assign and deassign statements are procedural code to do
structural assignments, and to turn that structural assignment
@ -5094,16 +5101,29 @@ statement
{ $$ = 0;
yyerror(@1, "error: Error in while loop condition.");
}
| compressed_statement ';'
{ $$ = $1; }
| delay1 statement_or_null
{ PExpr*del = $1->front();
assert($1->size() == 1);
delete $1;
PDelayStatement*tmp = new PDelayStatement(del, $2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
/* SytemVerilog adds the compressed_statement */
| compressed_statement ';'
{ $$ = $1; }
/* increment/decrement expressions can also be statements. When used
as statements, we can rewrite a++ as a += 1, and so on. */
| inc_or_dec_expression ';'
{ $$ = pform_compressed_assign_from_inc_dec(@1, $1); }
/* */
| delay1 statement_or_null
{ PExpr*del = $1->front();
assert($1->size() == 1);
delete $1;
PDelayStatement*tmp = new PDelayStatement(del, $2);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| event_control attribute_list_opt statement_or_null
{ PEventStatement*tmp = $1;
if (tmp == 0) {
@ -5129,6 +5149,9 @@ statement
tmp->set_statement($6);
$$ = tmp;
}
/* Various assignment statements */
| lpvalue '=' expression ';'
{ PAssign*tmp = new PAssign($1,$3);
FILE_NAME(tmp, @1);
@ -5184,6 +5207,8 @@ statement
FILE_NAME(tmp, @1);
$$ = tmp;
}
| K_wait '(' expression ')' statement_or_null
{ PEventStatement*tmp;
PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3);

View File

@ -2208,6 +2208,43 @@ svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
range_tmp, names);
}
/*
* The parser calls this in the rule that matches increment/decrement
* statements. The rule that does the matching creates a PEUnary with
* all the information we need, but here we convert that expression to
* a compressed assignment statement.
*/
PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, PExpr*exp)
{
PEUnary*expu = dynamic_cast<PEUnary*> (exp);
ivl_assert(*exp, expu != 0);
char use_op = 0;
switch (expu->get_op()) {
case 'i':
case 'I':
use_op = '+';
break;
case 'd':
case 'D':
use_op = '-';
break;
default:
ivl_assert(*exp, 0);
break;
}
PExpr*lval = expu->get_expr();
PExpr*rval = new PENumber(new verinum((uint64_t)1, 1));
FILE_NAME(rval, loc);
PAssign*tmp = new PAssign(lval, use_op, rval);
FILE_NAME(tmp, loc);
delete exp;
return tmp;
}
void pform_set_attrib(perm_string name, perm_string key, char*value)
{
if (PWire*cur = lexical_scope->wires_find(name)) {

View File

@ -398,6 +398,13 @@ extern svector<PWire*>*pform_make_task_ports(const struct vlltype&loc,
data_type_t*vtype,
list<perm_string>*names);
/*
* The parser uses this function to convert a unary
* increment/decrement expression to the equivilent compressed
* assignment statement.
*/
extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc,
PExpr*exp);
/*
* These are functions that the outside-the-parser code uses the do