Elaborate foreach loops as synthetic for loops.
Create an implicit scope to hold the index variable, and generate a for loop to perform the functionality of the foreach.
This commit is contained in:
parent
335db49282
commit
f602ae84ab
10
Statement.cc
10
Statement.cc
|
|
@ -336,6 +336,16 @@ PForce::~PForce()
|
||||||
delete expr_;
|
delete expr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PForeach::PForeach(perm_string av, perm_string ix, Statement*s)
|
||||||
|
: array_var_(av), index_var_(ix), statement_(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PForeach::~PForeach()
|
||||||
|
{
|
||||||
|
delete statement_;
|
||||||
|
}
|
||||||
|
|
||||||
PForever::PForever(Statement*s)
|
PForever::PForever(Statement*s)
|
||||||
: statement_(s)
|
: statement_(s)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
16
Statement.h
16
Statement.h
|
|
@ -443,6 +443,22 @@ class PForce : public Statement {
|
||||||
PExpr*expr_;
|
PExpr*expr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PForeach : public Statement {
|
||||||
|
public:
|
||||||
|
explicit PForeach(perm_string var, perm_string ix, Statement*stmt);
|
||||||
|
~PForeach();
|
||||||
|
|
||||||
|
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||||
|
virtual void elaborate_scope(Design*des, NetScope*scope) const;
|
||||||
|
virtual void elaborate_sig(Design*des, NetScope*scope) const;
|
||||||
|
virtual void dump(ostream&out, unsigned ind) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
perm_string array_var_;
|
||||||
|
perm_string index_var_;
|
||||||
|
Statement*statement_;
|
||||||
|
};
|
||||||
|
|
||||||
class PForever : public Statement {
|
class PForever : public Statement {
|
||||||
public:
|
public:
|
||||||
explicit PForever(Statement*s);
|
explicit PForever(Statement*s);
|
||||||
|
|
|
||||||
|
|
@ -1890,6 +1890,18 @@ void PEventStatement::elaborate_scope(Design*des, NetScope*scope) const
|
||||||
statement_ -> elaborate_scope(des, scope);
|
statement_ -> elaborate_scope(des, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The standard says that we create an implicit scope for foreach
|
||||||
|
* loops, but that is just to hold the index variables, and we'll
|
||||||
|
* handle them by creating unique names. So just jump into the
|
||||||
|
* contained statement for scope elaboration.
|
||||||
|
*/
|
||||||
|
void PForeach::elaborate_scope(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
if (statement_)
|
||||||
|
statement_ -> elaborate_scope(des, scope);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Statements that contain a further statement but do not
|
* Statements that contain a further statement but do not
|
||||||
* intrinsically add a scope need to elaborate_scope the contained
|
* intrinsically add a scope need to elaborate_scope the contained
|
||||||
|
|
|
||||||
|
|
@ -806,6 +806,12 @@ void PEventStatement::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
statement_->elaborate_sig(des, scope);
|
statement_->elaborate_sig(des, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PForeach::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
if (statement_)
|
||||||
|
statement_->elaborate_sig(des, scope);
|
||||||
|
}
|
||||||
|
|
||||||
void PForever::elaborate_sig(Design*des, NetScope*scope) const
|
void PForever::elaborate_sig(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
if (statement_)
|
if (statement_)
|
||||||
|
|
|
||||||
59
elaborate.cc
59
elaborate.cc
|
|
@ -4575,6 +4575,65 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The foreach statement can be written as a for statement like so:
|
||||||
|
*
|
||||||
|
* for (<idx> = $low(<array>) ; <idx> <= $high(<array>) ; <idx> += 1)
|
||||||
|
* <statement_>
|
||||||
|
*
|
||||||
|
* The <idx> variable is already known to be in the containing named
|
||||||
|
* block scope, which was created by the parser.
|
||||||
|
*/
|
||||||
|
NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
// Get the signal for the index variable.
|
||||||
|
pform_name_t index_name;
|
||||||
|
index_name.push_back(name_component_t(index_var_));
|
||||||
|
NetNet*idx_sig = des->find_signal(scope, index_name);
|
||||||
|
ivl_assert(*this, idx_sig);
|
||||||
|
|
||||||
|
NetESignal*idx_exp = new NetESignal(idx_sig);
|
||||||
|
idx_exp->set_line(*this);
|
||||||
|
|
||||||
|
// Get the signal for the array variable
|
||||||
|
pform_name_t array_name;
|
||||||
|
array_name.push_back(name_component_t(array_var_));
|
||||||
|
NetNet*array_sig = des->find_signal(scope, array_name);
|
||||||
|
ivl_assert(*this, array_sig);
|
||||||
|
|
||||||
|
NetESignal*array_exp = new NetESignal(array_sig);
|
||||||
|
array_exp->set_line(*this);
|
||||||
|
|
||||||
|
// Make an initialization expression for the index.
|
||||||
|
NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1);
|
||||||
|
init_expr->set_line(*this);
|
||||||
|
init_expr->parm(0, array_exp);
|
||||||
|
|
||||||
|
// Make a condition expression: idx <= $high(array)
|
||||||
|
NetESFunc*high_exp = new NetESFunc("$high", IVL_VT_BOOL, 32, 1);
|
||||||
|
high_exp->set_line(*this);
|
||||||
|
high_exp->parm(0, array_exp);
|
||||||
|
|
||||||
|
NetEBComp*cond_expr = new NetEBComp('L', idx_exp, high_exp);
|
||||||
|
cond_expr->set_line(*this);
|
||||||
|
|
||||||
|
/* Elaborate the statement that is contained in the foreach
|
||||||
|
loop. */
|
||||||
|
NetProc*sub = statement_->elaborate(des, scope);
|
||||||
|
|
||||||
|
/* Make a step statement: idx += 1 */
|
||||||
|
NetAssign_*idx_lv = new NetAssign_(idx_sig);
|
||||||
|
NetEConst*step_val = make_const_val(1);
|
||||||
|
NetAssign*step = new NetAssign(idx_lv, '+', step_val);
|
||||||
|
step->set_line(*this);
|
||||||
|
|
||||||
|
NetForLoop*stmt = new NetForLoop(idx_sig, init_expr, cond_expr, sub, step);
|
||||||
|
stmt->set_line(*this);
|
||||||
|
stmt->wrap_up();
|
||||||
|
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* elaborate the for loop as the equivalent while loop. This eases the
|
* elaborate the for loop as the equivalent while loop. This eases the
|
||||||
* task for the target code generator. The structure is:
|
* task for the target code generator. The structure is:
|
||||||
|
|
|
||||||
29
parse.y
29
parse.y
|
|
@ -1376,12 +1376,29 @@ loop_statement /* IEEE1800-2005: A.6.8 */
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
| K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' statement_or_null
|
// When matching a foreach loop, implicitly create a named block
|
||||||
{ yyerror(@1, "sorry: foreach loops not supported");
|
// to hold the definitions for the index variables.
|
||||||
delete[]$3;
|
| K_foreach '(' IDENTIFIER '[' loop_variables ']' ')'
|
||||||
delete $5;
|
{ static unsigned foreach_counter = 0;
|
||||||
delete $8;
|
char for_block_name[64];
|
||||||
$$ = 0;
|
snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter);
|
||||||
|
foreach_counter += 1;
|
||||||
|
|
||||||
|
PBlock*tmp = pform_push_block_scope(for_block_name, PBlock::BL_SEQ);
|
||||||
|
FILE_NAME(tmp, @1);
|
||||||
|
current_block_stack.push(tmp);
|
||||||
|
|
||||||
|
pform_make_foreach_declarations(@1, $5);
|
||||||
|
}
|
||||||
|
statement_or_null
|
||||||
|
{ PForeach*tmp_for = pform_make_foreach(@1, $3, $5, $9);
|
||||||
|
|
||||||
|
pform_pop_scope();
|
||||||
|
vector<Statement*>tmp_for_list(1);
|
||||||
|
tmp_for_list[0] = tmp_for;
|
||||||
|
PBlock*tmp_blk = current_block_stack.top();
|
||||||
|
tmp_blk->set_statement(tmp_for_list);
|
||||||
|
$$ = tmp_blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Error forms for loop statements. */
|
/* Error forms for loop statements. */
|
||||||
|
|
|
||||||
36
pform.cc
36
pform.cc
|
|
@ -704,6 +704,42 @@ PCallTask* pform_make_call_task(const struct vlltype&loc,
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pform_make_foreach_declarations(const struct vlltype&loc,
|
||||||
|
std::list<perm_string>*loop_vars)
|
||||||
|
{
|
||||||
|
static const struct str_pair_t str = { IVL_DR_STRONG, IVL_DR_STRONG };
|
||||||
|
|
||||||
|
list<decl_assignment_t*>assign_list;
|
||||||
|
for (list<perm_string>::const_iterator cur = loop_vars->begin()
|
||||||
|
; cur != loop_vars->end() ; ++ cur) {
|
||||||
|
decl_assignment_t*tmp_assign = new decl_assignment_t;
|
||||||
|
tmp_assign->name = lex_strings.make(*cur);
|
||||||
|
assign_list.push_back(tmp_assign);
|
||||||
|
}
|
||||||
|
|
||||||
|
pform_makewire(loc, 0, str, &assign_list, NetNet::REG, &size_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
PForeach* pform_make_foreach(const struct vlltype&loc,
|
||||||
|
char*name,
|
||||||
|
list<perm_string>*loop_vars,
|
||||||
|
Statement*stmt)
|
||||||
|
{
|
||||||
|
perm_string use_name = lex_strings.make(name);
|
||||||
|
delete[]name;
|
||||||
|
|
||||||
|
perm_string use_index = loop_vars->front();
|
||||||
|
loop_vars->pop_front();
|
||||||
|
|
||||||
|
ivl_assert(loc, loop_vars->empty());
|
||||||
|
delete loop_vars;
|
||||||
|
|
||||||
|
PForeach*fe = new PForeach(use_name, use_index, stmt);
|
||||||
|
FILE_NAME(fe, loc);
|
||||||
|
|
||||||
|
return fe;
|
||||||
|
}
|
||||||
|
|
||||||
static void pform_put_behavior_in_scope(PProcess*pp)
|
static void pform_put_behavior_in_scope(PProcess*pp)
|
||||||
{
|
{
|
||||||
lexical_scope->behaviors.push_back(pp);
|
lexical_scope->behaviors.push_back(pp);
|
||||||
|
|
|
||||||
8
pform.h
8
pform.h
|
|
@ -285,6 +285,12 @@ extern PCallTask* pform_make_call_task(const struct vlltype&loc,
|
||||||
const pform_name_t&name,
|
const pform_name_t&name,
|
||||||
const std::list<PExpr*>&parms);
|
const std::list<PExpr*>&parms);
|
||||||
|
|
||||||
|
extern void pform_make_foreach_declarations(const struct vlltype&loc,
|
||||||
|
std::list<perm_string>*loop_vars);
|
||||||
|
extern PForeach* pform_make_foreach(const struct vlltype&loc,
|
||||||
|
char*ident,
|
||||||
|
std::list<perm_string>*loop_vars,
|
||||||
|
Statement*stmt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The makewire functions announce to the pform code new wires. These
|
* The makewire functions announce to the pform code new wires. These
|
||||||
|
|
@ -349,7 +355,7 @@ extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list<perm
|
||||||
|
|
||||||
extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
extern void pform_set_struct_type(struct_type_t*struct_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||||
|
|
||||||
extern void pform_set_string_type(string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
extern void pform_set_string_type(const string_type_t*string_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*attr);
|
||||||
|
|
||||||
extern void pform_set_class_type(class_type_t*class_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*addr);
|
extern void pform_set_class_type(class_type_t*class_type, std::list<perm_string>*names, NetNet::Type net_type, std::list<named_pexpr_t>*addr);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -967,6 +967,15 @@ void PForce::dump(ostream&out, unsigned ind) const
|
||||||
<< "; /* " << get_fileline() << " */" << endl;
|
<< "; /* " << get_fileline() << " */" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PForeach::dump(ostream&fd, unsigned ind) const
|
||||||
|
{
|
||||||
|
fd << setw(ind) << "" << "foreach "
|
||||||
|
<< "variable=" << array_var_
|
||||||
|
<< ", index=" << index_var_
|
||||||
|
<< " /* " << get_fileline() << " */" << endl;
|
||||||
|
statement_->dump(fd, ind+3);
|
||||||
|
}
|
||||||
|
|
||||||
void PForever::dump(ostream&out, unsigned ind) const
|
void PForever::dump(ostream&out, unsigned ind) const
|
||||||
{
|
{
|
||||||
out << setw(ind) << "" << "forever /* " << get_fileline() << " */" << endl;
|
out << setw(ind) << "" << "forever /* " << get_fileline() << " */" << endl;
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,13 @@
|
||||||
# include "parse_misc.h"
|
# include "parse_misc.h"
|
||||||
# include "ivl_assert.h"
|
# include "ivl_assert.h"
|
||||||
|
|
||||||
static void pform_set_string_type(string_type_t*, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
static void pform_set_string_type(const string_type_t*, perm_string name, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||||
{
|
{
|
||||||
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING);
|
PWire*net = pform_get_make_wire_in_scope(name, net_type, NetNet::NOT_A_PORT, IVL_VT_STRING);
|
||||||
pform_bind_attributes(net->attributes, attr, true);
|
pform_bind_attributes(net->attributes, attr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pform_set_string_type(string_type_t*string_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
void pform_set_string_type(const string_type_t*string_type, list<perm_string>*names, NetNet::Type net_type, list<named_pexpr_t>*attr)
|
||||||
{
|
{
|
||||||
for (list<perm_string>::iterator cur = names->begin()
|
for (list<perm_string>::iterator cur = names->begin()
|
||||||
; cur != names->end() ; ++ cur) {
|
; cur != names->end() ; ++ cur) {
|
||||||
|
|
|
||||||
|
|
@ -42,3 +42,5 @@ ivl_variable_type_t vector_type_t::figure_packed_base_type(void) const
|
||||||
{
|
{
|
||||||
return base_type;
|
return base_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atom2_type_t size_type (32, true);
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,8 @@ struct atom2_type_t : public data_type_t {
|
||||||
ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const;
|
ivl_type_s* elaborate_type_raw(Design*des, NetScope*scope) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern atom2_type_t size_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The vector_type_t class represents types in the old Verilog
|
* The vector_type_t class represents types in the old Verilog
|
||||||
* way. Some typical examples:
|
* way. Some typical examples:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue