Skip to content

Commit d0c223d

Browse files
authored
Merge pull request #1678 from diffblue/verilog-return
Verilog: `return` statements
2 parents 1fd97b7 + 78c2b09 commit d0c223d

10 files changed

Lines changed: 166 additions & 16 deletions

File tree

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# EBMC 5.10
22

33
* cast properties given with -p to Boolean if need be
4+
* SystemVerilog: return statements
45
* SystemVerilog: assignments to a part-select of a struct
56
* SystemVerilog: timeunits and timeprecision
67
* SystemVerilog: recursive module definitions

regression/verilog/functioncall/return1.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CORE
22
return1.sv
33

4-
^file .* line 4: synthesis of return not supported$
5-
^EXIT=2$
4+
^\[main\.assert\.1\] always main\.some_int\(\) == 123: PROVED .*$
5+
^EXIT=0$
66
^SIGNAL=0$
77
--
88
^warning: ignoring
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
KNOWNBUG
1+
CORE
22
return2.sv
33

44
^EXIT=0$
55
^SIGNAL=0$
66
--
77
^warning: ignoring
88
--
9-
This segfaults.

regression/verilog/functioncall/return2.sv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
function int some_int(bit some_input);
2-
int data = 456;
2+
int data;
3+
data = 456;
34

45
if(some_input) begin
56
data = 0;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
return1.sv
3+
4+
^\[main\.assert\.1\] main\.some_data == 123: PROVED .*$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
--
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module main;
2+
3+
int some_data;
4+
5+
task some_task();
6+
some_data = 123;
7+
return;
8+
endtask
9+
10+
initial begin
11+
some_task();
12+
assert(some_data == 123);
13+
end
14+
15+
endmodule
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
return2.sv
3+
4+
^\[main\.some_task\.a0\] 0: PROVED .*$
5+
^\[main\.a1] 0: REFUTED$
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring
10+
--
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module main;
2+
3+
int some_data;
4+
5+
task some_task();
6+
return;
7+
// should not fail
8+
a0: assert(0);
9+
endtask
10+
11+
initial begin
12+
some_task();
13+
// should fail
14+
a1: assert(0);
15+
end
16+
17+
endmodule

src/verilog/verilog_synthesis.cpp

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,21 @@ exprt verilog_synthesist::expand_function_call(
443443
throw errort().with_location(call.source_location())
444444
<< "function call cannot call task";
445445
}
446-
446+
447+
// preserve the previous call frame, if any
448+
auto old_tf_frame = tf_frame;
449+
450+
// remember the guard
451+
auto entry_guard = value_map->guard;
452+
453+
// create a fresh call frame
454+
tf_frame = tf_framet{};
455+
456+
const symbolt &return_symbol =
457+
ns.lookup(id2string(symbol.name) + "." + id2string(symbol.base_name));
458+
459+
tf_frame.value().return_value = return_symbol.symbol_expr();
460+
447461
const code_typet::parameterst &parameters=
448462
code_type.parameters();
449463

@@ -472,14 +486,22 @@ exprt verilog_synthesist::expand_function_call(
472486
for(auto &statement : symbol.value.operands())
473487
synth_statement(to_verilog_statement(statement));
474488

475-
// replace function call by return value symbol
476-
const symbolt &return_symbol=
477-
ns.lookup(id2string(symbol.name)+"."+
478-
id2string(symbol.base_name));
489+
// merge in edges from 'return' statements, if any
490+
for(auto &state : tf_frame.value().return_statement_states)
491+
{
492+
auto guard_expr = conjunction(state.guard);
493+
merge(
494+
guard_expr, state.current, value_map->current, false, value_map->current);
495+
merge(guard_expr, state.final, value_map->final, true, value_map->final);
496+
}
479497

480-
// get the current value
498+
// replace function call by return value symbol
481499
auto result = synth_expr(return_symbol.symbol_expr(), symbol_statet::CURRENT);
482500

501+
// restore the previous task/function frame
502+
tf_frame = old_tf_frame;
503+
value_map->guard = entry_guard;
504+
483505
return result;
484506
}
485507

@@ -3076,6 +3098,47 @@ void verilog_synthesist::synth_repeat(
30763098

30773099
/*******************************************************************\
30783100
3101+
Function: verilog_synthesist::synth_return
3102+
3103+
Inputs:
3104+
3105+
Outputs:
3106+
3107+
Purpose:
3108+
3109+
\*******************************************************************/
3110+
3111+
void verilog_synthesist::synth_return(const verilog_returnt &statement)
3112+
{
3113+
// There has to be a tf frame
3114+
PRECONDITION(tf_frame.has_value());
3115+
3116+
auto &frame = tf_frame.value();
3117+
3118+
// return value?
3119+
if(statement.has_value())
3120+
{
3121+
// assign to the symbol with the function's name
3122+
DATA_INVARIANT(
3123+
frame.return_value.has_value(),
3124+
"return with value requires return value symbol");
3125+
3126+
verilog_assignt assignment{
3127+
ID_verilog_blocking_assign,
3128+
frame.return_value.value(),
3129+
statement.value()};
3130+
3131+
synth_assign(assignment);
3132+
}
3133+
3134+
frame.return_statement_states.push_back(*value_map);
3135+
3136+
// set guard to false
3137+
value_map->guard.push_back(false_exprt{});
3138+
}
3139+
3140+
/*******************************************************************\
3141+
30793142
Function: verilog_synthesist::synth_forever
30803143
30813144
Inputs:
@@ -3132,6 +3195,15 @@ void verilog_synthesist::synth_function_call_or_task_enable(
31323195

31333196
const code_typet &code_type=to_code_type(symbol.type);
31343197

3198+
// preserve the previous call frame, if any
3199+
auto old_tf_frame = tf_frame;
3200+
3201+
// remember the guard
3202+
auto entry_guard = value_map->guard;
3203+
3204+
// create a fresh call frame
3205+
tf_frame = tf_framet{};
3206+
31353207
const code_typet::parameterst &parameters=
31363208
code_type.parameters();
31373209

@@ -3158,6 +3230,23 @@ void verilog_synthesist::synth_function_call_or_task_enable(
31583230
for(auto &statement : symbol.value.operands())
31593231
synth_statement(to_verilog_statement(statement));
31603232

3233+
// merge in edges from 'return' statements, if any
3234+
for(auto &state : tf_frame.value().return_statement_states)
3235+
{
3236+
auto guard_expr = conjunction(state.guard);
3237+
merge(
3238+
guard_expr,
3239+
state.current,
3240+
value_map->current,
3241+
false,
3242+
value_map->current);
3243+
merge(guard_expr, state.final, value_map->final, true, value_map->final);
3244+
}
3245+
3246+
// restore the previous task/function frame
3247+
tf_frame = old_tf_frame;
3248+
value_map->guard = entry_guard;
3249+
31613250
// do assignments to output parameters
31623251
for(unsigned i=0; i<parameters.size(); i++)
31633252
{
@@ -3266,10 +3355,7 @@ void verilog_synthesist::synth_statement(
32663355
else if(statement.id()==ID_repeat)
32673356
synth_repeat(to_verilog_repeat(statement));
32683357
else if(statement.id() == ID_return)
3269-
{
3270-
throw errort().with_location(statement.source_location())
3271-
<< "synthesis of return not supported";
3272-
}
3358+
synth_return(to_verilog_return(statement));
32733359
else if(statement.id()==ID_forever)
32743360
synth_forever(to_verilog_forever(statement));
32753361
else if(statement.id()==ID_function_call)

src/verilog/verilog_synthesis_class.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,18 @@ class verilog_synthesist:
207207
}
208208

209209
value_mapt *value_map;
210-
210+
211+
// task/function call frame
212+
class tf_framet
213+
{
214+
public:
215+
std::optional<symbol_exprt> return_value;
216+
std::vector<value_mapt> return_statement_states;
217+
};
218+
219+
// the call frame is optional since we might not be in a task or function
220+
std::optional<tf_framet> tf_frame;
221+
211222
void merge(
212223
const exprt &guard,
213224
const value_mapt::mapt &true_map,
@@ -267,6 +278,7 @@ class verilog_synthesist:
267278
void synth_forever(const verilog_forevert &);
268279
void synth_while(const verilog_whilet &);
269280
void synth_repeat(const verilog_repeatt &);
281+
void synth_return(const verilog_returnt &);
270282
void synth_function_call_or_task_enable(const verilog_function_callt &);
271283
void synth_assign(const verilog_assignt &);
272284
void

0 commit comments

Comments
 (0)