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; unsigned flags) const;
virtual verinum* eval_const(Design*des, NetScope*sc) 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: private:
NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const; 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 <pform_name> hierarchy_identifier
%type <expr> assignment_pattern expression expr_primary expr_mintypmax %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> branch_probe_expression
%type <expr> delay_value delay_value_simple %type <expr> delay_value delay_value_simple
%type <exprs> delay1 delay3 delay3_opt delay_value_list %type <exprs> delay1 delay3 delay3_opt delay_value_list
@ -665,6 +665,35 @@ implicit_class_handle /* IEEE1800-2005: A.8.4 */
| K_super | 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 number : BASED_NUMBER
{ $$ = $1; based_size = 0;} { $$ = $1; based_size = 0;}
| DEC_NUMBER | DEC_NUMBER
@ -1790,32 +1819,10 @@ branch_probe_expression
expression expression
: expr_primary : expr_primary
{ $$ = $1; } { $$ = $1; }
| inc_or_dec_expression
{ $$ = $1; }
| '+' expr_primary %prec UNARY_PREC | '+' expr_primary %prec UNARY_PREC
{ $$ = $2; } { $$ = $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 | '-' expr_primary %prec UNARY_PREC
{ PEUnary*tmp = new PEUnary('-', $2); { PEUnary*tmp = new PEUnary('-', $2);
FILE_NAME(tmp, @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 /* assign and deassign statements are procedural code to do
structural assignments, and to turn that structural assignment structural assignments, and to turn that structural assignment
@ -5094,16 +5101,29 @@ statement
{ $$ = 0; { $$ = 0;
yyerror(@1, "error: Error in while loop condition."); yyerror(@1, "error: Error in while loop condition.");
} }
| compressed_statement ';'
{ $$ = $1; } /* SytemVerilog adds the compressed_statement */
| delay1 statement_or_null
{ PExpr*del = $1->front(); | compressed_statement ';'
assert($1->size() == 1); { $$ = $1; }
delete $1;
PDelayStatement*tmp = new PDelayStatement(del, $2); /* increment/decrement expressions can also be statements. When used
FILE_NAME(tmp, @1); as statements, we can rewrite a++ as a += 1, and so on. */
$$ = tmp;
} | 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 | event_control attribute_list_opt statement_or_null
{ PEventStatement*tmp = $1; { PEventStatement*tmp = $1;
if (tmp == 0) { if (tmp == 0) {
@ -5129,6 +5149,9 @@ statement
tmp->set_statement($6); tmp->set_statement($6);
$$ = tmp; $$ = tmp;
} }
/* Various assignment statements */
| lpvalue '=' expression ';' | lpvalue '=' expression ';'
{ PAssign*tmp = new PAssign($1,$3); { PAssign*tmp = new PAssign($1,$3);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
@ -5184,6 +5207,8 @@ statement
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| K_wait '(' expression ')' statement_or_null | K_wait '(' expression ')' statement_or_null
{ PEventStatement*tmp; { PEventStatement*tmp;
PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3); 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); 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) void pform_set_attrib(perm_string name, perm_string key, char*value)
{ {
if (PWire*cur = lexical_scope->wires_find(name)) { 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, data_type_t*vtype,
list<perm_string>*names); 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 * These are functions that the outside-the-parser code uses the do