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