2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/register.h"
21 #include "kernel/log.h"
26 extern void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
);
30 PRIVATE_NAMESPACE_BEGIN
32 void proc_clean_switch(RTLIL::SwitchRule
*sw
, RTLIL::CaseRule
*parent
, bool &did_something
, int &count
, int max_depth
)
34 if (sw
->signal
.size() > 0 && sw
->signal
.is_fully_const())
36 int found_matching_case_idx
= -1;
37 for (int i
= 0; i
< int(sw
->cases
.size()) && found_matching_case_idx
< 0; i
++)
39 RTLIL::CaseRule
*cs
= sw
->cases
[i
];
40 if (cs
->compare
.size() == 0)
42 for (int j
= 0; j
< int(cs
->compare
.size()); j
++) {
43 RTLIL::SigSpec
&val
= cs
->compare
[j
];
44 if (!val
.is_fully_const())
46 if (val
== sw
->signal
) {
48 found_matching_case_idx
= i
;
51 cs
->compare
.erase(cs
->compare
.begin()+(j
--));
53 if (cs
->compare
.size() == 0 && found_matching_case_idx
< 0) {
54 sw
->cases
.erase(sw
->cases
.begin()+(i
--));
58 while (found_matching_case_idx
>= 0 && int(sw
->cases
.size()) > found_matching_case_idx
+1) {
59 delete sw
->cases
.back();
62 if (found_matching_case_idx
== 0)
63 sw
->signal
= RTLIL::SigSpec();
66 if (parent
->switches
.front() == sw
&& sw
->cases
.size() == 1 &&
67 (sw
->signal
.size() == 0 || sw
->cases
[0]->compare
.empty()))
70 for (auto &action
: sw
->cases
[0]->actions
)
71 parent
->actions
.push_back(action
);
72 for (auto sw2
: sw
->cases
[0]->switches
)
73 parent
->switches
.push_back(sw2
);
74 sw
->cases
[0]->switches
.clear();
80 bool all_fully_def
= true;
81 for (auto cs
: sw
->cases
)
84 proc_clean_case(cs
, did_something
, count
, max_depth
-1);
86 for (auto cmp
: cs
->compare
)
89 if (!cmp
.is_fully_def())
90 all_fully_def
= false;
92 if (sw
->signal
.size() != size
)
93 all_fully_def
= false;
97 for (auto cs
= sw
->cases
.begin(); cs
!= sw
->cases
.end();)
101 did_something
= true;
103 cs
= sw
->cases
.erase(cs
);
110 while (!sw
->cases
.empty() && sw
->cases
.back()->empty())
112 did_something
= true;
113 delete sw
->cases
.back();
114 sw
->cases
.pop_back();
120 PRIVATE_NAMESPACE_END
121 YOSYS_NAMESPACE_BEGIN
123 void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
)
125 for (size_t i
= 0; i
< cs
->actions
.size(); i
++) {
126 if (cs
->actions
[i
].first
.size() == 0) {
127 did_something
= true;
128 cs
->actions
.erase(cs
->actions
.begin() + (i
--));
131 for (size_t i
= 0; i
< cs
->switches
.size(); i
++) {
132 RTLIL::SwitchRule
*sw
= cs
->switches
[i
];
134 cs
->switches
.erase(cs
->switches
.begin() + (i
--));
135 did_something
= true;
138 } else if (max_depth
!= 0)
139 proc_clean_switch(sw
, cs
, did_something
, count
, max_depth
-1);
144 PRIVATE_NAMESPACE_BEGIN
146 void proc_clean(RTLIL::Module
*mod
, RTLIL::Process
*proc
, int &total_count
)
149 bool did_something
= true;
150 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++) {
151 for (size_t j
= 0; j
< proc
->syncs
[i
]->actions
.size(); j
++)
152 if (proc
->syncs
[i
]->actions
[j
].first
.size() == 0)
153 proc
->syncs
[i
]->actions
.erase(proc
->syncs
[i
]->actions
.begin() + (j
--));
154 if (proc
->syncs
[i
]->actions
.size() == 0) {
155 delete proc
->syncs
[i
];
156 proc
->syncs
.erase(proc
->syncs
.begin() + (i
--));
159 while (did_something
) {
160 did_something
= false;
161 proc_clean_case(&proc
->root_case
, did_something
, count
, -1);
164 log("Found and cleaned up %d empty switch%s in `%s.%s'.\n", count
, count
== 1 ? "" : "es", mod
->name
.c_str(), proc
->name
.c_str());
165 total_count
+= count
;
168 struct ProcCleanPass
: public Pass
{
169 ProcCleanPass() : Pass("proc_clean", "remove empty parts of processes") { }
170 void help() YS_OVERRIDE
172 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
174 log(" proc_clean [selection]\n");
176 log("This pass removes empty parts of processes and ultimately removes a process\n");
177 log("if it contains only empty structures.\n");
180 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
183 log_header(design
, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
185 extra_args(args
, 1, design
);
187 for (auto mod
: design
->modules()) {
188 std::vector
<RTLIL::IdString
> delme
;
189 if (!design
->selected(mod
))
191 for (auto &proc_it
: mod
->processes
) {
192 if (!design
->selected(mod
, proc_it
.second
))
194 proc_clean(mod
, proc_it
.second
, total_count
);
195 if (proc_it
.second
->syncs
.size() == 0 && proc_it
.second
->root_case
.switches
.size() == 0 &&
196 proc_it
.second
->root_case
.actions
.size() == 0) {
197 log("Removing empty process `%s.%s'.\n", log_id(mod
), proc_it
.second
->name
.c_str());
198 delme
.push_back(proc_it
.first
);
201 for (auto &id
: delme
) {
202 delete mod
->processes
[id
];
203 mod
->processes
.erase(id
);
207 log("Cleaned up %d empty switch%s.\n", total_count
, total_count
== 1 ? "" : "es");
211 PRIVATE_NAMESPACE_END