diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index edd3b18a8..5638ec3c2 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -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 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; diff --git a/passes/pmgen/peepopt_shiftadd.pmg b/passes/pmgen/peepopt_shiftadd.pmg index e690ff651..62f54efe5 100644 --- a/passes/pmgen/peepopt_shiftadd.pmg +++ b/passes/pmgen/peepopt_shiftadd.pmg @@ -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); } }