Skip to content

Commit

Permalink
Fix reduction methods for verilatoed types
Browse files Browse the repository at this point in the history
* Fix return type for calls with `with` clause
* Fix missing index incrementation
* Fix incorrect neutral element (affects zero-sized aggregates)

Signed-off-by: Krzysztof Boronski <[email protected]>
  • Loading branch information
kboronski-ant committed Oct 15, 2024
1 parent 0dce97b commit 061e58d
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 65 deletions.
99 changes: 39 additions & 60 deletions include/verilated_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,8 @@ class VlQueue final {

public:
using const_iterator = typename Deque::const_iterator;
template <class Func>
using WithFuncReturnType = decltype(std::declval<Func>()(0, std::declval<T_Value>()));

private:
// MEMBERS
Expand Down Expand Up @@ -831,70 +833,56 @@ class VlQueue final {
return out;
}
template <typename Func>
T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
WithFuncReturnType<Func> r_sum(Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
IData index = 0;
for (const auto& i : m_deque) out += with_func(index++, i);
return out;
}
T_Value r_product() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.cbegin();
T_Value out{*it};
++it;
for (; it != m_deque.cend(); ++it) out *= *it;
T_Value out = T_Value(1);
for (const auto& i : m_deque) out *= i;
return out;
}
template <typename Func>
T_Value r_product(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.cbegin();
WithFuncReturnType<Func> r_product(Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
IData index = 0;
T_Value out{with_func(index, *it)};
++it;
++index;
for (; it != m_deque.cend(); ++it) out *= with_func(index++, *it);
for (const auto& i : m_deque) out *= with_func(index++, i);
return out;
}
T_Value r_and() const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.cbegin();
T_Value out{*it};
++it;
for (; it != m_deque.cend(); ++it) out &= *it;
T_Value out = ~T_Value(0);
for (const auto& i : m_deque) out &= i;
return out;
}
template <typename Func>
T_Value r_and(Func with_func) const {
if (m_deque.empty()) return T_Value(0);
auto it = m_deque.cbegin();
WithFuncReturnType<Func> r_and(Func with_func) const {
IData index = 0;
T_Value out{with_func(index, *it)};
++it;
++index;
for (; it != m_deque.cend(); ++it) out &= with_func(index, *it);
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
for (const auto& i : m_deque) out &= with_func(index++, i);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
T_Value out = T_Value(0);
for (const auto& i : m_deque) out |= i;
return out;
}
template <typename Func>
T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
WithFuncReturnType<Func> r_or(Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
IData index = 0;
for (const auto& i : m_deque) out |= with_func(index++, i);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
T_Value out = T_Value(0); // Type must have assignment operator
for (const auto& i : m_deque) out ^= i;
return out;
}
template <typename Func>
T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
IData index = 0;
for (const auto& i : m_deque) out ^= with_func(index++, i);
return out;
Expand Down Expand Up @@ -931,6 +919,9 @@ class VlAssocArray final {

public:
using const_iterator = typename Map::const_iterator;
template <class Func>
using WithFuncReturnType
= decltype(std::declval<Func>()(std::declval<T_Key>(), std::declval<T_Value>()));

private:
// MEMBERS
Expand Down Expand Up @@ -1177,64 +1168,52 @@ class VlAssocArray final {
return out;
}
template <typename Func>
T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator
WithFuncReturnType<Func> r_sum(Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
for (const auto& i : m_map) out += with_func(i.first, i.second);
return out;
}
T_Value r_product() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.cbegin();
T_Value out{it->second};
++it;
for (; it != m_map.cend(); ++it) out *= it->second;
T_Value out = T_Value(1);
for (const auto& i : m_map) out *= i.second;
return out;
}
template <typename Func>
T_Value r_product(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.cbegin();
T_Value out{with_func(it->first, it->second)};
++it;
for (; it != m_map.cend(); ++it) out *= with_func(it->first, it->second);
WithFuncReturnType<Func> r_product(Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
for (const auto& i : m_map) out *= with_func(i.first, i.second);
return out;
}
T_Value r_and() const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.cbegin();
T_Value out{it->second};
++it;
for (; it != m_map.cend(); ++it) out &= it->second;
T_Value out = ~T_Value(0);
for (const auto& i : m_map) out &= i.second;
return out;
}
template <typename Func>
T_Value r_and(Func with_func) const {
if (m_map.empty()) return T_Value(0);
auto it = m_map.cbegin();
T_Value out{with_func(it->first, it->second)};
++it;
for (; it != m_map.cend(); ++it) out &= with_func(it->first, it->second);
WithFuncReturnType<Func> r_and(Func with_func) const {
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
for (const auto& i : m_map) out &= with_func(i.first, i.second);
return out;
}
T_Value r_or() const {
T_Value out(0); // Type must have assignment operator
T_Value out = T_Value(0);
for (const auto& i : m_map) out |= i.second;
return out;
}
template <typename Func>
T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator
T_Value out = T_Value(0);
for (const auto& i : m_map) out |= with_func(i.first, i.second);
return out;
}
T_Value r_xor() const {
T_Value out(0); // Type must have assignment operator
T_Value out = T_Value(0);
for (const auto& i : m_map) out ^= i.second;
return out;
}
template <typename Func>
T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator
WithFuncReturnType<Func> r_xor(Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
return out;
}
Expand Down
36 changes: 33 additions & 3 deletions test_regress/t/t_assoc_method.v
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
`define checkp(gotv,expv_s) do begin string gotv_s; gotv_s = $sformatf("%p", gotv); if ((gotv_s) !== (expv_s)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv_s), (expv_s)); `stop; end end while(0);


module t (/*AUTOARG*/);
typedef struct { int x, y; } point;

function automatic int vec_len_squared(point p);
return p.x * p.x + p.y * p.y;
endfunction

initial begin
int q[int];
int qe[int]; // Empty
Expand All @@ -18,6 +24,7 @@ module t (/*AUTOARG*/);
point points_q[int];
point points_qv[$];
int i;
bit b;

q = '{10:1, 11:2, 12:2, 13:4, 14:3};
`checkp(q, "'{'ha:'h1, 'hb:'h2, 'hc:'h2, 'hd:'h4, 'he:'h3} ");
Expand Down Expand Up @@ -116,8 +123,12 @@ module t (/*AUTOARG*/);

i = qe.sum;
`checkh(i, 32'h0);
i = qe.product;
i = qe.sum with (item + 1);
`checkh(i, 32'h0);
i = qe.product;
`checkh(i, 32'h1);
i = qe.product with (item + 1);
`checkh(i, 32'h1);

q = '{10:32'b1100, 11:32'b1010};
i = q.and;
Expand All @@ -134,11 +145,17 @@ module t (/*AUTOARG*/);
`checkh(i, 32'b0110);

i = qe.and;
`checkh(i, 32'b0);
`checkh(i, 32'hffff_ffff);
i = qe.and with (item + 1);
`checkh(i, 32'hffff_ffff);
i = qe.or;
`checkh(i, 32'b0);
i = qe.or with (item + 1);
`checkh(i, 32'b0);
i = qe.xor;
`checkh(i, 32'b0);
i = qe.xor with (item + 1);
`checkh(i, 32'b0);

i = q.and();
`checkh(i, 32'b1000);
Expand All @@ -154,7 +171,7 @@ module t (/*AUTOARG*/);
`checkh(i, 32'b0110);

i = qe.and();
`checkh(i, 32'b0);
`checkh(i, 32'hffff_ffff);
i = qe.or();
`checkh(i, 32'b0);
i = qe.xor();
Expand All @@ -165,6 +182,19 @@ module t (/*AUTOARG*/);
`checkh(q == qe, 1'b1);
`checkh(q != qe, 1'b0);

i = points_q.sum with (vec_len_squared(item));
`checkh(i, 32'h2a);
i = points_q.product with (vec_len_squared(item));
`checkh(i, 32'h6a4);
b = points_q.sum with (vec_len_squared(item) == 5);
`checkh(b, 1'b1);
b = points_q.sum with (vec_len_squared(item) == 0);
`checkh(b, 1'b0);
b = points_q.product with (vec_len_squared(item) inside {5, 17});
`checkh(b, 1'b0);
b = points_q.sum with (vec_len_squared(item) inside {5, 17, 20});
`checkh(b, 1'b1);

$write("*-* All Finished *-*\n");
$finish;
end
Expand Down
30 changes: 28 additions & 2 deletions test_regress/t/t_queue_method.v
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module t (/*AUTOARG*/);
int qvunused[$]; // Value returns (unused)
int qi[$]; // Index returns
int i;
bit b;
string string_q[$];
string string_qv[$];
point_3d points_q[$]; // Same as q and qv, but complex value type
Expand Down Expand Up @@ -186,9 +187,13 @@ module t (/*AUTOARG*/);

i = qe.sum;
`checkh(i, 32'h0);
i = qe.sum with (item + 1);
`checkh(i, 32'h0);

i = qe.product;
`checkh(i, 32'h0);
`checkh(i, 32'h1);
i = qe.product with (item + 1);
`checkh(i, 32'h1);

q = '{32'b1100, 32'b1010};
i = q.and;
Expand All @@ -205,17 +210,38 @@ module t (/*AUTOARG*/);
`checkh(i, 32'b0110);

i = qe.and;
`checkh(i, 32'b0);
`checkh(i, 32'hffff_ffff);
i = qe.and with (item + 1);
`checkh(i, 32'hffff_ffff);
i = qe.or;
`checkh(i, 32'b0);
i = qe.or with (item + 1);
`checkh(i, 32'b0);
i = qe.xor;
`checkh(i, 32'b0);
i = qe.xor with (item + 1);
`checkh(i, 32'b0);

q = '{1, 2};
qe = '{1, 2};
`checkh(q == qe, 1'b1);
`checkh(q != qe, 1'b0);

string_q = {"a", "bc", "def", "ghij"};

i = string_q.sum with (item.len);
`checkh(i, 10);
i = string_q.product with (item.len);
`checkh(i, 24);
b = string_q.sum with (item == "bc");
`checkh(b, 1'b1);
b = string_q.sum with (item == "");
`checkh(b, 1'b0);
b = string_q.product with (item inside {"a", "bc", "def"});
`checkh(b, 1'b0);
b = string_q.product with (item inside {"a", "bc", "def", "ghij"});
`checkh(b, 1'b1);

$write("*-* All Finished *-*\n");
$finish;
end
Expand Down

0 comments on commit 061e58d

Please sign in to comment.