Fix expression type for packed struct member access (GitHub issue #386)

A NetESelect is used for accessing packed struct members and also for
accessing dynamic array elements. In these cases the expr_type() and
enumeration() methods should reflect the member/element type.
This commit is contained in:
Martin Whitaker 2020-11-20 16:50:11 +00:00
parent ad862020bb
commit 0fada92389
3 changed files with 44 additions and 29 deletions

View File

@ -1958,6 +1958,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
unsigned long use_width = struct_type->packed_width();
pform_name_t completed_path;
ivl_type_t member_type = 0;
do {
const name_component_t member_comp = member_path.front();
const perm_string&member_name = member_comp.name;
@ -1985,28 +1986,29 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
des->errors += 1;
return 0;
}
member_type = member->net_type;
if (debug_elaborate) {
cerr << li->get_fileline() << ": check_for_struct_members: "
<< "Member type: " << *(member->net_type)
<< " (" << typeid(*(member->net_type)).name() << ")"
<< "Member type: " << *member_type
<< " (" << typeid(*member_type).name() << ")"
<< endl;
}
off += tmp_off;
ivl_assert(*li, use_width >= (unsigned long)member->net_type->packed_width());
use_width = member->net_type->packed_width();
ivl_assert(*li, use_width >= (unsigned long)member_type->packed_width());
use_width = member_type->packed_width();
// At this point, off and use_width are the part select
// expressed by the member_comp, which is a member of the
// struct. We can further refine the part select with any
// indices that might be present.
if (const netstruct_t*tmp_struct = dynamic_cast<const netstruct_t*>(member->net_type)) {
if (const netstruct_t*tmp_struct = dynamic_cast<const netstruct_t*>(member_type)) {
// If the member is itself a struct, then get
// ready to go on to the next iteration.
struct_type = tmp_struct;
} else if (const netenum_t*tmp_enum = dynamic_cast<const netenum_t*> (member->net_type)) {
} else if (const netenum_t*tmp_enum = dynamic_cast<const netenum_t*> (member_type)) {
// If the element is an enum, then we don't have
// anything special to do.
@ -2017,7 +2019,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
}
struct_type = 0;
} else if (const netvector_t*mem_vec = dynamic_cast<const netvector_t*>(member->net_type)) {
} else if (const netvector_t*mem_vec = dynamic_cast<const netvector_t*>(member_type)) {
if (debug_elaborate) {
cerr << li->get_fileline() << ": check_for_struct_members: "
@ -2104,7 +2106,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
// there is no next struct type.
struct_type = 0;
} else if (const netparray_t*array = dynamic_cast<const netparray_t*>(member->net_type)) {
} else if (const netparray_t*array = dynamic_cast<const netparray_t*>(member_type)) {
// If the member is a parray, then the elements
// are themselves packed object, including
@ -2178,7 +2180,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
} else {
// Unknown type?
cerr << li->get_fileline() << ": internal error: "
<< "Unexpected member type? " << *(member->net_type)
<< "Unexpected member type? " << *member_type
<< endl;
des->errors += 1;
struct_type = 0;
@ -2224,7 +2226,7 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
NetESignal*sig = new NetESignal(net);
NetExpr *base = packed_base? packed_base : make_const_val(off);
NetESelect*sel = new NetESelect(sig, base, use_width);
NetESelect*sel = new NetESelect(sig, base, use_width, member_type);
if (debug_elaborate) {
cerr << li->get_fileline() << ": check_for_struct_member: "
@ -5395,7 +5397,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
cerr << get_fileline() << ": debug: "
<< "Bit select of a dynamic array becomes NetESelect." << endl;
}
NetESelect*res = new NetESelect(net, mux, darray->element_width());
NetESelect*res = new NetESelect(net, mux, darray->element_width(), darray->element_type());
res->set_line(*net);
return res;
}
@ -5597,13 +5599,15 @@ NetExpr* PEIdent::elaborate_expr_net_bit_last_(Design*, NetScope*,
}
unsigned use_width = 1;
ivl_type_t use_type = 0;
if (const netdarray_t*darray = net->sig()->darray_type()) {
use_width = darray->element_width();
use_type = darray->element_type();
}
NetELast*mux = new NetELast(net->sig());
mux->set_line(*this);
NetESelect*ss = new NetESelect(net, mux, use_width);
NetESelect*ss = new NetESelect(net, mux, use_width, use_type);
ss->set_line(*this);
return ss;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2019 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2020 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -403,7 +403,14 @@ ivl_variable_type_t NetEProperty::expr_type() const
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid,
ivl_select_type_t sel_type)
: expr_(exp), base_(base), sel_type_(sel_type)
: expr_(exp), base_(base), use_type_(0), sel_type_(sel_type)
{
expr_width(wid);
}
NetESelect::NetESelect(NetExpr*exp, NetExpr*base, unsigned wid,
ivl_type_t use_type)
: expr_(exp), base_(base), use_type_(use_type), sel_type_(IVL_SEL_OTHER)
{
expr_width(wid);
}
@ -431,6 +438,9 @@ ivl_select_type_t NetESelect::select_type() const
ivl_variable_type_t NetESelect::expr_type() const
{
if (use_type_)
return use_type_->base_type();
ivl_variable_type_t type = expr_->expr_type();
// Special case: If the sub-expression is an IVL_VT_STRING,
@ -439,20 +449,12 @@ ivl_variable_type_t NetESelect::expr_type() const
if (type == IVL_VT_STRING && expr_width()==8)
return IVL_VT_BOOL;
if (type != IVL_VT_DARRAY)
return type;
return type;
}
ivl_assert(*this, type == IVL_VT_DARRAY);
// Special case: If the expression is a DARRAY, then the
// sub-expression must be a NetESignal and the type of the
// NetESelect expression is the element type of the arrayed signal.
NetESignal*sig = dynamic_cast<NetESignal*>(expr_);
ivl_assert(*this, sig);
const netarray_t*array_type = dynamic_cast<const netarray_t*> (sig->sig()->net_type());
ivl_assert(*this, array_type);
return array_type->element_type()->base_type();
const netenum_t* NetESelect::enumeration() const
{
return dynamic_cast<const netenum_t*> (use_type_);
}
bool NetESelect::has_width() const

View File

@ -4401,21 +4401,29 @@ class NetEConcat : public NetExpr {
* If the base expression is null, then this expression node can be
* used to express width expansion, signed or unsigned depending on
* the has_sign() flag.
*
* An alternative form of this expression node is used for dynamic
* array word selects and for packed struct member selects. In this
* case use_type indicates the type of the selected element/member.
*/
class NetESelect : public NetExpr {
public:
NetESelect(NetExpr*exp, NetExpr*base, unsigned wid,
ivl_select_type_t sel_type = IVL_SEL_OTHER);
NetESelect(NetExpr*exp, NetExpr*base, unsigned wid,
ivl_type_t use_type);
~NetESelect();
const NetExpr*sub_expr() const;
const NetExpr*select() const;
ivl_select_type_t select_type() const;
// The type of a NetESelect is the base type of the
// sub-expression.
// The type of a bit/part select is the base type of the
// sub-expression. The type of an array/member select is
// the base type of the element/member.
virtual ivl_variable_type_t expr_type() const;
virtual const netenum_t* enumeration() const;
virtual NexusSet* nex_input(bool rem_out = true, bool always_sens = false,
bool nested_func = false) const;
@ -4431,6 +4439,7 @@ class NetESelect : public NetExpr {
private:
NetExpr*expr_;
NetExpr*base_;
ivl_type_t use_type_;
ivl_select_type_t sel_type_;
};