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"
25 extern void proc_clean_switch(RTLIL::SwitchRule
*sw
, RTLIL::CaseRule
*parent
, bool &did_something
, int &count
, int max_depth
);
26 extern void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
);
28 void proc_clean_switch(RTLIL::SwitchRule
*sw
, RTLIL::CaseRule
*parent
, bool &did_something
, int &count
, int max_depth
)
30 if (sw
->signal
.size() > 0 && sw
->signal
.is_fully_const())
32 int found_matching_case_idx
= -1;
33 for (int i
= 0; i
< int(sw
->cases
.size()) && found_matching_case_idx
< 0; i
++)
35 RTLIL::CaseRule
*cs
= sw
->cases
[i
];
36 if (cs
->compare
.size() == 0)
38 for (int j
= 0; j
< int(cs
->compare
.size()); j
++) {
39 RTLIL::SigSpec
&val
= cs
->compare
[j
];
40 if (!val
.is_fully_const())
42 if (val
== sw
->signal
) {
44 found_matching_case_idx
= i
;
47 cs
->compare
.erase(cs
->compare
.begin()+(j
--));
49 if (cs
->compare
.size() == 0 && found_matching_case_idx
< 0) {
50 sw
->cases
.erase(sw
->cases
.begin()+(i
--));
54 while (found_matching_case_idx
>= 0 && int(sw
->cases
.size()) > found_matching_case_idx
+1) {
55 delete sw
->cases
.back();
58 if (found_matching_case_idx
== 0)
59 sw
->signal
= RTLIL::SigSpec();
62 if (sw
->cases
.size() == 1 && (sw
->signal
.size() == 0 || sw
->cases
[0]->compare
.empty()))
65 for (auto &action
: sw
->cases
[0]->actions
)
66 parent
->actions
.push_back(action
);
67 for (auto sw2
: sw
->cases
[0]->switches
)
68 parent
->switches
.push_back(sw2
);
69 sw
->cases
[0]->switches
.clear();
75 bool all_cases_are_empty
= true;
76 for (auto cs
: sw
->cases
) {
77 if (cs
->actions
.size() != 0 || cs
->switches
.size() != 0)
78 all_cases_are_empty
= false;
80 proc_clean_case(cs
, did_something
, count
, max_depth
-1);
82 if (all_cases_are_empty
) {
84 for (auto cs
: sw
->cases
)
91 void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
)
93 for (size_t i
= 0; i
< cs
->actions
.size(); i
++) {
94 if (cs
->actions
[i
].first
.size() == 0) {
96 cs
->actions
.erase(cs
->actions
.begin() + (i
--));
99 for (size_t i
= 0; i
< cs
->switches
.size(); i
++) {
100 RTLIL::SwitchRule
*sw
= cs
->switches
[i
];
101 if (sw
->cases
.size() == 0) {
102 cs
->switches
.erase(cs
->switches
.begin() + (i
--));
103 did_something
= true;
106 } else if (max_depth
!= 0)
107 proc_clean_switch(sw
, cs
, did_something
, count
, max_depth
-1);
111 static void proc_clean(RTLIL::Module
*mod
, RTLIL::Process
*proc
, int &total_count
)
114 bool did_something
= true;
115 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++) {
116 for (size_t j
= 0; j
< proc
->syncs
[i
]->actions
.size(); j
++)
117 if (proc
->syncs
[i
]->actions
[j
].first
.size() == 0)
118 proc
->syncs
[i
]->actions
.erase(proc
->syncs
[i
]->actions
.begin() + (j
--));
119 if (proc
->syncs
[i
]->actions
.size() == 0) {
120 delete proc
->syncs
[i
];
121 proc
->syncs
.erase(proc
->syncs
.begin() + (i
--));
124 while (did_something
) {
125 did_something
= false;
126 proc_clean_case(&proc
->root_case
, did_something
, count
, -1);
129 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());
130 total_count
+= count
;
133 struct ProcCleanPass
: public Pass
{
134 ProcCleanPass() : Pass("proc_clean", "remove empty parts of processes") { }
137 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
139 log(" proc_clean [selection]\n");
141 log("This pass removes empty parts of processes and ultimately removes a process\n");
142 log("if it contains only empty structures.\n");
145 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
148 log_header("Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
150 extra_args(args
, 1, design
);
152 for (auto &mod_it
: design
->modules
) {
153 std::vector
<std::string
> delme
;
154 if (!design
->selected(mod_it
.second
))
156 for (auto &proc_it
: mod_it
.second
->processes
) {
157 if (!design
->selected(mod_it
.second
, proc_it
.second
))
159 proc_clean(mod_it
.second
, proc_it
.second
, total_count
);
160 if (proc_it
.second
->syncs
.size() == 0 && proc_it
.second
->root_case
.switches
.size() == 0 &&
161 proc_it
.second
->root_case
.actions
.size() == 0) {
162 log("Removing empty process `%s.%s'.\n", mod_it
.first
.c_str(), proc_it
.second
->name
.c_str());
163 delme
.push_back(proc_it
.first
);
166 for (auto &id
: delme
) {
167 delete mod_it
.second
->processes
[id
];
168 mod_it
.second
->processes
.erase(id
);
172 log("Cleaned up %d empty switch%s.\n", total_count
, total_count
== 1 ? "" : "es");