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;
basic_prep = false;
lookahead = false;
in_lvalue_from_above = false;
in_param_from_above = false;
in_lvalue = false;
in_param = false;
if (child1)
children.push_back(child1);
@ -238,6 +242,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
children.push_back(child3);
if (child4)
children.push_back(child4);
fixup_hierarchy_flags();
}
// create a (deep recursive) copy of a node
@ -249,6 +255,10 @@ AstNode *AstNode::clone() const
it = it->clone();
for (auto &it : that->attributes)
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;
}
@ -256,10 +266,13 @@ AstNode *AstNode::clone() const
void AstNode::cloneInto(AstNode *other) const
{
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 = *tmp;
tmp->children.clear();
tmp->attributes.clear();
other->fixup_hierarchy_flags();
delete tmp;
}
@ -351,6 +364,10 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
if (is_enum) {
fprintf(f, " type=enum");
}
if (in_lvalue)
fprintf(f, " in_lvalue");
if (in_param)
fprintf(f, " in_param");
fprintf(f, "\n");
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);
}
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);
}
}
@ -1150,7 +1167,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
ast->children.swap(new_children);
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_autowire = autowire;
ast->fixup_hierarchy_flags(true);
log_assert(current_ast->type == AST_DESIGN);
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();
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;
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->fixup_hierarchy_flags(true);
(*new_ast_out) = new_ast;
return modname;
}

View File

@ -221,6 +221,13 @@ namespace AST
std::string filename;
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
AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr);
AstNode *clone() const;
@ -343,6 +350,24 @@ namespace AST
// to evaluate widths of dynamic ranges)
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
[[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);
for (auto c : node->id2ast->children)
wire->children.push_back(c->clone());
wire->fixup_hierarchy_flags();
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;
while (wire->simplify(true, false, 1, -1, false, false)) { }
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);
AstNode *left = range->children.at(0)->clone();
AstNode *right = range->children.at(1)->clone();
while (left->simplify(true, false, 1, -1, false, true)) { }
while (right->simplify(true, false, 1, -1, false, true)) { }
left->set_in_param_flag(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)
input_error("Function %s has non-constant width!",
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());
fake_ast->children[0]->delete_children();
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;
bool fake_ast_sign = true;

View File

@ -41,6 +41,95 @@ YOSYS_NAMESPACE_BEGIN
using namespace AST;
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
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);
enum_item_str.append(val.as_string());
//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->is_signed = template_node->is_signed;
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
current_scope[name] = wnode;
@ -525,7 +614,7 @@ const RTLIL::Module* AstNode::lookup_cell_module()
auto reprocess_after = [this] (const std::string &modname) {
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;
@ -705,6 +794,11 @@ AstNode *AstNode::clone_at_zero()
it = it->clone_at_zero();
for (auto &it : that->attributes)
it.second = it.second->clone();
that->set_in_lvalue_flag(false);
that->set_in_param_flag(false);
that->fixup_hierarchy_flags();
return that;
}
@ -743,8 +837,7 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire)
{
log_assert(block->type == AST_BLOCK);
log_assert(wire->type == AST_WIRE);
block->attributes[auto_nosync_prefix + wire->str] = AstNode::mkconst_int(1,
false);
block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(1, false));
}
// 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`
AstNode *wire = it->second;
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"
@ -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
// 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 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;
for (auto &it : node->attributes)
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->location = node->location;
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.
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;
@ -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 (attributes.count(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) {
if (first_node->attributes.count(it.first) > 0)
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--));
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(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_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
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) {
auto item_node = current_scope[children[0]->str];
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);
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)) {
// replace instance with wire representing the packed structure
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
newNode->is_input = this->is_input;
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_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
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);
children.insert(children.begin(), rng);
}
fixup_hierarchy_flags();
did_something = true;
}
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) {
// replace with wire representing the packed structure
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;
current_scope[str] = this;
// 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_left = template_node->range_left;
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)
children.push_back(template_child->clone());
fixup_hierarchy_flags();
did_something = true;
}
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];
children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true));
fixup_hierarchy_flags();
did_something = true;
}
@ -2052,6 +2151,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
else
children[0] = new AstNode(AST_RANGE, index_expr);
fixup_hierarchy_flags();
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));
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
fixup_hierarchy_flags();
did_something = true;
}
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];
children[0] = mkconst_bits(sig.as_const().bits, is_signed);
delete old_child_0;
fixup_hierarchy_flags();
}
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];
children[0] = new AstNode(AST_REALVALUE);
children[0]->realvalue = as_realvalue;
fixup_hierarchy_flags();
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->str = sname;
// 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 (children[0]->type == AST_RANGE)
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)));
wire->str = wire_id;
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);
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
buf = next_ast->children[1]->clone();
buf->set_in_param_flag(true);
{
int expr_width_hint = -1;
bool expr_sign_hint = true;
@ -2548,6 +2652,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
continue;
buf = child->clone();
buf->set_in_param_flag(true);
while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { }
if (buf->type != AST_CONSTANT) {
// 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.back()->was_checked = true;
children.push_back(node);
fixup_hierarchy_flags();
did_something = true;
}
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.back()->was_checked = true;
children.push_back(node);
fixup_hierarchy_flags();
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();
lvalue->delete_children();
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,
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())));
@ -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)));
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;
while (wire_mask->simplify(true, false, 1, -1, false, false)) { }
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)));
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;
while (wire_data->simplify(true, false, 1, -1, false, false)) { }
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)));
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_signed = shamt_sign_hint;
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();
lvalue->delete_children();
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);
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(type, lvalue, t);
newNode->children.push_back(t);
newNode->fixup_hierarchy_flags(true);
}
goto apply_newNode;
@ -2942,6 +3051,7 @@ skip_dynamic_range_lvalue_expansion:;
assign_check->children[0]->str = id_check;
assign_check->children[0]->was_checked = true;
}
assign_check->fixup_hierarchy_flags();
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));
@ -2951,6 +3061,7 @@ skip_dynamic_range_lvalue_expansion:;
}
assign_en->children[0]->str = id_en;
assign_en->children[0]->was_checked = true;
assign_en->fixup_hierarchy_flags();
newNode = new AstNode(AST_BLOCK);
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)
{
children.push_back(mkconst_int(1, false, 1));
fixup_hierarchy_flags();
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++);
current_ast_mod->children.push_back(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)) { }
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));
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)) { }
if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE)
@ -3860,6 +3973,7 @@ skip_dynamic_range_lvalue_expansion:;
if (all_args_const) {
AstNode *func_workspace = decl->clone();
func_workspace->set_in_param_flag(true);
func_workspace->str = prefix_id(prefix, "$result");
newNode = func_workspace->eval_const_function(this, in_param || require_const_eval);
delete func_workspace;
@ -4004,9 +4118,9 @@ skip_dynamic_range_lvalue_expansion:;
wire->is_input = false;
wire->is_output = false;
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)
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;
@ -4045,6 +4159,7 @@ skip_dynamic_range_lvalue_expansion:;
range->children.push_back(mkconst_int(0, true));
}
}
wire->fixup_hierarchy_flags();
// updates the sizing
while (wire->simplify(true, false, 1, -1, false, true)) { }
delete arg;
@ -4364,6 +4479,7 @@ apply_newNode:
newNode->filename = filename;
newNode->location = location;
newNode->cloneInto(this);
fixup_hierarchy_flags();
delete newNode;
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->is_reg = 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);
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->was_checked = true;
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);
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);
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);
children[0]->delete_children();
@ -5001,6 +5121,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
type = AST_ASSIGN_EQ;
children[0]->was_checked = true;
fixup_hierarchy_flags();
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->was_checked = true;
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);
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->is_signed = mem_signed;
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);
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);
case_node->children.push_back(cond_node);
// fixup on the full hierarchy below case_node
case_node->fixup_hierarchy_flags(true);
if (block)
{
size_t assign_idx = 0;
@ -5126,10 +5250,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
}
else
{
AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK));
proc->children[0]->children.push_back(case_node);
AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, case_node));
mod->children.push_back(proc);
mod->children.push_back(assign_addr);
mod->fixup_hierarchy_flags();
}
delete_children();
@ -5138,8 +5262,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
str = id_data;
}
if (bit_part_sel)
if (bit_part_sel) {
children.push_back(bit_part_sel);
fixup_hierarchy_flags();
}
did_something = true;
}
@ -5302,6 +5428,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
{
block->children.push_back(child->clone());
}
block->set_in_param_flag(true);
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();
if (!cond->replace_variables(variables, fcall, must_succeed))
goto finished;
cond->set_in_param_flag(true);
while (cond->simplify(true, false, 1, -1, false, true)) { }
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();
if (!num->replace_variables(variables, fcall, must_succeed))
goto finished;
num->set_in_param_flag(true);
while (num->simplify(true, false, 1, -1, false, true)) { }
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();
if (!expr->replace_variables(variables, fcall, must_succeed))
goto finished;
expr->set_in_param_flag(true);
while (expr->simplify(true, false, 1, -1, false, true)) { }
AstNode *sel_case = NULL;
@ -5512,6 +5642,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
goto finished;
cond = new AstNode(AST_EQ, expr->clone(), cond);
cond->set_in_param_flag(true);
while (cond->simplify(true, false, 1, -1, false, true)) { }
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.insert(block->children.begin(), stmt->children.begin(), stmt->children.end());
stmt->children.clear();
block->fixup_hierarchy_flags();
delete stmt;
continue;
}
@ -5581,7 +5713,7 @@ void AstNode::allocateDefaultEnumValues()
int last_enum_int = -1;
for (auto node : children) {
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++) {
switch (node->children[i]->type) {
case AST_NONE: