diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 0c0e8a3bc..f42a8c16c 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -336,6 +336,10 @@ namespace AST // Helper for looking up identifiers which are prefixed with the current module name std::string try_pop_module_prefix() const; + // helper to clone the node with some of its subexpressions replaced with zero (this is used + // to evaluate widths of dynamic ranges) + AstNode *clone_at_zero(); + // helper to print errors from simplify/genrtlil code [[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3)); }; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 652514312..ba75ee97f 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -887,10 +887,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (range->children.size() == 1) this_width = 1; else if (!range->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } + AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); + AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); + while (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) { } + while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; @@ -1460,10 +1460,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } if (!children[0]->range_valid) { - AstNode *left_at_zero_ast = children[0]->children[0]->clone(); - AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } + AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); + AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); + while (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) { } + while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 6a2c190e0..882dde296 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -773,6 +773,44 @@ static IdentUsage always_asgn_before_use(const AstNode *node, const std::string return IdentUsage::NotReferenced; } +AstNode *AstNode::clone_at_zero() +{ + int width_hint; + bool sign_hint; + AstNode *pointee; + + switch (type) { + case AST_IDENTIFIER: + if (id2ast) + pointee = id2ast; + else if (current_scope.count(str)) + pointee = current_scope[str]; + else + break; + + if (pointee->type != AST_WIRE && + pointee->type != AST_AUTOWIRE && + pointee->type != AST_MEMORY) + break; + + YS_FALLTHROUGH; + case AST_MEMRD: + detectSignWidth(width_hint, sign_hint); + return mkconst_int(0, sign_hint, width_hint); + + default: + break; + } + + AstNode *that = new AstNode; + *that = *this; + for (auto &it : that->children) + it = it->clone_at_zero(); + for (auto &it : that->attributes) + it.second = it.second->clone(); + return that; +} + static bool try_determine_range_width(AstNode *range, int &result_width) { log_assert(range->type == AST_RANGE); @@ -782,11 +820,11 @@ static bool try_determine_range_width(AstNode *range, int &result_width) return true; } - AstNode *left_at_zero_ast = range->children[0]->clone(); - AstNode *right_at_zero_ast = range->children[1]->clone(); + AstNode *left_at_zero_ast = range->children[0]->clone_at_zero(); + AstNode *right_at_zero_ast = range->children[1]->clone_at_zero(); - while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) {} - while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) {} + while (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {} + while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {} bool ok = false; if (left_at_zero_ast->type == AST_CONSTANT @@ -873,6 +911,8 @@ static void check_auto_nosync(AstNode *node) // nodes that link to a different node using names and lexical scoping. bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) { + log_assert(!at_zero); + static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -4202,16 +4242,6 @@ replace_fcall_later:; if (current_scope[str]->children[0]->isConst()) newNode = current_scope[str]->children[0]->clone(); } - else if (at_zero && current_scope.count(str) > 0) { - AstNode *node = current_scope[str]; - if (node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY) - newNode = mkconst_int(0, sign_hint, width_hint); - } - break; - case AST_MEMRD: - if (at_zero) { - newNode = mkconst_int(0, sign_hint, width_hint); - } break; case AST_BIT_NOT: if (children[0]->type == AST_CONSTANT) {