diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index 9dd90072d..8b973c9a8 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -34,6 +34,7 @@ PEEPOPT_PATTERN += passes/opt/peepopt_muldiv.pmg PEEPOPT_PATTERN += passes/opt/peepopt_muldiv_c.pmg PEEPOPT_PATTERN += passes/opt/peepopt_muxorder.pmg PEEPOPT_PATTERN += passes/opt/peepopt_formal_clockgateff.pmg +PEEPOPT_PATTERN += passes/opt/peepopt_sub_neg.pmg passes/opt/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) $(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^) diff --git a/passes/opt/peepopt.cc b/passes/opt/peepopt.cc index 8448b0485..cb6174d66 100644 --- a/passes/opt/peepopt.cc +++ b/passes/opt/peepopt.cc @@ -121,6 +121,7 @@ struct PeepoptPass : public Pass { pm.run_shiftmul_left(); pm.run_muldiv(); pm.run_muldiv_c(); + pm.run_sub_neg(); if (muxorder) pm.run_muxorder(); } diff --git a/passes/opt/peepopt_sub_neg.pmg b/passes/opt/peepopt_sub_neg.pmg new file mode 100644 index 000000000..0b23c1ea4 --- /dev/null +++ b/passes/opt/peepopt_sub_neg.pmg @@ -0,0 +1,62 @@ +pattern sub_neg +// +// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license. +// Transforms -(a-b) ----> (b-a) + +state a b sub_y + +match sub + // Select sub + select sub->type == $sub +endmatch + +code a b sub_y + // Get sub signals + a = port(sub, \A); + b = port(sub, \B); + sub_y = port(sub, \Y); + + bool a_signed = sub->getParam(ID::A_SIGNED).as_bool(); + bool b_signed = sub->getParam(ID::B_SIGNED).as_bool(); + + // Fanout of each sub Y bit should be 1 (no bit-split) + if (nusers(sub_y) != 2) + reject; + + // Both operands need to be signed to be swapped + if (!a_signed || !b_signed) + reject; + + // A and B can be interchanged + branch; + std::swap(a, b); +endcode + +match neg + // Select neg of form -(a-b) + select neg->type == $neg + + index remove_bottom_padding(port(neg, \A)) === sub_y +endmatch + +code + // Get neg signals + SigSpec neg_a = port(neg, \A); + SigSpec neg_y = port(neg, \Y); + + bool a_signed = neg->getParam(ID::A_SIGNED).as_bool(); + if (!a_signed) + reject; + + // Rewire to only keep sub + sub->setPort(\A, b); + sub->setPort(\B, a); + sub->setPort(\Y, neg_y); + + // Remove neg + autoremove(neg); + + // Log, fixup, accept + log("sub_neg pattern in %s: neg=%s, sub=%s\n", log_id(module), log_id(neg), log_id(sub)); + accept; +endcode diff --git a/tests/peepopt/neg_sub.ys b/tests/peepopt/neg_sub.ys new file mode 100644 index 000000000..17980f632 --- /dev/null +++ b/tests/peepopt/neg_sub.ys @@ -0,0 +1,102 @@ +log -header "Test simple positive case" +log -push +design -reset +read_verilog <