diff --git a/Changes b/Changes index ed008683b..968e3f05c 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix non-arrayed cells with interface arrays, bug1153. [John Stevenson] +**** Add stack trace when can't optimize function, bug1158. [Todd Strader] + **** Add warning on mis-sized literal, bug1156. [Todd Strader] diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 4ed8e2693..00e679a3c 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -44,12 +44,25 @@ #include "V3Task.h" #include +#include //============================================================================ //###################################################################### // Simulate class functions +class SimulateStackNode { +public: + // MEMBERS + AstFuncRef* m_funcp; + V3TaskConnects* m_tconnects; + // CONSTRUCTORS + SimulateStackNode(AstFuncRef* funcp, V3TaskConnects* tconnects): + m_funcp(funcp), + m_tconnects(tconnects) {} + ~SimulateStackNode() {} +}; + class SimulateVisitor : public AstNVisitor { // Simulate a node tree, returning value of variables // Two major operating modes: @@ -90,6 +103,7 @@ private: // Simulating: deque m_numFreeps; ///< List of all numbers free and not in use deque m_numAllps; ///< List of all numbers free and in use + deque m_callStack; ///< Call stack for verbose error messages // Cleanup // V3Numbers that represents strings are a bit special and the API for V3Number does not allow changing them. @@ -103,6 +117,54 @@ private: return level; } + // Potentially very slow, intended for debugging + string prettyNumber(V3Number* nump, AstNodeDType* dtypep) { + if (AstRefDType* refdtypep = dtypep->castRefDType()) { + dtypep = refdtypep->skipRefp(); + } + if (AstStructDType* stp = dtypep->castStructDType()) { + if (stp->packed()) { + ostringstream out; + out<<"'{"; + for (AstMemberDType* itemp = stp->membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) { + int width = itemp->width(); + int lsb = itemp->lsb(); + int msb = lsb + width - 1; + V3Number fieldNum = V3Number(nump->fileline(), width); + fieldNum.opSel(*nump, msb, lsb); + out<name()<<": "; + if (AstNodeDType * childTypep = itemp->subDTypep()) { + out<nextp()) out<<", "; + } + out<<"}"; + return out.str(); + } + } else if (AstPackArrayDType * arrayp = dtypep->castPackArrayDType()) { + if (AstNodeDType * childTypep = arrayp->subDTypep()) { + ostringstream out; + out<<"["; + int arrayElements = arrayp->elementsConst(); + for (int element = 0; element < arrayElements; ++element) { + int width = childTypep->width(); + int lsb = width * element; + int msb = lsb + width - 1; + V3Number fieldNum = V3Number(nump->fileline(), width); + fieldNum.opSel(*nump, msb, lsb); + int arrayElem = arrayp->lsb() + element; + out<ascii(); + } + // Checking METHODS public: /// Call other-this function on all new *non-constant* var references @@ -119,6 +181,19 @@ public: cout<::iterator it=m_callStack.begin(); it !=m_callStack.end(); ++it) { + AstFuncRef* funcp = (*it)->m_funcp; + stack<<"\nCalled from:\n"<fileline()<<" "<prettyName()<<"() with parameters:"; + V3TaskConnects* tconnects = (*it)->m_tconnects; + for (V3TaskConnects::iterator conIt = tconnects->begin(); conIt != tconnects->end(); ++conIt) { + AstVar* portp = conIt->first; + AstNode* pinp = conIt->second->exprp(); + AstNodeDType* dtypep = pinp->dtypep(); + stack<<"\n "<prettyName()<<" = "<accept(*this); + m_callStack.pop_front(); if (!m_checkOnly && optimizable()) { // Grab return value from output variable (if it's a function) if (!funcp->fvarp()) nodep->v3fatalSrc("Function reference points at non-function"); diff --git a/test_regress/t/t_func_const2_bad.pl b/test_regress/t/t_func_const2_bad.pl new file mode 100755 index 000000000..a3319eb7b --- /dev/null +++ b/test_regress/t/t_func_const2_bad.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2017 by Todd Strader. 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. +# +compile ( + v_flags2 => ["--lint-only"], + fails=>1, + expect=> +q{%Warning-USERFATAL: f_add = 15 +%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. +%Error: t/t_func_const2_bad.v:10: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' +%Error: t/t_func_const2_bad.v:21: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing +Called from: +t/t_func_const2_bad.v:26: f_add() with parameters: + a = 32'h7 + b = 32'h8 +Called from: +t/t_func_const2_bad.v:10: f_add2() with parameters: + a = ?32?sh7 + b = ?32?sh8 + c = ?32?sh9 +}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_const2_bad.v b/test_regress/t/t_func_const2_bad.v new file mode 100644 index 000000000..63c459bf2 --- /dev/null +++ b/test_regress/t/t_func_const2_bad.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Todd Strader. + +module t; + + localparam P6 = f_add(5, 1); + localparam P14 = f_add2(2, 3, f_add(4, 5)); + localparam P24 = f_add2(7, 8, 9); + + initial begin + // Should never get here + $write("*-* All Finished *-*\n"); + $finish; + end + + function integer f_add(input [31:0] a, input [31:0] b); + f_add = a+b; + if (f_add == 15) + $fatal(2, "f_add = 15"); + endfunction + + // Speced ok: function called from function + function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c); + f_add2 = f_add(a,b)+c; + endfunction +endmodule diff --git a/test_regress/t/t_func_const_bad.pl b/test_regress/t/t_func_const_bad.pl index cc5968499..90b9b276d 100755 --- a/test_regress/t/t_func_const_bad.pl +++ b/test_regress/t/t_func_const_bad.pl @@ -11,24 +11,39 @@ compile ( v_flags2 => ["--lint-only"], fails=>1, expect=> -q{%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output' -%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VAR 'o': Language violation: Outputs not allowed in constant functions -%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted' -%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions -%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_nonparam' -%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable -%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_infinite' -%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant WHILE: Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above 1024 -%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_stop' -%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant STOP: .stop executed during function constification; maybe indicates assertion firing +q{%Error: t/t_func_const_bad.v:11: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output' +%Error: t/t_func_const_bad.v:12: ... Location of non-constant VAR 'o': Language violation: Outputs not allowed in constant functions +%Error: t/t_func_const_bad.v:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted' +%Error: t/t_func_const_bad.v:22: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions +Called from: +t/t_func_const_bad.v:20: f_bad_dotted() with parameters: + a = ?32?sh2 +%Error: t/t_func_const_bad.v:27: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_nonparam' +%Error: t/t_func_const_bad.v:29: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable +Called from: +t/t_func_const_bad.v:27: f_bad_nonparam() with parameters: + a = ?32?sh3 +%Error: t/t_func_const_bad.v:35: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_infinite' +%Error: t/t_func_const_bad.v:37: ... Location of non-constant WHILE: Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above 1024 +Called from: +t/t_func_const_bad.v:35: f_bad_infinite() with parameters: + a = ?32?sh3 +%Error: t/t_func_const_bad.v:43: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_stop' +%Error: t/t_func_const_bad.v:45: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing +Called from: +t/t_func_const_bad.v:43: f_bad_stop() with parameters: + a = ?32?sh3 -Info: Printing in loop: 0 -Info: Printing in loop: 1 -Info: Printing in loop: 2 %Warning-USERFATAL: Fatal Error -%Warning-USERFATAL: Use ... verilator lint_off USERFATAL ... and lint_on around source to disable this message. -%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_fatal' -%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant STOP: .stop executed during function constification; maybe indicates assertion firing -%Error: Exiting due to.*}, +%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. +%Error: t/t_func_const_bad.v:49: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_fatal' +%Error: t/t_func_const_bad.v:54: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing +Called from: +t/t_func_const_bad.v:49: f_bad_fatal() with parameters: + a = ?32?sh3 +}, ); ok(1); diff --git a/test_regress/t/t_func_const_packed_array_bad.pl b/test_regress/t/t_func_const_packed_array_bad.pl new file mode 100755 index 000000000..7620c90f2 --- /dev/null +++ b/test_regress/t/t_func_const_packed_array_bad.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2017 by Todd Strader. 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. +# +compile ( + v_flags2 => ["--lint-only"], + fails=>1, + expect=> +q{%Warning-USERFATAL: f_add = 15 +%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. +%Error: t/t_func_const_packed_array_bad.v:11: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' +%Error: t/t_func_const_packed_array_bad.v:22: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing +Called from: +t/t_func_const_packed_array_bad.v:30: f_add() with parameters: + params = [0 = 32'h7, 1 = 32'h8] +Called from: +t/t_func_const_packed_array_bad.v:11: f_add2() with parameters: + a = ?32?sh7 + b = ?32?sh8 + c = ?32?sh9 +}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_const_packed_array_bad.v b/test_regress/t/t_func_const_packed_array_bad.v new file mode 100644 index 000000000..0ed2aa96c --- /dev/null +++ b/test_regress/t/t_func_const_packed_array_bad.v @@ -0,0 +1,32 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Todd Strader. + +module t; + + localparam [ 1 : 0 ] [ 31 : 0 ] P = {32'd5, 32'd1}; + localparam P6 = f_add(P); + localparam P14 = f_add2(2, 3, f_add(P)); + localparam P24 = f_add2(7, 8, 9); + + initial begin + // Should never get here + $write("*-* All Finished *-*\n"); + $finish; + end + + function integer f_add(input [ 1 : 0 ] [ 31 : 0 ] params); + f_add = params[0]+params[1]; + if (f_add == 15) + $fatal(2, "f_add = 15"); + endfunction + + // Speced ok: function called from function + function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c); + logic [ 1 : 0 ] [ 31 : 0 ] params; + params[0] = a; + params[1] = b; + f_add2 = f_add(params)+c; + endfunction +endmodule diff --git a/test_regress/t/t_func_const_packed_struct_bad.pl b/test_regress/t/t_func_const_packed_struct_bad.pl new file mode 100755 index 000000000..dc9b98867 --- /dev/null +++ b/test_regress/t/t_func_const_packed_struct_bad.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2017 by Todd Strader. 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. +# +compile ( + v_flags2 => ["--lint-only"], + fails=>1, + expect=> +q{%Warning-USERFATAL: f_add = 15 +%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. +%Error: t/t_func_const_packed_struct_bad.v:13: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' +%Error: t/t_func_const_packed_struct_bad.v:24: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing +Called from: +t/t_func_const_packed_struct_bad.v:32: f_add() with parameters: + params = [0 = '{a: 32'h7, b: 32'h22b}, 1 = '{a: 32'h3039, b: 32'h8}] +Called from: +t/t_func_const_packed_struct_bad.v:13: f_add2() with parameters: + a = ?32?sh7 + b = ?32?sh8 + c = ?32?sh9 +}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_const_packed_struct_bad.v b/test_regress/t/t_func_const_packed_struct_bad.v new file mode 100644 index 000000000..46d52cc3d --- /dev/null +++ b/test_regress/t/t_func_const_packed_struct_bad.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Todd Strader. + +module t; + + typedef struct packed { + logic [ 31 : 0 ] a; + logic [ 31 : 0 ] b; + } params_t; + + localparam P24 = f_add2(7, 8, 9); + + initial begin + // Should never get here + $write("*-* All Finished *-*\n"); + $finish; + end + + function integer f_add(input params_t [ 1 : 0 ] params); + f_add = params[0].a+params[1].b; + if (f_add == 15) + $fatal(2, "f_add = 15"); + endfunction + + // Speced ok: function called from function + function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c); + params_t [ 1 : 0 ] params; + params[0] = '{a:a, b:555}; + params[1] = '{a:12345, b:b}; + f_add2 = f_add(params)+c; + endfunction +endmodule diff --git a/test_regress/t/t_func_const_packed_struct_bad2.pl b/test_regress/t/t_func_const_packed_struct_bad2.pl new file mode 100755 index 000000000..99d9651d8 --- /dev/null +++ b/test_regress/t/t_func_const_packed_struct_bad2.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2017 by Todd Strader. 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. +# +compile ( + v_flags2 => ["--lint-only"], + fails=>1, + expect=> +q{%Warning-USERFATAL: f_add = 15 +%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. +%Error: t/t_func_const_packed_struct_bad2.v:19: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' +%Error: t/t_func_const_packed_struct_bad2.v:30: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing +Called from: +t/t_func_const_packed_struct_bad2.v:42: f_add() with parameters: + params = [0 = '{a: 32'h7, foo: 6'hb, sub_params: '{b: 32'h37, bar: 8'h6f}}, 1 = '{a: 32'h3039, foo: 6'hc, sub_params: '{b: 32'h8, bar: 8'h70}}] +Called from: +t/t_func_const_packed_struct_bad2.v:19: f_add2() with parameters: + a = ?32?sh7 + b = ?32?sh8 + c = ?32?sh9 +}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_const_packed_struct_bad2.v b/test_regress/t/t_func_const_packed_struct_bad2.v new file mode 100644 index 000000000..01a38a45d --- /dev/null +++ b/test_regress/t/t_func_const_packed_struct_bad2.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Todd Strader. + +module t; + + typedef struct packed { + logic [ 31 : 0 ] b; + logic [ 7 : 0 ] bar; + } sub_params_t; + + typedef struct packed { + logic [ 31 : 0 ] a; + logic [ 5 : 0 ] foo; + sub_params_t sub_params; + } params_t; + + localparam P24 = f_add2(7, 8, 9); + + initial begin + // Should never get here + $write("*-* All Finished *-*\n"); + $finish; + end + + function integer f_add(input params_t [ 1 : 0 ] params); + f_add = params[0].a+params[1].sub_params.b; + if (f_add == 15) + $fatal(2, "f_add = 15"); + endfunction + + // Speced ok: function called from function + function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c); + params_t [ 1 : 0 ] params; + sub_params_t sp0; + sub_params_t sp1; + sp0 = '{b:55, bar:111}; + params[0] = '{a:a, foo:11, sub_params:sp0}; + sp1 = '{b:b, bar:112}; + params[1] = '{a:12345, foo:12, sub_params:sp1}; + f_add2 = f_add(params)+c; + endfunction +endmodule diff --git a/test_regress/t/t_func_const_struct_bad.pl b/test_regress/t/t_func_const_struct_bad.pl new file mode 100755 index 000000000..f19d1e1ef --- /dev/null +++ b/test_regress/t/t_func_const_struct_bad.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2017 by Todd Strader. 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. +# +compile ( + v_flags2 => ["--lint-only"], + fails=>1, + expect=> +q{%Warning-USERFATAL: f_add = 15 +%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message. +%Error: t/t_func_const_struct_bad.v:16: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2' +%Error: t/t_func_const_struct_bad.v:27: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing +Called from: +t/t_func_const_struct_bad.v:37: f_add() with parameters: + params = '{a: 32'h7, b: 32'h8} +Called from: +t/t_func_const_struct_bad.v:16: f_add2() with parameters: + a = ?32?sh7 + b = ?32?sh8 + c = ?32?sh9 +}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_const_struct_bad.v b/test_regress/t/t_func_const_struct_bad.v new file mode 100644 index 000000000..722ffab47 --- /dev/null +++ b/test_regress/t/t_func_const_struct_bad.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Todd Strader. + +module t; + + typedef struct packed { + logic [ 31 : 0 ] a; + logic [ 31 : 0 ] b; + } params_t; + + localparam params_t P = '{a:5, b:1}; + localparam P6 = f_add(P); + localparam P14 = f_add2(2, 3, f_add(P)); + localparam P24 = f_add2(7, 8, 9); + + initial begin + // Should never get here + $write("*-* All Finished *-*\n"); + $finish; + end + + function integer f_add(input params_t params); + f_add = params.a+params.b; + if (f_add == 15) + $fatal(2, "f_add = 15"); + endfunction + + // Speced ok: function called from function + function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c); + params_t params; + params = '{ + a: a, + b: b + }; + f_add2 = f_add(params)+c; + endfunction +endmodule