yosys/passes/silimate/peepopt_neg2sub.pmg

74 lines
1.7 KiB
Plaintext

pattern neg2sub
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Convert addition with negation back to subtraction
//
// a + (-b) ===> a - b
//
state <SigSpec> add_a add_b add_y neg_a neg_y
state <bool> add_a_signed add_b_signed neg_signed
state <bool> neg_on_a
match add
select add->type == $add
set add_a port(add, \A)
set add_b port(add, \B)
set add_y port(add, \Y)
set add_a_signed add->getParam(\A_SIGNED).as_bool()
set add_b_signed add->getParam(\B_SIGNED).as_bool()
endmatch
code neg_on_a
neg_on_a = true;
branch;
neg_on_a = false;
endcode
match neg
select neg->type == $neg
filter nusers(port(neg, \Y)) == 2
index <SigSpec> port(neg, \Y) === (neg_on_a ? add_a : add_b)
set neg_a port(neg, \A)
set neg_y port(neg, \Y)
set neg_signed neg->getParam(\A_SIGNED).as_bool()
endmatch
code add_a add_b add_y neg_a neg_y neg_on_a add_a_signed add_b_signed neg_signed
if (add_a_signed != add_b_signed)
reject;
if (neg_signed != (neg_on_a ? add_a_signed : add_b_signed))
reject;
{
int neg_y_width = GetSize(neg_y);
int add_y_width = GetSize(add_y);
// Reject if the negation truncates its input
if (GetSize(neg_a) > neg_y_width)
reject;
// Reject if the add result is wider than the negation boundary
if (add_y_width > neg_y_width)
reject;
SigSpec pos_op = neg_on_a ? add_b : add_a;
// Reuse the original add cell for stable naming
add->setPort(\A, pos_op);
add->setPort(\B, neg_a);
add->setPort(\Y, add_y);
add->type = $sub;
log(" add=%s, neg=%s (safe sub replacement)\n",
log_id(add), log_id(neg));
add->fixup_parameters();
autoremove(neg);
did_something = true;
}
accept;
endcode