mirror of https://github.com/YosysHQ/yosys.git
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:
parent
10d0e69588
commit
22b99413e8
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue