Add stack trace when can't optimize function, bug1158.

Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
This commit is contained in:
Todd Strader 2017-05-09 18:54:15 -04:00 committed by Wilson Snyder
parent 706a7802cc
commit 54bc8608e3
13 changed files with 437 additions and 14 deletions

View File

@ -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]

View File

@ -44,12 +44,25 @@
#include "V3Task.h"
#include <deque>
#include <sstream>
//============================================================================
//######################################################################
// 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<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
deque<SimulateStackNode*> 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<<itemp->name()<<": ";
if (AstNodeDType * childTypep = itemp->subDTypep()) {
out<<prettyNumber(&fieldNum, childTypep);
} else {
out<<fieldNum;
}
if (itemp->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<<arrayElem<<" = "<<prettyNumber(&fieldNum, childTypep);
if (element < arrayElements - 1) out<<", ";
}
out<<"]";
return out.str();
}
}
return nump->ascii();
}
// Checking METHODS
public:
/// Call other-this function on all new *non-constant* var references
@ -119,6 +181,19 @@ public:
cout<<endl;
}
m_whyNotOptimizable = why;
ostringstream stack;
for (deque<SimulateStackNode*>::iterator it=m_callStack.begin(); it !=m_callStack.end(); ++it) {
AstFuncRef* funcp = (*it)->m_funcp;
stack<<"\nCalled from:\n"<<funcp->fileline()<<" "<<funcp->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 "<<portp->prettyName()<<" = "<<prettyNumber(fetchNumber(pinp), dtypep);
}
}
m_whyNotOptimizable += stack.str();
}
}
inline bool optimizable() const { return m_whyNotNodep==NULL; }
@ -718,8 +793,11 @@ private:
}
}
}
SimulateStackNode stackNode(nodep, &tconnects);
m_callStack.push_front(&stackNode);
// Evaluate the function
funcp->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");

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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