From 03f35c3def316963195a02fc97120b14906bd218 Mon Sep 17 00:00:00 2001 From: Dag Lem Date: Mon, 1 Jan 2024 01:18:00 +0100 Subject: [PATCH] Resolve multiple dimensions defined in stages with typedef --- frontends/ast/simplify.cc | 142 ++++++++++++++--------------- frontends/verilog/verilog_parser.y | 2 +- 2 files changed, 70 insertions(+), 74 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 04d9af4d1..d0e94a25b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -554,6 +554,22 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de return wnode; } +static void prepend_ranges(AstNode *&range, AstNode *range_add) +{ + // Convert range to multirange. + if (range->type == AST_RANGE) + range = new AstNode(AST_MULTIRANGE, range); + + // Add range or ranges. + if (range_add->type == AST_RANGE) + range->children.insert(range->children.begin(), range_add->clone()); + else { + int i = 0; + for (auto child : range_add->children) + range->children.insert(range->children.begin() + i++, child->clone()); + } +} + // check if a node or its children contains an assignment to the given variable static bool node_contains_assignment_to(const AstNode* node, const AstNode* var) { @@ -1879,8 +1895,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin log_assert(resolved_type_node->children.size() == 1); AstNode *template_node = resolved_type_node->children[0]; - // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; + // Resolve the typedef from the bottom up, recursing within the current + // block of code. Defer further simplification until the complete type is + // resolved. + while (template_node->is_custom_type && template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure @@ -1893,90 +1911,68 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin goto apply_newNode; } - // Remove type reference - delete children[0]; - children.erase(children.begin()); - - if (type == AST_WIRE) - type = template_node->type; - is_reg = template_node->is_reg; - is_logic = template_node->is_logic; - is_signed = template_node->is_signed; - is_string = template_node->is_string; - is_custom_type = template_node->is_custom_type; - - range_valid = template_node->range_valid; - range_swapped = template_node->range_swapped; - range_left = template_node->range_left; - range_right = template_node->range_right; - - set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); + // Prepare replacement node. + newNode = template_node->clone(); + newNode->str = str; + newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); + newNode->is_input = is_input; + newNode->is_output = is_output; + newNode->is_wand = is_wand; + newNode->is_wor = is_wor; + for (auto &pair : attributes) + newNode->set_attribute(pair.first, pair.second->clone()); // if an enum then add attributes to support simulator tracing - annotateTypedEnums(template_node); + newNode->annotateTypedEnums(template_node); - // Insert clones children from template at beginning - for (int i = 0; i < GetSize(template_node->children); i++) - children.insert(children.begin() + i, template_node->children[i]->clone()); + bool add_packed_dimensions = (type == AST_WIRE && GetSize(children) > 1) || (type == AST_MEMORY && GetSize(children) > 2); - if (type == AST_MEMORY && GetSize(children) == 1) { - // Single-bit memories must have [0:0] range - AstNode *rng = make_range(0, 0); - children.insert(children.begin(), rng); + // Cannot add packed dimensions if unpacked dimensions are already specified. + if (add_packed_dimensions && newNode->type == AST_MEMORY) + input_error("Cannot extend unpacked type `%s' with packed dimensions\n", type_name.c_str()); + + // Add packed dimensions. + if (add_packed_dimensions) { + AstNode *packed = children[1]; + if (newNode->children.empty()) + newNode->children.insert(newNode->children.begin(), packed->clone()); + else + prepend_ranges(newNode->children[0], packed); } - fixup_hierarchy_flags(); - did_something = true; + + // Add unpacked dimensions. + if (type == AST_MEMORY) { + AstNode *unpacked = children.back(); + if (GetSize(newNode->children) < 2) + newNode->children.push_back(unpacked->clone()); + else + prepend_ranges(newNode->children[1], unpacked); + newNode->type = type; + } + + // Prepare to generate dimensions metadata for the resolved type. + newNode->dimensions.clear(); + newNode->unpacked_dimensions = 0; + + goto apply_newNode; } - log_assert(!is_custom_type); } // resolve types of parameters if (type == AST_LOCALPARAM || type == AST_PARAMETER) { if (is_custom_type) { - log_assert(children.size() == 2); + log_assert(children.size() >= 2); log_assert(children[1]->type == AST_WIRETYPE); - auto type_name = children[1]->str; - if (!current_scope.count(type_name)) { - input_error("Unknown identifier `%s' used as type name\n", type_name.c_str()); - } - AstNode *resolved_type_node = current_scope.at(type_name); - if (resolved_type_node->type != AST_TYPEDEF) - input_error("`%s' does not name a type\n", type_name.c_str()); - log_assert(resolved_type_node->children.size() == 1); - AstNode *template_node = resolved_type_node->children[0]; - - // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; - - if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { - // replace with wire representing the packed structure - newNode = make_packed_struct(template_node, str, attributes); - newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); - newNode->type = type; - current_scope[str] = this; - // copy param value, it needs to be 1st value - delete children[1]; - children.pop_back(); - newNode->children.insert(newNode->children.begin(), children[0]->clone()); - goto apply_newNode; - } - delete children[1]; - children.pop_back(); - - if (template_node->type == AST_MEMORY) + // Pretend it's a wire in order to resolve the type in the code block above. + AstNodeType param_type = type; + type = AST_WIRE; + AstNode *expr = children[0]; + children.erase(children.begin()); + while (simplify(const_fold, stage, width_hint, sign_hint)) {}; + type = param_type; + children.insert(children.begin(), expr); + if (children[1]->type == AST_MEMORY) input_error("unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str()); - is_signed = template_node->is_signed; - is_string = template_node->is_string; - is_custom_type = template_node->is_custom_type; - - range_valid = template_node->range_valid; - range_swapped = template_node->range_swapped; - range_left = template_node->range_left; - range_right = template_node->range_right; - - set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); - for (auto template_child : template_node->children) - children.push_back(template_child->clone()); fixup_hierarchy_flags(); did_something = true; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 244e24f31..c4b569c5a 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2122,7 +2122,7 @@ typedef_decl: astbuf1->children.push_back(astbuf2); if ($5 != NULL) { - if (!astbuf2) { + if (!astbuf2 && !astbuf1->is_custom_type) { addRange(astbuf1, 0, 0, false); } rewriteAsMemoryNode(astbuf1, $5);