Use `symbol_search()` for task and function calls
Task and function calls used as statements currently use `Design::find_task()` and `Design::find_function()`, which only search for scopes of the requested type. A closer variable, named event, or parameter is skipped. This can call a hidden task or function, and can make the non-void discarded-return path resolve a different symbol and abort. Use one `symbol_search()` for both task lookup and the function fallback so all declarations in the shared name space participate in lookup. Accept a function scope or the return variable of a recursive function call, while preserving the existing method fallback. Allow the terminal task or function name to be declared later while resolving a receiver prefix at the call position. Use the call position when the method fallback searches for the receiver as well. Remove the now unused `Design::find_task()` and `Design::find_function()` helpers. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
e5f2975a97
commit
7c5c1acf02
|
|
@ -251,7 +251,8 @@ class PCallTask : public Statement {
|
|||
|
||||
NetProc*elaborate_method_(Design*des, NetScope*scope,
|
||||
bool add_this_flag = false) const;
|
||||
NetProc*elaborate_function_(Design*des, NetScope*scope) const;
|
||||
NetProc *elaborate_function_(
|
||||
Design *des, NetScope *scope, NetScope *func_scope) const;
|
||||
NetProc*elaborate_void_function_(Design*des, NetScope*scope,
|
||||
NetFuncDef*def) const;
|
||||
NetProc *elaborate_non_void_function_(Design *des, NetScope *scope,
|
||||
|
|
|
|||
51
elaborate.cc
51
elaborate.cc
|
|
@ -3950,25 +3950,35 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
|||
{
|
||||
ivl_assert(*this, scope);
|
||||
|
||||
NetScope*pscope = scope;
|
||||
if (package_) {
|
||||
pscope = des->find_package(package_->pscope_name());
|
||||
ivl_assert(*this, pscope);
|
||||
symbol_search_results search_results;
|
||||
pform_scoped_name_t call_path(package_, path_);
|
||||
NetScope *task = nullptr;
|
||||
NetScope *func_scope = nullptr;
|
||||
if (symbol_search(this, des, scope, call_path, lexical_pos(),
|
||||
&search_results, true)) {
|
||||
if (search_results.is_scope()) {
|
||||
if (search_results.scope->type() == NetScope::TASK)
|
||||
task = search_results.scope;
|
||||
else if (search_results.scope->type() == NetScope::FUNC)
|
||||
func_scope = search_results.scope;
|
||||
} else if (test_function_return_value(search_results)) {
|
||||
// A recursive function call resolves to the function return
|
||||
// variable. Its containing scope is the function being called.
|
||||
func_scope = search_results.scope;
|
||||
}
|
||||
}
|
||||
|
||||
NetScope*task = des->find_task(pscope, path_);
|
||||
if (task == 0) {
|
||||
if (!task) {
|
||||
// For SystemVerilog this may be a few other things.
|
||||
if (gn_system_verilog()) {
|
||||
NetProc *tmp;
|
||||
// This could be a method attached to a signal
|
||||
// or defined in this object?
|
||||
bool try_implicit_this = scope->get_class_scope() && path_.size() == 1;
|
||||
tmp = elaborate_method_(des, scope, try_implicit_this);
|
||||
NetProc *tmp = elaborate_method_(des, scope, try_implicit_this);
|
||||
if (tmp) return tmp;
|
||||
// Or it could be a function call ignoring the return?
|
||||
tmp = elaborate_function_(des, scope);
|
||||
if (tmp) return tmp;
|
||||
if (func_scope)
|
||||
return elaborate_function_(des, scope, func_scope);
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: Enable of unknown task "
|
||||
|
|
@ -4307,7 +4317,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
// (internally represented as "@") is handled by there being a
|
||||
// "this" object in the instance scope.
|
||||
symbol_search_results sr;
|
||||
symbol_search(this, des, scope, use_path, UINT_MAX, &sr);
|
||||
symbol_search(this, des, scope, use_path, lexical_pos(), &sr);
|
||||
|
||||
NetNet*net = sr.net;
|
||||
if (net == 0)
|
||||
|
|
@ -4631,14 +4641,21 @@ NetProc *PCallTask::elaborate_non_void_function_(Design *des, NetScope *scope,
|
|||
return tmp->elaborate(des, scope);
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const
|
||||
NetProc *PCallTask::elaborate_function_(
|
||||
Design *des, NetScope *scope, NetScope *func_scope) const
|
||||
{
|
||||
NetFuncDef*func = des->find_function(scope, path_);
|
||||
ivl_assert(*this, func_scope);
|
||||
ivl_assert(*this, func_scope->type() == NetScope::FUNC);
|
||||
|
||||
// This is not a function, so this task call cannot be a function
|
||||
// call with a missing return assignment.
|
||||
if (!func)
|
||||
return nullptr;
|
||||
// The function signals might not have been elaborated yet.
|
||||
if (func_scope->elab_stage() < 2) {
|
||||
func_scope->need_const_func(true);
|
||||
const PFunction *pfunc = func_scope->func_pform();
|
||||
ivl_assert(*this, pfunc);
|
||||
pfunc->elaborate_sig(des, func_scope);
|
||||
}
|
||||
NetFuncDef *func = func_scope->func_def();
|
||||
ivl_assert(*this, func);
|
||||
|
||||
if (gn_system_verilog() && func->is_void())
|
||||
return elaborate_void_function_(des, scope, func);
|
||||
|
|
|
|||
|
|
@ -1030,38 +1030,6 @@ NetNet* Design::find_signal(NetScope*scope, pform_name_t path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetFuncDef* Design::find_function(NetScope*scope, const pform_name_t&name)
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
std::list<hname_t> eval_path = eval_scope_path(this, scope, name);
|
||||
NetScope*func = find_scope(scope, eval_path, NetScope::FUNC);
|
||||
if (func && (func->type() == NetScope::FUNC)) {
|
||||
// If a function is used in a parameter definition or in
|
||||
// a signal declaration, it is possible to get here before
|
||||
// the function's signals have been elaborated. If this is
|
||||
// the case, elaborate them now.
|
||||
if (func->elab_stage() < 2) {
|
||||
func->need_const_func(true);
|
||||
const PFunction*pfunc = func->func_pform();
|
||||
assert(pfunc);
|
||||
pfunc->elaborate_sig(this, func);
|
||||
}
|
||||
return func->func_def();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetScope* Design::find_task(NetScope*scope, const pform_name_t&name)
|
||||
{
|
||||
std::list<hname_t> eval_path = eval_scope_path(this, scope, name);
|
||||
NetScope*task = find_scope(scope, eval_path, NetScope::TASK);
|
||||
if (task && (task->type() == NetScope::TASK))
|
||||
return task;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Design::add_node(NetNode*net)
|
||||
{
|
||||
assert(net->design_ == 0);
|
||||
|
|
|
|||
|
|
@ -5215,12 +5215,6 @@ class Design {
|
|||
|
||||
NetNet*find_signal(NetScope*scope, pform_name_t path);
|
||||
|
||||
// Functions
|
||||
NetFuncDef* find_function(NetScope*scope, const pform_name_t&key);
|
||||
|
||||
// Tasks
|
||||
NetScope* find_task(NetScope*scope, const pform_name_t&name);
|
||||
|
||||
// NODES
|
||||
void add_node(NetNode*);
|
||||
void del_node(NetNode*);
|
||||
|
|
|
|||
Loading…
Reference in New Issue