mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-24 01:25:33 +00:00
muldiv_c peepopt pass
This commit is contained in:
parent
8afa827b94
commit
98db6bd2d8
3 changed files with 75 additions and 0 deletions
|
@ -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)
|
||||
|
|
|
@ -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<<K) where C and K are constants\n");
|
||||
log(" and A' is derived from A by appropriately inserting padding\n");
|
||||
log(" into the signal. (right variant)\n");
|
||||
|
@ -92,6 +94,7 @@ struct PeepoptPass : public Pass {
|
|||
pm.run_shiftmul_right();
|
||||
pm.run_shiftmul_left();
|
||||
pm.run_muldiv();
|
||||
pm.run_muldiv_c();
|
||||
pm.run_muxadd();
|
||||
}
|
||||
}
|
||||
|
|
71
passes/pmgen/peepopt_muldiv_c.pmg
Normal file
71
passes/pmgen/peepopt_muldiv_c.pmg
Normal file
|
@ -0,0 +1,71 @@
|
|||
pattern muldiv_c
|
||||
//
|
||||
// Transforms mul->div into div->mul when b and c are divisible constants:
|
||||
// y = (a * b_const) / c_const ===> a * (b_const / c_const)
|
||||
//
|
||||
|
||||
state <SigSpec> 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 <SigSpec> 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
|
Loading…
Add table
Add a link
Reference in a new issue