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