-
Notifications
You must be signed in to change notification settings - Fork 893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add muldiv_c
and muxadd
peepopts
#4740
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
pattern muldiv_c | ||
// | ||
// Authored by Akash Levy of Silimate, Inc. under ISC license. | ||
// Transforms mul->div into const->mul when b and c are divisible constants: | ||
// y = (a * b_const) / c_const ===> a * eval(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 | ||
// 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 | ||
|
||
// Check that b_const and c_const is constant | ||
filter b_const.is_fully_const() | ||
filter port(div, \B).is_fully_const() | ||
endmatch | ||
|
||
code | ||
// Get div signals | ||
SigSpec div_a = port(div, \A); | ||
SigSpec c_const = port(div, \B); | ||
SigSpec div_y = port(div, \Y); | ||
|
||
// Get offset of multiplier result chunk in divider | ||
int offset = GetSize(div_a) - GetSize(mul_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); | ||
int b_const_int_shifted = b_const_int << offset; | ||
|
||
// Check that there are only zeros before offset | ||
if (offset < 0 || !div_a.extract(0, offset).is_fully_zero()) | ||
reject; | ||
|
||
// Check that b is divisible by c | ||
if (b_const_int_shifted % c_const_int != 0) | ||
reject; | ||
|
||
// Rewire to only keep multiplier | ||
mul->setPort(\B, Const(b_const_int_shifted / 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 |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,57 @@ | ||||||||||||||||||||
pattern muxadd | ||||||||||||||||||||
// | ||||||||||||||||||||
// Authored by Akash Levy of Silimate, Inc. under ISC license. | ||||||||||||||||||||
// Transforms add->mux into mux->add: | ||||||||||||||||||||
// y = s ? (a + b) : a ===> y = a + (s ? b : 0) | ||||||||||||||||||||
// | ||||||||||||||||||||
|
||||||||||||||||||||
state <SigSpec> add_a add_b add_y | ||||||||||||||||||||
|
||||||||||||||||||||
match add | ||||||||||||||||||||
// Select adder | ||||||||||||||||||||
select add->type == $add | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
and replace the branch-and-swap pattern further below Requires new state
|
||||||||||||||||||||
endmatch | ||||||||||||||||||||
|
||||||||||||||||||||
code add_y add_a add_b | ||||||||||||||||||||
// Get adder signals | ||||||||||||||||||||
add_a = port(add, \A); | ||||||||||||||||||||
add_b = port(add, \B); | ||||||||||||||||||||
add_y = port(add, \Y); | ||||||||||||||||||||
|
||||||||||||||||||||
// Fanout of each adder Y bit should be 1 (no bit-split) | ||||||||||||||||||||
for (auto bit : add_y) | ||||||||||||||||||||
if (nusers(bit) != 2) | ||||||||||||||||||||
reject; | ||||||||||||||||||||
Comment on lines
+22
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
is all we need and more idiomatic. We know |
||||||||||||||||||||
|
||||||||||||||||||||
// A and B can be interchanged | ||||||||||||||||||||
branch; | ||||||||||||||||||||
std::swap(add_a, add_b); | ||||||||||||||||||||
endcode | ||||||||||||||||||||
|
||||||||||||||||||||
match mux | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can also match on the case of swapped mux inputs |
||||||||||||||||||||
// Select mux of form s ? (a + b) : a, allow leading 0s when A_WIDTH != Y_WIDTH | ||||||||||||||||||||
select mux->type == $mux | ||||||||||||||||||||
index <SigSpec> port(mux, \A) === SigSpec({Const(State::S0, GetSize(add_y)-GetSize(add_a)), add_a}) | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be zero-padded if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also I am not sure this doesn't crash on |
||||||||||||||||||||
index <SigSpec> port(mux, \B) === add_y | ||||||||||||||||||||
endmatch | ||||||||||||||||||||
|
||||||||||||||||||||
code | ||||||||||||||||||||
// Get mux signal | ||||||||||||||||||||
SigSpec mux_y = port(mux, \Y); | ||||||||||||||||||||
|
||||||||||||||||||||
// Create new mid wire | ||||||||||||||||||||
SigSpec mid = module->addWire(NEW_ID, GetSize(add_b)); | ||||||||||||||||||||
|
||||||||||||||||||||
// Rewire | ||||||||||||||||||||
mux->setPort(\A, Const(State::S0, GetSize(add_b))); | ||||||||||||||||||||
mux->setPort(\B, add_b); | ||||||||||||||||||||
mux->setPort(\Y, mid); | ||||||||||||||||||||
add->setPort(\B, mid); | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong side of the adder if the swap above was hit (we need to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Err, more like |
||||||||||||||||||||
add->setPort(\Y, mux_y); | ||||||||||||||||||||
|
||||||||||||||||||||
// Log, fixup, accept | ||||||||||||||||||||
log("muxadd pattern in %s: mux=%s, add=%s\n", log_id(module), log_id(mux), log_id(add)); | ||||||||||||||||||||
add->fixup_parameters(); | ||||||||||||||||||||
mux->fixup_parameters(); | ||||||||||||||||||||
accept; | ||||||||||||||||||||
endcode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No check that the divider and multiplier are connected