3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-22 23:25:51 +00:00

Merged with main

This commit is contained in:
AdvaySingh1 2026-02-04 13:00:22 -08:00
commit 8d22f6d7e1
28 changed files with 1174 additions and 51 deletions

View file

@ -258,9 +258,13 @@ struct SimInstance
if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) {
fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
if (id==0 && wire->name.isPublic()) {
log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
if (shared->debug) {
log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
}
} else {
log("Found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
if (shared->debug) {
log("Found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)));
}
}
fst_handles[wire] = id;
}
@ -2504,16 +2508,11 @@ struct AnnotateActivity : public OutputWriter {
}
}
// Retrieve VCD timescale
std::string timescale = worker->timescale;
double real_timescale = 1e-12; // ps
if (timescale == "ns")
real_timescale = 1e-9;
if (timescale == "fs")
real_timescale = 1e-15;
// TODO: remove all debug sections when dev is completed
bool debug = false;
// Retrieve timescale from converted VCD file
double real_timescale = worker->fst->getTimescale();
if (worker->debug) {
log_debug("Timescale %e seconds extracted from converted VCD file", real_timescale);
}
// Compute clock period, find the highest toggling signal and compute its average period
SignalActivityDataMap::iterator itr = dataMap.find(clk);
@ -2527,31 +2526,32 @@ struct AnnotateActivity : public OutputWriter {
std::stringstream ss;
ss << std::setprecision(4) << real_timescale;
worker->top->module->set_string_attribute("$TIMESCALE", ss.str());
if (debug) {
std::cout << "Clock toggle count: " << clktoggleCounts[0] << "\n";
std::cout << "Max time: " << max_time << "\n";
std::cout << "Clock period: " << clk_period << "\n";
std::cout << "Frequency: " << frequency << "\n";
if (worker->debug) {
log_debug("Clock toggle count: %f", clktoggleCounts[0]);
log_debug("Max time: %d", max_time);
log_debug("Clock period: %f", clk_period);
log_debug("Frequency: %f", frequency);
}
double totalActivity = 0.0f;
double totalDuty = 0.0f;
// TODO make this debug code less messy and more readable.
worker->top->write_output_header(
[debug](IdString name) {
if (debug)
std::cout << stringf("module %s\n", log_id(name));
[&](IdString name) {
if (worker->debug)
log_debug("module %s", log_id(name));
},
[debug]() {
if (debug)
std::cout << "endmodule\n";
[&]() {
if (worker->debug)
log_debug("endmodule");
},
[&use_signal, &dataMap, max_time, real_timescale, clk_period, debug, &totalActivity, &totalDuty]
(const char *name, int size, Wire *w, int id, bool) {
[&](const char *name, int size, Wire *w, int id, bool) {
if (!use_signal.at(id) || (w == nullptr))
return;
SignalActivityDataMap::const_iterator itr = dataMap.find(id);
const std::vector<double_t> &toggleCounts = itr->second.toggleCounts;
const std::vector<uint64_t> &highTimes = itr->second.highTimes;
if (debug) {
if (worker->debug) {
std::string full_name = form_vcd_name(name, size, w);
std::cout << full_name << " " << id << ":\n";
std::cout << " TC: ";
@ -2577,10 +2577,8 @@ struct AnnotateActivity : public OutputWriter {
totalActivity += activity;
activity_str += std::to_string(activity) + " ";
}
if (debug) {
std::cout << activity_str;
std::cout << "\n";
std::cout << " DUTY: ";
if (worker->debug) {
log_debug(" ACKT: %s", activity_str.c_str());
}
std::string duty_str;
for (uint32_t i = 0; i < (uint32_t)size; i++) {
@ -2589,9 +2587,8 @@ struct AnnotateActivity : public OutputWriter {
totalDuty += duty;
duty_str += std::to_string(duty) + " ";
}
if (debug) {
std::cout << duty_str;
std::cout << "\n";
if (worker->debug) {
log_debug(" DUTY: %s", duty_str.c_str());
}
w->set_string_attribute("$ACKT", activity_str);
w->set_string_attribute("$DUTY", duty_str);

View file

@ -33,3 +33,20 @@ PEEPOPT_PATTERN += passes/silimate/peepopt_muxinvprop.pmg
passes/silimate/peepopt_muxmode.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
OBJS += passes/silimate/negopt.o
GENFILES += passes/silimate/peepopt_negopt.h
passes/silimate/negopt.o: passes/silimate/peepopt_negopt.h
$(eval $(call add_extra_objs,passes/silimate/peepopt_negopt.h))
PEEPOPT_PATTERN = passes/silimate/peepopt_manual2sub.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_sub2neg.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_negexpand.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_negneg.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_negmux.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_negrebuild.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_muxneg.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_neg2sub.pmg
passes/silimate/peepopt_negopt.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)

119
passes/silimate/negopt.cc Normal file
View file

@ -0,0 +1,119 @@
/*
* Copyright (C) 2025 Silimate, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
//
// Authored by Abhinav Tondapu of Silimate, Inc.
//
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
#include "passes/silimate/peepopt_negopt.h"
struct NegoptPass : public Pass {
NegoptPass() : Pass("negopt", "optimize negation patterns in arithmetic") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" negopt [options] [selection]\n");
log("\n");
log("This pass optimizes negation patterns in arithmetic expressions.\n");
log("\n");
log(" -pre\n");
log(" Run pre-optimization transformations:\n" );
log(" - manual2sub: a + ~b + 1 => a - b\n" );
log(" - sub2neg: a - b => a + (-b)\n" );
log(" - negexpand: -(a + b) => (-a) + (-b)\n");
log(" - negneg: -(-a) => a\n" );
log(" - negmux: -(s?a:b) => s?(-a):(-b)\n");
log("\n");
log(" -post\n");
log(" Run post-optimization transformations:\n" );
log(" - negrebuild: (-a)+(-b) => -(a + b)\n");
log(" - muxneg: s?(-a):(-b) => -(s?a:b)\n");
log(" - neg2sub: a + (-b) => a - b\n" );
log("\n");
log("When called without options, both -pre and -post are executed.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool run_pre = false;
bool run_post = false;
log_header(design, "Executing NEGOPT pass (optimize negation patterns).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-pre") {
run_pre = true;
continue;
}
if (args[argidx] == "-post") {
run_post = true;
continue;
}
break;
}
extra_args(args, argidx, design);
if (!run_pre && !run_post) {
run_pre = true;
run_post = true;
}
for (auto module : design->selected_modules()) {
if (run_pre) {
did_something = true;
while (did_something) {
did_something = false;
peepopt_pm pm(module);
pm.setup(module->selected_cells());
pm.run_manual2sub(); // Reduce manual 2's complement to subtraction first
pm.run_sub2neg();
pm.run_negexpand();
pm.run_negneg();
pm.run_negmux();
}
}
if (run_post) {
did_something = true;
while (did_something) {
did_something = false;
peepopt_pm pm(module);
pm.setup(module->selected_cells());
pm.run_negrebuild();
pm.run_muxneg();
pm.run_neg2sub();
}
}
}
}
} NegoptPass;
PRIVATE_NAMESPACE_END

View file

@ -0,0 +1,171 @@
pattern manual2sub
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Canonicalize manual 2's complement subtraction:
// Case A: (a + ~b) + 1 ===> a - b
// Case B: a + (~b + 1) ===> a - b
//
// Note: Fanout checking includes module connections to avoid breaking
// designs where intermediate results are used by output assignments.
//
state <SigSpec> minuend subtrahend result_sig
state <bool> is_signed
state <SigSpec> inner_y
// 1. Match the "root" add (the one that produces the final result)
match root_add
select root_add->type == $add
set result_sig port(root_add, \Y)
set is_signed root_add->getParam(ID::A_SIGNED).as_bool()
endmatch
// 2. Case A: (a + ~b) + 1
// Check if root_add has a constant 1
code root_add inner_y
{
SigSpec pa = root_add->getPort(ID::A);
SigSpec pb = root_add->getPort(ID::B);
auto is_one = [](SigSpec s) {
if (!s.is_fully_const()) return false;
Const c = s.as_const();
for (int i = 0; i < c.size(); i++) {
if (i == 0 && c[i] != State::S1) return false;
if (i > 0 && c[i] != State::S0) return false;
}
return true;
};
if (is_one(pa)) {
inner_y = pb;
} else if (is_one(pb)) {
inner_y = pa;
} else {
branch;
reject;
}
}
endcode
// Find the inner add
match inner_add_A
select inner_add_A->type == $add
index <SigSpec> port(inner_add_A, \Y) === inner_y
select nusers(port(inner_add_A, \Y)) == 2
endmatch
// Find the NOT gate on one of the ports of inner_add_A
match not_gate_A
select not_gate_A->type == $not
filter not_gate_A->getPort(ID::Y) == inner_add_A->getPort(ID::A) || not_gate_A->getPort(ID::Y) == inner_add_A->getPort(ID::B)
set subtrahend port(not_gate_A, \A)
endmatch
code root_add inner_add_A not_gate_A subtrahend minuend result_sig is_signed
{
// Require consistent signedness on the root add.
if (root_add->getParam(ID::B_SIGNED).as_bool() != is_signed)
reject;
if (inner_add_A->getParam(ID::A_SIGNED).as_bool() != is_signed)
reject;
if (inner_add_A->getParam(ID::B_SIGNED).as_bool() != is_signed)
reject;
if (not_gate_A->getPort(ID::Y) == inner_add_A->getPort(ID::A))
minuend = inner_add_A->getPort(ID::B);
else
minuend = inner_add_A->getPort(ID::A);
// Create the subtraction cell
log("manual2sub in %s: Found (a + ~b) + 1 pattern, creating $sub for %s\n", log_id(module), log_signal(result_sig));
Cell *sub = module->addSub(NEW_ID, minuend, subtrahend, result_sig, is_signed);
// Let fixup_parameters handle width adjustments
sub->fixup_parameters();
// Remove old cells
autoremove(root_add);
autoremove(inner_add_A);
autoremove(not_gate_A);
did_something = true;
accept;
}
endcode
// 3. Case B: a + (~b + 1)
code root_add
// Just fall through to the next match
endcode
// Find the inner add on either port of root_add
match inner_add_B
select inner_add_B->type == $add
filter inner_add_B->getPort(ID::Y) == root_add->getPort(ID::A) || inner_add_B->getPort(ID::Y) == root_add->getPort(ID::B)
select nusers(port(inner_add_B, \Y)) == 2
endmatch
// Check if inner_add_B has a constant 1 and a NOT gate
match not_gate_B
select not_gate_B->type == $not
filter not_gate_B->getPort(ID::Y) == inner_add_B->getPort(ID::A) || not_gate_B->getPort(ID::Y) == inner_add_B->getPort(ID::B)
endmatch
code root_add inner_add_B not_gate_B minuend subtrahend result_sig is_signed
{
// Require consistent signedness on the root add.
if (root_add->getParam(ID::B_SIGNED).as_bool() != is_signed)
reject;
if (inner_add_B->getParam(ID::A_SIGNED).as_bool() != is_signed)
reject;
if (inner_add_B->getParam(ID::B_SIGNED).as_bool() != is_signed)
reject;
SigSpec pa = inner_add_B->getPort(ID::A);
SigSpec pb = inner_add_B->getPort(ID::B);
SigSpec not_y = not_gate_B->getPort(ID::Y);
auto is_one = [](SigSpec s) {
if (!s.is_fully_const()) return false;
Const c = s.as_const();
for (int i = 0; i < c.size(); i++) {
if (i == 0 && c[i] != State::S1) return false;
if (i > 0 && c[i] != State::S0) return false;
}
return true;
};
bool valid = false;
if (is_one(pa) && pb == not_y) valid = true;
if (is_one(pb) && pa == not_y) valid = true;
if (!valid) reject;
subtrahend = not_gate_B->getPort(ID::A);
if (inner_add_B->getPort(ID::Y) == root_add->getPort(ID::A))
minuend = root_add->getPort(ID::B);
else
minuend = root_add->getPort(ID::A);
// Create the subtraction cell
log("manual2sub in %s: Found a + (~b + 1) pattern, creating $sub for %s\n", log_id(module), log_signal(result_sig));
Cell *sub = module->addSub(NEW_ID, minuend, subtrahend, result_sig, is_signed);
// Let fixup_parameters handle width adjustments
sub->fixup_parameters();
// Remove old cells
autoremove(root_add);
autoremove(inner_add_B);
autoremove(not_gate_B);
did_something = true;
accept;
}
endcode

View file

@ -0,0 +1,59 @@
pattern muxneg
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Factor negation out of mux
//
// s ? (-a) : (-b) ===> -(s ? a : b)
//
state <SigSpec> mux_a mux_b mux_s mux_y neg_a_in neg_b_in
state <bool> neg_a_signed neg_b_signed
match mux
select mux->type == $mux
set mux_a port(mux, \A)
set mux_b port(mux, \B)
set mux_s port(mux, \S)
set mux_y port(mux, \Y)
endmatch
match neg_a
select neg_a->type == $neg
select nusers(port(neg_a, \Y)) == 2
index <SigSpec> port(neg_a, \Y) === mux_a
set neg_a_in port(neg_a, \A)
set neg_a_signed neg_a->getParam(\A_SIGNED).as_bool()
endmatch
match neg_b
select neg_b->type == $neg
select nusers(port(neg_b, \Y)) == 2
index <SigSpec> port(neg_b, \Y) === mux_b
set neg_b_in port(neg_b, \A)
set neg_b_signed neg_b->getParam(\A_SIGNED).as_bool()
endmatch
code mux_a mux_b mux_s mux_y neg_a_in neg_b_in neg_a_signed neg_b_signed
if (neg_a_signed != neg_b_signed)
reject;
{
int width = GetSize(mux_y);
SigSpec mux_out = module->addWire(NEW_ID, width);
Cell *new_mux = module->addMux(NEW_ID, neg_a_in, neg_b_in, mux_s, mux_out);
Cell *new_neg = module->addNeg(NEW_ID, mux_out, mux_y, neg_a_signed);
log("muxneg pattern in %s: mux=%s, neg_a=%s, neg_b=%s\n",
log_id(module), log_id(mux), log_id(neg_a), log_id(neg_b));
new_mux->fixup_parameters();
new_neg->fixup_parameters();
autoremove(mux);
autoremove(neg_a);
autoremove(neg_b);
did_something = true;
}
accept;
endcode

View file

@ -0,0 +1,60 @@
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
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
select 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_signed neg->getParam(\A_SIGNED).as_bool()
endmatch
code add_a add_b add_y neg_a 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;
{
Cell *new_sub;
if (neg_on_a)
new_sub = module->addSub(NEW_ID, add_b, neg_a, add_y, add_b_signed);
else
new_sub = module->addSub(NEW_ID, add_a, neg_a, add_y, add_a_signed);
log("neg2sub pattern in %s: add=%s, neg=%s\n",
log_id(module), log_id(add), log_id(neg));
new_sub->fixup_parameters();
autoremove(add);
autoremove(neg);
did_something = true;
}
accept;
endcode

View file

@ -0,0 +1,56 @@
pattern negexpand
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Expand negation over addition
//
// -(a + b) ===> (-a) + (-b)
//
state <SigSpec> neg_a neg_y add_a add_b
state <bool> a_signed
match neg
select neg->type == $neg
set neg_a port(neg, \A)
set neg_y port(neg, \Y)
set a_signed neg->getParam(\A_SIGNED).as_bool()
endmatch
match add
select add->type == $add
index <SigSpec> port(add, \Y) === neg_a
select nusers(port(add, \Y)) == 2
set add_a port(add, \A)
set add_b port(add, \B)
endmatch
code neg_a neg_y add_a add_b a_signed
if (add->getParam(\A_SIGNED).as_bool() != a_signed)
reject;
if (add->getParam(\B_SIGNED).as_bool() != a_signed)
reject;
{
// Use output width for negations to handle overflow correctly
int width = GetSize(neg_y);
SigSpec neg_add_a = module->addWire(NEW_ID, width);
Cell *neg_a_cell = module->addNeg(NEW_ID, add_a, neg_add_a, a_signed);
SigSpec neg_add_b = module->addWire(NEW_ID, width);
Cell *neg_b_cell = module->addNeg(NEW_ID, add_b, neg_add_b, a_signed);
Cell *new_add = module->addAdd(NEW_ID, neg_add_a, neg_add_b, neg_y, a_signed);
log("negexpand pattern in %s: neg=%s, add=%s\n",
log_id(module), log_id(neg), log_id(add));
neg_a_cell->fixup_parameters();
neg_b_cell->fixup_parameters();
new_add->fixup_parameters();
autoremove(neg);
autoremove(add);
did_something = true;
}
accept;
endcode

View file

@ -0,0 +1,52 @@
pattern negmux
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Distribute negation over mux
//
// -(s ? a : b) ===> s ? (-a) : (-b)
//
state <SigSpec> neg_a neg_y mux_a mux_b mux_s
state <bool> a_signed
match neg
select neg->type == $neg
set neg_a port(neg, \A)
set neg_y port(neg, \Y)
set a_signed neg->getParam(\A_SIGNED).as_bool()
endmatch
match mux
select mux->type == $mux
index <SigSpec> port(mux, \Y) === neg_a
select nusers(port(mux, \Y)) == 2
set mux_a port(mux, \A)
set mux_b port(mux, \B)
set mux_s port(mux, \S)
endmatch
code neg_a neg_y mux_a mux_b mux_s a_signed
{
int width = GetSize(neg_y);
SigSpec neg_mux_a = module->addWire(NEW_ID, width);
Cell *neg_a_cell = module->addNeg(NEW_ID, mux_a, neg_mux_a, a_signed);
SigSpec neg_mux_b = module->addWire(NEW_ID, width);
Cell *neg_b_cell = module->addNeg(NEW_ID, mux_b, neg_mux_b, a_signed);
Cell *new_mux = module->addMux(NEW_ID, neg_mux_a, neg_mux_b, mux_s, neg_y);
log("negmux pattern in %s: neg=%s, mux=%s\n",
log_id(module), log_id(neg), log_id(mux));
neg_a_cell->fixup_parameters();
neg_b_cell->fixup_parameters();
new_mux->fixup_parameters();
autoremove(neg);
autoremove(mux);
did_something = true;
}
accept;
endcode

View file

@ -0,0 +1,35 @@
pattern negneg
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Simplify double negation
//
// -(-a) ===> a
//
state <SigSpec> neg1_a neg1_y neg2_a
match neg1
select neg1->type == $neg
set neg1_a port(neg1, \A)
set neg1_y port(neg1, \Y)
endmatch
match neg2
select neg2->type == $neg
index <SigSpec> port(neg2, \Y) === neg1_a
select nusers(port(neg2, \Y)) == 2
set neg2_a port(neg2, \A)
endmatch
code neg1_a neg1_y neg2_a
module->connect(neg1_y, neg2_a);
log("negneg pattern in %s: neg1=%s, neg2=%s\n",
log_id(module), log_id(neg1), log_id(neg2));
autoremove(neg1);
autoremove(neg2);
did_something = true;
accept;
endcode

View file

@ -0,0 +1,63 @@
pattern negrebuild
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Rebuild addition of negations into negation of addition
//
// (-a) + (-b) ===> -(a + b)
//
state <SigSpec> add_a add_b add_y neg1_a neg2_a
state <bool> add_signed add_b_signed neg1_signed neg2_signed
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_signed add->getParam(\A_SIGNED).as_bool()
set add_b_signed add->getParam(\B_SIGNED).as_bool()
endmatch
match neg1
select neg1->type == $neg
select nusers(port(neg1, \Y)) == 2
index <SigSpec> port(neg1, \Y) === add_a
set neg1_a port(neg1, \A)
set neg1_signed neg1->getParam(\A_SIGNED).as_bool()
endmatch
match neg2
select neg2->type == $neg
select nusers(port(neg2, \Y)) == 2
index <SigSpec> port(neg2, \Y) === add_b
set neg2_a port(neg2, \A)
set neg2_signed neg2->getParam(\A_SIGNED).as_bool()
endmatch
code add_a add_b add_y neg1_a neg2_a add_signed add_b_signed neg1_signed neg2_signed
if (add_signed != add_b_signed)
reject;
if (neg1_signed != add_signed || neg2_signed != add_signed)
reject;
{
int width = GetSize(add_y);
SigSpec sum = module->addWire(NEW_ID, width);
Cell *new_add = module->addAdd(NEW_ID, neg1_a, neg2_a, sum, add_signed);
Cell *new_neg = module->addNeg(NEW_ID, sum, add_y, add_signed);
log("negrebuild pattern in %s: add=%s, neg1=%s, neg2=%s\n",
log_id(module), log_id(add), log_id(neg1), log_id(neg2));
new_add->fixup_parameters();
new_neg->fixup_parameters();
autoremove(add);
autoremove(neg1);
autoremove(neg2);
did_something = true;
}
accept;
endcode

View file

@ -0,0 +1,42 @@
pattern sub2neg
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Convert subtraction to addition with negation
//
// a - b ===> a + (-b)
//
state <SigSpec> sub_a sub_b sub_y
state <bool> a_signed b_signed
match sub
select sub->type == $sub
filter !sub->getPort(\B).is_fully_const()
set sub_a port(sub, \A)
set sub_b port(sub, \B)
set sub_y port(sub, \Y)
set a_signed sub->getParam(\A_SIGNED).as_bool()
set b_signed sub->getParam(\B_SIGNED).as_bool()
endmatch
code sub_a sub_b sub_y a_signed b_signed
if (a_signed != b_signed)
reject;
{
int width = GetSize(sub_y);
SigSpec neg_y = module->addWire(NEW_ID, width);
Cell *neg = module->addNeg(NEW_ID, sub_b, neg_y, b_signed);
Cell *add = module->addAdd(NEW_ID, sub_a, neg_y, sub_y, a_signed);
log("sub2neg pattern in %s: sub=%s -> neg=%s, add=%s\n",
log_id(module), log_id(sub), log_id(neg), log_id(add));
neg->fixup_parameters();
add->fixup_parameters();
autoremove(sub);
did_something = true;
}
accept;
endcode

View file

@ -2873,4 +2873,4 @@ struct AbcPass : public Pass {
}
} AbcPass;
PRIVATE_NAMESPACE_END
PRIVATE_NAMESPACE_END