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/index_normalize.h"
32 
33 #include <cassert>
34 #include "verilog/analyze/constant.h"
35 #include "verilog/analyze/evaluate.h"
36 #include "verilog/analyze/resolve.h"
37 #include "verilog/ast/ast.h"
38 
39 using namespace std;
40 
41 namespace cascade {
42 
run(ModuleDeclaration * md)43 void IndexNormalize::run(ModuleDeclaration* md) {
44   FixUses fu;
45   md->accept(&fu);
46   FixDecls fd;
47   md->accept(&fd);
48 
49   // We may have deleted some static constant variables inside declarations.
50   Resolve().invalidate(md);
51 }
52 
FixDecls()53 IndexNormalize::FixDecls::FixDecls() : Editor() { }
54 
edit(GenvarDeclaration * gd)55 void IndexNormalize::FixDecls::edit(GenvarDeclaration* gd) {
56   fix_arity(gd->get_id());
57   if (gd->is_non_null_dim()) {
58     fix_dim(gd->get_dim());
59   }
60 }
61 
edit(LocalparamDeclaration * ld)62 void IndexNormalize::FixDecls::edit(LocalparamDeclaration* ld) {
63   fix_arity(ld->get_id());
64   if (ld->is_non_null_dim()) {
65     fix_dim(ld->get_dim());
66   }
67 }
68 
edit(NetDeclaration * nd)69 void IndexNormalize::FixDecls::edit(NetDeclaration* nd) {
70   fix_arity(nd->get_id());
71   if (nd->is_non_null_dim()) {
72     fix_dim(nd->get_dim());
73   }
74 }
75 
edit(ParameterDeclaration * pd)76 void IndexNormalize::FixDecls::edit(ParameterDeclaration* pd) {
77   fix_arity(pd->get_id());
78   if (pd->is_non_null_dim()) {
79     fix_dim(pd->get_dim());
80   }
81 }
82 
edit(RegDeclaration * rd)83 void IndexNormalize::FixDecls::edit(RegDeclaration* rd) {
84   fix_arity(rd->get_id());
85   if (rd->is_non_null_dim()) {
86     fix_dim(rd->get_dim());
87   }
88 }
89 
fix_arity(Identifier * id) const90 void IndexNormalize::FixDecls::fix_arity(Identifier* id) const {
91   for (auto i = id->begin_dim(), ie = id->end_dim(); i != ie; ++i) {
92     assert((*i)->is(Node::Tag::range_expression));
93     auto* re = static_cast<RangeExpression*>(*i);
94     fix_dim(re);
95   }
96 }
97 
fix_dim(RangeExpression * re) const98 void IndexNormalize::FixDecls::fix_dim(RangeExpression* re) const {
99   assert(Constant().is_static_constant(re));
100   const auto rng = Evaluate().get_range(re);
101   assert(rng.first >= rng.second);
102   if (rng.second == 0) {
103     return;
104   }
105 
106   re->set_type(RangeExpression::Type::CONSTANT);
107   re->replace_upper(new Number(Bits(32, rng.first-rng.second)));
108   re->replace_lower(new Number(Bits(32, 0)));
109   Evaluate().invalidate(re);
110 }
111 
FixUses()112 IndexNormalize::FixUses::FixUses() : Editor() { }
113 
edit(Attributes * a)114 void IndexNormalize::FixUses::edit(Attributes* a) {
115   // Don't descend past here
116   (void) a;
117 }
118 
edit(Identifier * id)119 void IndexNormalize::FixUses::edit(Identifier* id) {
120   const auto* r = Resolve().get_resolution(id);
121   assert(r != nullptr);
122   const auto* p = r->get_parent();
123   assert(p != nullptr);
124   assert(p->is_subclass_of(Node::Tag::declaration));
125   const auto* d = static_cast<const Declaration*>(p);
126 
127   // Fix array indices. Typechecking should ensure that there are as many of
128   // these as appear in this variable's declaration.
129   size_t i = 0;
130   for (size_t ie = r->size_dim(); i < ie; ++i) {
131     assert(r->get_dim(i)->is(Node::Tag::range_expression));
132     fix_use(id, i, static_cast<const RangeExpression*>(r->get_dim(i)));
133   }
134   // The presence of a bit-select doesn't gaurantee that a range appears in a
135   // declaration (see parameters, for example). When a range doesn't exist in a
136   // declaration, it defaults to having 0 as a lsb, and nothing needs to be
137   // done here.
138   if ((i < id->size_dim()) && d->is_non_null_dim()) {
139     fix_use(id, i, d->get_dim());
140   }
141 }
142 
edit(ModuleDeclaration * md)143 void IndexNormalize::FixUses::edit(ModuleDeclaration* md) {
144   // Only descend on items
145   md->accept_items(this);
146 }
147 
edit(GenvarDeclaration * gd)148 void IndexNormalize::FixUses::edit(GenvarDeclaration* gd) {
149   // Does nothing; don't descend past here.
150   (void) gd;
151 }
152 
edit(LocalparamDeclaration * ld)153 void IndexNormalize::FixUses::edit(LocalparamDeclaration* ld) {
154   // Does nothing; don't descend past here.
155   (void) ld;
156 }
157 
edit(NetDeclaration * nd)158 void IndexNormalize::FixUses::edit(NetDeclaration* nd) {
159   // Does nothing; don't descend past here.
160   (void) nd;
161 }
162 
edit(ParameterDeclaration * pd)163 void IndexNormalize::FixUses::edit(ParameterDeclaration* pd) {
164   // Does nothing; don't descend past here.
165   (void) pd;
166 }
167 
edit(RegDeclaration * rd)168 void IndexNormalize::FixUses::edit(RegDeclaration* rd) {
169   // Does nothing; don't descend past here.
170   (void) rd;
171 }
172 
edit(DebugStatement * ds)173 void IndexNormalize::FixUses::edit(DebugStatement* ds) {
174   // Does nothing; don't descend past here.
175   (void) ds;
176 }
177 
fix_use(Identifier * id,size_t n,const RangeExpression * re) const178 void IndexNormalize::FixUses::fix_use(Identifier* id, size_t n, const RangeExpression* re) const {
179   assert(Constant().is_static_constant(re));
180   const auto rng = Evaluate().get_range(re);
181   assert(rng.first >= rng.second);
182   if (rng.second == 0) {
183     return;
184   }
185 
186   if (id->get_dim(n)->is(Node::Tag::range_expression)) {
187     fix_range(id, n, rng.second);
188   } else {
189     fix_scalar(id, n, rng.second);
190   }
191 }
192 
fix_scalar(Identifier * id,size_t n,size_t delta) const193 void IndexNormalize::FixUses::fix_scalar(Identifier* id, size_t n, size_t delta) const {
194   assert(!id->get_dim(n)->is(Node::Tag::range_expression));
195   auto* expr = id->get_dim(n);
196 
197   if (Constant().is_static_constant(expr)) {
198     id->replace_dim(n, new Number(Bits(32, Evaluate().get_value(expr).to_uint()-delta)));
199   } else {
200     id->replace_dim(n, new BinaryExpression(expr->clone(), BinaryExpression::Op::MINUS, new Number(Bits(32, delta))));
201   }
202 }
203 
fix_range(Identifier * id,size_t n,size_t delta) const204 void IndexNormalize::FixUses::fix_range(Identifier* id, size_t n, size_t delta) const {
205   assert(id->get_dim(n)->is(Node::Tag::range_expression));
206   auto* re = static_cast<RangeExpression*>(id->get_dim(n));
207 
208   switch (re->get_type()) {
209     case RangeExpression::Type::CONSTANT:
210       assert(Constant().is_static_constant(re->get_upper()));
211       assert(Constant().is_static_constant(re->get_lower()));
212       re->replace_upper(new Number(Bits(32, Evaluate().get_value(re->get_upper()).to_uint()-delta)));
213       re->replace_lower(new Number(Bits(32, Evaluate().get_value(re->get_lower()).to_uint()-delta)));
214       Evaluate().invalidate(re);
215       break;
216     case RangeExpression::Type::PLUS:
217     case RangeExpression::Type::MINUS:
218       if (Constant().is_static_constant(re->get_upper())) {
219         re->replace_upper(new Number(Bits(32, Evaluate().get_value(re->get_upper()).to_uint()-delta)));
220       } else {
221         re->replace_upper(new BinaryExpression(re->get_upper()->clone(), BinaryExpression::Op::MINUS, new Number(Bits(32, delta))));
222       }
223       break;
224     default:
225       assert(false);
226       break;
227   }
228 }
229 
230 } // namespace cascade
231