From e75ad281fcccc71013a6287edb3190c3c27be11a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Jan 2022 11:30:48 +0100 Subject: [PATCH 1/2] Elaborate enums in the order they have been declared enums for a scope are stored in a std::set. This means when iterating over the enums during elaboration it is possible that they are elaborated in a different order than they have been declared in. This causes problems if one enum references items of the other enum. E.g. ``` enum { A } a; enum { B = A } b; ``` In the current implementation whether this works or not depends on the pointer values of the enum_type_t for `a` and `b`, which can change between environments. To make sure that enums are elaborated in the same order use a std::vector instead of a std::set. Signed-off-by: Lars-Peter Clausen --- PExpr.cc | 2 +- PScope.h | 2 +- elab_scope.cc | 4 ++-- pform.cc | 8 +++++--- pform_dump.cc | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index e60a3fbba..842bdc311 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -390,7 +390,7 @@ PEIdent::~PEIdent() static bool find_enum_constant(LexicalScope*scope, perm_string name) { - for (set::const_iterator cur = scope->enum_sets.begin() ; + for (vector::const_iterator cur = scope->enum_sets.begin() ; cur != scope->enum_sets.end() ; ++ cur) { for (list::const_iterator idx = (*cur)->names->begin() ; idx != (*cur)->names->end() ; ++ idx) { diff --git a/PScope.h b/PScope.h index e500a7e02..fd573350e 100644 --- a/PScope.h +++ b/PScope.h @@ -139,7 +139,7 @@ class LexicalScope { std::list elab_tasks; // Enumeration sets. - std::set enum_sets; + std::vector enum_sets; // A count of the generate constructs in this scope. This is // used to automatically name unnamed generate blocks, as diff --git a/elab_scope.cc b/elab_scope.cc index b145bb887..244e1bed1 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -393,7 +393,7 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, } static void elaborate_scope_enumerations(Design*des, NetScope*scope, - const set&enum_types) + const vector&enum_types) { if (debug_scopes) { cerr << scope->get_fileline() << ": " << __func__ << ": " @@ -402,7 +402,7 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, << endl; } - for (set::const_iterator cur = enum_types.begin() + for (vector::const_iterator cur = enum_types.begin() ; cur != enum_types.end() ; ++ cur) { enum_type_t*curp = *cur; elaborate_scope_enumeration(des, scope, curp); diff --git a/pform.cc b/pform.cc index 1ee8de7d9..3abce4071 100644 --- a/pform.cc +++ b/pform.cc @@ -829,8 +829,10 @@ static void pform_put_wire_in_scope(perm_string name, PWire*net) void pform_put_enum_type_in_scope(enum_type_t*enum_set) { - if (lexical_scope->enum_sets.count(enum_set)) - return; + if (std::find(lexical_scope->enum_sets.begin(), + lexical_scope->enum_sets.end(), enum_set) != + lexical_scope->enum_sets.end()) + return; set enum_names; list::const_iterator cur; @@ -846,7 +848,7 @@ void pform_put_enum_type_in_scope(enum_type_t*enum_set) } } - lexical_scope->enum_sets.insert(enum_set); + lexical_scope->enum_sets.push_back(enum_set); } PWire*pform_get_make_wire_in_scope(const struct vlltype&, perm_string name, diff --git a/pform_dump.cc b/pform_dump.cc index b563e9041..32c4fb9d8 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1544,7 +1544,7 @@ void LexicalScope::dump_localparams_(ostream&out, unsigned indent) const void LexicalScope::dump_enumerations_(ostream&out, unsigned indent) const { - for (set::const_iterator cur = enum_sets.begin() + for (vector::const_iterator cur = enum_sets.begin() ; cur != enum_sets.end() ; ++ cur) { out << setw(indent) << "" << "enum {" << endl; From 67b29ab5d4e9e4e6c0b1428bfa95694b96e2de92 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 22 Jan 2022 11:47:24 +0100 Subject: [PATCH 2/2] Add a regression test to check enum elaboration order Test that enums are elaborated in declaration order and a enum declaration can reference a item of an enum that was declared before it. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/enum_order.v | 25 +++++++++++++++++++++++++ ivtest/regress-sv.list | 1 + 2 files changed, 26 insertions(+) create mode 100644 ivtest/ivltests/enum_order.v diff --git a/ivtest/ivltests/enum_order.v b/ivtest/ivltests/enum_order.v new file mode 100644 index 000000000..8f763a916 --- /dev/null +++ b/ivtest/ivltests/enum_order.v @@ -0,0 +1,25 @@ +// Verify that enums can reference items from enums declared before them + +module test; + +enum logic { + A = 1 +} a; + +enum logic { + B = A +} b; + +enum logic { + C = B +} c; + +initial begin + if (A == B && A == C) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end +end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index b42729baf..b5d223bca 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -237,6 +237,7 @@ enum_in_struct normal,-g2005-sv ivltests enum_in_class normal,-g2005-sv ivltests enum_in_class_name_coll CE,-g2005-sv ivltests enum_next normal,-g2005-sv ivltests +enum_order normal,-g2005-sv ivltests enum_ports normal,-g2005-sv ivltests enum_test1 normal,-g2005-sv ivltests enum_test2 normal,-g2005-sv ivltests