From c0adbd0deb1b19ebf118759946bc4534245baa26 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 25 Sep 2022 14:39:58 +0200 Subject: [PATCH] Add support for handling `super` keyword SystemVerilog allows to use the `super` keyword to access properties and methods of a base class. This is useful if there is for example an identifier with the same name in the current class as in the base class and the code wants to access the base class identifier. To support this a bit of refactoring is required. Currently properties are internally referenced by name, this does not work if there are multiple properties of the same. Instead reference properties always by index. In addition when looking up an identifier that resolves to an object return both the type and the object itself. This is necessary since both `this` and `super` resolve to the same object, but each with a different type. Signed-off-by: Lars-Peter Clausen --- PExpr.h | 4 +-- elab_expr.cc | 82 +++++++++++++++++++++--------------------------- elab_lval.cc | 13 ++++---- elaborate.cc | 2 +- net_assign.cc | 14 +++------ net_expr.cc | 5 ++- netlist.h | 7 +++-- netmisc.h | 4 +-- symbol_search.cc | 26 ++++++++++----- t-dll-proc.cc | 20 +----------- 10 files changed, 76 insertions(+), 101 deletions(-) diff --git a/PExpr.h b/PExpr.h index 14ba1577a..8114eff2b 100644 --- a/PExpr.h +++ b/PExpr.h @@ -417,6 +417,7 @@ class PEIdent : public PExpr { index_component_t::ctype_t, bool need_const_idx) const; NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*, + const netclass_t *class_type, NetNet*, pform_name_t) const; bool elaborate_lval_net_packed_member_(Design*, NetScope*, @@ -511,8 +512,7 @@ class PEIdent : public PExpr { unsigned flags) const; NetExpr *elaborate_expr_class_field_(Design*des, NetScope*scope, - NetNet*net, - const name_component_t&comp, + const symbol_search_results &sr, unsigned expr_wid, unsigned flags) const; diff --git a/elab_expr.cc b/elab_expr.cc index 9088387bd..c084b8029 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1480,8 +1480,7 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, // and the scope is the scope where the instance lives. The class method // in turn defines it's own scope. Use that to find the return value. if (search_results.net && search_results.net->data_type()==IVL_VT_CLASS) { - NetNet*net = search_results.net; - const netclass_t*class_type = net->class_type(); + const netclass_t *class_type = dynamic_cast(search_results.type); ivl_assert(*this, class_type); NetScope*method = class_type->method_from_name(method_name); @@ -2536,12 +2535,26 @@ static NetExpr* class_static_property_expression(const LineInfo*li, } NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope, - NetNet*net, - const name_component_t&comp, + const symbol_search_results &sr, unsigned expr_wid, unsigned flags) const { - const netclass_t*class_type = net->class_type(); + + const netclass_t *class_type = dynamic_cast(sr.type); + const name_component_t comp = sr.path_tail.front(); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_expr: " + << "Ident " << sr.path_head + << " look for property " << comp << endl; + } + + if (sr.path_tail.size() > 1) { + cerr << get_fileline() << ": sorry: " + << "Nested member path not yet supported for class properties." + << endl; + return nullptr; + } ivl_type_t par_type; const NetExpr *par_val = class_type->get_parameter(des, comp.name, par_type); @@ -2562,7 +2575,7 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope, if (debug_elaborate) { cerr << get_fileline() << ": check_for_class_property: " << "Property " << comp.name - << " of net " << net->name() + << " of net " << sr.net->name() << ", context scope=" << scope_path(scope) << endl; } @@ -2582,7 +2595,7 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope, prop_name); } - NetEProperty*tmp = new NetEProperty(net, comp.name); + NetEProperty*tmp = new NetEProperty(sr.net, pidx); tmp->set_line(*this); return tmp; } @@ -2751,6 +2764,7 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope, use_search_results.path_tail.push_back(search_results.path_head.back()); use_search_results.path_head.push_back(name_component_t(perm_string::literal(THIS_TOKEN))); use_search_results.net = scope->find_signal(perm_string::literal(THIS_TOKEN)); + use_search_results.type = use_search_results.net->net_type(); ivl_assert(*this, use_search_results.net); return elaborate_expr_method_(des, scope, use_search_results); @@ -3026,12 +3040,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, if (search_results.par_val) cerr << get_fileline() << ": PECallFunction::elaborate_expr_method_: " << "search_results.par_val: " << *search_results.par_val << endl; - if (search_results.par_type) + if (search_results.type) cerr << get_fileline() << ": PECallFunction::elaborate_expr_method_: " - << "search_results.par_type: " << *search_results.par_type << endl; + << "search_results.type: " << *search_results.type << endl; } - if (search_results.par_val && search_results.par_type) { + if (search_results.par_val && search_results.type) { return elaborate_expr_method_par_(des, scope, search_results); } @@ -3177,7 +3191,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, perm_string method_name = search_results.path_tail.back().name; NetNet*net = search_results.net; - const netclass_t*class_type = net->class_type(); + const netclass_t*class_type = dynamic_cast(search_results.type); ivl_assert(*this, class_type); NetScope*method = class_type->method_from_name(method_name); @@ -3285,10 +3299,10 @@ NetExpr* PECallFunction::elaborate_expr_method_par_(Design*des, NetScope*scope, const { ivl_assert(*this, search_results.par_val); - ivl_assert(*this, search_results.par_type); + ivl_assert(*this, search_results.type); const NetExpr*par_val = search_results.par_val; - ivl_type_t par_type = search_results.par_type; + ivl_type_t par_type = search_results.type; perm_string method_name = search_results.path_tail.back().name; // If the parameter is of type string, then look for the standard string @@ -4230,8 +4244,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) // 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(); + const netclass_t *class_type = dynamic_cast(sr.type); + if (class_type && !sr.path_tail.empty()) { perm_string pname = peek_tail_name(sr.path_tail); ivl_type_t par_type; const NetExpr *par = class_type->get_parameter(des, pname, par_type); @@ -4349,24 +4363,8 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return check_for_struct_members(this, des, use_scope, net, sr.path_head.back().index, sr.path_tail); - } else if (net->class_type()) { - const name_component_t member_comp = sr.path_tail.front(); - - if (debug_elaborate) { - cerr << get_fileline() << ": PEIdent::elaborate_expr: " - << "Ident " << sr.path_head - << " look for property " << member_comp << endl; - } - - if (sr.path_tail.size() > 1) { - cerr << get_fileline() << ": sorry: " - << "Nested member path not yet supported in this context." - << endl; - return nullptr; - } - - return elaborate_expr_class_field_(des, scope, net, - member_comp, 0, flags); + } else if (dynamic_cast(sr.type)) { + return elaborate_expr_class_field_(des, scope, sr, 0, flags); } } @@ -4570,7 +4568,7 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, << " canonical index: " << *canon_index << endl; } - NetEProperty*tmp = new NetEProperty(this_net, member_name, canon_index); + NetEProperty*tmp = new NetEProperty(this_net, pidx, canon_index); tmp->set_line(*this); return tmp; } @@ -4667,7 +4665,7 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, } return elaborate_expr_param_or_specparam_(des, scope, sr.par_val, - sr.scope, sr.par_type, + sr.scope, sr.type, expr_wid, flags); } @@ -4882,18 +4880,8 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope, return 0; } - if (sr.net->class_type() && !sr.path_tail.empty()) { - if (debug_elaborate) { - cerr << get_fileline() << ": PEIdent::elaborate_expr: " - "Ident " << sr.path_head - << " look for class property " << sr.path_tail - << endl; - } - - ivl_assert(*this, sr.path_tail.size() == 1); - const name_component_t member_comp = sr.path_tail.front(); - return elaborate_expr_class_field_(des, use_scope, - sr.net, member_comp, + if (dynamic_cast(sr.type) && !sr.path_tail.empty()) { + return elaborate_expr_class_field_(des, use_scope, sr, expr_wid, flags); } diff --git a/elab_lval.cc b/elab_lval.cc index cdbf52b0e..3c8a82c69 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -285,8 +285,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, // If the variable is a class object, then handle it with the // net_class_member_ method. - if (reg->class_type() && !member_path.empty() && gn_system_verilog()) { - NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, member_path); + const netclass_t *class_type = dynamic_cast(sr.type); + if (class_type && !member_path.empty() && gn_system_verilog()) { + NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, class_type, reg, member_path); return lv; } @@ -475,7 +476,7 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, } NetAssign_*this_lval = new NetAssign_(this_net); - this_lval->set_property(member_name); + this_lval->set_property(member_name, pidx); if (canon_index) this_lval->set_word(canon_index); return this_lval; @@ -1078,7 +1079,8 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, * obj, and member_path=base.x. */ NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, - NetNet*sig, pform_name_t member_path) const + const netclass_t *class_type, NetNet*sig, + pform_name_t member_path) const { if (debug_elaborate) { cerr << get_fileline() << ": PEIdent::elaborate_lval_net_class_member_: " @@ -1086,7 +1088,6 @@ NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope << " of " << sig->name() << "." << endl; } - const netclass_t*class_type = sig->class_type(); ivl_assert(*this, class_type); // Iterate over the member_path. This handles nested class @@ -1149,7 +1150,7 @@ NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope } lv = lv? new NetAssign_(lv) : new NetAssign_(sig); - lv->set_property(method_name); + lv->set_property(method_name, pidx); // Now get the type of the property. ivl_type_t ptype = class_type->get_prop_type(pidx); diff --git a/elaborate.cc b/elaborate.cc index 25e47d236..41ce06ca0 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3906,7 +3906,7 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, "$ivl_queue_method$pop_back"); } - if (const netclass_t*class_type = net->class_type()) { + if (const netclass_t*class_type = dynamic_cast(par_type)) { NetScope*task = class_type->method_from_name(method_name); if (task == 0) { // If an implicit this was added it is not an error if we diff --git a/net_assign.cc b/net_assign.cc index d3ecf5215..45379b265 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -158,10 +158,7 @@ const ivl_type_s* NetAssign_::net_type() const return ntype; if (const netclass_t*class_type = dynamic_cast(ntype)) { - int pidx = class_type->property_idx_from_name(member_); - ivl_assert(*this, pidx >= 0); - ivl_type_t tmp = class_type->get_prop_type(pidx); - return tmp; + return class_type->get_prop_type(member_idx_); } if (const netdarray_t*darray = dynamic_cast (ntype)) { @@ -178,10 +175,7 @@ const ivl_type_s* NetAssign_::net_type() const if (member_.nil()) return sig_->net_type(); - int pidx = class_type->property_idx_from_name(member_); - ivl_assert(*sig_, pidx >= 0); - ivl_type_t tmp = class_type->get_prop_type(pidx); - return tmp; + return class_type->get_prop_type(member_idx_); } if (const netdarray_t*darray = dynamic_cast (sig_->net_type())) { @@ -246,10 +240,10 @@ void NetAssign_::set_part(NetExpr*base, unsigned wid, sel_type_ = sel_type; } -void NetAssign_::set_property(const perm_string&mname) +void NetAssign_::set_property(const perm_string&mname, unsigned idx) { - //ivl_assert(*sig_, sig_->class_type()); member_ = mname; + member_idx_ = idx; } /* diff --git a/net_expr.cc b/net_expr.cc index db163e84a..25f10dcb5 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -382,13 +382,12 @@ NetENull::~NetENull() { } -NetEProperty::NetEProperty(NetNet*net, perm_string pnam, NetExpr*idx) -: net_(net), index_(idx) +NetEProperty::NetEProperty(NetNet*net, size_t pidx, NetExpr*idx) +: net_(net), pidx_(pidx), index_(idx) { const netclass_t*use_type = dynamic_cast(net->net_type()); assert(use_type); - pidx_ = use_type->property_idx_from_name(pnam); ivl_type_t prop_type = use_type->get_prop_type(pidx_); expr_width(prop_type->packed_width()); cast_signed(prop_type->get_signed()); diff --git a/netlist.h b/netlist.h index 78cb7a8ef..45cb82ee8 100644 --- a/netlist.h +++ b/netlist.h @@ -2838,8 +2838,8 @@ class NetAssign_ { ivl_select_type_t = IVL_SEL_OTHER); // Set the member or property name if the signal type is a // class. - void set_property(const perm_string&name); - inline perm_string get_property(void) const { return member_; } + void set_property(const perm_string&name, unsigned int idx); + inline int get_property_idx(void) const { return member_idx_; } // Determine if the assigned object is signed or unsigned. // This is used when determining the expression type for @@ -2897,6 +2897,7 @@ class NetAssign_ { NetExpr*word_; // member/property if signal is a class. perm_string member_; + int member_idx_ = -1; bool signed_; bool turn_sig_to_wire_on_release_; @@ -4579,7 +4580,7 @@ class NetENull : public NetExpr { */ class NetEProperty : public NetExpr { public: - NetEProperty(NetNet*n, perm_string pname, NetExpr*canon_index =0); + NetEProperty(NetNet*n, size_t pidx_, NetExpr*canon_index =0); ~NetEProperty(); inline const NetNet* get_sig() const { return net_; } diff --git a/netmisc.h b/netmisc.h index 621a95757..c523b4e61 100644 --- a/netmisc.h +++ b/netmisc.h @@ -48,7 +48,7 @@ struct symbol_search_results { net = 0; cls_val = 0; par_val = 0; - par_type = 0; + type = 0; eve = 0; } @@ -80,7 +80,7 @@ struct symbol_search_results { // If this was a parameter, the value expression and the // optional value dimensions. const NetExpr*par_val; - ivl_type_t par_type; + ivl_type_t type; // If this is a named event, ... NetEvent*eve; diff --git a/symbol_search.cc b/symbol_search.cc index 2815777c7..2b6cc707f 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -132,12 +132,6 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, if (scope->genvar_tmp.str() && path_tail.name == scope->genvar_tmp) return false; - if (path_tail.name == "#") { - cerr << li->get_fileline() << ": sorry: " - << "Implicit class handle \"super\" not supported." << endl; - return false; - } - // These items cannot be seen outside the bounding module where // the search starts. But we continue searching up because scope // names can match. For example: @@ -151,10 +145,26 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, // ... top.not_ok; // Matches. // endmodule if (!passed_module_boundary) { + // Special case `super` keyword. Return the `this` object, but + // with the type of the base class. + if (path_tail.name == "#") { + if (NetNet *net = scope->find_signal(perm_string::literal(THIS_TOKEN))) { + const netclass_t *class_type = dynamic_cast(net->net_type()); + path.push_back(path_tail); + res->scope = scope; + res->net = net; + res->type = class_type->get_super(); + res->path_head = path; + return true; + } + return false; + } + if (NetNet*net = scope->find_signal(path_tail.name)) { path.push_back(path_tail); res->scope = scope; res->net = net; + res->type = net->net_type(); res->path_head = path; return true; } @@ -167,7 +177,7 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, return true; } - if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->par_type)) { + if (const NetExpr*par = scope->get_parameter(des, path_tail.name, res->type)) { path.push_back(path_tail); res->scope = scope; res->par_val = par; @@ -326,7 +336,7 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope, net = recurse.net; cls_val = recurse.cls_val; par = recurse.par_val; - par_type = recurse.par_type; + par_type = recurse.type; eve = recurse.eve; if (! flag) { return 0; diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 27ec54785..ab4ee69d2 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -179,8 +179,6 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con cur->width_ = asn->lwidth(); - ivl_type_t nest_type = 0; - if (asn->sig()) { cur->type_ = IVL_LVAL_REG; cur->n.sig = find_signal(des_, asn->sig()); @@ -188,7 +186,6 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con } else { const NetAssign_*asn_nest = asn->nest(); ivl_assert(*li, asn_nest); - nest_type = asn_nest->net_type(); struct ivl_lval_s*cur_nest = new struct ivl_lval_s; make_single_lval_(li, cur_nest, asn_nest); @@ -209,22 +206,7 @@ bool dll_target::make_single_lval_(const LineInfo*li, struct ivl_lval_s*cur, con expr_ = 0; } - cur->property_idx = -1; - perm_string pname = asn->get_property(); - if (!pname.nil()) { - const netclass_t*use_type; - switch (cur->type_) { - case IVL_LVAL_LVAL: - assert(nest_type); - use_type = dynamic_cast (nest_type); - break; - default: - use_type = dynamic_cast (cur->n.sig->net_type); - break; - } - assert(use_type); - cur->property_idx = use_type->property_idx_from_name(pname); - } + cur->property_idx = asn->get_property_idx(); return flag; }