mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-06 17:44:09 +00:00
Merge pull request #1169 from whitequark/more-proc-cleanups
A new proc_prune pass
This commit is contained in:
commit
a0787c12f0
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
OBJS += passes/proc/proc.o
|
OBJS += passes/proc/proc.o
|
||||||
|
OBJS += passes/proc/proc_prune.o
|
||||||
OBJS += passes/proc/proc_clean.o
|
OBJS += passes/proc/proc_clean.o
|
||||||
OBJS += passes/proc/proc_rmdead.o
|
OBJS += passes/proc/proc_rmdead.o
|
||||||
OBJS += passes/proc/proc_init.o
|
OBJS += passes/proc/proc_init.o
|
||||||
|
@ -7,4 +8,3 @@ OBJS += passes/proc/proc_arst.o
|
||||||
OBJS += passes/proc/proc_mux.o
|
OBJS += passes/proc/proc_mux.o
|
||||||
OBJS += passes/proc/proc_dlatch.o
|
OBJS += passes/proc/proc_dlatch.o
|
||||||
OBJS += passes/proc/proc_dff.o
|
OBJS += passes/proc/proc_dff.o
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct ProcPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log(" proc_clean\n");
|
log(" proc_clean\n");
|
||||||
log(" proc_rmdead\n");
|
log(" proc_rmdead\n");
|
||||||
|
log(" proc_prune\n");
|
||||||
log(" proc_init\n");
|
log(" proc_init\n");
|
||||||
log(" proc_arst\n");
|
log(" proc_arst\n");
|
||||||
log(" proc_mux\n");
|
log(" proc_mux\n");
|
||||||
|
@ -83,6 +84,7 @@ struct ProcPass : public Pass {
|
||||||
Pass::call(design, "proc_clean");
|
Pass::call(design, "proc_clean");
|
||||||
if (!ifxmode)
|
if (!ifxmode)
|
||||||
Pass::call(design, "proc_rmdead");
|
Pass::call(design, "proc_rmdead");
|
||||||
|
Pass::call(design, "proc_prune");
|
||||||
Pass::call(design, "proc_init");
|
Pass::call(design, "proc_init");
|
||||||
if (global_arst.empty())
|
if (global_arst.empty())
|
||||||
Pass::call(design, "proc_arst");
|
Pass::call(design, "proc_arst");
|
||||||
|
|
|
@ -172,7 +172,7 @@ restart_proc_arst:
|
||||||
sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
|
sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
|
||||||
}
|
}
|
||||||
for (auto &action : sync->actions) {
|
for (auto &action : sync->actions) {
|
||||||
RTLIL::SigSpec rspec = action.second;
|
RTLIL::SigSpec rspec = assign_map(action.second);
|
||||||
RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
|
RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
|
||||||
for (int i = 0; i < GetSize(rspec); i++)
|
for (int i = 0; i < GetSize(rspec); i++)
|
||||||
if (rspec[i].wire == NULL)
|
if (rspec[i].wire == NULL)
|
||||||
|
|
|
@ -26,21 +26,7 @@
|
||||||
USING_YOSYS_NAMESPACE
|
USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
|
void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc)
|
||||||
{
|
|
||||||
log_assert(rule.compare.size() == 0);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
RTLIL::SigSpec tmp = sig;
|
|
||||||
for (auto &it : rule.actions)
|
|
||||||
tmp.replace(it.first, it.second);
|
|
||||||
if (tmp == sig)
|
|
||||||
break;
|
|
||||||
sig = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
|
|
||||||
{
|
{
|
||||||
bool found_init = false;
|
bool found_init = false;
|
||||||
|
|
||||||
|
@ -53,9 +39,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
|
||||||
for (auto &action : sync->actions)
|
for (auto &action : sync->actions)
|
||||||
{
|
{
|
||||||
RTLIL::SigSpec lhs = action.first;
|
RTLIL::SigSpec lhs = action.first;
|
||||||
RTLIL::SigSpec rhs = action.second;
|
RTLIL::SigSpec rhs = sigmap(action.second);
|
||||||
|
|
||||||
proc_get_const(rhs, proc->root_case);
|
|
||||||
|
|
||||||
if (!rhs.is_fully_const())
|
if (!rhs.is_fully_const())
|
||||||
log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs));
|
log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs));
|
||||||
|
@ -120,10 +104,12 @@ struct ProcInitPass : public Pass {
|
||||||
extra_args(args, 1, design);
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
for (auto mod : design->modules())
|
for (auto mod : design->modules())
|
||||||
if (design->selected(mod))
|
if (design->selected(mod)) {
|
||||||
|
SigMap sigmap(mod);
|
||||||
for (auto &proc_it : mod->processes)
|
for (auto &proc_it : mod->processes)
|
||||||
if (design->selected(mod, proc_it.second))
|
if (design->selected(mod, proc_it.second))
|
||||||
proc_init(mod, proc_it.second);
|
proc_init(mod, sigmap, proc_it.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} ProcInitPass;
|
} ProcInitPass;
|
||||||
|
|
||||||
|
|
158
passes/proc/proc_prune.cc
Normal file
158
passes/proc/proc_prune.cc
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 whitequark <whitequark@whitequark.org>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kernel/register.h"
|
||||||
|
#include "kernel/sigtools.h"
|
||||||
|
#include "kernel/log.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
USING_YOSYS_NAMESPACE
|
||||||
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct PruneWorker
|
||||||
|
{
|
||||||
|
RTLIL::Module *module;
|
||||||
|
SigMap sigmap;
|
||||||
|
|
||||||
|
int removed_count = 0, promoted_count = 0;
|
||||||
|
|
||||||
|
PruneWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {}
|
||||||
|
|
||||||
|
pool<RTLIL::SigBit> do_switch(RTLIL::SwitchRule *sw, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected)
|
||||||
|
{
|
||||||
|
pool<RTLIL::SigBit> all_assigned;
|
||||||
|
bool full_case = sw->get_bool_attribute("\\full_case");
|
||||||
|
bool first = true;
|
||||||
|
for (auto it : sw->cases) {
|
||||||
|
if (it->compare.empty())
|
||||||
|
full_case = true;
|
||||||
|
pool<RTLIL::SigBit> case_assigned = do_case(it, assigned, affected);
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
all_assigned = case_assigned;
|
||||||
|
} else {
|
||||||
|
for (auto &bit : all_assigned)
|
||||||
|
if (!case_assigned[bit])
|
||||||
|
all_assigned.erase(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (full_case)
|
||||||
|
assigned.insert(all_assigned.begin(), all_assigned.end());
|
||||||
|
return assigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool<RTLIL::SigBit> do_case(RTLIL::CaseRule *cs, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected,
|
||||||
|
bool root = false)
|
||||||
|
{
|
||||||
|
for (auto it = cs->switches.rbegin(); it != cs->switches.rend(); ++it) {
|
||||||
|
pool<RTLIL::SigBit> sw_assigned = do_switch((*it), assigned, affected);
|
||||||
|
assigned.insert(sw_assigned.begin(), sw_assigned.end());
|
||||||
|
}
|
||||||
|
pool<RTLIL::SigSig> remove;
|
||||||
|
for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ++it) {
|
||||||
|
RTLIL::SigSpec lhs = sigmap(it->first);
|
||||||
|
bool redundant = true;
|
||||||
|
for (auto &bit : lhs) {
|
||||||
|
if (bit.wire && !assigned[bit]) {
|
||||||
|
redundant = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (redundant) {
|
||||||
|
removed_count++;
|
||||||
|
remove.insert(*it);
|
||||||
|
} else {
|
||||||
|
if (root) {
|
||||||
|
bool promotable = true;
|
||||||
|
for (auto &bit : lhs) {
|
||||||
|
if (bit.wire && affected[bit]) {
|
||||||
|
promotable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (promotable) {
|
||||||
|
promoted_count++;
|
||||||
|
module->connect(*it);
|
||||||
|
remove.insert(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &bit : lhs)
|
||||||
|
if (bit.wire)
|
||||||
|
assigned.insert(bit);
|
||||||
|
for (auto &bit : lhs)
|
||||||
|
if (bit.wire)
|
||||||
|
affected.insert(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto it = cs->actions.begin(); it != cs->actions.end(); ) {
|
||||||
|
if (remove[*it]) {
|
||||||
|
it = cs->actions.erase(it);
|
||||||
|
} else it++;
|
||||||
|
}
|
||||||
|
return assigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_process(RTLIL::Process *pr)
|
||||||
|
{
|
||||||
|
pool<RTLIL::SigBit> affected;
|
||||||
|
do_case(&pr->root_case, {}, affected, /*root=*/true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProcPrunePass : public Pass {
|
||||||
|
ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { }
|
||||||
|
void help() YS_OVERRIDE
|
||||||
|
{
|
||||||
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||||
|
log("\n");
|
||||||
|
log(" proc_prune [selection]\n");
|
||||||
|
log("\n");
|
||||||
|
log("This pass identifies assignments in processes that are always overwritten by\n");
|
||||||
|
log("a later assignment to the same signal and removes them.\n");
|
||||||
|
log("\n");
|
||||||
|
}
|
||||||
|
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
|
{
|
||||||
|
int total_removed_count = 0, total_promoted_count = 0;
|
||||||
|
log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n");
|
||||||
|
|
||||||
|
extra_args(args, 1, design);
|
||||||
|
|
||||||
|
for (auto mod : design->modules()) {
|
||||||
|
if (!design->selected(mod))
|
||||||
|
continue;
|
||||||
|
PruneWorker worker(mod);
|
||||||
|
for (auto &proc_it : mod->processes) {
|
||||||
|
if (!design->selected(mod, proc_it.second))
|
||||||
|
continue;
|
||||||
|
worker.do_process(proc_it.second);
|
||||||
|
}
|
||||||
|
total_removed_count += worker.removed_count;
|
||||||
|
total_promoted_count += worker.promoted_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Removed %d redundant assignment%s.\n",
|
||||||
|
total_removed_count, total_removed_count == 1 ? "" : "s");
|
||||||
|
log("Promoted %d assignment%s to connection%s.\n",
|
||||||
|
total_promoted_count, total_promoted_count == 1 ? "" : "s", total_promoted_count == 1 ? "" : "s");
|
||||||
|
}
|
||||||
|
} ProcPrunePass;
|
||||||
|
|
||||||
|
PRIVATE_NAMESPACE_END
|
Loading…
Reference in a new issue