diff --git a/include/verilated_types.h b/include/verilated_types.h index c93da6dea..773b20212 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -485,6 +485,8 @@ private: public: using const_iterator = typename Deque::const_iterator; + template + using WithFuncReturnType = decltype(std::declval()(0, std::declval())); private: // MEMBERS @@ -831,70 +833,63 @@ public: return out; } template - T_Value r_sum(Func with_func) const { - T_Value out(0); // Type must have assignment operator + WithFuncReturnType r_sum(Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(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; + if (m_deque.empty()) return T_Value(0); // The big three do it this way + T_Value out = T_Value(1); + for (const auto& i : m_deque) out *= i; return out; } template - T_Value r_product(Func with_func) const { - if (m_deque.empty()) return T_Value(0); - auto it = m_deque.cbegin(); + WithFuncReturnType r_product(Func with_func) const { + if (m_deque.empty()) return WithFuncReturnType(0); // The big three do it this way + WithFuncReturnType out = WithFuncReturnType(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; + if (m_deque.empty()) return T_Value(0); // The big three do it this way + T_Value out = ~T_Value(0); + for (const auto& i : m_deque) out &= i; return out; } template - T_Value r_and(Func with_func) const { - if (m_deque.empty()) return T_Value(0); - auto it = m_deque.cbegin(); + WithFuncReturnType r_and(Func with_func) const { + if (m_deque.empty()) return WithFuncReturnType(0); // The big three do it this way IData index = 0; - T_Value out{with_func(index, *it)}; - ++it; - ++index; - for (; it != m_deque.cend(); ++it) out &= with_func(index, *it); + WithFuncReturnType out = ~WithFuncReturnType(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 - T_Value r_or(Func with_func) const { - T_Value out(0); // Type must have assignment operator + WithFuncReturnType r_or(Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(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 +#ifdef VERILATOR_BIG3_NULLARY_ARITHMETICS_QUIRKS + if (m_deque.empty()) return T_Value(0); +#endif + T_Value out = T_Value(0); for (const auto& i : m_deque) out ^= i; return out; } template - T_Value r_xor(Func with_func) const { - T_Value out(0); // Type must have assignment operator + WithFuncReturnType r_xor(Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(0); IData index = 0; for (const auto& i : m_deque) out ^= with_func(index++, i); return out; @@ -931,6 +926,9 @@ private: public: using const_iterator = typename Map::const_iterator; + template + using WithFuncReturnType + = decltype(std::declval()(std::declval(), std::declval())); private: // MEMBERS @@ -1177,64 +1175,56 @@ public: return out; } template - T_Value r_sum(Func with_func) const { - T_Value out(0); // Type must have assignment operator + WithFuncReturnType r_sum(Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(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; + if (m_map.empty()) return T_Value(0); // The big three do it this way + T_Value out = T_Value(1); + for (const auto& i : m_map) out *= i.second; return out; } template - 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 r_product(Func with_func) const { + if (m_map.empty()) return WithFuncReturnType(0); // The big three do it this way + WithFuncReturnType out = WithFuncReturnType(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; + if (m_map.empty()) return T_Value(0); // The big three do it this way + T_Value out = ~T_Value(0); + for (const auto& i : m_map) out &= i.second; return out; } template - 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 r_and(Func with_func) const { + if (m_map.empty()) return WithFuncReturnType(0); // The big three do it this way + WithFuncReturnType out = ~WithFuncReturnType(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 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 - T_Value r_xor(Func with_func) const { - T_Value out(0); // Type must have assignment operator + WithFuncReturnType r_xor(Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(0); for (const auto& i : m_map) out ^= with_func(i.first, i.second); return out; } diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v index 76edc7dd6..0cc6c5d2b 100644 --- a/test_regress/t/t_assoc_method.v +++ b/test_regress/t/t_assoc_method.v @@ -1,15 +1,21 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2019 by Wilson Snyder. +// any use, without warranty, 2024 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 `define stop $stop `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 @@ -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} "); @@ -116,8 +123,12 @@ 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); + i = qe.product with (item + 1); + `checkh(i, 32'h0); q = '{10:32'b1100, 11:32'b1010}; i = q.and; @@ -135,10 +146,16 @@ module t (/*AUTOARG*/); i = qe.and; `checkh(i, 32'b0); + i = qe.and with (item + 1); + `checkh(i, 32'h0); 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); @@ -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 diff --git a/test_regress/t/t_assoc_wildcard_method.v b/test_regress/t/t_assoc_wildcard_method.v index 85ff6606d..5fdaadcc9 100644 --- a/test_regress/t/t_assoc_wildcard_method.v +++ b/test_regress/t/t_assoc_wildcard_method.v @@ -9,12 +9,20 @@ `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 qe [ * ]; // Empty - Note spaces around [*] for parsing coverage + point points_q[*] = '{"a": point'{1, 2}, "b": point'{2, 4}, "c": point'{1, 4}}; int qv[$]; // Value returns int qi[$]; // Index returns int i; + bit b; string v; q = '{"a":1, "b":2, "c":2, "d":4, "e":3}; @@ -95,11 +103,17 @@ module t (/*AUTOARG*/); `checkh(i, 32'b0110); i = qe.and; - `checkh(i, 32'b0); + `checkh(i, 32'h0); + i = qe.and with (item + 1); + `checkh(i, 32'h0); 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); @@ -121,6 +135,19 @@ module t (/*AUTOARG*/); i = qe.xor(); `checkh(i, 32'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 diff --git a/test_regress/t/t_dynarray_method.v b/test_regress/t/t_dynarray_method.v index c06fa9ab4..33712ad83 100644 --- a/test_regress/t/t_dynarray_method.v +++ b/test_regress/t/t_dynarray_method.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2019 by Wilson Snyder. +// any use, without warranty, 2024 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 `define stop $stop diff --git a/test_regress/t/t_dynarray_method_bad.out b/test_regress/t/t_dynarray_method_bad.out new file mode 100644 index 000000000..e08898cd9 --- /dev/null +++ b/test_regress/t/t_dynarray_method_bad.out @@ -0,0 +1,27 @@ +%Warning-WIDTHTRUNC: t/t_dynarray_method_bad.v:19:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's CMETHODHARD 'r_sum' generates 64 bits. + : ... note: In instance 't' + 19 | i = s.sum with (item.len); + | ^ + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. +%Warning-WIDTHTRUNC: t/t_dynarray_method_bad.v:21:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's CMETHODHARD 'r_product' generates 64 bits. + : ... note: In instance 't' + 21 | i = s.product with (item.len); + | ^ +%Warning-WIDTHTRUNC: t/t_dynarray_method_bad.v:23:9: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CMETHODHARD 'r_sum' generates 64 bits. + : ... note: In instance 't' + 23 | b = s.sum with (item == "hello"); + | ^ +%Warning-WIDTHTRUNC: t/t_dynarray_method_bad.v:25:9: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CMETHODHARD 'r_sum' generates 64 bits. + : ... note: In instance 't' + 25 | b = s.sum with (item == ""); + | ^ +%Warning-WIDTHTRUNC: t/t_dynarray_method_bad.v:27:9: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CMETHODHARD 'r_product' generates 64 bits. + : ... note: In instance 't' + 27 | b = s.product with (item inside {"hello", "sad"}); + | ^ +%Warning-WIDTHTRUNC: t/t_dynarray_method_bad.v:29:9: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CMETHODHARD 'r_product' generates 64 bits. + : ... note: In instance 't' + 29 | b = s.product with (item inside { "hello", "sad", "world" }); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_dynarray_method_bad.py b/test_regress/t/t_dynarray_method_bad.py new file mode 100755 index 000000000..31228c9a7 --- /dev/null +++ b/test_regress/t/t_dynarray_method_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_dynarray_method_bad.v b/test_regress/t/t_dynarray_method_bad.v new file mode 100644 index 000000000..1f0ead380 --- /dev/null +++ b/test_regress/t/t_dynarray_method_bad.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`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 checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\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*/); + string s[] = { "hello", "sad", "sad", "world" }; + + initial begin + int i; + bit b; + + i = s.sum with (item.len); + `checkh(i, 10); + i = s.product with (item.len); + `checkh(i, 24); + b = s.sum with (item == "hello"); + `checkh(b, 1'b1); + b = s.sum with (item == ""); + `checkh(b, 1'b0); + b = s.product with (item inside {"hello", "sad"}); + `checkh(b, 1'b0); + b = s.product with (item inside { "hello", "sad", "world" }); + `checkh(b, 1'b1); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index b8706db89..84919f529 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2019 by Wilson Snyder. +// any use, without warranty, 2024 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 `define stop $stop @@ -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 @@ -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); + i = qe.product with (item + 1); + `checkh(i, 32'h0); q = '{32'b1100, 32'b1010}; i = q.and; @@ -206,16 +211,37 @@ module t (/*AUTOARG*/); i = qe.and; `checkh(i, 32'b0); + i = qe.and with (item + 1); + `checkh(i, 32'b0); 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