P4C
The P4 Compiler
 
Loading...
Searching...
No Matches
def_use.h
1/*
2Copyright 2016 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_DEF_USE_H_
18#define FRONTENDS_P4_DEF_USE_H_
19
20#include <absl/container/flat_hash_set.h>
21#include <absl/container/inlined_vector.h>
22
23#include "frontends/common/resolveReferences/referenceMap.h"
24#include "ir/ir.h"
25#include "lib/alloc_trace.h"
26#include "lib/hash.h"
27#include "lib/hvec_map.h"
28#include "lib/ordered_set.h"
29#include "typeMap.h"
30
31namespace P4 {
32
33class StorageFactory;
34class LocationSet;
35
37class StorageLocation : public IHasDbPrint, public ICastable {
38 static unsigned crtid;
39
40 public:
41 virtual ~StorageLocation() {}
42 unsigned id;
43 const IR::Type *type;
44 const cstring name;
45 StorageLocation(const IR::Type *type, cstring name) : id(crtid++), type(type), name(name) {
46 CHECK_NULL(type);
47 }
48 void dbprint(std::ostream &out) const override { out << id << " " << name; }
49 cstring toString() const { return name; }
50
52 const LocationSet *getValidBits() const;
53 virtual void addValidBits(LocationSet *result) const = 0;
55 const LocationSet *removeHeaders() const;
56 virtual void removeHeaders(LocationSet *result) const = 0;
58 const LocationSet *getLastIndexField() const;
59 virtual void addLastIndexField(LocationSet *result) const = 0;
60
61 DECLARE_TYPEINFO(StorageLocation);
62};
63
67 public:
68 BaseLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {
69 if (auto tt = type->to<IR::Type_Tuple>())
70 BUG_CHECK(tt->getSize() == 0, "%1%: tuples with fields are not base locations", tt);
71 else if (auto ts = type->to<IR::Type_StructLike>())
72 BUG_CHECK(ts->fields.size() == 0, "%1%: structs with fields are not base locations",
73 tt);
74 else
75 BUG_CHECK(type->is<IR::Type_Bits>() || type->is<IR::Type_Enum>() ||
76 type->is<IR::Type_Boolean>() || type->is<IR::Type_Var>() ||
77 type->is<IR::Type_Error>() || type->is<IR::Type_Varbits>() ||
78 type->is<IR::Type_Newtype>() || type->is<IR::Type_SerEnum>() ||
79 type->is<IR::Type_List>(),
80 "%1%: unexpected type", type);
81 }
82 void addValidBits(LocationSet *) const override {}
83 void addLastIndexField(LocationSet *) const override {}
84 void removeHeaders(LocationSet *result) const override;
85
86 DECLARE_TYPEINFO(BaseLocation, StorageLocation);
87};
88
91 protected:
93 friend class StorageFactory;
94 WithFieldsLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {}
95
96 public:
97 void createField(cstring name, StorageLocation *field) {
98 fieldLocations.emplace(name, field);
99 CHECK_NULL(field);
100 }
101 void replaceField(cstring field, StorageLocation *replacement) {
102 fieldLocations[field] = replacement;
103 }
105 return Values(fieldLocations);
106 }
107 void dbprint(std::ostream &out) const override {
108 for (auto f : fieldLocations) out << *f.second << " ";
109 }
110
111 DECLARE_TYPEINFO(WithFieldsLocation, StorageLocation);
112};
113
116 public:
117 StructLocation(const IR::Type *type, cstring name) : WithFieldsLocation(type, name) {
118 BUG_CHECK(type->is<IR::Type_StructLike>(), "%1%: unexpected type", type);
119 }
120 void addField(cstring field, LocationSet *addTo) const;
121 void addValidBits(LocationSet *result) const override;
122 void removeHeaders(LocationSet *result) const override;
123 void addLastIndexField(LocationSet *result) const override;
124 bool isHeader() const { return type->is<IR::Type_Header>(); }
125 bool isHeaderUnion() const { return type->is<IR::Type_HeaderUnion>(); }
126 bool isStruct() const { return type->is<IR::Type_Struct>(); }
127
128 DECLARE_TYPEINFO(StructLocation, WithFieldsLocation);
129};
130
133 protected:
134 absl::InlinedVector<const StorageLocation *, 8> elements;
135 friend class StorageFactory;
136
137 void createElement(unsigned index, StorageLocation *element) {
138 elements[index] = element;
139 CHECK_NULL(element);
140 }
141
142 public:
143 IndexedLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {
144 CHECK_NULL(type);
145 auto it = type->to<IR::Type_Indexed>();
146 BUG_CHECK(it != nullptr, "%1%: unexpected type", type);
147 elements.resize(it->getSize());
148 }
149 void addElement(unsigned index, LocationSet *result) const;
150 auto begin() const { return elements.cbegin(); }
151 auto end() const { return elements.cend(); }
152
153 DECLARE_TYPEINFO(IndexedLocation, StorageLocation);
154};
155
158 public:
159 TupleLocation(const IR::Type *type, cstring name) : IndexedLocation(type, name) {}
160 size_t getSize() const { return elements.size(); }
161 void addValidBits(LocationSet *) const override {}
162 void addLastIndexField(LocationSet *) const override {}
163 void removeHeaders(LocationSet *result) const override;
164
165 DECLARE_TYPEINFO(TupleLocation, IndexedLocation);
166};
167
169 const StorageLocation *lastIndexField; // accessed by lastIndex
170 public:
171 ArrayLocation(const IR::Type *type, cstring name)
172 : IndexedLocation(type, name), lastIndexField(nullptr) {}
173 void setLastIndexField(const StorageLocation *location) { lastIndexField = location; }
174 const StorageLocation *getLastIndexField() const { return lastIndexField; }
175 void dbprint(std::ostream &out) const override {
176 for (unsigned i = 0; i < elements.size(); i++) out << *elements.at(i) << " ";
177 }
178 void addValidBits(LocationSet *result) const override;
179 void removeHeaders(LocationSet *) const override {} // no results added
180 void addLastIndexField(LocationSet *result) const override;
181
182 DECLARE_TYPEINFO(ArrayLocation, IndexedLocation);
183};
184
186 public:
187 StorageLocation *create(const IR::Type *type, cstring name) const;
188
189 static const cstring validFieldName;
190 static const cstring indexFieldName;
191};
192
195class LocationSet : public IHasDbPrint {
197
198 public:
199 LocationSet() = default;
200 explicit LocationSet(const ordered_set<const StorageLocation *> &other) : locations(other) {}
201 explicit LocationSet(const StorageLocation *location) {
202 CHECK_NULL(location);
203 locations.emplace(location);
204 }
205 static const LocationSet *empty;
206
207 const LocationSet *getField(cstring field) const;
208 const LocationSet *getValidField() const;
209 const LocationSet *getIndex(unsigned index) const;
210 const LocationSet *allElements() const;
211 const LocationSet *getArrayLastIndex() const;
212
213 void add(const StorageLocation *location) {
214 CHECK_NULL(location);
215 locations.emplace(location);
216 }
217 const LocationSet *join(const LocationSet *other) const;
220 const LocationSet *canonicalize() const;
221 void addCanonical(const StorageLocation *location);
222 ordered_set<const StorageLocation *>::const_iterator begin() const {
223 return locations.cbegin();
224 }
225 ordered_set<const StorageLocation *>::const_iterator end() const { return locations.cend(); }
226 void dbprint(std::ostream &out) const override {
227 if (locations.empty()) out << "LocationSet::empty";
228 for (auto l : locations) {
229 l->dbprint(out);
230 out << " ";
231 }
232 }
233 // only defined for canonical representations
234 bool overlaps(const LocationSet *other) const;
235 bool isEmpty() const { return locations.empty(); }
236};
237
239class StorageMap : public IHasDbPrint {
242 StorageFactory factory;
243
244 public:
245 ReferenceMap *refMap;
246 TypeMap *typeMap;
247
248 StorageMap(ReferenceMap *refMap, TypeMap *typeMap) : refMap(refMap), typeMap(typeMap) {
249 CHECK_NULL(refMap);
250 CHECK_NULL(typeMap);
251 }
252 StorageLocation *add(const IR::IDeclaration *decl) {
253 CHECK_NULL(decl);
254 auto type = typeMap->getType(decl->getNode(), true);
255 auto loc = factory.create(type, decl->getName() + "/" + decl->externalName());
256 if (loc != nullptr) storage.emplace(decl, loc);
257 return loc;
258 }
259 StorageLocation *getOrAdd(const IR::IDeclaration *decl) {
260 auto s = getStorage(decl);
261 if (s != nullptr) return s;
262 return add(decl);
263 }
264 StorageLocation *getStorage(const IR::IDeclaration *decl) const {
265 CHECK_NULL(decl);
266 auto result = ::get(storage, decl);
267 return result;
268 }
269 void dbprint(std::ostream &out) const override {
270 for (auto &it : storage) out << it.first << ": " << it.second << Log::endl;
271 }
272};
273
275class ProgramPoint : public IHasDbPrint {
283 absl::InlinedVector<const IR::Node *, 8> stack; // Has inline space for 8 nodes
284
285 public:
286 ProgramPoint() = default;
287 ProgramPoint(const ProgramPoint &other) : stack(other.stack) {}
288 explicit ProgramPoint(const IR::Node *node) {
289 CHECK_NULL(node);
290 assign(node);
291 }
292 ProgramPoint(const ProgramPoint &context, const IR::Node *node);
296 ProgramPoint after() { return ProgramPoint(*this, nullptr); }
297 bool operator==(const ProgramPoint &other) const;
298 std::size_t hash() const;
299 void dbprint(std::ostream &out) const override {
300 if (isBeforeStart()) {
301 out << "<BeforeStart>";
302 } else {
303 bool first = true;
304 for (auto n : stack) {
305 if (!first) out << "//";
306 if (!n)
307 out << "After end";
308 else
309 out << dbp(n);
310 first = false;
311 }
312 auto l = stack.back();
313 if (l != nullptr &&
314 (l->is<IR::AssignmentStatement>() || l->is<IR::MethodCallStatement>()))
315 out << "[[" << l << "]]";
316 }
317 }
318 void assign(const ProgramPoint &context, const IR::Node *node);
319 void assign(const IR::Node *node) { stack.assign({node}); }
320 void clear() { stack.clear(); }
321 const IR::Node *last() const { return stack.empty() ? nullptr : stack.back(); }
322 bool isBeforeStart() const { return stack.empty(); }
323 auto begin() const { return stack.begin(); }
324 auto end() const { return stack.end(); }
325 ProgramPoint &operator=(const ProgramPoint &) = default;
326 ProgramPoint &operator=(ProgramPoint &&) = default;
327};
328} // namespace P4
329
330// inject hash into std namespace so it is picked up by std::unordered_set
331namespace std {
332template <>
333struct hash<P4::ProgramPoint> {
335 typedef std::size_t result_type;
336 result_type operator()(argument_type const &s) const { return s.hash(); }
337};
338} // namespace std
339
340namespace Util {
341template <>
342struct Hasher<P4::ProgramPoint> {
343 size_t operator()(const P4::ProgramPoint &p) const { return p.hash(); }
344};
345} // namespace Util
346
347namespace P4 {
349 typedef absl::flat_hash_set<ProgramPoint, Util::Hash> Points;
350 Points points;
351 explicit ProgramPoints(const Points &points) : points(points) {}
352
353 public:
354 ProgramPoints() = default;
355 explicit ProgramPoints(ProgramPoint point) { points.emplace(point); }
356 void add(ProgramPoint point) { points.emplace(point); }
357 void add(const ProgramPoints *from);
358 const ProgramPoints *merge(const ProgramPoints *with) const;
359 bool operator==(const ProgramPoints &other) const;
360 void dbprint(std::ostream &out) const override {
361 out << "{";
362 for (auto p : points) out << p << " ";
363 out << "}";
364 }
365 size_t size() const { return points.size(); }
366 bool containsBeforeStart() const {
367 return points.find(ProgramPoint::beforeStart) != points.end();
368 }
369 Points::const_iterator begin() const { return points.cbegin(); }
370 Points::const_iterator end() const { return points.cend(); }
371};
372
374class Definitions : public IHasDbPrint {
379 bool unreachable = false;
380
381 public:
382 Definitions() = default;
383 Definitions(const Definitions &other)
384 : definitions(other.definitions), unreachable(other.unreachable) {}
385 Definitions *joinDefinitions(const Definitions *other) const;
387 Definitions *writes(ProgramPoint point, const LocationSet *locations) const;
388 void setDefintion(const BaseLocation *loc, const ProgramPoints *point) {
389 CHECK_NULL(loc);
390 CHECK_NULL(point);
391 definitions[loc] = point;
392 }
393 void setDefinition(const StorageLocation *loc, const ProgramPoints *point);
394 void setDefinition(const LocationSet *loc, const ProgramPoints *point);
395 Definitions *setUnreachable() {
396 unreachable = true;
397 return this;
398 }
399 bool isUnreachable() const { return unreachable; }
400 bool hasLocation(const BaseLocation *location) const {
401 return definitions.find(location) != definitions.end();
402 }
403 const ProgramPoints *getPoints(const BaseLocation *location) const {
404 auto r = ::get(definitions, location);
405 BUG_CHECK(r != nullptr, "no definitions found for %1%", location);
406 return r;
407 }
408 const ProgramPoints *getPoints(const LocationSet *locations) const;
409 bool operator==(const Definitions &other) const;
410 void dbprint(std::ostream &out) const override {
411 if (unreachable) {
412 out << " Unreachable" << Log::endl;
413 }
414 if (definitions.empty()) out << " Empty definitions";
415 bool first = true;
416 for (auto d : definitions) {
417 if (!first) out << Log::endl;
418 out << " " << *d.first << "=>" << *d.second;
419 first = false;
420 }
421 }
422 Definitions *cloneDefinitions() const { return new Definitions(*this); }
423 void removeLocation(const StorageLocation *loc);
424 bool empty() const { return definitions.empty(); }
425 size_t size() const { return definitions.size(); }
426};
427
434
435 public:
436 StorageMap *storageMap;
437 AllDefinitions(ReferenceMap *refMap, TypeMap *typeMap)
438 : storageMap(new StorageMap(refMap, typeMap)) {}
439 Definitions *getDefinitions(ProgramPoint point, bool emptyIfNotFound = false) {
440 auto it = atPoint.find(point);
441 if (it == atPoint.end()) {
442 if (emptyIfNotFound) {
443 auto defs = new Definitions();
444 setDefinitionsAt(point, defs, false);
445 return defs;
446 }
447 BUG("Unknown point %1% for definitions", &point);
448 }
449 return it->second;
450 }
451 void setDefinitionsAt(ProgramPoint point, Definitions *defs, bool overwrite) {
452 if (!overwrite) {
453 auto it = atPoint.find(point);
454 if (it != atPoint.end()) {
455 LOG2("Overwriting definitions at " << point << ": " << it->second << " with "
456 << defs);
457 BUG_CHECK(false, "Overwriting definitions at %1%", point);
458 }
459 }
460 atPoint[point] = defs;
461 }
462 void dbprint(std::ostream &out) const override {
463 for (auto e : atPoint) out << e.first << " => " << e.second << Log::endl;
464 }
465};
466
478class ComputeWriteSet : public Inspector, public IHasDbPrint {
479 protected:
480 AllDefinitions *allDefinitions;
485 const StorageMap *storageMap;
487 bool lhs;
490 bool virtualMethod;
492 alloc_trace_cb_t nested_trace;
493 static int nest_count;
494
497 ComputeWriteSet(const ComputeWriteSet *source, ProgramPoint context, Definitions *definitions)
498 : allDefinitions(source->allDefinitions),
499 currentDefinitions(definitions),
500 returnedDefinitions(nullptr),
502 callingContext(context),
503 storageMap(source->storageMap),
504 lhs(false),
505 virtualMethod(false) {
506 visitDagOnce = false;
507 }
508 void visitVirtualMethods(const IR::IndexedVector<IR::Declaration> &locals);
509 void enterScope(const IR::ParameterList *parameters,
510 const IR::IndexedVector<IR::Declaration> *locals, ProgramPoint startPoint,
511 bool clear = true);
512 void exitScope(const IR::ParameterList *parameters,
513 const IR::IndexedVector<IR::Declaration> *locals);
514 Definitions *getDefinitionsAfter(const IR::ParserState *state);
515 bool setDefinitions(Definitions *defs, const IR::Node *who = nullptr, bool overwrite = false);
516 ProgramPoint getProgramPoint(const IR::Node *node = nullptr) const;
517 const LocationSet *getWrites(const IR::Expression *expression) const {
518 auto result = ::get(writes, expression);
519 BUG_CHECK(result != nullptr, "No location set known for %1%", expression);
520 return result;
521 }
522 void expressionWrites(const IR::Expression *expression, const LocationSet *loc) {
523 CHECK_NULL(expression);
524 CHECK_NULL(loc);
525 LOG3(expression << dbp(expression) << " writes " << loc);
526 BUG_CHECK(writes.find(expression) == writes.end() || expression->is<IR::Literal>(),
527 "Expression %1% write set already set", expression);
528 writes.emplace(expression, loc);
529 }
530 void dbprint(std::ostream &out) const override {
531 if (writes.empty()) out << "No writes";
532 for (auto &it : writes) out << it.first << " writes " << it.second << Log::endl;
533 }
534 profile_t init_apply(const IR::Node *root) override {
535 auto rv = Inspector::init_apply(root);
536 LOG1("starting ComputWriteSet" << Log::indent);
537 if (nest_count++ == 0 && LOGGING(2)) {
538 memuse.clear();
539 nested_trace = memuse.start();
540 }
541 return rv;
542 }
543 void end_apply() override {
544 LOG1("finished CWS" << Log::unindent);
545 if (--nest_count == 0 && LOGGING(2)) {
546 memuse.stop(nested_trace);
547 LOG2(memuse);
548 }
549 }
550
551 public:
552 explicit ComputeWriteSet(AllDefinitions *allDefinitions)
553 : allDefinitions(allDefinitions),
554 currentDefinitions(nullptr),
555 returnedDefinitions(nullptr),
556 exitDefinitions(new Definitions()),
557 storageMap(allDefinitions->storageMap),
558 lhs(false),
559 virtualMethod(false) {
560 CHECK_NULL(allDefinitions);
561 visitDagOnce = false;
562 }
563
564 // expressions
565 bool preorder(const IR::Literal *expression) override;
566 bool preorder(const IR::Slice *expression) override;
567 bool preorder(const IR::TypeNameExpression *expression) override;
568 bool preorder(const IR::PathExpression *expression) override;
569 bool preorder(const IR::Member *expression) override;
570 bool preorder(const IR::ArrayIndex *expression) override;
571 bool preorder(const IR::Operation_Binary *expression) override;
572 bool preorder(const IR::Mux *expression) override;
573 bool preorder(const IR::SelectExpression *expression) override;
574 bool preorder(const IR::ListExpression *expression) override;
575 bool preorder(const IR::Operation_Unary *expression) override;
576 bool preorder(const IR::MethodCallExpression *expression) override;
577 bool preorder(const IR::DefaultExpression *expression) override;
578 bool preorder(const IR::Expression *expression) override;
579 bool preorder(const IR::InvalidHeader *expression) override;
580 bool preorder(const IR::InvalidHeaderUnion *expression) override;
581 bool preorder(const IR::P4ListExpression *expression) override;
582 bool preorder(const IR::HeaderStackExpression *expression) override;
583 bool preorder(const IR::StructExpression *expression) override;
584 // statements
585 bool preorder(const IR::P4Parser *parser) override;
586 bool preorder(const IR::P4Control *control) override;
587 bool preorder(const IR::P4Action *action) override;
588 bool preorder(const IR::P4Table *table) override;
589 bool preorder(const IR::Function *function) override;
590 bool preorder(const IR::AssignmentStatement *statement) override;
591 bool preorder(const IR::ReturnStatement *statement) override;
592 bool preorder(const IR::ExitStatement *statement) override;
593 bool preorder(const IR::IfStatement *statement) override;
594 bool preorder(const IR::BlockStatement *statement) override;
595 bool preorder(const IR::SwitchStatement *statement) override;
596 bool preorder(const IR::EmptyStatement *statement) override;
597 bool preorder(const IR::MethodCallStatement *statement) override;
598
599 const LocationSet *writtenLocations(const IR::Expression *expression) {
600 expression->apply(*this);
601 return getWrites(expression);
602 }
603};
604
605} // namespace P4
606
607#endif /* FRONTENDS_P4_DEF_USE_H_ */
Definition alloc_trace.h:26
Definition castable.h:34
Definition source_file.h:38
Definition map.h:143
Definition def_use.h:428
Definition def_use.h:168
Definition def_use.h:66
Definition def_use.h:478
bool lhs
if true we are processing an expression on the lhs of an assignment
Definition def_use.h:487
AllocTrace memuse
True if we are analyzing a virtual method.
Definition def_use.h:491
Definitions * returnedDefinitions
Before statement currently processed.
Definition def_use.h:482
void visitVirtualMethods(const IR::IndexedVector< IR::Declaration > &locals)
Statements and other control structures.
Definition def_use.cpp:735
Definitions * exitDefinitions
Definitions after return statements.
Definition def_use.h:483
Definitions * currentDefinitions
Result computed by this pass.
Definition def_use.h:481
ComputeWriteSet(const ComputeWriteSet *source, ProgramPoint context, Definitions *definitions)
Definition def_use.h:497
hvec_map< const IR::Expression *, const LocationSet * > writes
For each expression the location set it writes.
Definition def_use.h:489
ProgramPoint callingContext
Definitions after exit statements.
Definition def_use.h:484
List of definers for each base storage (at a specific program point).
Definition def_use.h:374
Definitions * writes(ProgramPoint point, const LocationSet *locations) const
Point writes the specified LocationSet.
Definition def_use.cpp:344
Interface for locations that support an index operation.
Definition def_use.h:132
Definition def_use.h:195
const LocationSet * canonicalize() const
Definition def_use.cpp:231
Indicates a statement in the program.
Definition def_use.h:275
static ProgramPoint beforeStart
A point logically before the function/control/action start.
Definition def_use.h:294
ProgramPoint after()
We use a nullptr to indicate a point after the previous context.
Definition def_use.h:296
Definition def_use.h:348
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition def_use.h:185
Abstraction for something that is has a left value (variable, parameter)
Definition def_use.h:37
const LocationSet * getLastIndexField() const
Definition def_use.cpp:158
const LocationSet * removeHeaders() const
Definition def_use.cpp:104
const LocationSet * getValidBits() const
Definition def_use.cpp:152
Maps a declaration to its associated storage.
Definition def_use.h:239
Definition def_use.h:115
Definition def_use.h:157
Definition typeMap.h:42
Base class for location sets that contain fields.
Definition def_use.h:90
Definition cstring.h:72
Definition hvec_map.h:29
Definition ordered_set.h:30
Definition applyOptionsPragmas.cpp:24
STL namespace.
Definition hash.h:123
Definition gc.h:26