mirror of https://github.com/YosysHQ/yosys.git
Various ast changes for early expression width detection (prep for constfold fixes)
This commit is contained in:
parent
0b4a64ac6a
commit
943329c1dc
|
@ -646,12 +646,37 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
|
|||
return node;
|
||||
}
|
||||
|
||||
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
|
||||
{
|
||||
std::vector<RTLIL::State> bits = this->bits;
|
||||
if (width >= 0 && width < int(bits.size()))
|
||||
bits.resize(width);
|
||||
if (width >= 0 && width > int(bits.size())) {
|
||||
RTLIL::State extbit = RTLIL::State::S0;
|
||||
if (is_signed && !bits.empty())
|
||||
extbit = bits.back();
|
||||
while (width > int(bits.size()))
|
||||
bits.push_back(extbit);
|
||||
}
|
||||
return RTLIL::Const(bits);
|
||||
}
|
||||
|
||||
RTLIL::Const AstNode::bitsAsConst(int width)
|
||||
{
|
||||
return bitsAsConst(width, is_signed);
|
||||
}
|
||||
|
||||
// create a new AstModule from an AST_MODULE AST node
|
||||
static AstModule* process_module(AstNode *ast)
|
||||
{
|
||||
assert(ast->type == AST_MODULE);
|
||||
log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
|
||||
|
||||
current_module = new AstModule;
|
||||
current_module->ast = NULL;
|
||||
current_module->name = ast->str;
|
||||
current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
|
||||
|
||||
current_ast_mod = ast;
|
||||
AstNode *ast_before_simplify = ast->clone();
|
||||
|
||||
|
@ -661,7 +686,7 @@ static AstModule* process_module(AstNode *ast)
|
|||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
while (ast->simplify(!flag_noopt, false, false, 0)) { }
|
||||
while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
|
||||
|
||||
if (flag_dump_ast2) {
|
||||
log("Dumping verilog AST after simplification:\n");
|
||||
|
@ -687,11 +712,6 @@ static AstModule* process_module(AstNode *ast)
|
|||
ast->attributes["\\placeholder"] = AstNode::mkconst_int(1, false);
|
||||
}
|
||||
|
||||
current_module = new AstModule;
|
||||
current_module->ast = NULL;
|
||||
current_module->name = ast->str;
|
||||
current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
|
||||
|
||||
ignoreThisSignalsInInitial = RTLIL::SigSpec();
|
||||
|
||||
for (auto &attr : ast->attributes) {
|
||||
|
|
|
@ -164,7 +164,7 @@ namespace AST
|
|||
|
||||
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
|
||||
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
|
||||
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage);
|
||||
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint);
|
||||
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
|
||||
void replace_ids(std::map<std::string, std::string> &rules);
|
||||
void mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<AstNode*> &mem2reg_candidates, bool sync_proc, bool async_proc, bool force_mem2reg);
|
||||
|
@ -193,6 +193,10 @@ namespace AST
|
|||
// helper functions for creating AST nodes for constants
|
||||
static AstNode *mkconst_int(uint32_t v, bool is_signed, int width = 32);
|
||||
static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed);
|
||||
|
||||
// helper function for creating sign-extended const objects
|
||||
RTLIL::Const bitsAsConst(int width, bool is_signed);
|
||||
RTLIL::Const bitsAsConst(int width = -1);
|
||||
};
|
||||
|
||||
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
|
||||
|
|
|
@ -508,8 +508,10 @@ struct AST_INTERNAL::ProcessGenerator
|
|||
void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
|
||||
{
|
||||
std::string type_name;
|
||||
bool dummy_sign_hint = true;
|
||||
// int dummy_width_hint = -1;
|
||||
bool sub_sign_hint = true;
|
||||
int sub_width_hint = -1;
|
||||
int this_width = 0;
|
||||
AstNode *range = NULL;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
@ -520,23 +522,81 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
|
|||
break;
|
||||
|
||||
case AST_IDENTIFIER:
|
||||
if ((id2ast && !id2ast->is_signed) || children.size() > 0)
|
||||
sign_hint = false;
|
||||
width_hint = std::max(width_hint, genRTLIL().width);
|
||||
if (!id2ast)
|
||||
log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
if ((id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) && id2ast->children[0]->type == AST_CONSTANT) {
|
||||
this_width = id2ast->children[0]->bits.size();
|
||||
if (children.size() != 0)
|
||||
range = children[0];
|
||||
} else if (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE) {
|
||||
if (!id2ast->range_valid) {
|
||||
if (id2ast->type == AST_AUTOWIRE)
|
||||
this_width = 1;
|
||||
else {
|
||||
current_ast_mod->dumpAst(stdout, "");
|
||||
printf("---\n");
|
||||
dumpAst(stdout, "");
|
||||
fflush(stdout);
|
||||
log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
}
|
||||
} else {
|
||||
this_width = id2ast->range_left - id2ast->range_right + 1;
|
||||
if (children.size() != 0)
|
||||
range = children[0];
|
||||
}
|
||||
} else if (id2ast->type == AST_GENVAR) {
|
||||
this_width = 32;
|
||||
} else if (id2ast->type == AST_MEMORY) {
|
||||
if (!id2ast->children[0]->range_valid)
|
||||
log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
|
||||
} else
|
||||
log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
|
||||
if (range) {
|
||||
if (range->children.size() == 1)
|
||||
this_width = 1;
|
||||
else if (!range->range_valid) {
|
||||
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
|
||||
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
|
||||
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
|
||||
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
|
||||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
|
||||
delete left_at_zero_ast;
|
||||
delete right_at_zero_ast;
|
||||
} else
|
||||
this_width = range->range_left - range->range_right + 1;
|
||||
} else
|
||||
width_hint = std::max(width_hint, this_width);
|
||||
break;
|
||||
|
||||
case AST_TO_SIGNED:
|
||||
children.at(0)->detectSignWidthWorker(width_hint, dummy_sign_hint);
|
||||
children.at(0)->detectSignWidthWorker(width_hint, sub_sign_hint);
|
||||
break;
|
||||
|
||||
case AST_TO_UNSIGNED:
|
||||
children.at(0)->detectSignWidthWorker(width_hint, dummy_sign_hint);
|
||||
children.at(0)->detectSignWidthWorker(width_hint, sub_sign_hint);
|
||||
sign_hint = false;
|
||||
break;
|
||||
|
||||
case AST_CONCAT:
|
||||
for (auto child : children) {
|
||||
sub_width_hint = 0;
|
||||
sub_sign_hint = true;
|
||||
child->detectSignWidthWorker(width_hint, sign_hint);
|
||||
this_width += sub_width_hint;
|
||||
}
|
||||
width_hint = std::max(width_hint, this_width);
|
||||
sign_hint = false;
|
||||
break;
|
||||
|
||||
case AST_REPLICATE:
|
||||
width_hint = std::max(width_hint, genRTLIL().width);
|
||||
if (children[0]->type != AST_CONSTANT)
|
||||
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
|
||||
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
|
||||
width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
|
||||
sign_hint = false;
|
||||
break;
|
||||
|
||||
|
@ -797,8 +857,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
if (!children[0]->range_valid) {
|
||||
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
|
||||
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
|
||||
while (left_at_zero_ast->simplify(true, true, false, 1)) { }
|
||||
while (right_at_zero_ast->simplify(true, true, false, 1)) { }
|
||||
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
|
||||
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
|
||||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
|
|
|
@ -43,7 +43,7 @@ using namespace AST_INTERNAL;
|
|||
//
|
||||
// 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 at_zero, bool in_lvalue, int stage)
|
||||
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint)
|
||||
{
|
||||
AstNode *newNode = NULL;
|
||||
bool did_something = false;
|
||||
|
@ -52,7 +52,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
{
|
||||
assert(type == AST_MODULE);
|
||||
|
||||
while (simplify(const_fold, at_zero, in_lvalue, 1)) { }
|
||||
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint)) { }
|
||||
|
||||
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
|
||||
{
|
||||
|
@ -71,6 +71,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
reg->is_reg = true;
|
||||
reg->is_signed = node->is_signed;
|
||||
children.push_back(reg);
|
||||
while (reg->simplify(true, false, false, 1, -1, false)) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +85,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
}
|
||||
}
|
||||
|
||||
while (simplify(const_fold, at_zero, in_lvalue, 2)) { }
|
||||
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint)) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -174,6 +175,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
auto backup_current_block_child = current_block_child;
|
||||
auto backup_current_top_block = current_top_block;
|
||||
|
||||
// calculate width and sign hints
|
||||
if (type == AST_RANGE) {
|
||||
width_hint = -1;
|
||||
sign_hint = false;
|
||||
}
|
||||
if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE || type == AST_ASSIGN) {
|
||||
while (children[0]->simplify(false, at_zero, true, stage, -1, false) == true) { }
|
||||
children[0]->detectSignWidth(width_hint, sign_hint);
|
||||
}
|
||||
|
||||
// simplify all children first
|
||||
// (iterate by index as e.g. auto wires can add new children in the process)
|
||||
for (size_t i = 0; i < children.size(); i++) {
|
||||
|
@ -188,6 +199,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
break;
|
||||
while (did_something_here && i < children.size()) {
|
||||
bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
|
||||
int width_hint_here = width_hint;
|
||||
bool sign_hint_here = sign_hint;
|
||||
if (i == 0 && type == AST_REPLICATE)
|
||||
const_fold_here = true;
|
||||
if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE))
|
||||
|
@ -198,13 +211,17 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
}
|
||||
if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK)
|
||||
current_top_block = children[i];
|
||||
did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage);
|
||||
if (i == 1 && (type == AST_SHIFT_LEFT || type == AST_SHIFT_RIGHT || type == AST_SHIFT_SLEFT || type == AST_SHIFT_SRIGHT)) {
|
||||
while (children[i]->simplify(false, at_zero, in_lvalue_here, stage, -1, false) == true) { }
|
||||
children[i]->detectSignWidth(width_hint_here, sign_hint_here);
|
||||
}
|
||||
did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here);
|
||||
if (did_something_here)
|
||||
did_something = true;
|
||||
}
|
||||
}
|
||||
for (auto &attr : attributes) {
|
||||
while (attr.second->simplify(true, false, false, stage)) { }
|
||||
while (attr.second->simplify(true, false, false, stage, -1, false)) { }
|
||||
}
|
||||
|
||||
current_block = backup_current_block;
|
||||
|
@ -351,7 +368,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
|
||||
// eval 1st expression
|
||||
AstNode *varbuf = init_ast->children[1]->clone();
|
||||
while (varbuf->simplify(true, false, false, stage)) { }
|
||||
while (varbuf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
|
||||
|
||||
if (varbuf->type != AST_CONSTANT)
|
||||
log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
|
||||
|
@ -373,7 +390,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
{
|
||||
// eval 2nd expression
|
||||
AstNode *buf = while_ast->clone();
|
||||
while (buf->simplify(true, false, false, stage)) { }
|
||||
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
|
||||
|
||||
if (buf->type != AST_CONSTANT)
|
||||
log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
|
||||
|
@ -412,7 +429,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
|
||||
// eval 3rd expression
|
||||
buf = next_ast->children[1]->clone();
|
||||
while (buf->simplify(true, false, false, stage)) { }
|
||||
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
|
||||
|
||||
if (buf->type != AST_CONSTANT)
|
||||
log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
|
||||
|
@ -446,7 +463,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
if (type == AST_GENIF && children.size() != 0)
|
||||
{
|
||||
AstNode *buf = children[0]->clone();
|
||||
while (buf->simplify(true, false, false, stage)) { }
|
||||
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
|
||||
if (buf->type != AST_CONSTANT) {
|
||||
for (auto f : log_files)
|
||||
dumpAst(f, "verilog-ast> ");
|
||||
|
@ -584,8 +601,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
|
|||
shift_expr = range->children[1]->clone();
|
||||
AstNode *left_at_zero_ast = range->children[0]->clone();
|
||||
AstNode *right_at_zero_ast = range->children[1]->clone();
|
||||
while (left_at_zero_ast->simplify(true, true, false, stage)) { }
|
||||
while (right_at_zero_ast->simplify(true, true, false, stage)) { }
|
||||
while (left_at_zero_ast->simplify(true, true, false, stage, -1, false)) { }
|
||||
while (right_at_zero_ast->simplify(true, true, false, stage, -1, false)) { }
|
||||
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
|
||||
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
|
||||
str.c_str(), filename.c_str(), linenum);
|
||||
|
@ -636,16 +653,19 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
wire_addr->str = id_addr;
|
||||
current_ast_mod->children.push_back(wire_addr);
|
||||
current_scope[wire_addr->str] = wire_addr;
|
||||
while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||
wire_data->str = id_data;
|
||||
current_ast_mod->children.push_back(wire_data);
|
||||
current_scope[wire_data->str] = wire_data;
|
||||
while (wire_data->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
AstNode *wire_en = new AstNode(AST_WIRE);
|
||||
wire_en->str = id_en;
|
||||
current_ast_mod->children.push_back(wire_en);
|
||||
current_scope[wire_en->str] = wire_en;
|
||||
while (wire_en->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
std::vector<RTLIL::State> x_bits;
|
||||
x_bits.push_back(RTLIL::State::Sx);
|
||||
|
@ -749,6 +769,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
wire->is_input = false;
|
||||
wire->is_output = false;
|
||||
current_ast_mod->children.push_back(wire);
|
||||
while (wire->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
replace_rules[child->str] = wire->str;
|
||||
|
||||
|
@ -899,8 +920,8 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
if (0) { case AST_POS: const_func = RTLIL::const_pos; }
|
||||
if (0) { case AST_NEG: const_func = RTLIL::const_neg; }
|
||||
if (children[0]->type == AST_CONSTANT) {
|
||||
RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1);
|
||||
newNode = mkconst_bits(y.bits, children[0]->is_signed);
|
||||
RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint), dummy_arg, sign_hint, false, width_hint);
|
||||
newNode = mkconst_bits(y.bits, sign_hint);
|
||||
}
|
||||
break;
|
||||
case AST_TERNARY:
|
||||
|
@ -1048,12 +1069,14 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
|
|||
wire_addr->is_reg = true;
|
||||
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||
mod->children.push_back(wire_addr);
|
||||
while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||
wire_data->str = id_data;
|
||||
wire_data->is_reg = true;
|
||||
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||
mod->children.push_back(wire_data);
|
||||
while (wire_data->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
assert(block != NULL);
|
||||
size_t assign_idx = 0;
|
||||
|
@ -1099,11 +1122,13 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
|
|||
wire_addr->str = id_addr;
|
||||
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||
mod->children.push_back(wire_addr);
|
||||
while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||
wire_data->str = id_data;
|
||||
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||
mod->children.push_back(wire_data);
|
||||
while (wire_data->simplify(true, false, false, 1, -1, false)) { }
|
||||
|
||||
AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
|
||||
assign_addr->children[0]->str = id_addr;
|
||||
|
|
|
@ -73,3 +73,10 @@ module test10(a, b, c, y);
|
|||
assign y = ^(a ? b : c);
|
||||
endmodule
|
||||
|
||||
module test11(a, b, y);
|
||||
input signed [3:0] a;
|
||||
input signed [3:0] b;
|
||||
output signed [5:0] y;
|
||||
assign y = -(5'd27);
|
||||
endmodule
|
||||
|
||||
|
|
Loading…
Reference in New Issue