mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-24 01:25:33 +00:00
opt_expr: improve simplification of comparisons with large constants.
The idea behind this simplification is that a N-bit signal X being compared with an M-bit constant where M>N and the constant has Nth or higher bit set, it either always succeeds or always fails. However, the existing implementation only worked with one-hot signals for some reason. It also printed incorrect messages. This commit adjusts the simplification to have as much power as possible, and fixes other bugs.
This commit is contained in:
parent
4fd458290c
commit
bf8db55ef3
2 changed files with 65 additions and 70 deletions
|
@ -259,6 +259,22 @@ bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative)
|
|||
return last_bit_one;
|
||||
}
|
||||
|
||||
int get_highest_hot_index(RTLIL::SigSpec signal)
|
||||
{
|
||||
for (int i = GetSize(signal) - 1; i >= 0; i--)
|
||||
{
|
||||
if (signal[i] == RTLIL::State::S0)
|
||||
continue;
|
||||
|
||||
if (signal[i] == RTLIL::State::S1)
|
||||
return i;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if the signal has only one bit set, return the index of that bit.
|
||||
// otherwise return -1
|
||||
int get_onehot_bit_index(RTLIL::SigSpec signal)
|
||||
|
@ -1345,9 +1361,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
|
|||
}
|
||||
|
||||
// simplify comparisons
|
||||
// currently, only replaces comparisons with an extreme of the signal range with a constant
|
||||
// TODO: since, unlike the following optimization, this one does not assume that both inputs to the cell are constant,
|
||||
// it is more robust; the following optimization should be folded into this one at some point
|
||||
if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
|
||||
{
|
||||
IdString cmp_type = cell->type;
|
||||
|
@ -1405,29 +1418,53 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
|
|||
replace = true;
|
||||
}
|
||||
|
||||
int const_bit_set = get_onehot_bit_index(const_sig);
|
||||
if (const_bit_set >= 0 && const_bit_set < var_width)
|
||||
int const_bit_hot = get_onehot_bit_index(const_sig);
|
||||
if (const_bit_hot >= 0 && const_bit_hot < var_width)
|
||||
{
|
||||
RTLIL::SigSpec var_high_sig(RTLIL::State::S0, var_width - const_bit_set);
|
||||
for (int i = const_bit_set; i < var_width; i++) {
|
||||
var_high_sig[i - const_bit_set] = var_sig[i];
|
||||
RTLIL::SigSpec var_high_sig(RTLIL::State::S0, var_width - const_bit_hot);
|
||||
for (int i = const_bit_hot; i < var_width; i++) {
|
||||
var_high_sig[i - const_bit_hot] = var_sig[i];
|
||||
}
|
||||
|
||||
if (cmp_type == "$lt")
|
||||
{
|
||||
condition = stringf("unsigned X<%s", log_signal(const_sig));
|
||||
replacement = stringf("!X[%d:%d]", var_width - 1, const_bit_set);
|
||||
replacement = stringf("!X[%d:%d]", var_width - 1, const_bit_hot);
|
||||
module->addLogicNot(NEW_ID, var_high_sig, cell->getPort("\\Y"));
|
||||
remove = true;
|
||||
}
|
||||
if (cmp_type == "$ge")
|
||||
{
|
||||
condition = stringf("unsigned X>=%s", log_signal(const_sig));
|
||||
replacement = stringf("|X[%d:%d]", var_width - 1, const_bit_set);
|
||||
replacement = stringf("|X[%d:%d]", var_width - 1, const_bit_hot);
|
||||
module->addReduceOr(NEW_ID, var_high_sig, cell->getPort("\\Y"));
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
|
||||
int const_bit_set = get_highest_hot_index(const_sig);
|
||||
if(const_bit_set >= var_width)
|
||||
{
|
||||
string cmp_name;
|
||||
if (cmp_type == "$lt" || cmp_type == "$le")
|
||||
{
|
||||
if (cmp_type == "$lt") cmp_name = "<";
|
||||
if (cmp_type == "$le") cmp_name = "<=";
|
||||
condition = stringf("unsigned X[%d:0]%s%s", var_width - 1, cmp_name.c_str(), log_signal(const_sig));
|
||||
replacement = "constant 1";
|
||||
replace_sig[0] = State::S1;
|
||||
replace = true;
|
||||
}
|
||||
if (cmp_type == "$gt" || cmp_type == "$ge")
|
||||
{
|
||||
if (cmp_type == "$gt") cmp_name = ">";
|
||||
if (cmp_type == "$ge") cmp_name = ">=";
|
||||
condition = stringf("unsigned X[%d:0]%s%s", var_width - 1, cmp_name.c_str(), log_signal(const_sig));
|
||||
replacement = "constant 0";
|
||||
replace_sig[0] = State::S0;
|
||||
replace = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* signed */
|
||||
|
@ -1460,66 +1497,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
|
|||
}
|
||||
}
|
||||
|
||||
// replace a<0 or a>=0 with the top bit of a
|
||||
if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le"))
|
||||
{
|
||||
//used to decide whether the signal needs to be negated
|
||||
bool is_lt = false;
|
||||
|
||||
//references the variable signal in the comparison
|
||||
RTLIL::SigSpec sigVar;
|
||||
|
||||
//references the constant signal in the comparison
|
||||
RTLIL::SigSpec sigConst;
|
||||
|
||||
// note that this signal must be constant for the optimization
|
||||
// to take place, but it is not checked beforehand.
|
||||
// If new passes are added, this signal must be checked for const-ness
|
||||
|
||||
//width of the variable port
|
||||
int width;
|
||||
int const_width;
|
||||
|
||||
bool var_signed;
|
||||
|
||||
if (cell->type == "$lt" || cell->type == "$ge") {
|
||||
is_lt = cell->type == "$lt" ? 1 : 0;
|
||||
sigVar = cell->getPort("\\A");
|
||||
sigConst = cell->getPort("\\B");
|
||||
width = cell->parameters["\\A_WIDTH"].as_int();
|
||||
const_width = cell->parameters["\\B_WIDTH"].as_int();
|
||||
var_signed = cell->parameters["\\A_SIGNED"].as_bool();
|
||||
} else
|
||||
if (cell->type == "$gt" || cell->type == "$le") {
|
||||
is_lt = cell->type == "$gt" ? 1 : 0;
|
||||
sigVar = cell->getPort("\\B");
|
||||
sigConst = cell->getPort("\\A");
|
||||
width = cell->parameters["\\B_WIDTH"].as_int();
|
||||
const_width = cell->parameters["\\A_WIDTH"].as_int();
|
||||
var_signed = cell->parameters["\\B_SIGNED"].as_bool();
|
||||
} else
|
||||
log_abort();
|
||||
|
||||
if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false)
|
||||
{
|
||||
int const_bit_set = get_onehot_bit_index(sigConst);
|
||||
if(const_bit_set >= width && const_bit_set >= 0){
|
||||
RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
|
||||
if(is_lt){
|
||||
a_prime[0] = RTLIL::State::S1;
|
||||
log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
|
||||
}
|
||||
else{
|
||||
log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
|
||||
}
|
||||
module->connect(cell->getPort("\\Y"), a_prime);
|
||||
module->remove(cell);
|
||||
did_something = true;
|
||||
goto next_cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next_cell:;
|
||||
#undef ACTION_DO
|
||||
#undef ACTION_DO_Y
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue