Rework PEIdent::test_width() to use new-style symbol_search().

This fixes issue #527.
This commit is contained in:
Martin Whitaker 2021-07-31 14:18:52 +01:00
parent e547a8355d
commit 83d9b5deda
1 changed files with 74 additions and 89 deletions

View File

@ -3966,12 +3966,6 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&)
unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
{ {
NetNet* net = 0;
ivl_type_t cls_val = 0;
const NetExpr*par = 0;
ivl_type_t par_type = 0;
NetEvent* eve = 0;
NetScope*use_scope = scope; NetScope*use_scope = scope;
if (package_) { if (package_) {
use_scope = des->find_package(package_->pscope_name()); use_scope = des->find_package(package_->pscope_name());
@ -3982,8 +3976,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
return tmp; return tmp;
} }
NetScope*found_in = symbol_search(this, des, use_scope, path_, symbol_search_results sr;
net, par, eve, par_type, cls_val); symbol_search(this, des, use_scope, path_, &sr);
// If there is a part/bit select expression, then process it // If there is a part/bit select expression, then process it
// here. This constrains the results no matter what kind the // here. This constrains the results no matter what kind the
@ -3994,7 +3988,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
if (!name_tail.index.empty()) { if (!name_tail.index.empty()) {
const index_component_t&index_tail = name_tail.index.back(); const index_component_t&index_tail = name_tail.index.back();
// Skip full array word net selects. // Skip full array word net selects.
if (!net || (name_tail.index.size() > net->unpacked_dimensions())) { if (!sr.net || (name_tail.index.size() > sr.net->unpacked_dimensions())) {
use_sel = index_tail.sel; use_sel = index_tail.sel;
} }
} }
@ -4029,7 +4023,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// slice width will be. If not, then assume it will be a // slice width will be. If not, then assume it will be a
// simple bit select. If the net only has a single dimension // simple bit select. If the net only has a single dimension
// then this is still a simple bit select. // then this is still a simple bit select.
if ((net == 0) || (net->packed_dimensions() <= 1)) if ((sr.net == 0) || (sr.net->packed_dimensions() <= 1))
use_width = 1; use_width = 1;
break; break;
case index_component_t::SEL_BIT_LAST: case index_component_t::SEL_BIT_LAST:
@ -4042,31 +4036,31 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
ivl_assert(*this, 0); ivl_assert(*this, 0);
} }
if (const netdarray_t*darray = net ? net->darray_type() : 0) { if (const netdarray_t*darray = sr.net ? sr.net->darray_type() : 0) {
switch (use_sel) { switch (use_sel) {
case index_component_t::SEL_BIT: case index_component_t::SEL_BIT:
case index_component_t::SEL_BIT_LAST: case index_component_t::SEL_BIT_LAST:
expr_type_ = darray->element_base_type(); expr_type_ = darray->element_base_type();
expr_width_ = darray->element_width(); expr_width_ = darray->element_width();
min_width_ = expr_width_; min_width_ = expr_width_;
signed_flag_ = net->get_signed(); signed_flag_ = sr.net->get_signed();
break; break;
default: default:
expr_type_ = net->data_type(); expr_type_ = sr.net->data_type();
expr_width_ = net->vector_width(); expr_width_ = sr.net->vector_width();
min_width_ = expr_width_; min_width_ = expr_width_;
signed_flag_ = net->get_signed(); signed_flag_ = sr.net->get_signed();
break; break;
} }
return expr_width_; return expr_width_;
} }
// Look for a class property. // Look for a class property.
if (gn_system_verilog() && cls_val) { if (gn_system_verilog() && sr.cls_val) {
expr_type_ = cls_val->base_type(); expr_type_ = sr.cls_val->base_type();
expr_width_ = cls_val->packed_width(); expr_width_ = sr.cls_val->packed_width();
min_width_ = expr_width_; min_width_ = expr_width_;
signed_flag_ = cls_val->get_signed(); signed_flag_ = sr.cls_val->get_signed();
return expr_width_; return expr_width_;
} }
@ -4074,10 +4068,10 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// We have a bit/part select. Account for any remaining dimensions // We have a bit/part select. Account for any remaining dimensions
// beyond the indexed dimension. // beyond the indexed dimension.
size_t use_depth = name_tail.index.size(); size_t use_depth = name_tail.index.size();
if (net) { if (sr.net) {
if (use_depth >= net->unpacked_dimensions()) if (use_depth >= sr.net->unpacked_dimensions())
use_depth -= net->unpacked_dimensions(); use_depth -= sr.net->unpacked_dimensions();
use_width *= net->slice_width(use_depth); use_width *= sr.net->slice_width(use_depth);
} }
expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic
@ -4089,14 +4083,56 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
} }
// The width of a signal expression is the width of the signal. // The width of a signal expression is the width of the signal.
if (net != 0) { if (sr.net != 0) {
// If this net is a struct, the path tail may be
// a struct member. If it is, then we know the
// width of this identifier by knowing the width
// of the member. We don't even need to know
// anything about positions in containing arrays.
if (sr.net->struct_type() != 0 && !sr.path_tail.empty()) {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PEIdent::test_width: "
<< "Net " << sr.path_head << " is a struct, "
<< "checking width of member " << sr.path_tail << endl;
}
const netstruct_t::member_t*mem;
unsigned long unused;
mem = get_struct_member(this, des, scope, sr.net,
peek_tail_name(sr.path_tail), unused);
if (mem) {
expr_type_ = mem->data_type();
expr_width_ = mem->net_type->packed_width();
min_width_ = expr_width_;
signed_flag_ = mem->get_signed();
return expr_width_;
}
}
// Similarly, if this net is an object, the path tail may
// be a class property.
if (sr.net->class_type() != 0 && !sr.path_tail.empty()) {
const netclass_t*class_type = sr.net->class_type();
perm_string pname = peek_tail_name(sr.path_tail);
int pidx = class_type->property_idx_from_name(pname);
if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
expr_type_ = ptype->base_type();
expr_width_ = ptype->packed_width();
min_width_ = expr_width_;
signed_flag_ = ptype->get_signed();
return expr_width_;
}
}
size_t use_depth = name_tail.index.size(); size_t use_depth = name_tail.index.size();
// Account for unpacked dimensions by assuming that the // Account for unpacked dimensions by assuming that the
// unpacked dimensions are consumed first, so subtract // unpacked dimensions are consumed first, so subtract
// the unpacked dimensions from the dimension depth // the unpacked dimensions from the dimension depth
// useable for making the slice. // useable for making the slice.
if (use_depth >= net->unpacked_dimensions()) { if (use_depth >= sr.net->unpacked_dimensions()) {
use_depth -= net->unpacked_dimensions(); use_depth -= sr.net->unpacked_dimensions();
} else { } else {
// In this case, we have a slice of an unpacked // In this case, we have a slice of an unpacked
@ -4105,19 +4141,19 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
use_depth = 0; use_depth = 0;
} }
expr_type_ = net->data_type(); expr_type_ = sr.net->data_type();
expr_width_ = net->slice_width(use_depth); expr_width_ = sr.net->slice_width(use_depth);
min_width_ = expr_width_; min_width_ = expr_width_;
signed_flag_ = net->get_signed(); signed_flag_ = sr.net->get_signed();
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::test_width: " cerr << get_fileline() << ": PEIdent::test_width: "
<< net->name() << " is a net, " << sr.net->name() << " is a net, "
<< "type=" << expr_type_ << "type=" << expr_type_
<< ", width=" << expr_width_ << ", width=" << expr_width_
<< ", signed_=" << (signed_flag_ ? "true" : "false") << ", signed_=" << (signed_flag_ ? "true" : "false")
<< ", use_depth=" << use_depth << ", use_depth=" << use_depth
<< ", packed_dimensions=" << net->packed_dimensions() << ", packed_dimensions=" << sr.net->packed_dimensions()
<< ", unpacked_dimensions=" << net->unpacked_dimensions() << ", unpacked_dimensions=" << sr.net->unpacked_dimensions()
<< endl; << endl;
} }
return expr_width_; return expr_width_;
@ -4125,7 +4161,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// The width of an enumeration literal is the width of the // The width of an enumeration literal is the width of the
// enumeration base. // enumeration base.
if (const NetEConstEnum*par_enum = dynamic_cast<const NetEConstEnum*> (par)) { if (const NetEConstEnum*par_enum = dynamic_cast<const NetEConstEnum*> (sr.par_val)) {
const netenum_t*use_enum = par_enum->enumeration(); const netenum_t*use_enum = par_enum->enumeration();
ivl_assert(*this, use_enum != 0); ivl_assert(*this, use_enum != 0);
@ -4139,13 +4175,13 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
// The width of a parameter is the width of the parameter value // The width of a parameter is the width of the parameter value
// (as evaluated earlier). // (as evaluated earlier).
if (par != 0) { if (sr.par_val != 0) {
expr_type_ = par->expr_type(); expr_type_ = sr.par_val->expr_type();
expr_width_ = par->expr_width(); expr_width_ = sr.par_val->expr_width();
min_width_ = expr_width_; min_width_ = expr_width_;
signed_flag_ = par->has_sign(); signed_flag_ = sr.par_val->has_sign();
if (!par->has_width() && (mode < LOSSLESS)) if (!sr.par_val->has_width() && (mode < LOSSLESS))
mode = LOSSLESS; mode = LOSSLESS;
return expr_width_; return expr_width_;
@ -4170,57 +4206,6 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
return expr_width_; return expr_width_;
} }
// If this is SystemVerilog then maybe this is a structure element.
if (gn_system_verilog() && found_in==0 && path_.size() >= 2) {
pform_name_t use_path = path_;
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
ivl_assert(*this, net == 0);
symbol_search(this, des, scope, use_path, net, par, eve, par_type, cls_val);
// Check to see if we have a net and if so is it a structure?
if (net != 0) {
// If this net is a struct, the method name may be
// a struct member. If it is, then we know the
// width of this identifier my knowing the width
// of the member. We don't even need to know
// anything about positions in containing arrays.
if (net->struct_type() != 0) {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PEIdent::test_width: "
<< "Net " << use_path << " is a struct, "
<< "checking width of member " << method_name << endl;
}
const netstruct_t::member_t*mem;
unsigned long unused;
mem = get_struct_member(this, des, scope, net,
method_name, unused);
if (mem) {
expr_type_ = mem->data_type();
expr_width_ = mem->net_type->packed_width();
min_width_ = expr_width_;
signed_flag_ = mem->get_signed();
return expr_width_;
}
}
if (const netclass_t*class_type = net->class_type()) {
int pidx = class_type->property_idx_from_name(method_name);
if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
expr_type_ = ptype->base_type();
expr_width_ = ptype->packed_width();
min_width_ = expr_width_;
signed_flag_ = ptype->get_signed();
return expr_width_;
}
}
}
}
// Not a net, and not a parameter? Give up on the type, but // Not a net, and not a parameter? Give up on the type, but
// set the width to 0. // set the width to 0.
expr_type_ = IVL_VT_NO_TYPE; expr_type_ = IVL_VT_NO_TYPE;