mirror of https://github.com/YosysHQ/yosys.git
ast/simplify: Use clone_at_zero() for "at_zero" evaluations
The correct way of using the 'at_zero' regime of simplify is to perform the simplification on a cloned AST subtree, otherwise the "at_zero" evaluation seeps into the main tree. Move the effect of the 'at_zero' flag to the cloning itself, so that the simplify flag can be retired. We assume we can rely on id2ast in the new clone method.
This commit is contained in:
parent
77d4b5230e
commit
4fceeb3b32
|
@ -336,6 +336,10 @@ namespace AST
|
||||||
// Helper for looking up identifiers which are prefixed with the current module name
|
// Helper for looking up identifiers which are prefixed with the current module name
|
||||||
std::string try_pop_module_prefix() const;
|
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
|
// helper to print errors from simplify/genrtlil code
|
||||||
[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3));
|
[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3));
|
||||||
};
|
};
|
||||||
|
|
|
@ -887,10 +887,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
||||||
if (range->children.size() == 1)
|
if (range->children.size() == 1)
|
||||||
this_width = 1;
|
this_width = 1;
|
||||||
else if (!range->range_valid) {
|
else if (!range->range_valid) {
|
||||||
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
|
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() : left_at_zero_ast->clone();
|
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, 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, true, 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)
|
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());
|
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;
|
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) {
|
if (!children[0]->range_valid) {
|
||||||
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
|
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() : left_at_zero_ast->clone();
|
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, 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, true, 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)
|
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());
|
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;
|
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
|
||||||
|
|
|
@ -773,6 +773,44 @@ static IdentUsage always_asgn_before_use(const AstNode *node, const std::string
|
||||||
return IdentUsage::NotReferenced;
|
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)
|
static bool try_determine_range_width(AstNode *range, int &result_width)
|
||||||
{
|
{
|
||||||
log_assert(range->type == AST_RANGE);
|
log_assert(range->type == AST_RANGE);
|
||||||
|
@ -782,11 +820,11 @@ static bool try_determine_range_width(AstNode *range, int &result_width)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *left_at_zero_ast = range->children[0]->clone();
|
AstNode *left_at_zero_ast = range->children[0]->clone_at_zero();
|
||||||
AstNode *right_at_zero_ast = range->children[1]->clone();
|
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 (left_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {}
|
||||||
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) {}
|
while (right_at_zero_ast->simplify(true, false, false, 1, -1, false, false)) {}
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
if (left_at_zero_ast->type == AST_CONSTANT
|
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.
|
// 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)
|
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 int recursion_counter = 0;
|
||||||
static bool deep_recursion_warning = false;
|
static bool deep_recursion_warning = false;
|
||||||
|
|
||||||
|
@ -4202,16 +4242,6 @@ replace_fcall_later:;
|
||||||
if (current_scope[str]->children[0]->isConst())
|
if (current_scope[str]->children[0]->isConst())
|
||||||
newNode = current_scope[str]->children[0]->clone();
|
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;
|
break;
|
||||||
case AST_BIT_NOT:
|
case AST_BIT_NOT:
|
||||||
if (children[0]->type == AST_CONSTANT) {
|
if (children[0]->type == AST_CONSTANT) {
|
||||||
|
|
Loading…
Reference in New Issue