Don't evaluate built-in system functions if they are overridden.

We don't support evaluating user-defined system functions at compile
time. If possible, defer evaluation until run time. If used in a
constant expression, output a "sorry" message.
This commit is contained in:
Martin Whitaker 2019-10-19 16:12:17 +01:00
parent bf655003e8
commit 1069a0ef02
9 changed files with 72 additions and 32 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998-2016 Stephen Williams <steve@icarus.com> * Copyright (c) 1998-2019 Stephen Williams <steve@icarus.com>
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
@ -203,12 +203,12 @@ PEBShift::~PEBShift()
} }
PECallFunction::PECallFunction(const pform_name_t&n, const vector<PExpr *> &parms) PECallFunction::PECallFunction(const pform_name_t&n, const vector<PExpr *> &parms)
: package_(0), path_(n), parms_(parms) : package_(0), path_(n), parms_(parms), is_overridden_(false)
{ {
} }
PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const vector<PExpr *> &parms) PECallFunction::PECallFunction(PPackage*pkg, const pform_name_t&n, const vector<PExpr *> &parms)
: package_(pkg), path_(n), parms_(parms) : package_(pkg), path_(n), parms_(parms), is_overridden_(false)
{ {
} }
@ -221,7 +221,7 @@ static pform_name_t pn_from_ps(perm_string n)
} }
PECallFunction::PECallFunction(PPackage*pkg, perm_string n, const list<PExpr *> &parms) PECallFunction::PECallFunction(PPackage*pkg, perm_string n, const list<PExpr *> &parms)
: package_(pkg), path_(pn_from_ps(n)), parms_(parms.size()) : package_(pkg), path_(pn_from_ps(n)), parms_(parms.size()), is_overridden_(false)
{ {
int tmp_idx = 0; int tmp_idx = 0;
assert(parms_.size() == parms.size()); assert(parms_.size() == parms.size());
@ -231,18 +231,18 @@ PECallFunction::PECallFunction(PPackage*pkg, perm_string n, const list<PExpr *>
} }
PECallFunction::PECallFunction(perm_string n, const vector<PExpr*>&parms) PECallFunction::PECallFunction(perm_string n, const vector<PExpr*>&parms)
: package_(0), path_(pn_from_ps(n)), parms_(parms) : package_(0), path_(pn_from_ps(n)), parms_(parms), is_overridden_(false)
{ {
} }
PECallFunction::PECallFunction(perm_string n) PECallFunction::PECallFunction(perm_string n)
: package_(0), path_(pn_from_ps(n)) : package_(0), path_(pn_from_ps(n)), is_overridden_(false)
{ {
} }
// NOTE: Anachronism. Try to work all use of svector out. // NOTE: Anachronism. Try to work all use of svector out.
PECallFunction::PECallFunction(const pform_name_t&n, const list<PExpr *> &parms) PECallFunction::PECallFunction(const pform_name_t&n, const list<PExpr *> &parms)
: package_(0), path_(n), parms_(parms.size()) : package_(0), path_(n), parms_(parms.size()), is_overridden_(false)
{ {
int tmp_idx = 0; int tmp_idx = 0;
assert(parms_.size() == parms.size()); assert(parms_.size() == parms.size());
@ -252,7 +252,7 @@ PECallFunction::PECallFunction(const pform_name_t&n, const list<PExpr *> &parms)
} }
PECallFunction::PECallFunction(perm_string n, const list<PExpr*>&parms) PECallFunction::PECallFunction(perm_string n, const list<PExpr*>&parms)
: package_(0), path_(pn_from_ps(n)), parms_(parms.size()) : package_(0), path_(pn_from_ps(n)), parms_(parms.size()), is_overridden_(false)
{ {
int tmp_idx = 0; int tmp_idx = 0;
assert(parms_.size() == parms.size()); assert(parms_.size() == parms.size());

View File

@ -928,6 +928,9 @@ class PECallFunction : public PExpr {
pform_name_t path_; pform_name_t path_;
std::vector<PExpr *> parms_; std::vector<PExpr *> parms_;
// For system functions.
bool is_overridden_;
bool check_call_matches_definition_(Design*des, NetScope*dscope) const; bool check_call_matches_definition_(Design*des, NetScope*dscope) const;

View File

@ -286,7 +286,8 @@ struct sfunc_return_type {
const char* name; const char* name;
ivl_variable_type_t type; ivl_variable_type_t type;
unsigned wid; unsigned wid;
int signed_flag; bool signed_flag;
bool override_flag;
}; };
extern const struct sfunc_return_type* lookup_sys_func(const char*name); extern const struct sfunc_return_type* lookup_sys_func(const char*name);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2013 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2019 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -233,7 +233,7 @@ NetESelect* NetESelect::dup_expr() const
NetESFunc* NetESFunc::dup_expr() const NetESFunc* NetESFunc::dup_expr() const
{ {
NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms()); NetESFunc*tmp = new NetESFunc(name_, type_, expr_width(), nparms(), is_overridden_);
ivl_assert(*this, tmp); ivl_assert(*this, tmp);
tmp->cast_signed(has_sign()); tmp->cast_signed(has_sign());

View File

@ -1202,6 +1202,8 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
min_width_ = expr_width_; min_width_ = expr_width_;
signed_flag_ = sfunc_info->signed_flag; signed_flag_ = sfunc_info->signed_flag;
is_overridden_ = sfunc_info->override_flag;
if (debug_elaborate) if (debug_elaborate)
cerr << get_fileline() << ": debug: test_width " cerr << get_fileline() << ": debug: test_width "
<< "of system function " << name << "of system function " << name
@ -1547,10 +1549,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
if ((nparms == 1) && (parms_[0] == 0)) if ((nparms == 1) && (parms_[0] == 0))
nparms = 0; nparms = 0;
NetESFunc*fun = new NetESFunc(name, expr_type_, expr_width_, nparms); NetESFunc*fun = new NetESFunc(name, expr_type_, expr_width_, nparms, is_overridden_);
fun->set_line(*this); fun->set_line(*this);
if (!fun->is_built_in()) { bool need_const = NEED_CONST & flags;
/* We don't support evaluating overridden functions. */
if (is_overridden_ && (need_const || scope->need_const_func())) {
cerr << get_fileline() << ": sorry: Cannot evaluate "
"overridden system function." << endl;
des->errors += 1;
}
if (is_overridden_ || !fun->is_built_in()) {
if (scope->need_const_func()) { if (scope->need_const_func()) {
cerr << get_fileline() << ": error: " << name cerr << get_fileline() << ": error: " << name
<< " is not a built-in function, so cannot" << " is not a built-in function, so cannot"
@ -1567,8 +1578,6 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
expression as much as possible, and use the reduced expression as much as possible, and use the reduced
expression if one is created. */ expression if one is created. */
bool need_const = NEED_CONST & flags;
/* These functions can work in a constant context with a signal expression. */ /* These functions can work in a constant context with a signal expression. */
if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0]))) { if ((nparms == 1) && (dynamic_cast<PEIdent*>(parms_[0]))) {
if (strcmp(name, "$dimensions") == 0) need_const = false; if (strcmp(name, "$dimensions") == 0) need_const = false;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2018 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2019 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -2400,6 +2400,10 @@ NetESFunc::ID NetESFunc::built_in_id_() const
NetExpr* NetESFunc::eval_tree() NetExpr* NetESFunc::eval_tree()
{ {
/* We don't support evaluating overridden functions. */
if (is_overridden_)
return 0;
/* Get the ID for this system function if it can be used as a /* Get the ID for this system function if it can be used as a
* constant function. */ * constant function. */
ID id = built_in_id_(); ID id = built_in_id_();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2019 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -461,15 +461,15 @@ bool NetESelect::has_width() const
} }
NetESFunc::NetESFunc(const char*n, ivl_variable_type_t t, NetESFunc::NetESFunc(const char*n, ivl_variable_type_t t,
unsigned width, unsigned np) unsigned width, unsigned np, bool is_overridden)
: name_(0), type_(t), enum_type_(0), parms_(np) : name_(0), type_(t), enum_type_(0), parms_(np), is_overridden_(is_overridden)
{ {
name_ = lex_strings.add(n); name_ = lex_strings.add(n);
expr_width(width); expr_width(width);
} }
NetESFunc::NetESFunc(const char*n, ivl_type_t rtype, unsigned np) NetESFunc::NetESFunc(const char*n, ivl_type_t rtype, unsigned np)
: NetExpr(rtype), name_(0), type_(IVL_VT_NO_TYPE), enum_type_(0), parms_(np) : NetExpr(rtype), name_(0), type_(IVL_VT_NO_TYPE), enum_type_(0), parms_(np), is_overridden_(false)
{ {
name_ = lex_strings.add(n); name_ = lex_strings.add(n);
expr_width(rtype->packed_width()); expr_width(rtype->packed_width());
@ -485,7 +485,7 @@ NetESFunc::NetESFunc(const char*n, ivl_type_t rtype, unsigned np)
} }
NetESFunc::NetESFunc(const char*n, const netenum_t*enum_type, unsigned np) NetESFunc::NetESFunc(const char*n, const netenum_t*enum_type, unsigned np)
: name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np) : name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np), is_overridden_(false)
{ {
name_ = lex_strings.add(n); name_ = lex_strings.add(n);
expr_width(enum_type->packed_width()); expr_width(enum_type->packed_width());

View File

@ -4538,7 +4538,7 @@ class NetESFunc : public NetExpr {
public: public:
NetESFunc(const char*name, ivl_variable_type_t t, NetESFunc(const char*name, ivl_variable_type_t t,
unsigned width, unsigned nprms); unsigned width, unsigned nprms, bool is_overridden =false);
NetESFunc(const char*name, ivl_type_t rtype, unsigned nprms); NetESFunc(const char*name, ivl_type_t rtype, unsigned nprms);
NetESFunc(const char*name, const netenum_t*enum_type, unsigned nprms); NetESFunc(const char*name, const netenum_t*enum_type, unsigned nprms);
~NetESFunc(); ~NetESFunc();
@ -4634,6 +4634,7 @@ class NetESFunc : public NetExpr {
ivl_variable_type_t type_; ivl_variable_type_t type_;
const netenum_t*enum_type_; const netenum_t*enum_type_;
std::vector<NetExpr*>parms_; std::vector<NetExpr*>parms_;
bool is_overridden_;
ID built_in_id_() const; ID built_in_id_() const;

View File

@ -30,14 +30,14 @@
*/ */
static const struct sfunc_return_type sfunc_table[] = { static const struct sfunc_return_type sfunc_table[] = {
{ "$realtime", IVL_VT_REAL, 1, 0 }, { "$realtime", IVL_VT_REAL, 1, false, false },
{ "$bitstoreal", IVL_VT_REAL, 1, 0 }, { "$bitstoreal", IVL_VT_REAL, 1, false, false },
{ "$itor", IVL_VT_REAL, 1, 0 }, { "$itor", IVL_VT_REAL, 1, false, false },
{ "$realtobits", IVL_VT_LOGIC, 64, 0 }, { "$realtobits", IVL_VT_LOGIC, 64, false, false },
{ "$time", IVL_VT_LOGIC, 64, 0 }, { "$time", IVL_VT_LOGIC, 64, false, false },
{ "$stime", IVL_VT_LOGIC, 32, 0 }, { "$stime", IVL_VT_LOGIC, 32, false, false },
{ "$simtime", IVL_VT_LOGIC, 64, 0 }, { "$simtime", IVL_VT_LOGIC, 64, false, false },
{ 0, IVL_VT_LOGIC, 32, 0 } { 0, IVL_VT_LOGIC, 32, false, false }
}; };
struct sfunc_return_type_cell : sfunc_return_type { struct sfunc_return_type_cell : sfunc_return_type {
@ -69,9 +69,8 @@ void cleanup_sys_func_table()
} }
} }
const struct sfunc_return_type* lookup_sys_func(const char*name) static struct sfunc_return_type* find_in_sys_func_list(const char*name)
{ {
/* First, try to find the name in the function list. */
struct sfunc_return_type_cell*cur = sfunc_list_head; struct sfunc_return_type_cell*cur = sfunc_list_head;
while (cur) { while (cur) {
if (strcmp(cur->name, name) == 0) if (strcmp(cur->name, name) == 0)
@ -80,6 +79,16 @@ const struct sfunc_return_type* lookup_sys_func(const char*name)
cur = cur->next; cur = cur->next;
} }
return 0;
}
const struct sfunc_return_type* lookup_sys_func(const char*name)
{
/* First, try to find the name in the function list. */
struct sfunc_return_type*def = find_in_sys_func_list(name);
if (def)
return def;
/* Next, look in the core table. */ /* Next, look in the core table. */
unsigned idx = 0; unsigned idx = 0;
while (sfunc_table[idx].name) { while (sfunc_table[idx].name) {
@ -147,12 +156,21 @@ int load_sys_func_table(const char*path)
cp = stype + strcspn(stype, " \t\r\n"); cp = stype + strcspn(stype, " \t\r\n");
if (cp[0]) *cp++ = 0; if (cp[0]) *cp++ = 0;
struct sfunc_return_type*def = find_in_sys_func_list(name);
if (def) {
/* Keep the original definition, but flag that it
overrides a later definition. */
def->override_flag = true;
continue;
}
if (strcmp(stype,"vpiSysFuncReal") == 0) { if (strcmp(stype,"vpiSysFuncReal") == 0) {
cell = new struct sfunc_return_type_cell; cell = new struct sfunc_return_type_cell;
cell->name = lex_strings.add(name); cell->name = lex_strings.add(name);
cell->type = IVL_VT_REAL; cell->type = IVL_VT_REAL;
cell->wid = 1; cell->wid = 1;
cell->signed_flag = true; cell->signed_flag = true;
cell->override_flag = false;
append_to_list(cell); append_to_list(cell);
continue; continue;
} }
@ -163,6 +181,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_LOGIC; cell->type = IVL_VT_LOGIC;
cell->wid = 32; cell->wid = 32;
cell->signed_flag = true; cell->signed_flag = true;
cell->override_flag = false;
append_to_list(cell); append_to_list(cell);
continue; continue;
} }
@ -203,6 +222,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_LOGIC; cell->type = IVL_VT_LOGIC;
cell->wid = width; cell->wid = width;
cell->signed_flag = signed_flag; cell->signed_flag = signed_flag;
cell->override_flag = false;
append_to_list(cell); append_to_list(cell);
continue; continue;
} }
@ -213,6 +233,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_VOID; cell->type = IVL_VT_VOID;
cell->wid = 0; cell->wid = 0;
cell->signed_flag = false; cell->signed_flag = false;
cell->override_flag = false;
append_to_list(cell); append_to_list(cell);
continue; continue;
} }
@ -223,6 +244,7 @@ int load_sys_func_table(const char*path)
cell->type = IVL_VT_STRING; cell->type = IVL_VT_STRING;
cell->wid = 0; // string is a dynamic length type cell->wid = 0; // string is a dynamic length type
cell->signed_flag = false; cell->signed_flag = false;
cell->override_flag = false;
append_to_list(cell); append_to_list(cell);
continue; continue;
} }