diff options
Diffstat (limited to 'passes/opt/opt_expr.cc')
-rw-r--r-- | passes/opt/opt_expr.cc | 117 |
1 files changed, 47 insertions, 70 deletions
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 9abbdc6ac..76bcfd44f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -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 |