diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 9747973cb..4b712aec9 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -57,6 +57,7 @@ PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul_right.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftadd.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv_c.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muxadd.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 7de4e9fba..bfaf4961e 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -46,6 +46,8 @@ struct PeepoptPass : public Pass { log("\n"); log(" * muldiv - Replace (A*B)/B with A\n"); log("\n"); + log(" * muldiv_c - Replace (A*B)/C with A*(B/C) when C is a const divisible by B.\n"); + log("\n"); log(" * shiftmul - Replace A>>(B*C) with A'>>(B<div into div->mul when b and c are divisible constants: +// y = (a * b_const) / c_const ===> a * (b_const / c_const) +// + +state a b_const mul_y + +match mul + // Select multiplier + select mul->type == $mul +endmatch + +code a b_const mul_y + printf("CODING MUL!!!\n"); + + // Get multiplier signals + a = port(mul, \A); + b_const = port(mul, \B); + mul_y = port(mul, \Y); + + // Fanout of each multiplier Y bit should be 1 (no bit-split) + for (auto bit : mul_y) + if (nusers(bit) != 2) + reject; + + // A and B can be interchanged + branch; + std::swap(a, b_const); +endcode + +match div + // Select div of form (a * b_const) / c_const + select div->type == $div + index port(div, \A) === port(mul, \Y) + + // Check that b_const and c_const is constant + filter port(mul, \B).is_fully_const() + filter port(div, \B).is_fully_const() +endmatch + +code + printf("CODING DIV!!!\n"); + + // Get div signals + SigSpec c_const = port(div, \B); + SigSpec div_y = port(div, \Y); + + // Get properties and values of b_const and c_const + int b_const_width = mul->getParam(ID::B_WIDTH).as_int(); + bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool(); + bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool(); + int b_const_int = b_const.as_int(b_const_signed); + int c_const_int = c_const.as_int(c_const_signed); + + // Check that b is divisible by c + if (b_const_int % c_const_int != 0) + reject; + + // Rewire to only keep multiplier + mul->setPort(\B, Const(b_const_int / c_const_int, b_const_width)); + mul->setPort(\Y, div_y); + + // Remove divider + autoremove(div); + + // Log, fixup, accept + log("muldiv_const pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); + mul->fixup_parameters(); + accept; +endcode