Resolve multiple dimensions defined in stages with typedef

This commit is contained in:
Dag Lem 2024-01-01 01:18:00 +01:00 committed by Zachary Snow
parent e0d3977e19
commit 03f35c3def
2 changed files with 70 additions and 74 deletions

View File

@ -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;
}

View File

@ -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);