1 // Copyright 2017-2019 VMware, Inc.
2 // SPDX-License-Identifier: BSD-2-Clause
3 //
4 // The BSD-2 license (the License) set forth below applies to all parts of the
5 // Cascade project. You may not use this file except in compliance with the
6 // License.
7 //
8 // BSD-2 License
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright notice, this
14 // list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation
18 // and/or other materials provided with the distribution.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
21 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #include "verilog/transform/dead_code_eliminate.h"
32
33 #include "verilog/ast/ast.h"
34 #include "verilog/analyze/module_info.h"
35 #include "verilog/analyze/navigate.h"
36 #include "verilog/analyze/resolve.h"
37
38 namespace cascade {
39
DeadCodeEliminate()40 DeadCodeEliminate::DeadCodeEliminate() : Editor() { }
41
run(ModuleDeclaration * md)42 void DeadCodeEliminate::run(ModuleDeclaration* md) {
43 Index idx(this);
44 md->accept(&idx);
45 md->accept(this);
46 ModuleInfo(md).invalidate();
47 }
48
Index(DeadCodeEliminate * dce)49 DeadCodeEliminate::Index::Index(DeadCodeEliminate* dce) {
50 dce_ = dce;
51 }
52
visit(const Attributes * a)53 void DeadCodeEliminate::Index::visit(const Attributes* a) {
54 // Does nothing
55 (void) a;
56 }
57
visit(const Identifier * i)58 void DeadCodeEliminate::Index::visit(const Identifier* i) {
59 Visitor::visit(i);
60 const auto* r = Resolve().get_resolution(i);
61 if (r != nullptr) {
62 dce_->use_.insert(r);
63 }
64 }
65
visit(const LocalparamDeclaration * ld)66 void DeadCodeEliminate::Index::visit(const LocalparamDeclaration* ld) {
67 ld->accept_dim(this);
68 ld->accept_val(this);
69 }
70
visit(const NetDeclaration * nd)71 void DeadCodeEliminate::Index::visit(const NetDeclaration* nd) {
72 nd->accept_dim(this);
73 }
74
visit(const ParameterDeclaration * pd)75 void DeadCodeEliminate::Index::visit(const ParameterDeclaration* pd) {
76 pd->accept_dim(this);
77 pd->accept_val(this);
78 }
79
visit(const RegDeclaration * rd)80 void DeadCodeEliminate::Index::visit(const RegDeclaration* rd) {
81 rd->accept_dim(this);
82 rd->accept_val(this);
83 }
84
edit(ModuleDeclaration * md)85 void DeadCodeEliminate::edit(ModuleDeclaration* md) {
86 auto dead = false;
87 for (auto i = md->begin_items(); i != md->end_items(); ) {
88 if ((*i)->is_subclass_of(Node::Tag::declaration)) {
89 auto* d = static_cast<Declaration*>(*i);
90
91 const auto is_port = d->get_parent()->is(Node::Tag::port_declaration);
92 const auto is_stream =
93 d->is(Node::Tag::reg_declaration) &&
94 static_cast<RegDeclaration*>(d)->is_non_null_val() &&
95 static_cast<RegDeclaration*>(d)->get_val()->is(Node::Tag::fopen_expression);
96 const auto is_dead = use_.find(d->get_id()) == use_.end();
97
98 if (!is_port && !is_stream && is_dead) {
99 dead = true;
100 i = md->purge_items(i);
101 continue;
102 }
103 }
104 ++i;
105 }
106 if (dead) {
107 Navigate(md).invalidate();
108 }
109 }
110
edit(ParBlock * pb)111 void DeadCodeEliminate::edit(ParBlock* pb) {
112 auto dead = false;
113 for (auto i = pb->begin_decls(); i != pb->end_decls(); ) {
114 const auto is_dead = use_.find((*i)->get_id()) == use_.end();
115 if (is_dead) {
116 dead = true;
117 i = pb->purge_decls(i);
118 } else {
119 ++i;
120 }
121 }
122 if (dead) {
123 Navigate(pb).invalidate();
124 }
125 }
126
edit(SeqBlock * sb)127 void DeadCodeEliminate::edit(SeqBlock* sb) {
128 auto dead = false;
129 for (auto i = sb->begin_decls(); i != sb->end_decls(); ) {
130 const auto is_dead = use_.find((*i)->get_id()) == use_.end();
131 if (is_dead) {
132 dead = true;
133 i = sb->purge_decls(i);
134 } else {
135 ++i;
136 }
137 }
138 if (dead) {
139 Navigate(sb).invalidate();
140 }
141 }
142
143 } // namespace cascade
144