Merge pull request #785 from larsclausen/type-ref

Improve handling of type identifier references
This commit is contained in:
Stephen Williams 2022-10-16 20:52:52 -07:00 committed by GitHub
commit c2dbf4e483
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 399 additions and 74 deletions

View File

@ -33,7 +33,7 @@ PWire::PWire(perm_string n,
: name_(n), type_(t), port_type_(pt), data_type_(dt),
signed_(false),
port_set_(false), net_set_(false), is_scalar_(false),
error_cnt_(0), set_data_type_(0), discipline_(0)
error_cnt_(0), discipline_(0)
{
switch (rt) {
case SR_PORT:
@ -195,8 +195,11 @@ void PWire::set_unpacked_idx(const list<pform_range_t>&ranges)
void PWire::set_data_type(data_type_t*type)
{
assert(set_data_type_ == 0 || set_data_type_ == type);
set_data_type_ = type;
if (set_data_type_.get() == type)
return;
assert(!set_data_type_.get());
set_data_type_.reset(type);
}
void PWire::set_discipline(ivl_discipline_t d)

View File

@ -123,7 +123,7 @@ class PWire : public PNamedItem {
// This is the complex type of the wire. the data_type_ may
// modify how this is interpreted.
data_type_t*set_data_type_;
std::unique_ptr<data_type_t> set_data_type_;
ivl_discipline_t discipline_;

View File

@ -104,7 +104,7 @@ AS_IF( [test "x$with_m32" = xyes],
[])
CFLAGS="$CTARGETFLAGS $CFLAGS"
CXXFLAGS="$CTARGETFLAGS $CXXFLAGS"
CXXFLAGS="$CTARGETFLAGS $CXXFLAGS -std=c++11"
LDFLAGS="$CTARGETFLAGS $LDFLAGS"
# Check that we are using either the GNU compilers or the Sun compilers

View File

@ -444,7 +444,7 @@ static void blend_class_constructors(PClass*pclass)
// If we do not have an explicit constructor chain, but there
// is a parent class, then create an implicit chain.
if (chain_new==0 && pclass->type->base_type!=0) {
if (chain_new==0 && pclass->type->base_type) {
chain_new = new PChainConstructor(pclass->type->base_args);
chain_new->set_line(*pclass);
}
@ -512,16 +512,6 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
netclass_t*use_class = new netclass_t(use_type->name, use_base_class);
// If this is a package we need to remember the elaborated type so that
// scoped type references work. Since there is only one instance for each
// package this works. For classes defined in modules there might be
// multiple instances though. Each module instance will have its own class
// type instance, so the same does not work there.
if (scope->type() == NetScope::PACKAGE) {
ivl_assert(*pclass, use_type->save_elaborated_type == 0);
use_type->save_elaborated_type = use_class;
}
NetScope*class_scope = new NetScope(scope, hname_t(pclass->pscope_name()),
NetScope::CLASS, scope->unit());
class_scope->set_line(pclass);

View File

@ -939,10 +939,10 @@ bool test_ranges_eeq(const vector<netrange_t>&lef, const vector<netrange_t>&rig)
ivl_type_t PWire::elaborate_type(Design*des, NetScope*scope,
const std::vector<netrange_t>&packed_dimensions) const
{
if (set_data_type_ && !dynamic_cast<vector_type_t*>(set_data_type_)) {
ivl_type_t use_type = set_data_type_->elaborate_type(des, scope);
vector_type_t *vec_type = dynamic_cast<vector_type_t*>(set_data_type_.get());
if (set_data_type_ && !vec_type) {
ivl_assert(*this, packed_dimensions.empty());
return use_type;
return set_data_type_->elaborate_type(des, scope);
}
// Fallback method. Create vector type.
@ -1003,10 +1003,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
unsigned wid = 1;
vector<netrange_t>packed_dimensions;
NetScope *type_scope = scope;
if (set_data_type_ && !set_data_type_->name.nil())
type_scope = type_scope->find_typedef_scope(des, set_data_type_);
des->errors += error_cnt_;
if (port_set_ || net_set_) {
@ -1046,7 +1042,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
cerr << get_fileline() << ": PWire::elaborate_sig: "
<< "Evaluate ranges for net " << basename() << endl;
}
dimensions_ok &= evaluate_ranges(des, type_scope, this, nlist, net_);
dimensions_ok &= evaluate_ranges(des, scope, this, nlist, net_);
}
assert(net_set_ || net_.empty());
@ -1147,10 +1143,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
wtype = NetNet::WIRE;
}
ivl_type_t type = elaborate_type(des, type_scope, packed_dimensions);
ivl_type_t type = elaborate_type(des, scope, packed_dimensions);
// Create the type for the unpacked dimensions. If the
// unpacked_dimensions are empty this will just return the base type.
type = elaborate_array_type(des, type_scope, *this, type, unpacked_);
type = elaborate_array_type(des, scope, *this, type, unpacked_);
list<netrange_t> unpacked_dimensions;
// If this is an unpacked array extract the base type and unpacked

View File

@ -18,6 +18,7 @@
*/
# include "PExpr.h"
# include "PScope.h"
# include "pform_types.h"
# include "netlist.h"
# include "netclass.h"
@ -40,10 +41,7 @@ using namespace std;
*/
ivl_type_t data_type_t::elaborate_type(Design*des, NetScope*scope)
{
// User-defined types must be elaborated in the context
// where they were defined.
if (!name.nil())
scope = scope->find_typedef_scope(des, this);
scope = find_scope(des, scope);
ivl_assert(*this, scope);
Definitions*use_definitions = scope;
@ -57,6 +55,11 @@ ivl_type_t data_type_t::elaborate_type(Design*des, NetScope*scope)
return tmp;
}
NetScope *data_type_t::find_scope(Design *, NetScope *scope) const
{
return scope;
}
ivl_type_t data_type_t::elaborate_type_raw(Design*des, NetScope*) const
{
cerr << get_fileline() << ": internal error: "
@ -112,8 +115,6 @@ ivl_type_t atom_type_t::elaborate_type_raw(Design*des, NetScope*) const
ivl_type_t class_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
{
if (save_elaborated_type)
return save_elaborated_type;
return scope->find_class(des, name);
}
@ -366,3 +367,26 @@ ivl_type_t uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
return elaborate_array_type(des, scope, *this, btype, *dims.get());
}
ivl_type_t typeref_t::elaborate_type_raw(Design*des, NetScope*s) const
{
if (!s) {
// Try to recover
return new netvector_t(IVL_VT_LOGIC);
}
return type->elaborate_type(des, s);
}
NetScope *typeref_t::find_scope(Design *des, NetScope *s) const
{
// If a scope has been specified use that as a starting point for the
// search
if (scope)
s = des->find_package(scope->pscope_name());
if (!type->name.nil())
s = s->find_typedef_scope(des, type);
return s;
}

View File

@ -0,0 +1,29 @@
// Check that a packed array type identifier used for a module port is
// elaborated in the correct scope.
localparam A = 2;
typedef logic [A-1:0] T;
module test (
input T x
);
localparam A = 5;
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
initial begin
`check($bits(x), 2);
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,26 @@
// Check that it is possible to reference a package scoped type identifier as
// the type in a type cast expression.
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
package P;
typedef integer T;
endpackage
module test;
integer x;
initial begin
x = P::T'(-1024.123);
`check(x, -1024)
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,28 @@
// Check that it is possible to reference a package scoped type identifier as
// the type in a type cast expression, even if there is a identifier of the same
// name in the local scope.
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
package P;
typedef integer T;
endpackage
module test;
localparam T = 2;
integer x;
initial begin
x = P::T'(-1024.123);
`check(x, -1024)
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,39 @@
// Check that class types declared in a package can be referenced using a scoped
// type identifier.
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
package P;
localparam A = 8;
class C;
logic [A-1:0] x;
task t;
`check($bits(x), 8)
if (!failed) begin
$display("PASSED");
end
endtask
endclass
endpackage
module test;
localparam A = 4;
P::C c;
initial begin
c = new;
c.t();
end
endmodule

View File

@ -0,0 +1,38 @@
// Check that enum types declared in a package can be referenced using a scoped
// type identifier.
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
package P;
localparam X = 8;
typedef enum logic [X-1:0] {
A, B = X
} T;
endpackage
module test;
localparam X = 4;
typedef int T;
P::T x = P::B;
initial begin
`check(x, P::B)
`check(x, 8)
`check($bits(x), 8);
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,24 @@
// Check that it is possible to reference a package scoped type identifier in an
// expression.
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
package P;
typedef integer T;
endpackage
module test;
initial begin
`check($bits(P::T), $bits(integer))
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,26 @@
// Check that it is possible to reference a package scoped type identifier in an
// expression, even if there is a non type identifier of the same name in the
// current scope.
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
package P;
typedef integer T;
endpackage
module test;
integer T;
initial begin
`check($bits(P::T), $bits(integer))
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,40 @@
// Check that struct types declared in a package can be referenced using a
// scoped type identifier.
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
package P;
localparam A = 8;
typedef struct packed {
logic [A-1:0] x;
} T;
endpackage
typedef int T;
module test;
localparam A = 4;
typedef int T;
P::T x;
initial begin
x = 8'hff;
`check(x, 8'hff)
`check($bits(x), 8)
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -0,0 +1,51 @@
// Check that chained type definitions declared in different scopes work
// correctly.
package P1;
localparam A = 8;
typedef logic [A-1:0] T;
endpackage
package P2;
localparam A = 4;
typedef P1::T T;
endpackage
bit failed = 1'b0;
`define check(expr, val) \
if (expr !== val) begin \
$display("FAILED: %s, expected %0d, got %0d", `"expr`", val, expr); \
failed = 1'b1; \
end
module test;
localparam A = 2;
typedef P2::T T;
T x;
P1::T y;
P2::T z;
initial begin
x = 8'hff;
y = 8'hff;
z = 8'hff;
`check(x, 8'hff);
`check($bits(T), 8);
`check($bits(x), 8);
`check(y, 8'hff);
`check($bits(y), 8);
`check($bits(P1::T), 8);
`check(z, 8'hff);
`check($bits(z), 8);
`check($bits(P2::T), 8);
if (!failed) begin
$display("PASSED");
end
end
endmodule

View File

@ -372,6 +372,7 @@ module_nonansi_struct_fail CE,-g2005-sv ivltests
module_output_port_sv_var1 normal,-g2005-sv ivltests
module_output_port_sv_var2 normal,-g2005-sv ivltests
module_port_typedef_array1 normal,-g2005-sv ivltests
module_port_typedef_vector normal,-g2005-sv ivltests
named_begin normal,-g2009 ivltests
named_begin_fail CE,-g2009 ivltests
named_fork normal,-g2009 ivltests
@ -634,6 +635,13 @@ sv_ps_function2 normal,-g2009 ivltests
sv_ps_function3 normal,-g2009 ivltests
sv_ps_function4 normal,-g2009 ivltests
sv_ps_type1 normal,-g2009 ivltests
sv_ps_type_cast1 normal,-g2009 ivltests
sv_ps_type_cast2 normal,-g2009 ivltests
sv_ps_type_class1 normal,-g2009 ivltests
sv_ps_type_enum1 normal,-g2009 ivltests
sv_ps_type_expr1 normal,-g2009 ivltests
sv_ps_type_expr2 normal,-g2009 ivltests
sv_ps_type_struct1 normal,-g2009 ivltests
sv_ps_var1 normal,-g2009 ivltests
sv_queue1 normal,-g2009 ivltests
sv_queue2 normal,-g2009 ivltests
@ -705,6 +713,7 @@ sv_typedef_array_base1 normal,-g2009 ivltests
sv_typedef_array_base2 normal,-g2009 ivltests
sv_typedef_array_base3 normal,-g2009 ivltests
sv_typedef_array_base4 normal,-g2009 ivltests
sv_typedef_chained normal,-g2009 ivltests
sv_typedef_darray_base1 normal,-g2009 ivltests
sv_typedef_darray_base2 normal,-g2009 ivltests
sv_typedef_darray_base3 normal,-g2009 ivltests

View File

@ -438,6 +438,7 @@ sv_port_default6 CE,-g2009,-pallowsigned=1 ivltests
sv_port_default7 CE,-g2009,-pallowsigned=1 ivltests
sv_port_default8 CE,-g2009,-pallowsigned=1 ivltests
sv_port_default9 CE,-g2009 ivltests
sv_ps_type_class1 CE,-g2009 ivltests
sv_root_class CE,-g2009 ivltests
sv_typedef_scope3 CE,-g2009 ivltests
sv_unit2b CE,-g2009 ivltests

View File

@ -23,10 +23,6 @@
# include <typeinfo>
# include "ivl_assert.h"
#if __cplusplus < 201103L
#define unique_ptr auto_ptr
#endif
using namespace std;
/*

24
parse.y
View File

@ -28,6 +28,7 @@
# include "pform.h"
# include "Statement.h"
# include "PSpec.h"
# include "PPackage.h"
# include <stack>
# include <cstring>
# include <sstream>
@ -825,20 +826,9 @@ class_identifier
the class name is detected by the lexor as a TYPE_IDENTIFIER if it
does indeed match a name. */
class_declaration_endlabel_opt
: ':' TYPE_IDENTIFIER
{ class_type_t*tmp = dynamic_cast<class_type_t*> ($2.type);
if (tmp == 0) {
yyerror(@2, "error: class declaration endlabel \"%s\" is not a class name\n", $2.text);
$$ = 0;
} else {
$$ = strdupnew(tmp->name.str());
}
delete[]$2.text;
}
| ':' IDENTIFIER
{ $$ = $2; }
|
{ $$ = 0; }
: ':' TYPE_IDENTIFIER { $$ = $2.text; }
| ':' IDENTIFIER { $$ = $2; }
| { $$ = 0; }
;
/* This rule implements [ extends class_type ] in the
@ -1179,11 +1169,13 @@ ps_type_identifier /* IEEE1800-2017: A.9.3 */
: TYPE_IDENTIFIER
{ pform_set_type_referenced(@1, $1.text);
delete[]$1.text;
$$ = $1.type;
$$ = new typeref_t($1.type);
FILE_NAME($$, @1);
}
| package_scope TYPE_IDENTIFIER
{ lex_in_package_scope(0);
$$ = $2.type;
$$ = new typeref_t($2.type, $1);
FILE_NAME($$, @2);
delete[] $2.text;
}
;

View File

@ -173,6 +173,15 @@ ostream& data_type_t::debug_dump(ostream&out) const
return out;
}
std::ostream& typeref_t::debug_dump(ostream&out) const
{
if (scope)
out << scope->pscope_name() << "::";
out << type->name;
return out;
}
ostream& atom_type_t::debug_dump(ostream&out) const
{
if (signed_flag)

View File

@ -51,7 +51,7 @@ void pform_start_class_declaration(const struct vlltype&loc,
pform_cur_class = class_scope;
assert(type->base_type == 0);
type->base_type = base_type;
type->base_type.reset(base_type);
assert(type->base_args.empty());
if (base_exprs) {

View File

@ -33,10 +33,6 @@
# include <map>
# include <memory>
#if __cplusplus < 201103L
#define unique_ptr auto_ptr
#endif
/*
* parse-form types.
*/
@ -45,6 +41,7 @@ class Design;
class NetScope;
class Definitions;
class PExpr;
class PScope;
class PWire;
class Statement;
class netclass_t;
@ -165,6 +162,8 @@ class data_type_t : public PNamedItem {
virtual SymbolType symbol_type() const;
virtual NetScope *find_scope(Design* des, NetScope *scope) const;
perm_string name;
private:
@ -175,6 +174,19 @@ class data_type_t : public PNamedItem {
std::map<Definitions*,ivl_type_t> cache_type_elaborate_;
};
struct typeref_t : public data_type_t {
explicit typeref_t(data_type_t *t, PScope *s = 0) : scope(s), type(t) {}
ivl_type_t elaborate_type_raw(Design*des, NetScope*scope) const;
NetScope *find_scope(Design* des, NetScope *scope) const;
std::ostream& debug_dump(std::ostream&out) const;
private:
PScope *scope;
data_type_t *type;
};
struct void_type_t : public data_type_t {
virtual void pform_dump(std::ostream&out, unsigned indent) const;
};
@ -193,7 +205,7 @@ struct enum_type_t : public data_type_t {
SymbolType symbol_type() const;
data_type_t *base_type;
std::unique_ptr<data_type_t> base_type;
std::unique_ptr< std::list<named_pexpr_t> > names;
};
@ -270,7 +282,7 @@ struct array_base_t : public data_type_t {
inline explicit array_base_t(data_type_t*btype, std::list<pform_range_t>*pd)
: base_type(btype), dims(pd) { }
data_type_t*base_type;
std::unique_ptr<data_type_t> base_type;
std::unique_ptr< std::list<pform_range_t> > dims;
};
@ -323,8 +335,7 @@ struct string_type_t : public data_type_t {
struct class_type_t : public data_type_t {
inline explicit class_type_t(perm_string n)
: base_type(0), save_elaborated_type(0) { name = n; }
inline explicit class_type_t(perm_string n) { name = n; }
void pform_dump(std::ostream&out, unsigned indent) const;
void pform_dump_init(std::ostream&out, unsigned indent) const;
@ -333,15 +344,17 @@ struct class_type_t : public data_type_t {
// class that we are extending. This is nil if there is no
// hierarchy. If there are arguments to the base class, then
// put them in the base_args vector.
data_type_t*base_type;
std::unique_ptr<data_type_t> base_type;
std::list<PExpr*>base_args;
// This is a map of the properties. Map the name to the type.
struct prop_info_t : public LineInfo {
inline prop_info_t() : qual(property_qualifier_t::make_none()), type(0) { }
inline prop_info_t() : qual(property_qualifier_t::make_none()) { }
inline prop_info_t(property_qualifier_t q, data_type_t*t) : qual(q), type(t) { }
prop_info_t(prop_info_t&&) = default;
prop_info_t& operator=(prop_info_t&&) = default;
property_qualifier_t qual;
data_type_t* type;
std::unique_ptr<data_type_t> type;
};
std::map<perm_string, struct prop_info_t> properties;
@ -356,11 +369,6 @@ struct class_type_t : public data_type_t {
std::vector<Statement*> initialize_static;
ivl_type_t elaborate_type_raw(Design*, NetScope*) const;
// The save_elaborated_type member must be set to the pointer
// to the netclass_t object that is created to represent this
// type. The elaborate_type_raw() method uses this pointer,
// and it is used in some other situations as well.
netclass_t* save_elaborated_type;
virtual SymbolType symbol_type() const;
};
@ -425,8 +433,4 @@ extern std::ostream& operator<< (std::ostream&out, const pform_name_t&);
extern std::ostream& operator<< (std::ostream&out, const name_component_t&that);
extern std::ostream& operator<< (std::ostream&out, const index_component_t&that);
#if __cplusplus < 201103L
#undef unique_ptr
#endif
#endif /* IVL_pform_types_H */