peepopt: limit padding from shiftadd

The input to a shift operation is padded.
This reduced the final number of MUX cells
but during techmap it can create huge
temporary multiplexers in the log shifter.
This significantly increases runtime and resources.

A limit is added with a warning when it is used.
This commit is contained in:
Philippe Sauter 2024-06-14 15:30:03 +02:00
parent 62bff3a204
commit 2f0f10cb87
2 changed files with 23 additions and 3 deletions

View File

@ -25,6 +25,9 @@ PRIVATE_NAMESPACE_BEGIN
bool did_something;
// scratchpad configurations for pmgen
int shiftadd_max_ratio;
#include "passes/pmgen/peepopt_pm.h"
struct PeepoptPass : public Pass {
@ -50,6 +53,9 @@ struct PeepoptPass : public Pass {
log("\n");
log(" * shiftadd - Replace A>>(B+D) with (A'>>D)>>(B) where D is constant and\n");
log(" A' is derived from A by padding or cutting inaccessible bits.\n");
log(" Scratchpad: 'peepopt.shiftadd.max_data_multiple' (default: 2)\n");
log(" limits the amount of padding to a multiple of the data, \n");
log(" to avoid high resource usage from large temporary MUX trees.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
@ -63,6 +69,11 @@ struct PeepoptPass : public Pass {
}
extra_args(args, argidx, design);
// limit the padding from shiftadd to a multiple of the input data
// during techmap it creates (#data + #padding) * log(shift) $_MUX_ cells
// 2x implies there is a constant shift larger than the input-data which should be extremely rare
shiftadd_max_ratio = design->scratchpad_get_int("peepopt.shiftadd.max_data_multiple", 2);
for (auto module : design->selected_modules())
{
did_something = true;

View File

@ -91,11 +91,21 @@ code
// it should only differ if previous passes create invalid data
log_assert(!(offset>0 && var_signed));
SigSpec old_a = port(shift, \A); // data
std::string location = shift->get_src_attribute();
if(shiftadd_max_ratio>0 && offset<0 && -offset*shiftadd_max_ratio > old_a.size()) {
log_warning("at %s: candiate for shiftadd optimization (shifting '%s' by '%s - %d' bits) "
"was ignored to avoid high resource usage, see help peepopt\n",
location.c_str(), log_signal(old_a), log_signal(var_signal), -offset);
reject;
}
did_something = true;
log("shiftadd pattern in %s: shift=%s, add/sub=%s, offset: %d\n", \
log_id(module), log_id(shift), log_id(add), offset);
SigSpec old_a = port(shift, \A), new_a;
SigSpec new_a;
if(offset<0) {
// data >> (...-c) transformed to {data, c'X} >> (...)
SigSpec padding( (shift->type.in($shiftx) ? State::Sx : State::S0), -offset );
@ -107,14 +117,13 @@ code
new_a.append(old_a.extract_end(offset));
} else {
// warn user in case data is empty (no bits left)
std::string location = shift->get_src_attribute();
if (location.empty())
location = shift->name.str();
if(shift->type.in($shiftx))
log_warning("at %s: result of indexed part-selection is always constant (selecting from '%s' with index '%s + %d')\n", \
location.c_str(), log_signal(old_a), log_signal(var_signal), offset);
else
log_warning("at %s: result of shift operation is always constant (shifting '%s' by '%s + %d'-bits)\n", \
log_warning("at %s: result of shift operation is always constant (shifting '%s' by '%s + %d' bits)\n", \
location.c_str(), log_signal(old_a), log_signal(var_signal), offset);
}
}