Merge pull request #818 from larsclausen/void-cast

Add support for void cast function call
This commit is contained in:
Stephen Williams 2022-12-18 09:00:41 -08:00 committed by GitHub
commit 9d2244abb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 240 additions and 49 deletions

View File

@ -226,6 +226,8 @@ class PCallTask : public Statement {
bool elaborate_elab(Design*des, NetScope*scope) const;
void void_cast() { void_cast_ = true; }
private:
NetProc* elaborate_sys(Design*des, NetScope*scope) const;
NetProc* elaborate_usr(Design*des, NetScope*scope) const;
@ -235,6 +237,7 @@ class PCallTask : public Statement {
NetProc*elaborate_function_(Design*des, NetScope*scope) const;
NetProc*elaborate_void_function_(Design*des, NetScope*scope,
NetFuncDef*def) const;
NetProc *elaborate_non_void_function_(Design *des, NetScope *scope) const;
NetProc*elaborate_build_call_(Design*des, NetScope*scope,
NetScope*task, NetExpr*use_this) const;
@ -256,6 +259,7 @@ class PCallTask : public Statement {
PPackage*package_;
pform_name_t path_;
std::vector<PExpr*> parms_;
bool void_cast_ = false;
};
class PCase : public Statement {

View File

@ -3390,10 +3390,14 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const
{
if (peek_tail_name(path_)[0] == '$')
return elaborate_sys(des, scope);
else
if (peek_tail_name(path_)[0] == '$') {
if (void_cast_)
return elaborate_non_void_function_(des, scope);
else
return elaborate_sys(des, scope);
} else {
return elaborate_usr(des, scope);
}
}
/*
@ -3690,8 +3694,10 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
perm_string method_name,
const char*sys_task_name) const
{
cerr << get_fileline() << ": warning: method function '"
<< method_name << "' is being called as a task." << endl;
if (!void_cast_) {
cerr << get_fileline() << ": warning: method function '"
<< method_name << "' is being called as a task." << endl;
}
// Generate the function.
NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, 1);
@ -3896,16 +3902,8 @@ bool PCallTask::test_task_calls_ok_(Design*des, NetScope*scope) const
return true;
}
NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const
NetProc *PCallTask::elaborate_non_void_function_(Design *des, NetScope *scope) const
{
NetFuncDef*func = des->find_function(scope, path_);
// This is not a function, so this task call cannot be a function
// call with a missing return assignment.
if (! func) return 0;
if (gn_system_verilog() && func->is_void())
return elaborate_void_function_(des, scope, func);
// Generate a function call version of this task call.
PExpr*rval = new PECallFunction(package_, path_, parms_);
rval->set_file(get_file());
@ -3914,12 +3912,30 @@ NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const
PAssign*tmp = new PAssign(0, rval);
tmp->set_file(get_file());
tmp->set_lineno(get_lineno());
cerr << get_fileline() << ": warning: User function '"
<< peek_tail_name(path_) << "' is being called as a task." << endl;
if (!void_cast_) {
cerr << get_fileline() << ": warning: User function '"
<< peek_tail_name(path_) << "' is being called as a task." << endl;
}
// Elaborate the assignment to a dummy variable.
return tmp->elaborate(des, scope);
}
NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const
{
NetFuncDef*func = des->find_function(scope, path_);
// This is not a function, so this task call cannot be a function
// call with a missing return assignment.
if (!func)
return nullptr;
if (gn_system_verilog() && func->is_void())
return elaborate_void_function_(des, scope, func);
return elaborate_non_void_function_(des, scope);
}
NetProc* PCallTask::elaborate_void_function_(Design*des, NetScope*scope,
NetFuncDef*def) const
{
@ -3955,14 +3971,23 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
// that we can catch more errors.
test_task_calls_ok_(des, scope);
if (void_cast_) {
cerr << get_fileline() << ": error: void casting user task '"
<< peek_tail_name(path_) << "' is not allowed." << endl;
des->errors++;
}
} else if (task->type() == NetScope::FUNC) {
NetFuncDef*tmp = task->func_def();
if (!tmp->is_void()) {
cerr << get_fileline() << ": error: "
<< "Calling a non-void function as a task." << endl;
des->errors += 1;
}
if (!tmp->is_void())
return elaborate_non_void_function_(des, scope);
def = tmp;
if (void_cast_) {
cerr << get_fileline() << ": error: void casting user void function '"
<< peek_tail_name(path_) << "' is not allowed." << endl;
des->errors++;
}
}
/* The caller has checked the parms_ size to make sure it

View File

@ -0,0 +1,37 @@
// Check that void casts are supported
module test;
int a;
real b;
string c;
function int f1(int x);
a = x;
return x;
endfunction
function real f2(real x);
b = x;
return x;
endfunction
function string f3(string x);
c = x;
return x;
endfunction
initial begin
void'(f1(10));
void'(f2(1.0));
void'(f3("10"));
if (a === 10 && b == 1.0 && c == "10") begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,41 @@
// Check that void casts on class methods are supported
module test;
int a;
real b;
string c;
class C;
function int f1(int x);
a = x;
return x;
endfunction
function real f2(real x);
b = x;
return x;
endfunction
function string f3(string x);
c = x;
return x;
endfunction
endclass
C d;
initial begin
d = new;
void'(d.f1(10));
void'(d.f2(1.0));
void'(d.f3("10"));
if (a === 10 && b == 1.0 && c == "10") begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,18 @@
// Check that void casts on methods of built-in types is supported
module test;
int q[$];
initial begin
q.push_back(1);
void'(q.pop_back());
if (q.size() === 0) begin
$display("PASSED");
end else begin
$display("FAILED");
end
end
endmodule

View File

@ -0,0 +1,11 @@
// Check that void casts on SystemFunctions is supported
module test;
initial begin
void'($clog2(10));
$display("PASSED");
end
endmodule

View File

@ -0,0 +1,12 @@
// Check that void casting a void function results in an error
module test;
function void f(int x);
endfunction
initial begin
void'(f(10));
end
endmodule

View File

@ -0,0 +1,12 @@
// Check that void casting a task results in an error
module test;
task t(int x);
endtask
initial begin
void'(t(10));
end
endmodule

View File

@ -0,0 +1,9 @@
// Check that void casting an expression results in an error
module test;
initial begin
void'(1+2);
end
endmodule

View File

@ -803,6 +803,13 @@ sv_var_module_output1 normal,-g2005-sv ivltests
sv_var_module_output2 normal,-g2005-sv ivltests
sv_var_package normal,-g2005-sv ivltests
sv_var_task normal,-g2005-sv ivltests
sv_void_cast1 normal,-g2005-sv ivltests
sv_void_cast2 normal,-g2005-sv ivltests
sv_void_cast3 normal,-g2005-sv ivltests
sv_void_cast4 normal,-g2005-sv ivltests
sv_void_cast_fail1 CE,-g2005-sv ivltests
sv_void_cast_fail2 CE,-g2005-sv ivltests
sv_void_cast_fail3 CE,-g2005-sv ivltests
sv_wildcard_import1 normal,-g2009 ivltests
sv_wildcard_import2 normal,-g2009 ivltests
sv_wildcard_import3 normal,-g2009 ivltests

View File

@ -515,6 +515,9 @@ sv_typedef_queue_base1 CE,-g2009 ivltests # queue
sv_typedef_queue_base2 CE,-g2009 ivltests # queue
sv_typedef_queue_base3 CE,-g2009 ivltests # queue
sv_typedef_queue_base4 CE,-g2009 ivltests # queue
sv_void_cast1 CE,-g2009,-pallowsigned=1 ivltests # string
sv_void_cast2 CE,-g2009,-pallowsigned=1 ivltests # string, class
sv_void_cast3 CE,-g2009,-pallowsigned=1 ivltests # queue
wait_fork CE,-g2009 ivltests # wait fork and join_*
wild_cmp_err CE,-g2009 ivltests # ==?/!=?
wild_cmp_err2 CE,-g2009 ivltests # ==?/!=?
@ -977,6 +980,7 @@ sv_var_module_output1 normal,-g2005-sv,-pallowsigned=1 ivltests
sv_var_module_output2 normal,-g2005-sv,-pallowsigned=1 ivltests
sv_var_package normal,-g2005-sv,-pallowsigned=1 ivltests
sv_var_task normal,-g2005-sv,-pallowsigned=1 ivltests
sv_void_cast4 normal,-g2009,-pallowsigned=1 ivltests
test_dispwided normal,-pallowsigned=1 ivltests gold=test_dispwided.gold
test_inc_dec normal,-g2009,-pallowsigned=1 ivltests
test_enumsystem normal,-g2009,-pallowsigned=1,ivltests/enumsystem.vhd ivltests

67
parse.y
View File

@ -420,6 +420,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
PWire*wire;
std::vector<PWire*>*wires;
PCallTask *subroutine_call;
PEventStatement*event_statement;
Statement*statement;
std::vector<Statement*>*statement_list;
@ -685,6 +687,8 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <statement> analog_statement
%type <subroutine_call> subroutine_call
%type <join_keyword> join_keyword
%type <letter> spec_polarity
@ -6241,6 +6245,35 @@ spec_notifier
{ args_after_notifier = 0; delete[]$1; }
;
subroutine_call
: hierarchy_identifier argument_list_parens_opt
{ PCallTask*tmp = pform_make_call_task(@1, *$1, *$2);
delete $1;
delete $2;
$$ = tmp;
}
| class_hierarchy_identifier argument_list_parens_opt
{ PCallTask*tmp = new PCallTask(*$1, *$2);
FILE_NAME(tmp, @1);
delete $1;
delete $2;
$$ = tmp;
}
| SYSTEM_IDENTIFIER argument_list_parens_opt
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$2);
FILE_NAME(tmp,@1);
delete[]$1;
delete $2;
$$ = tmp;
}
| hierarchy_identifier '(' error ')'
{ yyerror(@3, "error: Syntax error in task arguments.");
list<PExpr*>pt;
PCallTask*tmp = pform_make_call_task(@1, *$1, pt);
delete $1;
$$ = tmp;
}
;
statement_item /* This is roughly statement_item in the LRM */
@ -6592,19 +6625,13 @@ statement_item /* This is roughly statement_item in the LRM */
FILE_NAME(tmp,@1);
$$ = tmp;
}
| SYSTEM_IDENTIFIER argument_list_parens_opt ';'
{ PCallTask*tmp = new PCallTask(lex_strings.make($1), *$2);
FILE_NAME(tmp,@1);
delete[]$1;
delete $2;
$$ = tmp;
}
| K_void '\'' '(' subroutine_call ')' ';'
{ $4->void_cast();
$$ = $4;
}
| hierarchy_identifier argument_list_parens_opt ';'
{ PCallTask*tmp = pform_make_call_task(@1, *$1, *$2);
delete $1;
delete $2;
$$ = tmp;
| subroutine_call ';'
{ $$ = $1;
}
| hierarchy_identifier K_with '{' constraint_block_item_list_opt '}' ';'
@ -6622,14 +6649,6 @@ statement_item /* This is roughly statement_item in the LRM */
$$ = tmp;
}
| class_hierarchy_identifier argument_list_parens_opt ';'
{ PCallTask*tmp = new PCallTask(*$1, *$2);
FILE_NAME(tmp, @1);
delete $1;
delete $2;
$$ = tmp;
}
/* IEEE1800 A.1.8: class_constructor_declaration with a call to
parent constructor. Note that the implicit_class_handle must
be K_super ("this.new" makes little sense) but that would
@ -6646,14 +6665,6 @@ statement_item /* This is roughly statement_item in the LRM */
delete $1;
$$ = tmp;
}
| hierarchy_identifier '(' error ')' ';'
{ yyerror(@3, "error: Syntax error in task arguments.");
list<PExpr*>pt;
PCallTask*tmp = pform_make_call_task(@1, *$1, pt);
delete $1;
$$ = tmp;
}
| error ';'
{ yyerror(@2, "error: malformed statement");
yyerrok;