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:
Cary R 2008-10-01 20:35:26 -07:00 committed by Stephen Williams
parent aebd9c2bc7
commit bd504ea14e
2 changed files with 97 additions and 90 deletions

View File

@ -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 ||
perm_string nm = peek_tail_name(path_);
if (nm[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") {
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());
rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1);
}
delete arg;
if (rtn != 0) {
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) {
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);
/* 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);
}
delete arg;
if (rtn != 0) {
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,16 +371,14 @@ 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) {
/* 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 "
"system function (" << *this << ")." << endl;

View File

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