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;
|
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
|
NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
/* Only $clog2 and the builtin mathematical functions can
|
/* Only $clog2 and the builtin mathematical functions can
|
||||||
* be a constant system function. */
|
* be a constant system function. */
|
||||||
perm_string name = peek_tail_name(path_);
|
perm_string nm = peek_tail_name(path_);
|
||||||
if (name[0] == '$' && (generation_flag >= GN_VER2005 ||
|
if (nm[0] == '$' && (generation_flag >= GN_VER2005 ||
|
||||||
gn_icarus_misc_flag || gn_verilog_ams_flag)) {
|
gn_icarus_misc_flag || gn_verilog_ams_flag)) {
|
||||||
if (name == "$clog2" ||
|
if (nm == "$clog2" ||
|
||||||
name == "$ln" ||
|
nm == "$ln" ||
|
||||||
name == "$log10" ||
|
nm == "$log10" ||
|
||||||
name == "$exp" ||
|
nm == "$exp" ||
|
||||||
name == "$sqrt" ||
|
nm == "$sqrt" ||
|
||||||
name == "$floor" ||
|
nm == "$floor" ||
|
||||||
name == "$ceil" ||
|
nm == "$ceil" ||
|
||||||
name == "$sin" ||
|
nm == "$sin" ||
|
||||||
name == "$cos" ||
|
nm == "$cos" ||
|
||||||
name == "$tan" ||
|
nm == "$tan" ||
|
||||||
name == "$asin" ||
|
nm == "$asin" ||
|
||||||
name == "$acos" ||
|
nm == "$acos" ||
|
||||||
name == "$atan" ||
|
nm == "$atan" ||
|
||||||
name == "$sinh" ||
|
nm == "$sinh" ||
|
||||||
name == "$cosh" ||
|
nm == "$cosh" ||
|
||||||
name == "$tanh" ||
|
nm == "$tanh" ||
|
||||||
name == "$asinh" ||
|
nm == "$asinh" ||
|
||||||
name == "$acosh" ||
|
nm == "$acosh" ||
|
||||||
name == "$atanh") {
|
nm == "$atanh") {
|
||||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||||
cerr << get_fileline() << ": error: " << name
|
cerr << get_fileline() << ": error: " << nm
|
||||||
<< " takes a single argument." << endl;
|
<< " takes a single argument." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||||
if (arg == 0) return 0;
|
if (arg == 0) return 0;
|
||||||
eval_expr(arg);
|
NetESFunc*rtn;
|
||||||
NetExpr*rtn;
|
if (nm == "$clog2") {
|
||||||
if (peek_tail_name(path_) == "$clog2") {
|
rtn = new NetESFunc(nm, IVL_VT_BOOL, integer_width, 1);
|
||||||
rtn = evaluate_clog2(arg);
|
|
||||||
} else {
|
} 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);
|
|
||||||
return rtn;
|
|
||||||
}
|
}
|
||||||
|
rtn->set_line(*this);
|
||||||
|
rtn->cast_signed(true);
|
||||||
|
rtn->parm(0, arg);
|
||||||
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == "$pow" ||
|
if (nm == "$pow" ||
|
||||||
name == "$atan2" ||
|
nm == "$atan2" ||
|
||||||
name == "$hypot") {
|
nm == "$hypot") {
|
||||||
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||||
cerr << get_fileline() << ": error: " << name
|
cerr << get_fileline() << ": error: " << nm
|
||||||
<< " takes two arguments." << endl;
|
<< " takes two arguments." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -335,45 +326,44 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||||
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
||||||
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
||||||
if (arg0 == 0 || arg1 == 0) return 0;
|
if (arg0 == 0 || arg1 == 0) return 0;
|
||||||
eval_expr(arg0);
|
NetESFunc*rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 2);
|
||||||
eval_expr(arg1);
|
rtn->set_line(*this);
|
||||||
NetExpr*rtn = evaluate_math_two_args(arg0, arg1, name.str());
|
rtn->cast_signed(true);
|
||||||
delete arg0;
|
rtn->parm(0, arg0);
|
||||||
delete arg1;
|
rtn->parm(1, arg1);
|
||||||
if (rtn != 0) {
|
return rtn;
|
||||||
rtn->set_line(*this);
|
|
||||||
return rtn;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These are only available with verilog-ams or icarus-misc. */
|
/* These are only available with verilog-ams or icarus-misc. */
|
||||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
||||||
(name == "$log" || name == "$abs")) {
|
(nm == "$log" || nm == "$abs")) {
|
||||||
if (parms_.size() != 1 || parms_[0] == 0) {
|
if (parms_.size() != 1 || parms_[0] == 0) {
|
||||||
cerr << get_fileline() << ": error: " << name
|
cerr << get_fileline() << ": error: " << nm
|
||||||
<< " takes a single argument." << endl;
|
<< " takes a single argument." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope);
|
||||||
if (arg == 0) return 0;
|
if (arg == 0) return 0;
|
||||||
eval_expr(arg);
|
NetESFunc*rtn;
|
||||||
NetExpr*rtn;
|
if (nm == "$log") {
|
||||||
if (peek_tail_name(path_) == "$log") {
|
rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1);
|
||||||
rtn = evaluate_math_one_arg(arg, name.str());
|
|
||||||
} else {
|
} else {
|
||||||
rtn = evaluate_abs(arg);
|
/* This can return either a real or an arbitrary
|
||||||
}
|
* width vector, so set things to fail if this
|
||||||
delete arg;
|
* does not get replaced with a constant during
|
||||||
if (rtn != 0) {
|
* elaboration. */
|
||||||
rtn->set_line(*this);
|
rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 1);
|
||||||
return rtn;
|
|
||||||
}
|
}
|
||||||
|
rtn->set_line(*this);
|
||||||
|
rtn->cast_signed(true);
|
||||||
|
rtn->parm(0, arg);
|
||||||
|
return rtn;
|
||||||
}
|
}
|
||||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
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) {
|
if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) {
|
||||||
cerr << get_fileline() << ": error: " << name
|
cerr << get_fileline() << ": error: " << nm
|
||||||
<< " takes two arguments." << endl;
|
<< " takes two arguments." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -381,15 +371,13 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const
|
||||||
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope);
|
||||||
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope);
|
||||||
if (arg0 == 0 || arg1 == 0) return 0;
|
if (arg0 == 0 || arg1 == 0) return 0;
|
||||||
eval_expr(arg0);
|
/* See $log above for why this has no type or width. */
|
||||||
eval_expr(arg1);
|
NetESFunc*rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 2);
|
||||||
NetExpr*rtn = evaluate_min_max(arg0, arg1, name.str());
|
rtn->set_line(*this);
|
||||||
delete arg0;
|
rtn->cast_signed(true);
|
||||||
delete arg1;
|
rtn->parm(0, arg0);
|
||||||
if (rtn != 0) {
|
rtn->parm(1, arg1);
|
||||||
rtn->set_line(*this);
|
return rtn;
|
||||||
return rtn;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cerr << get_fileline() << ": error: this is not a constant "
|
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));
|
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);
|
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||||
if (tmpi || tmpr) {
|
if (tmpi || tmpr) {
|
||||||
|
|
@ -1658,9 +1659,9 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
||||||
arg = verinum(tmpr->value().as_double(), true);
|
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()) {
|
if (!arg.is_defined()) {
|
||||||
verinum tmp (verinum::Vx, 32);
|
verinum tmp (verinum::Vx, integer_width);
|
||||||
tmp.has_sign(true);
|
tmp.has_sign(true);
|
||||||
NetEConst*rtn = new NetEConst(tmp);
|
NetEConst*rtn = new NetEConst(tmp);
|
||||||
return rtn;
|
return rtn;
|
||||||
|
|
@ -1688,7 +1689,7 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
||||||
if (is_neg && res < integer_width)
|
if (is_neg && res < integer_width)
|
||||||
res = integer_width;
|
res = integer_width;
|
||||||
|
|
||||||
verinum tmp (res, 32);
|
verinum tmp (res, integer_width);
|
||||||
NetEConst*rtn = new NetEConst(tmp);
|
NetEConst*rtn = new NetEConst(tmp);
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
@ -1696,8 +1697,9 @@ NetExpr* evaluate_clog2(NetExpr*arg)
|
||||||
return 0;
|
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);
|
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||||
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
NetECReal*tmpr = dynamic_cast<NetECReal *>(arg);
|
||||||
if (tmpi || tmpr) {
|
if (tmpi || tmpr) {
|
||||||
|
|
@ -1752,8 +1754,10 @@ NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name)
|
||||||
return 0;
|
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);
|
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0);
|
||||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
||||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
||||||
|
|
@ -1783,8 +1787,9 @@ NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetExpr* evaluate_abs(NetExpr*arg)
|
NetExpr* evaluate_abs(NetExpr*&arg)
|
||||||
{
|
{
|
||||||
|
eval_expr(arg);
|
||||||
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
NetEConst*tmpi = dynamic_cast<NetEConst *>(arg);
|
||||||
if (tmpi) {
|
if (tmpi) {
|
||||||
verinum arg = tmpi->value();
|
verinum arg = tmpi->value();
|
||||||
|
|
@ -1803,8 +1808,10 @@ NetExpr* evaluate_abs(NetExpr*arg)
|
||||||
return 0;
|
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);
|
NetEConst*tmpi0 = dynamic_cast<NetEConst *>(arg0);
|
||||||
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
NetECReal*tmpr0 = dynamic_cast<NetECReal *>(arg0);
|
||||||
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
NetEConst*tmpi1 = dynamic_cast<NetEConst *>(arg1);
|
||||||
|
|
@ -1879,11 +1886,13 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
||||||
<< " takes a single argument." << endl;
|
<< " takes a single argument." << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
NetExpr*arg = parm(0)->dup_expr();
|
||||||
if (strcmp(nm, "$clog2") == 0) {
|
if (strcmp(nm, "$clog2") == 0) {
|
||||||
rtn = evaluate_clog2(parm(0));
|
rtn = evaluate_clog2(arg);
|
||||||
} else {
|
} else {
|
||||||
rtn = evaluate_math_one_arg(parm(0), nm);
|
rtn = evaluate_math_one_arg(arg, nm);
|
||||||
}
|
}
|
||||||
|
delete arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(nm, "$pow") == 0 ||
|
if (strcmp(nm, "$pow") == 0 ||
|
||||||
|
|
@ -1894,7 +1903,11 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width)
|
||||||
<< " takes two arguments." << endl;
|
<< " takes two arguments." << endl;
|
||||||
return 0;
|
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) &&
|
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;
|
<< " takes a single argument." << endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
NetExpr*arg = parm(0)->dup_expr();
|
||||||
if (strcmp(nm, "$log") == 0) {
|
if (strcmp(nm, "$log") == 0) {
|
||||||
rtn = evaluate_math_one_arg(parm(0), nm);
|
rtn = evaluate_math_one_arg(arg, nm);
|
||||||
} else {
|
} else {
|
||||||
rtn = evaluate_abs(parm(0));
|
rtn = evaluate_abs(arg);
|
||||||
}
|
}
|
||||||
|
delete arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((gn_icarus_misc_flag || gn_verilog_ams_flag) &&
|
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;
|
<< " takes two arguments." << endl;
|
||||||
return 0;
|
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) {
|
if (rtn != 0) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue