diff options
-rw-r--r-- | passes/opt/opt_expr.cc | 68 | ||||
-rw-r--r-- | tests/opt/opt_expr_cmp.v | 5 |
2 files changed, 42 insertions, 31 deletions
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 989c949ce..9abbdc6ac 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1374,35 +1374,60 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (const_sig.is_fully_def() && const_sig.is_fully_const()) { std::string condition, replacement; - SigSpec result_sig(State::S0, GetSize(cell->getPort("\\Y"))); + SigSpec replace_sig(State::S0, GetSize(cell->getPort("\\Y"))); bool replace = false; + bool remove = false; if (!is_signed) { /* unsigned */ if (const_sig.is_fully_zero() && cmp_type == "$lt") { condition = "unsigned X<0"; replacement = "constant 0"; - result_sig[0] = State::S0; + replace_sig[0] = State::S0; replace = true; } if (const_sig.is_fully_zero() && cmp_type == "$ge") { condition = "unsigned X>=0"; replacement = "constant 1"; - result_sig[0] = State::S1; + replace_sig[0] = State::S1; replace = true; } if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == "$gt") { condition = "unsigned X>~0"; replacement = "constant 0"; - result_sig[0] = State::S0; + replace_sig[0] = State::S0; replace = true; } if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == "$le") { condition = "unsigned X<=~0"; replacement = "constant 1"; - result_sig[0] = State::S1; + replace_sig[0] = State::S1; replace = true; } + + int const_bit_set = get_onehot_bit_index(const_sig); + if (const_bit_set >= 0 && const_bit_set < 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]; + } + + if (cmp_type == "$lt") + { + condition = stringf("unsigned X<%s", log_signal(const_sig)); + replacement = stringf("!X[%d:%d]", var_width - 1, const_bit_set); + 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); + module->addReduceOr(NEW_ID, var_high_sig, cell->getPort("\\Y")); + remove = true; + } + } } else { /* signed */ @@ -1410,23 +1435,24 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { condition = "signed X<0"; replacement = stringf("X[%d]", var_width - 1); - result_sig[0] = var_sig[var_width - 1]; + replace_sig[0] = var_sig[var_width - 1]; replace = true; } if (const_sig.is_fully_zero() && cmp_type == "$ge") { condition = "signed X>=0"; replacement = stringf("X[%d]", var_width - 1); - module->addNot(NEW_ID, var_sig[var_width - 1], result_sig); - replace = true; + module->addNot(NEW_ID, var_sig[var_width - 1], cell->getPort("\\Y")); + remove = true; } } - if (replace) + if (replace || remove) { log("Replacing %s cell `%s' (implementing %s) with %s.\n", log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str()); - module->connect(cell->getPort("\\Y"), result_sig); + if (replace) + module->connect(cell->getPort("\\Y"), replace_sig); module->remove(cell); did_something = true; goto next_cell; @@ -1477,26 +1503,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons 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 >= 0 && const_bit_set < width) { - int bit_set = const_bit_set; - RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set); - for (int i = bit_set; i < width; i++) { - a_prime[i - bit_set] = sigVar[i]; - } - if (is_lt) { - log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n", - log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime)); - module->addLogicNot(NEW_ID, a_prime, cell->getPort("\\Y")); - } else { - log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n", - log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime)); - module->addReduceOr(NEW_ID, a_prime, cell->getPort("\\Y")); - } - module->remove(cell); - did_something = true; - goto next_cell; - } - else if(const_bit_set >= width && const_bit_set >= 0){ + 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; @@ -1509,7 +1516,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons module->remove(cell); did_something = true; goto next_cell; - } } } diff --git a/tests/opt/opt_expr_cmp.v b/tests/opt/opt_expr_cmp.v index 72372bdf0..500b15f1b 100644 --- a/tests/opt/opt_expr_cmp.v +++ b/tests/opt/opt_expr_cmp.v @@ -14,4 +14,9 @@ module top(...); output o2_2 = 4'sb0000 <= $signed(a); output o2_3 = $signed(a) < 4'sb0000; output o2_4 = $signed(a) >= 4'sb0000; + + output o3_1 = 4'b0100 > a; + output o3_2 = 4'b0100 <= a; + output o3_3 = a < 4'b0100; + output o3_4 = a >= 4'b0100; endmodule |