ast/simplify: Make in_lvalue/in_param into props of AST nodes

Instead of passing around in_lvalue/in_param flags to simplify, we make
the flags into properties of the AST nodes themselves. After the tree
is first parsed, we once do

  ast->fixup_hierarchy_flags(true)

to walk the full hierarchy and set the flags to their initial correct
values. Then as long as one is using ->clone(), ->cloneInto() and the
AstNode constructor (with children passed to it) to modify the tree, the
flags will be kept in sync automatically. On the other hand if we are
modifying the children list of an existing node, we may need to call

  node->fixup_hierarchy_flags()

to do a localized fixup. That fixup will update the flags on the node's
children, and will propagate the change down the tree if necessary.

clone() doesn't always retain the flags of the subtree being cloned. It
will produce a tree with a consistent setting of the flags, but the
root doesn't have in_param/in_lvalue set unless it's intrinsic to the
type of node being cloned (e.g. AST_PARAMETER). cloneInto() will make
sure the cloned subtree has the flags consistent with the new placement
in a hierarchy.

Add asserts to make sure the old and new way of determining the flags
agree.
This commit is contained in:
Martin Povišer 2023-04-05 11:00:07 +02:00
parent 10d0e69588
commit 22b99413e8
4 changed files with 222 additions and 42 deletions

View File

@ -229,6 +229,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
id2ast = NULL; id2ast = NULL;
basic_prep = false; basic_prep = false;
lookahead = false; lookahead = false;
in_lvalue_from_above = false;
in_param_from_above = false;
in_lvalue = false;
in_param = false;
if (child1) if (child1)
children.push_back(child1); children.push_back(child1);
@ -238,6 +242,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
children.push_back(child3); children.push_back(child3);
if (child4) if (child4)
children.push_back(child4); children.push_back(child4);
fixup_hierarchy_flags();
} }
// create a (deep recursive) copy of a node // create a (deep recursive) copy of a node
@ -249,6 +255,10 @@ AstNode *AstNode::clone() const
it = it->clone(); it = it->clone();
for (auto &it : that->attributes) for (auto &it : that->attributes)
it.second = it.second->clone(); it.second = it.second->clone();
that->set_in_lvalue_flag(false);
that->set_in_param_flag(false);
that->fixup_hierarchy_flags(); // fixup to set flags on cloned children
return that; return that;
} }
@ -256,10 +266,13 @@ AstNode *AstNode::clone() const
void AstNode::cloneInto(AstNode *other) const void AstNode::cloneInto(AstNode *other) const
{ {
AstNode *tmp = clone(); AstNode *tmp = clone();
tmp->in_lvalue_from_above = other->in_lvalue_from_above;
tmp->in_param_from_above = other->in_param_from_above;
other->delete_children(); other->delete_children();
*other = *tmp; *other = *tmp;
tmp->children.clear(); tmp->children.clear();
tmp->attributes.clear(); tmp->attributes.clear();
other->fixup_hierarchy_flags();
delete tmp; delete tmp;
} }
@ -351,6 +364,10 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
if (is_enum) { if (is_enum) {
fprintf(f, " type=enum"); fprintf(f, " type=enum");
} }
if (in_lvalue)
fprintf(f, " in_lvalue");
if (in_param)
fprintf(f, " in_param");
fprintf(f, "\n"); fprintf(f, "\n");
for (auto &it : attributes) { for (auto &it : attributes) {
@ -1091,7 +1108,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
ast->attributes.erase(ID::whitebox); ast->attributes.erase(ID::whitebox);
} }
AstNode *n = ast->attributes.at(ID::lib_whitebox); AstNode *n = ast->attributes.at(ID::lib_whitebox);
ast->attributes[ID::whitebox] = n; ast->set_attribute(ID::whitebox, n);
ast->attributes.erase(ID::lib_whitebox); ast->attributes.erase(ID::lib_whitebox);
} }
} }
@ -1150,7 +1167,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
ast->children.swap(new_children); ast->children.swap(new_children);
if (ast->attributes.count(ID::blackbox) == 0) { if (ast->attributes.count(ID::blackbox) == 0) {
ast->attributes[ID::blackbox] = AstNode::mkconst_int(1, false); ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false));
} }
} }
@ -1298,6 +1315,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
flag_pwires = pwires; flag_pwires = pwires;
flag_autowire = autowire; flag_autowire = autowire;
ast->fixup_hierarchy_flags(true);
log_assert(current_ast->type == AST_DESIGN); log_assert(current_ast->type == AST_DESIGN);
for (AstNode *child : current_ast->children) for (AstNode *child : current_ast->children)
{ {
@ -1748,7 +1767,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
AstNode *new_ast = ast->clone(); AstNode *new_ast = ast->clone();
if (!new_ast->attributes.count(ID::hdlname)) if (!new_ast->attributes.count(ID::hdlname))
new_ast->attributes[ID::hdlname] = AstNode::mkconst_str(stripped_name); new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name));
para_counter = 0; para_counter = 0;
for (auto child : new_ast->children) { for (auto child : new_ast->children) {
@ -1795,6 +1814,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
new_ast->children.push_back(defparam); new_ast->children.push_back(defparam);
} }
new_ast->fixup_hierarchy_flags(true);
(*new_ast_out) = new_ast; (*new_ast_out) = new_ast;
return modname; return modname;
} }

View File

@ -221,6 +221,13 @@ namespace AST
std::string filename; std::string filename;
AstSrcLocType location; AstSrcLocType location;
// are we embedded in an lvalue, param?
// (see fixup_hierarchy_flags)
bool in_lvalue;
bool in_param;
bool in_lvalue_from_above;
bool in_param_from_above;
// creating and deleting nodes // creating and deleting nodes
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr);
AstNode *clone() const; AstNode *clone() const;
@ -343,6 +350,24 @@ namespace AST
// to evaluate widths of dynamic ranges) // to evaluate widths of dynamic ranges)
AstNode *clone_at_zero(); AstNode *clone_at_zero();
void set_attribute(RTLIL::IdString key, AstNode *node)
{
attributes[key] = node;
node->set_in_param_flag(true);
}
// helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag
// can be overridden based on the intrinsic properties of this node, i.e. based on its type)
void set_in_lvalue_flag(bool flag, bool no_descend = false);
void set_in_param_flag(bool flag, bool no_descend = false);
// fix up the hierarchy flags (in_lvalue/in_param) of this node and its children
//
// to keep the flags in sync, fixup_hierarchy_flags(true) needs to be called once after
// parsing the AST to walk the full tree, then plain fixup_hierarchy_flags() performs
// localized fixups after modifying children/attributes of a particular node
void fixup_hierarchy_flags(bool force_descend = false);
// 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));
}; };

View File

@ -176,8 +176,9 @@ struct AST_INTERNAL::LookaheadRewriter
AstNode *wire = new AstNode(AST_WIRE); AstNode *wire = new AstNode(AST_WIRE);
for (auto c : node->id2ast->children) for (auto c : node->id2ast->children)
wire->children.push_back(c->clone()); wire->children.push_back(c->clone());
wire->fixup_hierarchy_flags();
wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++);
wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
wire->is_logic = true; wire->is_logic = true;
while (wire->simplify(true, false, 1, -1, false, false)) { } while (wire->simplify(true, false, 1, -1, false, false)) { }
current_ast_mod->children.push_back(wire); current_ast_mod->children.push_back(wire);
@ -1198,8 +1199,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
log_assert(range->type == AST_RANGE && range->children.size() == 2); log_assert(range->type == AST_RANGE && range->children.size() == 2);
AstNode *left = range->children.at(0)->clone(); AstNode *left = range->children.at(0)->clone();
AstNode *right = range->children.at(1)->clone(); AstNode *right = range->children.at(1)->clone();
while (left->simplify(true, false, 1, -1, false, true)) { } left->set_in_param_flag(true);
while (right->simplify(true, false, 1, -1, false, true)) { } right->set_in_param_flag(true);
while (left->simplify(true, in_lvalue, 1, -1, false, true)) { }
while (right->simplify(true, in_lvalue, 1, -1, false, true)) { }
if (left->type != AST_CONSTANT || right->type != AST_CONSTANT) if (left->type != AST_CONSTANT || right->type != AST_CONSTANT)
input_error("Function %s has non-constant width!", input_error("Function %s has non-constant width!",
RTLIL::unescape_id(str).c_str()); RTLIL::unescape_id(str).c_str());
@ -1552,7 +1555,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
children[0]->children[1]->clone() : children[0]->children[0]->clone()); children[0]->children[1]->clone() : children[0]->children[0]->clone());
fake_ast->children[0]->delete_children(); fake_ast->children[0]->delete_children();
if (member_node) if (member_node)
fake_ast->children[0]->attributes[ID::wiretype] = member_node->clone(); fake_ast->children[0]->set_attribute(ID::wiretype, member_node->clone());
int fake_ast_width = 0; int fake_ast_width = 0;
bool fake_ast_sign = true; bool fake_ast_sign = true;

View File

@ -41,6 +41,95 @@ YOSYS_NAMESPACE_BEGIN
using namespace AST; using namespace AST;
using namespace AST_INTERNAL; using namespace AST_INTERNAL;
void AstNode::set_in_lvalue_flag(bool flag, bool no_descend)
{
if (flag != in_lvalue_from_above) {
in_lvalue_from_above = flag;
if (!no_descend)
fixup_hierarchy_flags();
}
}
void AstNode::set_in_param_flag(bool flag, bool no_descend)
{
if (flag != in_param_from_above) {
in_param_from_above = flag;
if (!no_descend)
fixup_hierarchy_flags();
}
}
void AstNode::fixup_hierarchy_flags(bool force_descend)
{
// With forced descend, we disable the implicit
// descend from within the set_* functions, instead
// we do an explicit descend at the end of this function
in_param = in_param_from_above;
switch (type) {
case AST_PARAMETER:
case AST_LOCALPARAM:
case AST_DEFPARAM:
case AST_PARASET:
case AST_PREFIX:
in_param = true;
for (auto child : children)
child->set_in_param_flag(true, force_descend);
break;
case AST_REPLICATE:
case AST_WIRE:
case AST_GENIF:
case AST_GENCASE:
for (auto child : children)
child->set_in_param_flag(in_param, force_descend);
if (children.size() >= 1)
children[0]->set_in_param_flag(true, force_descend);
break;
case AST_GENFOR:
case AST_FOR:
for (auto child : children)
child->set_in_param_flag(in_param, force_descend);
if (children.size() >= 2)
children[1]->set_in_param_flag(true, force_descend);
break;
default:
in_param = in_param_from_above;
for (auto child : children)
child->set_in_param_flag(in_param, force_descend);
}
for (auto attr : attributes)
attr.second->set_in_param_flag(true, force_descend);
in_lvalue = in_lvalue_from_above;
switch (type) {
case AST_ASSIGN:
case AST_ASSIGN_EQ:
case AST_ASSIGN_LE:
if (children.size() >= 1)
children[0]->set_in_lvalue_flag(true, force_descend);
if (children.size() >= 2)
children[1]->set_in_lvalue_flag(in_lvalue, force_descend);
break;
default:
for (auto child : children)
child->set_in_lvalue_flag(in_lvalue, force_descend);
}
if (force_descend) {
for (auto child : children)
child->fixup_hierarchy_flags(true);
for (auto attr : attributes)
attr.second->fixup_hierarchy_flags(true);
}
}
// Process a format string and arguments for $display, $write, $sprintf, etc // Process a format string and arguments for $display, $write, $sprintf, etc
Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at) { Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at) {
@ -132,7 +221,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node)
RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed);
enum_item_str.append(val.as_string()); enum_item_str.append(val.as_string());
//set attribute for available val to enum item name mappings //set attribute for available val to enum item name mappings
attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); set_attribute(enum_item_str.c_str(), mkconst_str(enum_item->str));
} }
} }
} }
@ -464,7 +553,7 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de
wnode->range_valid = true; wnode->range_valid = true;
wnode->is_signed = template_node->is_signed; wnode->is_signed = template_node->is_signed;
for (auto &pair : attributes) { for (auto &pair : attributes) {
wnode->attributes[pair.first] = pair.second->clone(); wnode->set_attribute(pair.first, pair.second->clone());
} }
// make sure this node is the one in scope for this name // make sure this node is the one in scope for this name
current_scope[name] = wnode; current_scope[name] = wnode;
@ -525,7 +614,7 @@ const RTLIL::Module* AstNode::lookup_cell_module()
auto reprocess_after = [this] (const std::string &modname) { auto reprocess_after = [this] (const std::string &modname) {
if (!attributes.count(ID::reprocess_after)) if (!attributes.count(ID::reprocess_after))
attributes[ID::reprocess_after] = AstNode::mkconst_str(modname); set_attribute(ID::reprocess_after, AstNode::mkconst_str(modname));
}; };
const AstNode *celltype = nullptr; const AstNode *celltype = nullptr;
@ -705,6 +794,11 @@ AstNode *AstNode::clone_at_zero()
it = it->clone_at_zero(); it = it->clone_at_zero();
for (auto &it : that->attributes) for (auto &it : that->attributes)
it.second = it.second->clone(); it.second = it.second->clone();
that->set_in_lvalue_flag(false);
that->set_in_param_flag(false);
that->fixup_hierarchy_flags();
return that; return that;
} }
@ -743,8 +837,7 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire)
{ {
log_assert(block->type == AST_BLOCK); log_assert(block->type == AST_BLOCK);
log_assert(wire->type == AST_WIRE); log_assert(wire->type == AST_WIRE);
block->attributes[auto_nosync_prefix + wire->str] = AstNode::mkconst_int(1, block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(1, false));
false);
} }
// block names can be prefixed with an explicit scope during elaboration // block names can be prefixed with an explicit scope during elaboration
@ -785,7 +878,7 @@ static void check_auto_nosync(AstNode *node)
// mark the wire with `nosync` // mark the wire with `nosync`
AstNode *wire = it->second; AstNode *wire = it->second;
log_assert(wire->type == AST_WIRE); log_assert(wire->type == AST_WIRE);
wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
} }
// remove the attributes we've "consumed" // remove the attributes we've "consumed"
@ -806,7 +899,7 @@ static void check_auto_nosync(AstNode *node)
// //
// this function also does all name resolving and sets the id2ast member of all // this function also does all name resolving and sets the id2ast member of all
// 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 in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hint, bool sign_hint, bool in_param_)
{ {
static int recursion_counter = 0; static int recursion_counter = 0;
static bool deep_recursion_warning = false; static bool deep_recursion_warning = false;
@ -913,7 +1006,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
reg->is_signed = node->is_signed; reg->is_signed = node->is_signed;
for (auto &it : node->attributes) for (auto &it : node->attributes)
if (it.first != ID::mem2reg) if (it.first != ID::mem2reg)
reg->attributes.emplace(it.first, it.second->clone()); reg->set_attribute(it.first, it.second->clone());
reg->filename = node->filename; reg->filename = node->filename;
reg->location = node->location; reg->location = node->location;
children.push_back(reg); children.push_back(reg);
@ -994,7 +1087,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
// in certain cases a function must be evaluated constant. this is what in_param controls. // in certain cases a function must be evaluated constant. this is what in_param controls.
if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX)
in_param = true; in_param_ = true;
log_assert(in_param == in_param_);
log_assert(in_lvalue == in_lvalue_);
std::map<std::string, AstNode*> backup_scope; std::map<std::string, AstNode*> backup_scope;
@ -1015,7 +1110,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
if (!c->is_simple_const_expr()) { if (!c->is_simple_const_expr()) {
if (attributes.count(ID::dynports)) if (attributes.count(ID::dynports))
delete attributes.at(ID::dynports); delete attributes.at(ID::dynports);
attributes[ID::dynports] = AstNode::mkconst_int(1, true); set_attribute(ID::dynports, AstNode::mkconst_int(1, true));
} }
} }
} }
@ -1064,7 +1159,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
for (auto &it : node->attributes) { for (auto &it : node->attributes) {
if (first_node->attributes.count(it.first) > 0) if (first_node->attributes.count(it.first) > 0)
delete first_node->attributes[it.first]; delete first_node->attributes[it.first];
first_node->attributes[it.first] = it.second->clone(); first_node->set_attribute(it.first, it.second->clone());
} }
children.erase(children.begin()+(i--)); children.erase(children.begin()+(i--));
did_something = true; did_something = true;
@ -1261,6 +1356,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
asgn->children.push_back(arg); asgn->children.push_back(arg);
asgn->children.push_back(ident); asgn->children.push_back(ident);
} }
asgn->fixup_hierarchy_flags();
} }
@ -1382,7 +1478,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
range_left = template_node->range_left; range_left = template_node->range_left;
range_right = template_node->range_right; range_right = template_node->range_right;
attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
// Copy clones of children from template // Copy clones of children from template
for (auto template_child : template_node->children) { for (auto template_child : template_node->children) {
@ -1414,7 +1510,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) { if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) {
auto item_node = current_scope[children[0]->str]; auto item_node = current_scope[children[0]->str];
if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) { if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) {
attributes[ID::wiretype] = item_node->clone(); set_attribute(ID::wiretype, item_node->clone());
size_packed_struct(attributes[ID::wiretype], 0); size_packed_struct(attributes[ID::wiretype], 0);
add_members_to_scope(attributes[ID::wiretype], str); add_members_to_scope(attributes[ID::wiretype], str);
} }
@ -1809,7 +1905,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) {
// replace instance with wire representing the packed structure // replace instance with wire representing the packed structure
newNode = make_packed_struct(template_node, str, attributes); newNode = make_packed_struct(template_node, str, attributes);
newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
// add original input/output attribute to resolved wire // add original input/output attribute to resolved wire
newNode->is_input = this->is_input; newNode->is_input = this->is_input;
newNode->is_output = this->is_output; newNode->is_output = this->is_output;
@ -1834,7 +1930,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
range_left = template_node->range_left; range_left = template_node->range_left;
range_right = template_node->range_right; range_right = template_node->range_right;
attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
// if an enum then add attributes to support simulator tracing // if an enum then add attributes to support simulator tracing
annotateTypedEnums(template_node); annotateTypedEnums(template_node);
@ -1848,6 +1944,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
AstNode *rng = make_range(0, 0); AstNode *rng = make_range(0, 0);
children.insert(children.begin(), rng); children.insert(children.begin(), rng);
} }
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
log_assert(!is_custom_type); log_assert(!is_custom_type);
@ -1874,7 +1971,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) {
// replace with wire representing the packed structure // replace with wire representing the packed structure
newNode = make_packed_struct(template_node, str, attributes); newNode = make_packed_struct(template_node, str, attributes);
newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
newNode->type = type; newNode->type = type;
current_scope[str] = this; current_scope[str] = this;
// copy param value, it needs to be 1st value // copy param value, it needs to be 1st value
@ -1896,9 +1993,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
range_swapped = template_node->range_swapped; range_swapped = template_node->range_swapped;
range_left = template_node->range_left; range_left = template_node->range_left;
range_right = template_node->range_right; range_right = template_node->range_right;
attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
for (auto template_child : template_node->children) for (auto template_child : template_node->children)
children.push_back(template_child->clone()); children.push_back(template_child->clone());
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
log_assert(!is_custom_type); log_assert(!is_custom_type);
@ -2018,6 +2116,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
} }
delete children[1]; delete children[1];
children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true)); children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true));
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
@ -2052,6 +2151,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
else else
children[0] = new AstNode(AST_RANGE, index_expr); children[0] = new AstNode(AST_RANGE, index_expr);
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
@ -2067,6 +2167,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
children[0]->realvalue, log_signal(constvalue)); children[0]->realvalue, log_signal(constvalue));
delete children[0]; delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint); children[0] = mkconst_bits(constvalue.bits, sign_hint);
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
if (children[0]->type == AST_CONSTANT) { if (children[0]->type == AST_CONSTANT) {
@ -2076,6 +2177,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
AstNode *old_child_0 = children[0]; AstNode *old_child_0 = children[0];
children[0] = mkconst_bits(sig.as_const().bits, is_signed); children[0] = mkconst_bits(sig.as_const().bits, is_signed);
delete old_child_0; delete old_child_0;
fixup_hierarchy_flags();
} }
children[0]->is_signed = is_signed; children[0]->is_signed = is_signed;
} }
@ -2089,6 +2191,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
delete children[0]; delete children[0];
children[0] = new AstNode(AST_REALVALUE); children[0] = new AstNode(AST_REALVALUE);
children[0]->realvalue = as_realvalue; children[0]->realvalue = as_realvalue;
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
} }
@ -2105,7 +2208,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
newNode = new AstNode(AST_IDENTIFIER, range); newNode = new AstNode(AST_IDENTIFIER, range);
newNode->str = sname; newNode->str = sname;
// save type and original number of dimensions for $size() etc. // save type and original number of dimensions for $size() etc.
newNode->attributes[ID::wiretype] = item_node->clone(); newNode->set_attribute(ID::wiretype, item_node->clone());
if (!item_node->multirange_dimensions.empty() && children.size() > 0) { if (!item_node->multirange_dimensions.empty() && children.size() > 0) {
if (children[0]->type == AST_RANGE) if (children[0]->type == AST_RANGE)
newNode->integer = 1; newNode->integer = 1;
@ -2199,7 +2302,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
wire->str = wire_id; wire->str = wire_id;
if (current_block) if (current_block)
wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
current_ast_mod->children.push_back(wire); current_ast_mod->children.push_back(wire);
while (wire->simplify(true, false, 1, -1, false, false)) { } while (wire->simplify(true, false, 1, -1, false, false)) { }
@ -2387,6 +2490,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
// eval 3rd expression // eval 3rd expression
buf = next_ast->children[1]->clone(); buf = next_ast->children[1]->clone();
buf->set_in_param_flag(true);
{ {
int expr_width_hint = -1; int expr_width_hint = -1;
bool expr_sign_hint = true; bool expr_sign_hint = true;
@ -2548,6 +2652,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
continue; continue;
buf = child->clone(); buf = child->clone();
buf->set_in_param_flag(true);
while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { } while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { }
if (buf->type != AST_CONSTANT) { if (buf->type != AST_CONSTANT) {
// for (auto f : log_files) // for (auto f : log_files)
@ -2654,6 +2759,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
children.push_back(children_list.at(0)); children.push_back(children_list.at(0));
children.back()->was_checked = true; children.back()->was_checked = true;
children.push_back(node); children.push_back(node);
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
else if (str == "buf" || str == "not") else if (str == "buf" || str == "not")
@ -2704,6 +2810,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
children.push_back(children_list[0]); children.push_back(children_list[0]);
children.back()->was_checked = true; children.back()->was_checked = true;
children.push_back(node); children.push_back(node);
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
} }
@ -2782,7 +2889,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
AstNode *lvalue = children[0]->clone(); AstNode *lvalue = children[0]->clone();
lvalue->delete_children(); lvalue->delete_children();
if (member_node) if (member_node)
lvalue->attributes[ID::wiretype] = member_node->clone(); lvalue->set_attribute(ID::wiretype, member_node->clone());
lvalue->children.push_back(new AstNode(AST_RANGE, lvalue->children.push_back(new AstNode(AST_RANGE,
mkconst_int(end_bit, true), mkconst_int(start_bit, true))); mkconst_int(end_bit, true), mkconst_int(start_bit, true)));
cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone())));
@ -2795,14 +2902,14 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_mask->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
wire_mask->is_logic = true; wire_mask->is_logic = true;
while (wire_mask->simplify(true, false, 1, -1, false, false)) { } while (wire_mask->simplify(true, false, 1, -1, false, false)) { }
current_ast_mod->children.push_back(wire_mask); current_ast_mod->children.push_back(wire_mask);
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
wire_data->is_logic = true; wire_data->is_logic = true;
while (wire_data->simplify(true, false, 1, -1, false, false)) { } while (wire_data->simplify(true, false, 1, -1, false, false)) { }
current_ast_mod->children.push_back(wire_data); current_ast_mod->children.push_back(wire_data);
@ -2813,7 +2920,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true))); AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true)));
wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_sel->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
wire_sel->is_logic = true; wire_sel->is_logic = true;
wire_sel->is_signed = shamt_sign_hint; wire_sel->is_signed = shamt_sign_hint;
while (wire_sel->simplify(true, false, 1, -1, false, false)) { } while (wire_sel->simplify(true, false, 1, -1, false, false)) { }
@ -2825,7 +2932,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
AstNode *lvalue = children[0]->clone(); AstNode *lvalue = children[0]->clone();
lvalue->delete_children(); lvalue->delete_children();
if (member_node) if (member_node)
lvalue->attributes[ID::wiretype] = member_node->clone(); lvalue->set_attribute(ID::wiretype, member_node->clone());
AstNode *ref_mask = new AstNode(AST_IDENTIFIER); AstNode *ref_mask = new AstNode(AST_IDENTIFIER);
ref_mask->str = wire_mask->str; ref_mask->str = wire_mask->str;
@ -2882,6 +2989,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
t = new AstNode(AST_BIT_OR, t, ref_data); t = new AstNode(AST_BIT_OR, t, ref_data);
t = new AstNode(type, lvalue, t); t = new AstNode(type, lvalue, t);
newNode->children.push_back(t); newNode->children.push_back(t);
newNode->fixup_hierarchy_flags(true);
} }
goto apply_newNode; goto apply_newNode;
@ -2942,6 +3051,7 @@ skip_dynamic_range_lvalue_expansion:;
assign_check->children[0]->str = id_check; assign_check->children[0]->str = id_check;
assign_check->children[0]->was_checked = true; assign_check->children[0]->was_checked = true;
} }
assign_check->fixup_hierarchy_flags();
if (current_always == nullptr || current_always->type != AST_INITIAL) { if (current_always == nullptr || current_always->type != AST_INITIAL) {
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
@ -2951,6 +3061,7 @@ skip_dynamic_range_lvalue_expansion:;
} }
assign_en->children[0]->str = id_en; assign_en->children[0]->str = id_en;
assign_en->children[0]->was_checked = true; assign_en->children[0]->was_checked = true;
assign_en->fixup_hierarchy_flags();
newNode = new AstNode(AST_BLOCK); newNode = new AstNode(AST_BLOCK);
if (assign_check != nullptr) if (assign_check != nullptr)
@ -2973,6 +3084,7 @@ skip_dynamic_range_lvalue_expansion:;
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && children.size() == 1) if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && children.size() == 1)
{ {
children.push_back(mkconst_int(1, false, 1)); children.push_back(mkconst_int(1, false, 1));
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
@ -3003,7 +3115,7 @@ skip_dynamic_range_lvalue_expansion:;
wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
current_ast_mod->children.push_back(wire_tmp); current_ast_mod->children.push_back(wire_tmp);
current_scope[wire_tmp->str] = wire_tmp; current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
while (wire_tmp->simplify(true, false, 1, -1, false, false)) { } while (wire_tmp->simplify(true, false, 1, -1, false, false)) { }
wire_tmp->is_logic = true; wire_tmp->is_logic = true;
@ -3743,6 +3855,7 @@ skip_dynamic_range_lvalue_expansion:;
argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
args.push_back(children.at(i-2)->clone()); args.push_back(children.at(i-2)->clone());
args.back()->set_in_param_flag(true);
while (args.back()->simplify(true, false, stage, -1, false, true)) { } while (args.back()->simplify(true, false, stage, -1, false, true)) { }
if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE)
@ -3860,6 +3973,7 @@ skip_dynamic_range_lvalue_expansion:;
if (all_args_const) { if (all_args_const) {
AstNode *func_workspace = decl->clone(); AstNode *func_workspace = decl->clone();
func_workspace->set_in_param_flag(true);
func_workspace->str = prefix_id(prefix, "$result"); func_workspace->str = prefix_id(prefix, "$result");
newNode = func_workspace->eval_const_function(this, in_param || require_const_eval); newNode = func_workspace->eval_const_function(this, in_param || require_const_eval);
delete func_workspace; delete func_workspace;
@ -4004,9 +4118,9 @@ skip_dynamic_range_lvalue_expansion:;
wire->is_input = false; wire->is_input = false;
wire->is_output = false; wire->is_output = false;
wire->is_reg = true; wire->is_reg = true;
wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
if (child->type == AST_ENUM_ITEM) if (child->type == AST_ENUM_ITEM)
wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type]; wire->set_attribute(ID::enum_base_type, child->attributes[ID::enum_base_type]);
wire_cache[child->str] = wire; wire_cache[child->str] = wire;
@ -4045,6 +4159,7 @@ skip_dynamic_range_lvalue_expansion:;
range->children.push_back(mkconst_int(0, true)); range->children.push_back(mkconst_int(0, true));
} }
} }
wire->fixup_hierarchy_flags();
// updates the sizing // updates the sizing
while (wire->simplify(true, false, 1, -1, false, true)) { } while (wire->simplify(true, false, 1, -1, false, true)) { }
delete arg; delete arg;
@ -4364,6 +4479,7 @@ apply_newNode:
newNode->filename = filename; newNode->filename = filename;
newNode->location = location; newNode->location = location;
newNode->cloneInto(this); newNode->cloneInto(this);
fixup_hierarchy_flags();
delete newNode; delete newNode;
did_something = true; did_something = true;
} }
@ -4954,7 +5070,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
wire_addr->str = id_addr; wire_addr->str = id_addr;
wire_addr->is_reg = true; wire_addr->is_reg = true;
wire_addr->was_checked = true; wire_addr->was_checked = true;
wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
mod->children.push_back(wire_addr); mod->children.push_back(wire_addr);
while (wire_addr->simplify(true, false, 1, -1, false, false)) { } while (wire_addr->simplify(true, false, 1, -1, false, false)) { }
@ -4963,7 +5079,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
wire_data->is_reg = true; wire_data->is_reg = true;
wire_data->was_checked = true; wire_data->was_checked = true;
wire_data->is_signed = mem_signed; wire_data->is_signed = mem_signed;
wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
mod->children.push_back(wire_data); mod->children.push_back(wire_data);
while (wire_data->simplify(true, false, 1, -1, false, false)) { } while (wire_data->simplify(true, false, 1, -1, false, false)) { }
@ -4992,6 +5108,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
cond_node->children[1]->children.push_back(assign_reg); cond_node->children[1]->children.push_back(assign_reg);
case_node->children.push_back(cond_node); case_node->children.push_back(cond_node);
} }
// fixup on the full hierarchy below case_node
case_node->fixup_hierarchy_flags(true);
block->children.insert(block->children.begin()+assign_idx+2, case_node); block->children.insert(block->children.begin()+assign_idx+2, case_node);
children[0]->delete_children(); children[0]->delete_children();
@ -5001,6 +5121,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
type = AST_ASSIGN_EQ; type = AST_ASSIGN_EQ;
children[0]->was_checked = true; children[0]->was_checked = true;
fixup_hierarchy_flags();
did_something = true; did_something = true;
} }
@ -5071,7 +5192,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
wire_addr->is_reg = true; wire_addr->is_reg = true;
wire_addr->was_checked = true; wire_addr->was_checked = true;
if (block) if (block)
wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
mod->children.push_back(wire_addr); mod->children.push_back(wire_addr);
while (wire_addr->simplify(true, false, 1, -1, false, false)) { } while (wire_addr->simplify(true, false, 1, -1, false, false)) { }
@ -5081,7 +5202,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
wire_data->was_checked = true; wire_data->was_checked = true;
wire_data->is_signed = mem_signed; wire_data->is_signed = mem_signed;
if (block) if (block)
wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false));
mod->children.push_back(wire_data); mod->children.push_back(wire_data);
while (wire_data->simplify(true, false, 1, -1, false, false)) { } while (wire_data->simplify(true, false, 1, -1, false, false)) { }
@ -5115,6 +5236,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
cond_node->children[1]->children.push_back(assign_reg); cond_node->children[1]->children.push_back(assign_reg);
case_node->children.push_back(cond_node); case_node->children.push_back(cond_node);
// fixup on the full hierarchy below case_node
case_node->fixup_hierarchy_flags(true);
if (block) if (block)
{ {
size_t assign_idx = 0; size_t assign_idx = 0;
@ -5126,10 +5250,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
} }
else else
{ {
AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, case_node));
proc->children[0]->children.push_back(case_node);
mod->children.push_back(proc); mod->children.push_back(proc);
mod->children.push_back(assign_addr); mod->children.push_back(assign_addr);
mod->fixup_hierarchy_flags();
} }
delete_children(); delete_children();
@ -5138,8 +5262,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
str = id_data; str = id_data;
} }
if (bit_part_sel) if (bit_part_sel) {
children.push_back(bit_part_sel); children.push_back(bit_part_sel);
fixup_hierarchy_flags();
}
did_something = true; did_something = true;
} }
@ -5302,6 +5428,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
{ {
block->children.push_back(child->clone()); block->children.push_back(child->clone());
} }
block->set_in_param_flag(true);
while (!block->children.empty()) while (!block->children.empty())
{ {
@ -5444,6 +5571,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
AstNode *cond = stmt->children.at(0)->clone(); AstNode *cond = stmt->children.at(0)->clone();
if (!cond->replace_variables(variables, fcall, must_succeed)) if (!cond->replace_variables(variables, fcall, must_succeed))
goto finished; goto finished;
cond->set_in_param_flag(true);
while (cond->simplify(true, false, 1, -1, false, true)) { } while (cond->simplify(true, false, 1, -1, false, true)) { }
if (cond->type != AST_CONSTANT) { if (cond->type != AST_CONSTANT) {
@ -5469,6 +5597,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
AstNode *num = stmt->children.at(0)->clone(); AstNode *num = stmt->children.at(0)->clone();
if (!num->replace_variables(variables, fcall, must_succeed)) if (!num->replace_variables(variables, fcall, must_succeed))
goto finished; goto finished;
num->set_in_param_flag(true);
while (num->simplify(true, false, 1, -1, false, true)) { } while (num->simplify(true, false, 1, -1, false, true)) { }
if (num->type != AST_CONSTANT) { if (num->type != AST_CONSTANT) {
@ -5492,6 +5621,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
AstNode *expr = stmt->children.at(0)->clone(); AstNode *expr = stmt->children.at(0)->clone();
if (!expr->replace_variables(variables, fcall, must_succeed)) if (!expr->replace_variables(variables, fcall, must_succeed))
goto finished; goto finished;
expr->set_in_param_flag(true);
while (expr->simplify(true, false, 1, -1, false, true)) { } while (expr->simplify(true, false, 1, -1, false, true)) { }
AstNode *sel_case = NULL; AstNode *sel_case = NULL;
@ -5512,6 +5642,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
goto finished; goto finished;
cond = new AstNode(AST_EQ, expr->clone(), cond); cond = new AstNode(AST_EQ, expr->clone(), cond);
cond->set_in_param_flag(true);
while (cond->simplify(true, false, 1, -1, false, true)) { } while (cond->simplify(true, false, 1, -1, false, true)) { }
if (cond->type != AST_CONSTANT) { if (cond->type != AST_CONSTANT) {
@ -5547,6 +5678,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
block->children.erase(block->children.begin()); block->children.erase(block->children.begin());
block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end());
stmt->children.clear(); stmt->children.clear();
block->fixup_hierarchy_flags();
delete stmt; delete stmt;
continue; continue;
} }
@ -5581,7 +5713,7 @@ void AstNode::allocateDefaultEnumValues()
int last_enum_int = -1; int last_enum_int = -1;
for (auto node : children) { for (auto node : children) {
log_assert(node->type==AST_ENUM_ITEM); log_assert(node->type==AST_ENUM_ITEM);
node->attributes[ID::enum_base_type] = mkconst_str(str); node->set_attribute(ID::enum_base_type, mkconst_str(str));
for (size_t i = 0; i < node->children.size(); i++) { for (size_t i = 0; i < node->children.size(); i++) {
switch (node->children[i]->type) { switch (node->children[i]->type) {
case AST_NONE: case AST_NONE: