dfflegalize: Add tests for aldff lowering.
[yosys.git] / passes / proc / proc_prune.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2019 whitequark <whitequark@whitequark.org>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 struct PruneWorker
30 {
31 RTLIL::Module *module;
32 SigMap sigmap;
33
34 int removed_count = 0, promoted_count = 0;
35
36 PruneWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {}
37
38 pool<RTLIL::SigBit> do_switch(RTLIL::SwitchRule *sw, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected)
39 {
40 pool<RTLIL::SigBit> all_assigned;
41 bool full_case = sw->get_bool_attribute(ID::full_case);
42 bool first = true;
43 for (auto it : sw->cases) {
44 if (it->compare.empty())
45 full_case = true;
46 pool<RTLIL::SigBit> case_assigned = do_case(it, assigned, affected);
47 if (first) {
48 first = false;
49 all_assigned = case_assigned;
50 } else {
51 for (auto &bit : all_assigned)
52 if (!case_assigned[bit])
53 all_assigned.erase(bit);
54 }
55 }
56 if (full_case)
57 assigned.insert(all_assigned.begin(), all_assigned.end());
58 return assigned;
59 }
60
61 pool<RTLIL::SigBit> do_case(RTLIL::CaseRule *cs, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected,
62 bool root = false)
63 {
64 for (auto it = cs->switches.rbegin(); it != cs->switches.rend(); ++it) {
65 pool<RTLIL::SigBit> sw_assigned = do_switch((*it), assigned, affected);
66 assigned.insert(sw_assigned.begin(), sw_assigned.end());
67 }
68 for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ) {
69 RTLIL::SigSpec lhs = sigmap(it->first);
70 RTLIL::SigSpec rhs = sigmap(it->second);
71 SigSpec new_lhs, new_rhs;
72 SigSpec conn_lhs, conn_rhs;
73 for (int i = 0; i < GetSize(lhs); i++) {
74 SigBit bit = lhs[i];
75 if (bit.wire && !assigned[bit]) {
76 if (!affected[bit] && root) {
77 conn_lhs.append(bit);
78 conn_rhs.append(rhs[i]);
79 } else {
80 new_lhs.append(bit);
81 new_rhs.append(rhs[i]);
82 }
83 assigned.insert(bit);
84 affected.insert(bit);
85 }
86 }
87 if (GetSize(conn_lhs)) {
88 promoted_count++;
89 module->connect(conn_lhs, conn_rhs);
90 }
91 if (GetSize(new_lhs) == 0) {
92 if (GetSize(conn_lhs) == 0)
93 removed_count++;
94 cs->actions.erase((it++).base() - 1);
95 } else {
96 it->first = new_lhs;
97 it->second = new_rhs;
98 it++;
99 }
100 }
101 return assigned;
102 }
103
104 void do_process(RTLIL::Process *pr)
105 {
106 pool<RTLIL::SigBit> affected;
107 do_case(&pr->root_case, {}, affected, /*root=*/true);
108 }
109 };
110
111 struct ProcPrunePass : public Pass {
112 ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { }
113 void help() override
114 {
115 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
116 log("\n");
117 log(" proc_prune [selection]\n");
118 log("\n");
119 log("This pass identifies assignments in processes that are always overwritten by\n");
120 log("a later assignment to the same signal and removes them.\n");
121 log("\n");
122 }
123 void execute(std::vector<std::string> args, RTLIL::Design *design) override
124 {
125 int total_removed_count = 0, total_promoted_count = 0;
126 log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n");
127
128 extra_args(args, 1, design);
129
130 for (auto mod : design->modules()) {
131 if (!design->selected(mod))
132 continue;
133 PruneWorker worker(mod);
134 for (auto &proc_it : mod->processes) {
135 if (!design->selected(mod, proc_it.second))
136 continue;
137 worker.do_process(proc_it.second);
138 }
139 total_removed_count += worker.removed_count;
140 total_promoted_count += worker.promoted_count;
141 }
142
143 log("Removed %d redundant assignment%s.\n",
144 total_removed_count, total_removed_count == 1 ? "" : "s");
145 log("Promoted %d assignment%s to connection%s.\n",
146 total_promoted_count, total_promoted_count == 1 ? "" : "s", total_promoted_count == 1 ? "" : "s");
147 }
148 } ProcPrunePass;
149
150 PRIVATE_NAMESPACE_END