Merge pull request #1240 from ucb-bar/firrtl-properties+pow+xnor
[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("\\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 pool<RTLIL::SigSig> remove;
69 for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ++it) {
70 RTLIL::SigSpec lhs = sigmap(it->first);
71 bool redundant = true;
72 for (auto &bit : lhs) {
73 if (bit.wire && !assigned[bit]) {
74 redundant = false;
75 break;
76 }
77 }
78 if (redundant) {
79 removed_count++;
80 remove.insert(*it);
81 } else {
82 if (root) {
83 bool promotable = true;
84 for (auto &bit : lhs) {
85 if (bit.wire && affected[bit] && !assigned[bit]) {
86 promotable = false;
87 break;
88 }
89 }
90 if (promotable) {
91 RTLIL::SigSpec rhs = sigmap(it->second);
92 RTLIL::SigSig conn;
93 for (int i = 0; i < GetSize(lhs); i++) {
94 RTLIL::SigBit lhs_bit = lhs[i];
95 if (lhs_bit.wire && !assigned[lhs_bit]) {
96 conn.first.append_bit(lhs_bit);
97 conn.second.append(rhs.extract(i));
98 }
99 }
100 promoted_count++;
101 module->connect(conn);
102 remove.insert(*it);
103 }
104 }
105 for (auto &bit : lhs)
106 if (bit.wire)
107 assigned.insert(bit);
108 for (auto &bit : lhs)
109 if (bit.wire)
110 affected.insert(bit);
111 }
112 }
113 for (auto it = cs->actions.begin(); it != cs->actions.end(); ) {
114 if (remove[*it]) {
115 it = cs->actions.erase(it);
116 } else it++;
117 }
118 return assigned;
119 }
120
121 void do_process(RTLIL::Process *pr)
122 {
123 pool<RTLIL::SigBit> affected;
124 do_case(&pr->root_case, {}, affected, /*root=*/true);
125 }
126 };
127
128 struct ProcPrunePass : public Pass {
129 ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { }
130 void help() YS_OVERRIDE
131 {
132 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
133 log("\n");
134 log(" proc_prune [selection]\n");
135 log("\n");
136 log("This pass identifies assignments in processes that are always overwritten by\n");
137 log("a later assignment to the same signal and removes them.\n");
138 log("\n");
139 }
140 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
141 {
142 int total_removed_count = 0, total_promoted_count = 0;
143 log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n");
144
145 extra_args(args, 1, design);
146
147 for (auto mod : design->modules()) {
148 if (!design->selected(mod))
149 continue;
150 PruneWorker worker(mod);
151 for (auto &proc_it : mod->processes) {
152 if (!design->selected(mod, proc_it.second))
153 continue;
154 worker.do_process(proc_it.second);
155 }
156 total_removed_count += worker.removed_count;
157 total_promoted_count += worker.promoted_count;
158 }
159
160 log("Removed %d redundant assignment%s.\n",
161 total_removed_count, total_removed_count == 1 ? "" : "s");
162 log("Promoted %d assignment%s to connection%s.\n",
163 total_promoted_count, total_promoted_count == 1 ? "" : "s", total_promoted_count == 1 ? "" : "s");
164 }
165 } ProcPrunePass;
166
167 PRIVATE_NAMESPACE_END