aboutsummaryrefslogtreecommitdiffstats
path: root/passes/opt/share.cc
diff options
context:
space:
mode:
Diffstat (limited to 'passes/opt/share.cc')
-rw-r--r--passes/opt/share.cc159
1 files changed, 107 insertions, 52 deletions
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 3133cb2a6..22914eaa7 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* 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
@@ -113,8 +113,8 @@ struct ShareWorker
static int bits_macc_port(const Macc::port_t &p, int width)
{
if (GetSize(p.in_a) == 0 || GetSize(p.in_b) == 0)
- return std::min(std::max(GetSize(p.in_a), GetSize(p.in_b)), width);
- return std::min(GetSize(p.in_a), width) * std::min(GetSize(p.in_b), width) / 2;
+ return min(max(GetSize(p.in_a), GetSize(p.in_b)), width);
+ return min(GetSize(p.in_a), width) * min(GetSize(p.in_b), width) / 2;
}
static int bits_macc(const Macc &m, int width)
@@ -224,13 +224,13 @@ struct ShareWorker
supermacc->ports.push_back(p);
}
- int score = 1000 + abs(GetSize(p1.in_a) - GetSize(p2.in_a)) * std::max(abs(GetSize(p1.in_b) - GetSize(p2.in_b)), 1);
+ int score = 1000 + abs(GetSize(p1.in_a) - GetSize(p2.in_a)) * max(abs(GetSize(p1.in_b) - GetSize(p2.in_b)), 1);
- for (int i = 0; i < std::min(GetSize(p1.in_a), GetSize(p2.in_a)); i++)
+ for (int i = 0; i < min(GetSize(p1.in_a), GetSize(p2.in_a)); i++)
if (p1.in_a[i] == p2.in_a[i] && score > 0)
score--;
- for (int i = 0; i < std::min(GetSize(p1.in_b), GetSize(p2.in_b)); i++)
+ for (int i = 0; i < min(GetSize(p1.in_b), GetSize(p2.in_b)); i++)
if (p1.in_b[i] == p2.in_b[i] && score > 0)
score--;
@@ -243,7 +243,7 @@ struct ShareWorker
Macc m1(c1), m2(c2), supermacc;
int w1 = GetSize(c1->getPort("\\Y")), w2 = GetSize(c2->getPort("\\Y"));
- int width = std::max(w1, w2);
+ int width = max(w1, w2);
m1.optimize(w1);
m2.optimize(w2);
@@ -369,7 +369,9 @@ struct ShareWorker
}
if (cell->type == "$memrd") {
- if (!cell->parameters.at("\\CLK_ENABLE").as_bool())
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool())
+ continue;
+ if (config.opt_aggressive || !modwalker.sigmap(cell->getPort("\\ADDR")).is_fully_const())
shareable_cells.insert(cell);
continue;
}
@@ -387,7 +389,7 @@ struct ShareWorker
}
if (generic_ops.count(cell->type)) {
- if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 10)
+ if (config.opt_aggressive)
shareable_cells.insert(cell);
continue;
}
@@ -417,8 +419,8 @@ struct ShareWorker
int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
- if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
- if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ if (max(a1_width, a2_width) > 2 * min(a1_width, a2_width)) return false;
+ if (max(y1_width, y2_width) > 2 * min(y1_width, y2_width)) return false;
}
return true;
@@ -436,9 +438,9 @@ struct ShareWorker
int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
- if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
- if (std::max(b1_width, b2_width) > 2 * std::min(b1_width, b2_width)) return false;
- if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ if (max(a1_width, a2_width) > 2 * min(a1_width, a2_width)) return false;
+ if (max(b1_width, b2_width) > 2 * min(b1_width, b2_width)) return false;
+ if (max(y1_width, y2_width) > 2 * min(y1_width, y2_width)) return false;
}
return true;
@@ -456,15 +458,15 @@ struct ShareWorker
int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
- int min1_width = std::min(a1_width, b1_width);
- int max1_width = std::max(a1_width, b1_width);
+ int min1_width = min(a1_width, b1_width);
+ int max1_width = max(a1_width, b1_width);
- int min2_width = std::min(a2_width, b2_width);
- int max2_width = std::max(a2_width, b2_width);
+ int min2_width = min(a2_width, b2_width);
+ int max2_width = max(a2_width, b2_width);
- if (std::max(min1_width, min2_width) > 2 * std::min(min1_width, min2_width)) return false;
- if (std::max(max1_width, max2_width) > 2 * std::min(max1_width, max2_width)) return false;
- if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ if (max(min1_width, min2_width) > 2 * min(min1_width, min2_width)) return false;
+ if (max(max1_width, max2_width) > 2 * min(max1_width, max2_width)) return false;
+ if (max(y1_width, y2_width) > 2 * min(y1_width, y2_width)) return false;
}
return true;
@@ -473,7 +475,7 @@ struct ShareWorker
if (c1->type == "$macc")
{
if (!config.opt_aggressive)
- if (share_macc(c1, c2) > 2 * std::min(bits_macc(c1), bits_macc(c2))) return false;
+ if (share_macc(c1, c2) > 2 * min(bits_macc(c1), bits_macc(c2))) return false;
return true;
}
@@ -530,8 +532,8 @@ struct ShareWorker
RTLIL::SigSpec a2 = c2->getPort("\\A");
RTLIL::SigSpec y2 = c2->getPort("\\Y");
- int a_width = std::max(a1.size(), a2.size());
- int y_width = std::max(y1.size(), y2.size());
+ int a_width = max(a1.size(), a2.size());
+ int y_width = max(y1.size(), y2.size());
a1.extend_u0(a_width, a_signed);
a2.extend_u0(a_width, a_signed);
@@ -561,11 +563,11 @@ struct ShareWorker
if (config.generic_cbin_ops.count(c1->type))
{
- int score_unflipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()) +
- std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int());
+ int score_unflipped = max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()) +
+ max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int());
- int score_flipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()) +
- std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int());
+ int score_flipped = max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()) +
+ max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int());
if (score_flipped < score_unflipped)
{
@@ -628,13 +630,13 @@ struct ShareWorker
RTLIL::SigSpec b2 = c2->getPort("\\B");
RTLIL::SigSpec y2 = c2->getPort("\\Y");
- int a_width = std::max(a1.size(), a2.size());
- int b_width = std::max(b1.size(), b2.size());
- int y_width = std::max(y1.size(), y2.size());
+ int a_width = max(a1.size(), a2.size());
+ int b_width = max(b1.size(), b2.size());
+ int y_width = max(y1.size(), y2.size());
if (c1->type == "$shr" && a_signed)
{
- a_width = std::max(y_width, a_width);
+ a_width = max(y_width, a_width);
if (a1.size() < y1.size()) a1.extend_u0(y1.size(), true);
if (a2.size() < y2.size()) a2.extend_u0(y2.size(), true);
@@ -706,6 +708,10 @@ struct ShareWorker
if (c1->type == "$memrd")
{
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1);
+ RTLIL::SigSpec addr1 = c1->getPort("\\ADDR");
+ RTLIL::SigSpec addr2 = c2->getPort("\\ADDR");
+ if (addr1 != addr2)
+ supercell->setPort("\\ADDR", module->Mux(NEW_ID, addr2, addr1, act));
supercell_aux.insert(module->addPos(NEW_ID, supercell->getPort("\\DATA"), c2->getPort("\\DATA")));
supercell_aux.insert(supercell);
return supercell;
@@ -787,10 +793,59 @@ struct ShareWorker
return true;
}
- void optimize_activation_patterns(pool<ssc_pair_t> & /* patterns */)
+ void optimize_activation_patterns(pool<ssc_pair_t> &patterns)
{
// TODO: Remove patterns that are contained in other patterns
- // TODO: Consolidate pairs of patterns that only differ in the value for one signal bit
+
+ dict<SigSpec, pool<Const>> db;
+ bool did_something = false;
+
+ for (auto const &p : patterns)
+ {
+ auto &sig = p.first;
+ auto &val = p.second;
+ int len = GetSize(sig);
+
+ for (int i = 0; i < len; i++)
+ {
+ auto otherval = val;
+
+ if (otherval.bits[i] == State::S0)
+ otherval.bits[i] = State::S1;
+ else if (otherval.bits[i] == State::S1)
+ otherval.bits[i] = State::S0;
+ else
+ continue;
+
+ if (db[sig].count(otherval))
+ {
+ auto newsig = sig;
+ newsig.remove(i);
+
+ auto newval = val;
+ newval.bits.erase(newval.bits.begin() + i);
+
+ db[newsig].insert(newval);
+ db[sig].erase(otherval);
+
+ did_something = true;
+ goto next_pattern;
+ }
+ }
+
+ db[sig].insert(val);
+ next_pattern:;
+ }
+
+ if (!did_something)
+ return;
+
+ patterns.clear();
+ for (auto &it : db)
+ for (auto &val : it.second)
+ patterns.insert(make_pair(it.first, val));
+
+ optimize_activation_patterns(patterns);
}
const pool<ssc_pair_t> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
@@ -1105,7 +1160,7 @@ struct ShareWorker
RTLIL::Cell *cell = *shareable_cells.begin();
shareable_cells.erase(cell);
- log(" Analyzing resource sharing options for %s:\n", log_id(cell));
+ log(" Analyzing resource sharing options for %s (%s):\n", log_id(cell), log_id(cell->type));
const pool<ssc_pair_t> &cell_activation_patterns = find_cell_activation_patterns(cell, " ");
RTLIL::SigSpec cell_activation_signals = bits_from_activation_patterns(cell_activation_patterns);
@@ -1138,7 +1193,7 @@ struct ShareWorker
for (auto other_cell : candidates)
{
- log(" Analyzing resource sharing with %s:\n", log_id(other_cell));
+ log(" Analyzing resource sharing with %s (%s):\n", log_id(other_cell), log_id(other_cell->type));
const pool<ssc_pair_t> &other_cell_activation_patterns = find_cell_activation_patterns(other_cell, " ");
RTLIL::SigSpec other_cell_activation_signals = bits_from_activation_patterns(other_cell_activation_patterns);
@@ -1178,8 +1233,8 @@ struct ShareWorker
optimize_activation_patterns(filtered_cell_activation_patterns);
optimize_activation_patterns(filtered_other_cell_activation_patterns);
- ezDefaultSAT ez;
- SatGen satgen(&ez, &modwalker.sigmap);
+ ezSatPtr ez;
+ SatGen satgen(ez.get(), &modwalker.sigmap);
pool<RTLIL::Cell*> sat_cells;
std::set<RTLIL::SigBit> bits_queue;
@@ -1189,13 +1244,13 @@ struct ShareWorker
for (auto &p : filtered_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(cell), log_signal(p.first), log_signal(p.second));
- cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ cell_active.push_back(ez->vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
}
for (auto &p : filtered_other_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(other_cell), log_signal(p.first), log_signal(p.second));
- other_cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ other_cell_active.push_back(ez->vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
}
@@ -1230,36 +1285,36 @@ struct ShareWorker
log(" Adding exclusive control bits: %s vs. %s\n", log_signal(it.first), log_signal(it.second));
int sub1 = satgen.importSigBit(it.first);
int sub2 = satgen.importSigBit(it.second);
- ez.assume(ez.NOT(ez.AND(sub1, sub2)));
+ ez->assume(ez->NOT(ez->AND(sub1, sub2)));
}
- if (!ez.solve(ez.expression(ez.OpOr, cell_active))) {
+ if (!ez->solve(ez->expression(ez->OpOr, cell_active))) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(cell));
cells_to_remove.insert(cell);
break;
}
- if (!ez.solve(ez.expression(ez.OpOr, other_cell_active))) {
+ if (!ez->solve(ez->expression(ez->OpOr, other_cell_active))) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(other_cell));
cells_to_remove.insert(other_cell);
shareable_cells.erase(other_cell);
continue;
}
- ez.non_incremental();
+ ez->non_incremental();
all_ctrl_signals.sort_and_unify();
std::vector<int> sat_model = satgen.importSigSpec(all_ctrl_signals);
std::vector<bool> sat_model_values;
- int sub1 = ez.expression(ez.OpOr, cell_active);
- int sub2 = ez.expression(ez.OpOr, other_cell_active);
- ez.assume(ez.AND(sub1, sub2));
+ int sub1 = ez->expression(ez->OpOr, cell_active);
+ int sub2 = ez->expression(ez->OpOr, other_cell_active);
+ ez->assume(ez->AND(sub1, sub2));
log(" Size of SAT problem: %d cells, %d variables, %d clauses\n",
- GetSize(sat_cells), ez.numCnfVariables(), ez.numCnfClauses());
+ GetSize(sat_cells), ez->numCnfVariables(), ez->numCnfClauses());
- if (ez.solve(sat_model, sat_model_values)) {
+ if (ez->solve(sat_model, sat_model_values)) {
log(" According to the SAT solver this pair of cells can not be shared.\n");
log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), GetSize(sat_model_values));
for (int i = GetSize(sat_model_values)-1; i >= 0; i--)
@@ -1391,7 +1446,7 @@ struct SharePass : public Pass {
log("\n");
log(" -fast\n");
log(" Only consider the simple part of the control logic in SAT solving, resulting\n");
- log(" in much easier SAT problems at the cost of maybe missing some oportunities\n");
+ log(" in much easier SAT problems at the cost of maybe missing some opportunities\n");
log(" for resource sharing.\n");
log("\n");
log(" -limit N\n");
@@ -1445,7 +1500,7 @@ struct SharePass : public Pass {
config.generic_other_ops.insert("$alu");
config.generic_other_ops.insert("$macc");
- log_header("Executing SHARE pass (SAT-based resource sharing).\n");
+ log_header(design, "Executing SHARE pass (SAT-based resource sharing).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {