P4C
The P4 Compiler
Loading...
Searching...
No Matches
frontends/p4/alias.h
1/*
2Copyright 2019 VMware, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef FRONTENDS_P4_ALIAS_H_
18#define FRONTENDS_P4_ALIAS_H_
19
20/*
21 * A simple conservative syntactic alias analysis. Two things may
22 * alias if they refer to objects with the same name. This pass may
23 * be run early in the front end, before enough information is present
24 * (eg. def-use information) to do a precise alias analysis. Also,
25 * this pass is safe only if the expressions compared for aliasing are
26 * part of the *same statement*.
27 */
28
29#include "frontends/common/resolveReferences/resolveReferences.h"
30#include "ir/ir.h"
31
32namespace P4 {
33
34using namespace literals;
35
40struct LocationPath : public IHasDbPrint {
41 const IR::IDeclaration *root;
42 std::vector<cstring> path;
43
44 explicit LocationPath(const IR::IDeclaration *root) : root(root) { CHECK_NULL(root); }
45
46 const LocationPath *append(cstring suffix) const {
47 auto result = new LocationPath(root);
48 result->path = path;
49 result->path.push_back(suffix);
50 return result;
51 }
52
54 bool isPrefix(const LocationPath *other) const {
55 // Due to the structure of the P4 language, two distinct
56 // declarations can never alias.
57 if (root != other->root) return false;
58 size_t len = std::min(path.size(), other->path.size());
59 for (size_t i = 0; i < len; i++) {
60 if (path.at(i) == "*" || other->path.at(i) == "*") continue;
61 if (path.at(i) != other->path.at(i)) return false;
62 }
63 return true;
64 }
65
66 void dbprint(std::ostream &out) const override {
67 out << root->getName();
68 for (auto p : path) out << "." << p;
69 }
70};
71
75 public:
76 std::set<const LocationPath *> paths;
77
78 SetOfLocations() = default;
79 explicit SetOfLocations(const LocationPath *path) { add(path); }
80 explicit SetOfLocations(const SetOfLocations *set) : paths(set->paths) {}
81
82 void add(const LocationPath *path) { paths.emplace(path); }
83 bool overlaps(const SetOfLocations *other) const {
84 // Normally one of these sets has only one element, because
85 // one of the two is a left-value, so this should be fast.
86 for (auto s : paths) {
87 for (auto so : other->paths) {
88 if (s->isPrefix(so)) return true;
89 }
90 }
91 return false;
92 }
93
94 const SetOfLocations *join(const SetOfLocations *other) const {
95 auto result = new SetOfLocations(this);
96 for (auto p : other->paths) result->add(p);
97 return result;
98 }
99
101 const SetOfLocations *append(cstring suffix) const {
102 auto result = new SetOfLocations();
103 for (auto p : paths) {
104 auto append = p->append(suffix);
105 result->add(append);
106 }
107 return result;
108 }
109
110 void dbprint(std::ostream &out) const override {
111 for (auto p : paths) out << p << std::endl;
112 }
113};
114
117 std::map<const IR::Expression *, const SetOfLocations *> rw;
118
119 public:
120 ReadsWrites() { setName("ReadsWrites"); }
121
122 void postorder(const IR::Operation_Binary *expression) override {
123 auto left = ::P4::get(rw, expression->left);
124 auto right = ::P4::get(rw, expression->right);
125 CHECK_NULL(left);
126 CHECK_NULL(right);
127 rw.emplace(expression, left->join(right));
128 }
129
130 void postorder(const IR::PathExpression *expression) override {
131 auto decl = getDeclaration(expression->path);
132 auto path = new LocationPath(decl);
133 auto locs = new SetOfLocations(path);
134 rw.emplace(expression, locs);
135 }
136
137 void postorder(const IR::Operation_Unary *expression) override {
138 auto e = ::P4::get(rw, expression->expr);
139 CHECK_NULL(e);
140 rw.emplace(expression, e);
141 }
142
143 void postorder(const IR::Member *expression) override {
144 auto e = ::P4::get(rw, expression->expr);
145 CHECK_NULL(e);
146 auto result = e->append(expression->member);
147 rw.emplace(expression, result);
148 }
149
150 void postorder(const IR::ArrayIndex *expression) override {
151 auto e = ::P4::get(rw, expression->left);
152 CHECK_NULL(e);
153 const SetOfLocations *result;
154 if (expression->right->is<IR::Constant>()) {
155 int index = expression->right->to<IR::Constant>()->asInt();
156 result = e->append(Util::toString(index));
157 } else {
158 auto index = ::P4::get(rw, expression->right);
159 result = e->append("*"_cs)->join(index);
160 }
161 rw.emplace(expression, result);
162 }
163
164 void postorder(const IR::Literal *expression) override {
165 rw.emplace(expression, new SetOfLocations());
166 }
167
168 void postorder(const IR::InvalidHeader *expression) override {
169 rw.emplace(expression, new SetOfLocations());
170 }
171
172 void postorder(const IR::InvalidHeaderUnion *expression) override {
173 rw.emplace(expression, new SetOfLocations());
174 }
175
176 void postorder(const IR::HeaderStackExpression *expression) override {
177 rw.emplace(expression, new SetOfLocations());
178 }
179
180 void postorder(const IR::TypeNameExpression *expression) override {
181 rw.emplace(expression, new SetOfLocations());
182 }
183
184 void postorder(const IR::Operation_Ternary *expression) override {
185 auto e0 = ::P4::get(rw, expression->e0);
186 auto e1 = ::P4::get(rw, expression->e1);
187 auto e2 = ::P4::get(rw, expression->e2);
188 CHECK_NULL(e0);
189 CHECK_NULL(e1);
190 CHECK_NULL(e2);
191 rw.emplace(expression, e0->join(e1)->join(e2));
192 }
193
194 void postorder(const IR::AbstractSlice *expression) override {
195 auto e = ::P4::get(rw, expression->e0);
196 CHECK_NULL(e);
197 rw.emplace(expression, e);
198 }
199
200 void postorder(const IR::MethodCallExpression *expression) override {
201 auto e = ::P4::get(rw, expression->method);
202 for (auto a : *expression->arguments) {
203 auto s = ::P4::get(rw, a->expression);
204 CHECK_NULL(s);
205 e = e->join(s);
206 }
207 rw.emplace(expression, e);
208 }
209
210 void postorder(const IR::ConstructorCallExpression *expression) override {
211 const SetOfLocations *result = new SetOfLocations();
212 for (auto e : *expression->arguments) {
213 auto s = ::P4::get(rw, e->expression);
214 CHECK_NULL(s);
215 result = result->join(s);
216 }
217 rw.emplace(expression, result);
218 }
219
220 void postorder(const IR::StructExpression *expression) override {
221 const SetOfLocations *result = new SetOfLocations();
222 for (auto e : expression->components) {
223 auto s = ::P4::get(rw, e->expression);
224 CHECK_NULL(s);
225 result = result->join(s);
226 }
227 rw.emplace(expression, result);
228 }
229
230 void postorder(const IR::ListExpression *expression) override {
231 const SetOfLocations *result = new SetOfLocations();
232 for (auto e : expression->components) {
233 auto s = ::P4::get(rw, e);
234 CHECK_NULL(s);
235 result = result->join(s);
236 }
237 rw.emplace(expression, result);
238 }
239
240 void postorder(const IR::DefaultExpression *expression) override {
241 rw.emplace(expression, new SetOfLocations());
242 }
243
244 const SetOfLocations *get(const IR::Expression *expression, const Visitor::Context *ctxt) {
245 expression->apply(*this, ctxt);
246 auto result = ::P4::get(rw, expression);
247 CHECK_NULL(result);
248 LOG3("SetOfLocations(" << expression << ")=" << result);
249 return result;
250 }
251
252 bool mayAlias(const IR::Expression *left, const IR::Expression *right,
253 const Visitor::Context *ctxt) {
254 auto llocs = get(left, ctxt);
255 auto rlocs = get(right, ctxt);
256 CHECK_NULL(llocs);
257 CHECK_NULL(rlocs);
258 LOG3("Checking overlap between " << llocs << " and " << rlocs);
259 return llocs->overlaps(rlocs);
260 }
261};
262
263} // namespace P4
264
265#endif /* FRONTENDS_P4_ALIAS_H_ */
Definition stringify.h:33
The Declaration interface, representing objects with names.
Definition declaration.h:26
Definition visitor.h:400
Computes the SetOfLocations read and written by an expression.
Definition frontends/p4/alias.h:116
Visitor mixin for looking up names in enclosing scopes from the Visitor::Context.
Definition resolveReferences.h:35
Definition frontends/p4/alias.h:74
const SetOfLocations * append(cstring suffix) const
Append suffix to each location in the set.
Definition frontends/p4/alias.h:101
Definition cstring.h:85
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition frontends/p4/alias.h:40
bool isPrefix(const LocationPath *other) const
True if this path is a prefix of other or the other way around.
Definition frontends/p4/alias.h:54
Definition visitor.h:47