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