Do not evaluate parameters too early.
This patch pushes the evaluation of constant system functions into normal elaboration vs doing them in the preliminary parameter elaboration. It also fixes the compiler version of clog2 to return integer_width vs a fixed 32 bits.
This commit is contained in:
parent
aebd9c2bc7
commit
bd504ea14e
140
elab_pexpr.cc
140
elab_pexpr.cc
|
|
@ -268,66 +268,57 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/* Reuse these routines from eval_tree.cc. */
|
||||
NetExpr* evaluate_clog2(NetExpr*arg);
|
||||
NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name);
|
||||
NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name);
|
||||
NetExpr* evaluate_abs(NetExpr*arg);
|
||||
NetExpr* evaluate_min_max(NetExpr*arg0, NetExpr*arg1, const char*name);
|
||||
|
||||
NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||
{
|
||||
/* Only $clog2 and the builtin mathematical functions can
|
||||
* be a constant system function. */
|
||||
perm_string name = peek_tail_name(path_);
|
||||
if (name[0] == '$' && (generation_flag >= GN_VER2005 ||
|
||||
gn_icarus_misc_flag || gn_verilog_ams_flag)) {
|
||||
if (name == "$clog2" ||
|
||||
name == "$ln" ||
|
||||
name == "$log10" ||
|
||||
name == "$exp" ||
|
||||
name == "$sqrt" ||
|
||||
name == "$floor" ||
|
||||
name == "$ceil" ||
|
||||
name == "$sin" ||
|
||||
name == "$cos" ||
|
||||
name == "$tan" ||
|
||||
name == "$asin" ||
|
||||
name == "$acos" ||
|
||||
name == "$atan" ||
|
||||
name == "$sinh" ||
|
||||
name == "$cosh" ||
|
||||
name == "$tanh" ||
|
||||
name == "$asinh" ||
|
||||
name == "$acosh" ||
|
||||
name == "$atanh") {
|
||||
perm_string nm = peek_tail_name(path_);
|
||||
if (nm[0] == '$' && (generation_flag >= GN_VER2005 ||
|
||||
gn_icarus_misc_flag || gn_verilog_ams_flag)) {
|
||||
if (nm == "$clog2" ||
|
||||
nm == "$ln" ||
|
||||
nm == "$log10" ||
|
||||
nm == "$exp" ||
|
||||
nm == "$sqrt" ||
|
||||
nm == "$floor" ||
|
||||
nm == "$ceil" ||
|
||||
nm == "$sin" ||
|
||||
nm == "$cos" ||
|
||||
nm == "$tan" ||
|
||||
nm == "$asin" ||
|
||||
nm == "$acos" ||
|
||||
nm == "$atan" ||
|
||||
nm == "$sinh" ||
|
||||
nm == "$cosh" ||
|
||||
nm == "$tanh" ||
|
||||
nm == "$asinh" ||
|
||||
nm == "$acosh" ||
|
||||
nm == "$atanh") {
|
||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes a single argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||
if (arg == 0) return 0;
|
||||
eval_expr(arg);
|
||||
NetExpr*rtn;
|
||||
if (peek_tail_name(path_) == "$clog2") {
|
||||
rtn = evaluate_clog2(arg);
|
||||
NetESFunc*rtn;
|
||||
if (nm == "$clog2") {
|
||||
rtn = new NetESFunc(nm, IVL_VT_BOOL, integer_width, 1);
|
||||
} else {
|
||||
rtn = evaluate_math_one_arg(arg, name.str());
|
||||
}
|
||||
delete arg;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1);
|
||||
}
|
||||
rtn->set_line(*this);
|
||||
rtn->cast_signed(true);
|
||||
rtn->parm(0, arg);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
if (name == "$pow" ||
|
||||
name == "$atan2" ||
|
||||
name == "$hypot") {
|
||||
if (nm == "$pow" ||
|
||||
nm == "$atan2" ||
|
||||
nm == "$hypot") {
|
||||
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes two arguments." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
|
|
@ -335,45 +326,44 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
|||
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
||||
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
||||
if (arg0 == 0 || arg1 == 0) return 0;
|
||||
eval_expr(arg0);
|
||||
eval_expr(arg1);
|
||||
NetExpr*rtn = evaluate_math_two_args(arg0, arg1, name.str());
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
}
|
||||
NetESFunc*rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 2);
|
||||
rtn->set_line(*this);
|
||||
rtn->cast_signed(true);
|
||||
rtn->parm(0, arg0);
|
||||
rtn->parm(1, arg1);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/* These are only available with verilog-ams or icarus-misc. */
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(name == "$log" || name == "$abs")) {
|
||||
(nm == "$log" || nm == "$abs")) {
|
||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes a single argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||
if (arg == 0) return 0;
|
||||
eval_expr(arg);
|
||||
NetExpr*rtn;
|
||||
if (peek_tail_name(path_) == "$log") {
|
||||
rtn = evaluate_math_one_arg(arg, name.str());
|
||||
NetESFunc*rtn;
|
||||
if (nm == "$log") {
|
||||
rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1);
|
||||
} else {
|
||||
rtn = evaluate_abs(arg);
|
||||
}
|
||||
delete arg;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
/* This can return either a real or an arbitrary
|
||||
* width vector, so set things to fail if this
|
||||
* does not get replaced with a constant during
|
||||
* elaboration. */
|
||||
rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 1);
|
||||
}
|
||||
rtn->set_line(*this);
|
||||
rtn->cast_signed(true);
|
||||
rtn->parm(0, arg);
|
||||
return rtn;
|
||||
}
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
(name == "$min" || name == "$max")) {
|
||||
(nm == "$min" || nm == "$max")) {
|
||||
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||
cerr << get_fileline() << ": error: " << name
|
||||
cerr << get_fileline() << ": error: " << nm
|
||||
<< " takes two arguments." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
|
|
@ -381,15 +371,13 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
|||
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
||||
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
||||
if (arg0 == 0 || arg1 == 0) return 0;
|
||||
eval_expr(arg0);
|
||||
eval_expr(arg1);
|
||||
NetExpr*rtn = evaluate_min_max(arg0, arg1, name.str());
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
if (rtn != 0) {
|
||||
rtn->set_line(*this);
|
||||
return rtn;
|
||||
}
|
||||
/* See $log above for why this has no type or width. */
|
||||
NetESFunc*rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 2);
|
||||
rtn->set_line(*this);
|
||||
rtn->cast_signed(true);
|
||||
rtn->parm(0, arg0);
|
||||
rtn->parm(1, arg1);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: this is not a constant "
|
||||
|
|
|
|||
47
eval_tree.cc
47
eval_tree.cc
|
|
@ -1646,8 +1646,9 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width)
|
|||
return new NetEConst(verinum(res, 1));
|
||||
}
|
||||
|
||||
NetExpr* evaluate_clog2(NetExpr*arg)
|
||||
NetExpr* evaluate_clog2(NetExpr*&arg)
|
||||
{
|
||||
eval_expr(arg);
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||
if (tmpi || tmpr) {
|
||||
|
|
@ -1658,9 +1659,9 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
|||
arg = verinum(tmpr->value().as_double(), true);
|
||||
}
|
||||
|
||||
/* If we have an x in the verinum we return 32'bx. */
|
||||
/* If we have an x in the verinum we return 'bx. */
|
||||
if (!arg.is_defined()) {
|
||||
verinum tmp (verinum::Vx, 32);
|
||||
verinum tmp (verinum::Vx, integer_width);
|
||||
tmp.has_sign(true);
|
||||
NetEConst*rtn = new NetEConst(tmp);
|
||||
return rtn;
|
||||
|
|
@ -1688,7 +1689,7 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
|||
if (is_neg && res < integer_width)
|
||||
res = integer_width;
|
||||
|
||||
verinum tmp (res, 32);
|
||||
verinum tmp (res, integer_width);
|
||||
NetEConst*rtn = new NetEConst(tmp);
|
||||
return rtn;
|
||||
}
|
||||
|
|
@ -1696,8 +1697,9 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name)
|
||||
NetExpr* evaluate_math_one_arg(NetExpr*&arg, const char*name)
|
||||
{
|
||||
eval_expr(arg);
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||
if (tmpi || tmpr) {
|
||||
|
|
@ -1752,8 +1754,10 @@ NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name)
|
||||
NetExpr* evaluate_math_two_args(NetExpr*&arg0, NetExpr*&arg1, const char*name)
|
||||
{
|
||||
eval_expr(arg0);
|
||||
eval_expr(arg1);
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
||||
|
|
@ -1783,8 +1787,9 @@ NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* evaluate_abs(NetExpr*arg)
|
||||
NetExpr* evaluate_abs(NetExpr*&arg)
|
||||
{
|
||||
eval_expr(arg);
|
||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||
if (tmpi) {
|
||||
verinum arg = tmpi->value();
|
||||
|
|
@ -1803,8 +1808,10 @@ NetExpr* evaluate_abs(NetExpr*arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* evaluate_min_max(NetExpr*arg0, NetExpr*arg1, const char*name)
|
||||
NetExpr* evaluate_min_max(NetExpr*&arg0, NetExpr*&arg1, const char*name)
|
||||
{
|
||||
eval_expr(arg0);
|
||||
eval_expr(arg1);
|
||||
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0);
|
||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
||||
|
|
@ -1879,11 +1886,13 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
|||
<< " takes a single argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parm(0)->dup_expr();
|
||||
if (strcmp(nm, "$clog2") == 0) {
|
||||
rtn = evaluate_clog2(parm(0));
|
||||
rtn = evaluate_clog2(arg);
|
||||
} else {
|
||||
rtn = evaluate_math_one_arg(parm(0), nm);
|
||||
rtn = evaluate_math_one_arg(arg, nm);
|
||||
}
|
||||
delete arg;
|
||||
}
|
||||
|
||||
if (strcmp(nm, "$pow") == 0 ||
|
||||
|
|
@ -1894,7 +1903,11 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
|||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
rtn = evaluate_math_two_args(parm(0), parm(1), nm);
|
||||
NetExpr*arg0 = parm(0)->dup_expr();
|
||||
NetExpr*arg1 = parm(1)->dup_expr();
|
||||
rtn = evaluate_math_two_args(arg0, arg1, nm);
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
}
|
||||
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
|
|
@ -1904,11 +1917,13 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
|||
<< " takes a single argument." << endl;
|
||||
return 0;
|
||||
}
|
||||
NetExpr*arg = parm(0)->dup_expr();
|
||||
if (strcmp(nm, "$log") == 0) {
|
||||
rtn = evaluate_math_one_arg(parm(0), nm);
|
||||
rtn = evaluate_math_one_arg(arg, nm);
|
||||
} else {
|
||||
rtn = evaluate_abs(parm(0));
|
||||
rtn = evaluate_abs(arg);
|
||||
}
|
||||
delete arg;
|
||||
}
|
||||
|
||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||
|
|
@ -1918,7 +1933,11 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
|||
<< " takes two arguments." << endl;
|
||||
return 0;
|
||||
}
|
||||
rtn = evaluate_min_max(parm(0), parm(1), nm);
|
||||
NetExpr*arg0 = parm(0)->dup_expr();
|
||||
NetExpr*arg1 = parm(1)->dup_expr();
|
||||
rtn = evaluate_min_max(arg0, arg1, nm);
|
||||
delete arg0;
|
||||
delete arg1;
|
||||
}
|
||||
|
||||
if (rtn != 0) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue