SystemVerilog: support sum() with expressions on arrays
Enable queue/darray sum() with (expr) by lowering to a dedicated _with sfunc, evaluating the with-expression per item, and reducing appended values via new %queue/sum/obj/v runtime support. Add regressions for queue and dynamic-array sum_with and update locator docs. Made-with: Cursor
This commit is contained in:
parent
f9e3f9a3e4
commit
0568961f6b
65
elab_expr.cc
65
elab_expr.cc
|
|
@ -105,8 +105,13 @@ static NetExpr* elab_queue_locator_with_predicate(
|
|||
index_net->set_line(loc);
|
||||
index_net->local_flag(true);
|
||||
|
||||
NetExpr* pred = elab_and_eval(des, ws, with_expr, 1, false, false,
|
||||
IVL_VT_BOOL);
|
||||
NetExpr* pred = 0;
|
||||
if (method_suffix == "sum")
|
||||
pred = elab_and_eval(des, ws, with_expr, (int)ew, false, false,
|
||||
ivl_type_base(element_type));
|
||||
else
|
||||
pred = elab_and_eval(des, ws, with_expr, 1, false, false,
|
||||
IVL_VT_BOOL);
|
||||
if (!pred)
|
||||
return 0;
|
||||
|
||||
|
|
@ -131,6 +136,8 @@ static NetExpr* elab_queue_locator_with_predicate(
|
|||
sfunc_name = lex_strings.make("$ivl_queue_method$min_with");
|
||||
else if (method_suffix == "max")
|
||||
sfunc_name = lex_strings.make("$ivl_queue_method$max_with");
|
||||
else if (method_suffix == "sum")
|
||||
sfunc_name = lex_strings.make("$ivl_queue_method$sum_with");
|
||||
else
|
||||
ivl_assert(loc, 0);
|
||||
|
||||
|
|
@ -3849,10 +3856,16 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
if (with_expr_) {
|
||||
cerr << get_fileline() << ": sorry: queue sum() with a "
|
||||
<< "`with` clause is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
if (!parms_.empty()) {
|
||||
cerr << get_fileline() << ": error: array locator "
|
||||
<< "`with` clause cannot be combined with a "
|
||||
<< "method argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
return elab_queue_locator_with_predicate(
|
||||
des, scope, *this, with_expr_, prop,
|
||||
element_type, element_type, method_name);
|
||||
}
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: queue sum() for this "
|
||||
|
|
@ -4382,10 +4395,16 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
if (with_expr_) {
|
||||
cerr << get_fileline() << ": sorry: array sum() with a "
|
||||
<< "`with` clause is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
if (!parms_.empty()) {
|
||||
cerr << get_fileline() << ": error: array locator "
|
||||
<< "`with` clause cannot be combined with a "
|
||||
<< "method argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
return elab_queue_locator_with_predicate(
|
||||
des, scope, *this, with_expr_, prop,
|
||||
element_type, element_type, method_name);
|
||||
}
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: array sum() for this "
|
||||
|
|
@ -4782,10 +4801,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
if (with_expr_) {
|
||||
cerr << get_fileline() << ": sorry: dynamic array sum() with a "
|
||||
<< "`with` clause is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
if (!parms_.empty()) {
|
||||
cerr << get_fileline() << ": error: array locator `with` clause "
|
||||
"cannot be combined with a method argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
return elab_queue_locator_with_predicate(
|
||||
des, scope, *this, with_expr_, sub_expr, element_type,
|
||||
element_type, method_name);
|
||||
}
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: dynamic array sum() for this "
|
||||
|
|
@ -4953,10 +4977,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
if (with_expr_) {
|
||||
cerr << get_fileline() << ": sorry: queue sum() with a "
|
||||
<< "`with` clause is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
if (!parms_.empty()) {
|
||||
cerr << get_fileline() << ": error: array locator `with` clause "
|
||||
"cannot be combined with a method argument." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
return elab_queue_locator_with_predicate(
|
||||
des, scope, *this, with_expr_, sub_expr, element_type,
|
||||
element_type, method_name);
|
||||
}
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: queue sum() for this "
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ Behavior notes (LRM-oriented):
|
|||
* min() and max() return queues containing all elements equal to the
|
||||
selected extrema.
|
||||
|
||||
* sum() returns the scalar reduction sum of elements (integral vector types);
|
||||
empty arrays/queues yield 0. `sum() with (expr)` reduces the expression
|
||||
result for each item.
|
||||
|
||||
* For dynamic arrays, runtime support treats storage as vvp_darray (including
|
||||
atom-backed integral arrays), not only vvp_queue_vec4. See vvp/vthread.cc:
|
||||
get_queue_or_darray_vec4_from_net() and the %queue/* opcodes used for
|
||||
|
|
@ -51,3 +55,5 @@ Regression tests (see ivtest/vvp_tests/*.json and regress-vvp.list):
|
|||
sv_class_queue_prop_locators.v locator methods on class queue properties.
|
||||
sv_queue_sum.v integral sum() reduction on queues.
|
||||
sv_darray_sum.v integral sum() reduction on dynamic arrays.
|
||||
sv_queue_sum_with.v sum() with expression on queues.
|
||||
sv_darray_sum_with.v sum() with expression on dynamic arrays.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
// Regression: dynamic array sum() reduction with expression.
|
||||
|
||||
module top;
|
||||
|
||||
bit failed = 0;
|
||||
|
||||
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||
|
||||
int a[];
|
||||
int s;
|
||||
|
||||
initial begin
|
||||
a = '{10, -3, 5};
|
||||
|
||||
s = a.sum() with (item > 0);
|
||||
`CHK(s === 2);
|
||||
|
||||
s = a.sum() with (item + 1);
|
||||
`CHK(s === 15);
|
||||
|
||||
if (!failed)
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Regression: queue sum() reduction with expression.
|
||||
|
||||
module top;
|
||||
|
||||
bit failed = 0;
|
||||
|
||||
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||
|
||||
int q[$];
|
||||
int s;
|
||||
|
||||
initial begin
|
||||
q = '{4, 7, 2, 5};
|
||||
|
||||
s = q.sum() with (item > 3);
|
||||
`CHK(s === 3);
|
||||
|
||||
s = q.sum() with (item * 2);
|
||||
`CHK(s === 36);
|
||||
|
||||
if (!failed)
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -258,6 +258,7 @@ sv_darray_find_locators vvp_tests/sv_darray_find_locators.json
|
|||
sv_darray_min_max vvp_tests/sv_darray_min_max.json
|
||||
sv_darray_min_max_with vvp_tests/sv_darray_min_max_with.json
|
||||
sv_darray_sum vvp_tests/sv_darray_sum.json
|
||||
sv_darray_sum_with vvp_tests/sv_darray_sum_with.json
|
||||
sv_darray_unique vvp_tests/sv_darray_unique.json
|
||||
sv_darray_unique_with vvp_tests/sv_darray_unique_with.json
|
||||
sv_default_port_value1 vvp_tests/sv_default_port_value1.json
|
||||
|
|
@ -286,6 +287,7 @@ sv_queue_find_with vvp_tests/sv_queue_find_with.json
|
|||
sv_queue_min_max vvp_tests/sv_queue_min_max.json
|
||||
sv_queue_min_max_with vvp_tests/sv_queue_min_max_with.json
|
||||
sv_queue_sum vvp_tests/sv_queue_sum.json
|
||||
sv_queue_sum_with vvp_tests/sv_queue_sum_with.json
|
||||
sv_wildcard_import8 vvp_tests/sv_wildcard_import8.json
|
||||
sdf_header vvp_tests/sdf_header.json
|
||||
task_return1 vvp_tests/task_return1.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_darray_sum_with.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog dynamic array sum() with expression",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_queue_sum_with.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog queue sum() with expression",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -467,6 +467,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
mode = 8;
|
||||
else if (strcmp(name, "$ivl_queue_method$unique_index_with") == 0)
|
||||
mode = 9;
|
||||
else if (strcmp(name, "$ivl_queue_method$sum_with") == 0)
|
||||
mode = 10;
|
||||
else
|
||||
return 1;
|
||||
|
||||
|
|
@ -487,7 +489,7 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx);
|
||||
fprintf(vvp_out, " %%ix/vec4/s %u;\n", n_reg);
|
||||
if (mode == 0 || mode == 1 || mode == 6 || mode == 7 ||
|
||||
mode == 8 || mode == 9) {
|
||||
mode == 8 || mode == 9 || mode == 10) {
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
}
|
||||
if (!reverse) {
|
||||
|
|
@ -518,10 +520,16 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig);
|
||||
|
||||
int pf = draw_eval_condition(pred);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_nom,
|
||||
pf);
|
||||
clr_flag(pf);
|
||||
if (mode == 10) {
|
||||
draw_eval_vec4(pred);
|
||||
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
|
||||
} else {
|
||||
int pf = draw_eval_condition(pred);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count,
|
||||
lab_nom, pf);
|
||||
clr_flag(pf);
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
|
||||
|
|
@ -543,6 +551,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
|
||||
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
|
||||
} else if (mode == 10) {
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
|
||||
} else if (mode == 2) {
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
|
||||
|
|
@ -584,6 +594,9 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
if (mode == 0 || mode == 1) {
|
||||
/* Keep result queue object, drop class object beneath it. */
|
||||
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
|
||||
} else if (mode == 10) {
|
||||
fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
} else if (mode == 8 || mode == 9) {
|
||||
fprintf(vvp_out, " %%queue/unique/obj/v %u;\n",
|
||||
mode == 9 ? 32 : elem_wid);
|
||||
|
|
@ -602,7 +615,7 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%queue/size/v v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%ix/vec4/s %u;\n", n_reg);
|
||||
if (mode == 0 || mode == 1 || mode == 6 || mode == 7 ||
|
||||
mode == 8 || mode == 9) {
|
||||
mode == 8 || mode == 9 || mode == 10) {
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
}
|
||||
if (!reverse) {
|
||||
|
|
@ -633,10 +646,16 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig);
|
||||
|
||||
int pf = draw_eval_condition(pred);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_nom,
|
||||
pf);
|
||||
clr_flag(pf);
|
||||
if (mode == 10) {
|
||||
draw_eval_vec4(pred);
|
||||
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
|
||||
} else {
|
||||
int pf = draw_eval_condition(pred);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count,
|
||||
lab_nom, pf);
|
||||
clr_flag(pf);
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
|
||||
|
|
@ -658,6 +677,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%push/ix/vec4 %u, 32, 1;\n", i_reg);
|
||||
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
|
||||
} else if (mode == 10) {
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
|
||||
} else if (mode == 2) {
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
|
||||
|
|
@ -691,7 +712,9 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
|
||||
fprintf(vvp_out, "T_%u.%u ; loop end (var)\n", thread_count,
|
||||
lab_loop_end);
|
||||
if (mode == 8 || mode == 9) {
|
||||
if (mode == 10) {
|
||||
fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid);
|
||||
} else if (mode == 8 || mode == 9) {
|
||||
fprintf(vvp_out, " %%queue/unique/obj/v %u;\n",
|
||||
mode == 9 ? 32 : elem_wid);
|
||||
} else if (mode == 6 || mode == 7) {
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ extern bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_QUEUE_APPEND_WORD_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_SIZE_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_SUM_OBJ_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_SUM_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_SUM_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_WORD_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%queue/min/v", of_QUEUE_MIN_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/new_empty/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%queue/size/v", of_QUEUE_SIZE_V, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%queue/sum/obj/v", of_QUEUE_SUM_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%queue/sum/prop/v", of_QUEUE_SUM_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/sum/v", of_QUEUE_SUM_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/unique/index/obj/v", of_QUEUE_UNIQUE_INDEX_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
|
|
|
|||
|
|
@ -6467,6 +6467,22 @@ bool of_QUEUE_SUM_PROP_V(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_SUM_OBJ_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
vvp_object_t src_obj;
|
||||
thr->pop_object(src_obj);
|
||||
|
||||
vvp_queue_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_object(src_obj, qsrc, dsrc);
|
||||
vvp_vector4_t sum =
|
||||
qsrc ? queue_sum_words_src(qsrc, wid)
|
||||
: queue_sum_words_src(dsrc, wid);
|
||||
thr->push_vec4(sum);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_vector4_t cmp = thr->pop_vec4();
|
||||
|
|
|
|||
Loading…
Reference in New Issue