P4C
The P4 Compiler
Loading...
Searching...
No Matches
frontends/p4/def_use.h
1/*
2 * Copyright 2016 VMware, Inc.
3 * SPDX-FileCopyrightText: 2016 VMware, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef FRONTENDS_P4_DEF_USE_H_
9#define FRONTENDS_P4_DEF_USE_H_
10
11#include "absl/container/flat_hash_set.h"
12#include "absl/container/inlined_vector.h"
13#include "absl/container/node_hash_set.h"
14#include "frontends/common/resolveReferences/referenceMap.h"
15#include "ir/ir.h"
16#include "lib/alloc_trace.h"
17#include "lib/flat_map.h"
18#include "lib/hash.h"
19#include "lib/hvec_map.h"
20#include "lib/ordered_set.h"
21#include "typeMap.h"
22
23namespace P4 {
24
25class ComputeWriteSet;
26class StorageFactory;
27class LocationSet;
28
29// A location in the program. Includes the context from the visitor, which needs to
30// be copied out of the Visitor::Context objects, as they are allocated on the stack and
31// will become invalid as the IR traversal continues
32struct loc_t {
33 const IR::Node *node;
34 const loc_t *parent;
35 mutable std::size_t computedHash = 0;
36 bool operator==(const loc_t &a) const {
37 if (node != a.node) return false;
38 if (parent == a.parent) return true;
39 if (!parent || !a.parent) return false;
40 return *parent == *a.parent;
41 }
42 std::size_t hash() const;
43};
44
45// #define DEBUG_LOCATION_IDS
46
48class StorageLocation : public IHasDbPrint, public ICastable {
49#ifdef DEBUG_LOCATION_IDS
50 static unsigned crtid;
51 unsigned id;
52#endif
53
54 public:
55 virtual ~StorageLocation() {}
56 const IR::Type *type;
57 const cstring name;
58 StorageLocation(const IR::Type *type, cstring name)
59 :
60#ifdef DEBUG_LOCATION_IDS
61 id(crtid++),
62#endif
63 type(type),
64 name(name) {
65 CHECK_NULL(type);
66 }
67 void dbprint(std::ostream &out) const override {
68#ifdef DEBUG_LOCATION_IDS
69 out << id << " " << name;
70#else
71 out << dbp(type) << " " << name;
72#endif
73 }
74 cstring toString() const { return name; }
75
78 virtual void addValidBits(LocationSet *result) const = 0;
81 virtual void removeHeaders(LocationSet *result) const = 0;
84 virtual void addLastIndexField(LocationSet *result) const = 0;
85
86 DECLARE_TYPEINFO(StorageLocation);
87};
88
91class BaseLocation : public StorageLocation {
92 public:
93 BaseLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {
94 if (auto tt = type->to<IR::Type_Tuple>())
95 BUG_CHECK(tt->getSize() == 0, "%1%: tuples with fields are not base locations", tt);
96 else if (auto ts = type->to<IR::Type_StructLike>())
97 BUG_CHECK(ts->fields.size() == 0, "%1%: structs with fields are not base locations",
98 tt);
99 else
100 BUG_CHECK(type->is<IR::Type_Bits>() || type->is<IR::Type_Enum>() ||
101 type->is<IR::Type_Boolean>() || type->is<IR::Type_Var>() ||
102 type->is<IR::Type_Error>() || type->is<IR::Type_Varbits>() ||
103 type->is<IR::Type_Newtype>() || type->is<IR::Type_SerEnum>() ||
104 type->is<IR::Type_List>(),
105 "%1%: unexpected type", type);
106 }
107 void addValidBits(LocationSet *) const override {}
108 void addLastIndexField(LocationSet *) const override {}
109 void removeHeaders(LocationSet *result) const override;
110
111 DECLARE_TYPEINFO(BaseLocation, StorageLocation);
112};
113
115class WithFieldsLocation : public StorageLocation {
117 absl::InlinedVector<std::pair<cstring, const StorageLocation *>, 4>>
118 fieldLocations;
119
120 void createField(cstring name, StorageLocation *field) {
121 fieldLocations.emplace(name, field);
122 CHECK_NULL(field);
123 }
124 void replaceField(cstring field, StorageLocation *replacement) {
125 fieldLocations[field] = replacement;
126 }
127
128 friend class StorageFactory;
129
130 protected:
131 WithFieldsLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {}
132
133 public:
134 void addField(cstring field, LocationSet *addTo) const;
135 void removeHeaders(LocationSet *result) const override;
136 auto fields() const { return Values(fieldLocations); }
137 void dbprint(std::ostream &out) const override {
138 for (auto f : fieldLocations) out << *f.second << " ";
139 }
140
141 DECLARE_TYPEINFO(WithFieldsLocation, StorageLocation);
142};
143
145class StructLocation : public WithFieldsLocation {
146 protected:
147 StructLocation(const IR::Type *type, cstring name) : WithFieldsLocation(type, name) {
148 BUG_CHECK(type->is<IR::Type_StructLike>(), "%1%: unexpected type", type);
149 }
150 friend class StorageFactory;
151
152 public:
153 void addValidBits(LocationSet *result) const override;
154 void addLastIndexField(LocationSet *result) const override;
155 bool isHeader() const { return type->is<IR::Type_Header>(); }
156 bool isHeaderUnion() const { return type->is<IR::Type_HeaderUnion>(); }
157 bool isStruct() const { return type->is<IR::Type_Struct>(); }
158
159 DECLARE_TYPEINFO(StructLocation, WithFieldsLocation);
160};
161
163class IndexedLocation : public StorageLocation {
164 absl::InlinedVector<const StorageLocation *, 8> elements;
165
166 protected:
167 void createElement(unsigned index, StorageLocation *element) {
168 elements[index] = element;
169 CHECK_NULL(element);
170 }
171
172 IndexedLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {
173 CHECK_NULL(type);
174 const auto *it = type->to<IR::Type_Indexed>();
175 BUG_CHECK(it != nullptr, "%1%: unexpected type", type);
176 elements.resize(it->getSize());
177 }
178
179 friend class StorageFactory;
180
181 public:
182 void addElement(unsigned index, LocationSet *result) const;
183 auto begin() const { return elements.cbegin(); }
184 auto end() const { return elements.cend(); }
185 void dbprint(std::ostream &out) const override {
186 for (unsigned i = 0; i < elements.size(); i++) out << *elements.at(i) << " ";
187 }
188 size_t getSize() const { return elements.size(); }
189 void removeHeaders(LocationSet *result) const override;
190
191 DECLARE_TYPEINFO(IndexedLocation, StorageLocation);
192};
193
195class TupleLocation : public IndexedLocation {
196 protected:
197 TupleLocation(const IR::Type *type, cstring name) : IndexedLocation(type, name) {}
198 friend class StorageFactory;
199
200 public:
201 void addValidBits(LocationSet *) const override {}
202 void addLastIndexField(LocationSet *) const override {}
203
204 DECLARE_TYPEINFO(TupleLocation, IndexedLocation);
205};
206
207class ArrayLocation : public IndexedLocation {
208 const StorageLocation *lastIndexField = nullptr; // accessed by lastIndex
209
210 void setLastIndexField(const StorageLocation *location) { lastIndexField = location; }
211
212 protected:
213 ArrayLocation(const IR::Type *type, cstring name) : IndexedLocation(type, name) {}
214 friend class StorageFactory;
215
216 public:
217 const StorageLocation *getLastIndexField() const { return lastIndexField; }
218
219 void addValidBits(LocationSet *result) const override;
220 void removeHeaders(LocationSet *) const override {} // no results added
221 void addLastIndexField(LocationSet *result) const override;
222
223 DECLARE_TYPEINFO(ArrayLocation, IndexedLocation);
224};
225
227 // FIXME: Allocate StorageLocations from an arena, not global allocator
228 mutable std::vector<std::unique_ptr<StorageLocation>> storageLocations;
229
230 template <class T>
231 T *construct(const IR::Type *type, cstring name) const;
232
233 static constexpr std::string_view indexFieldName = "$last_index";
234
235 public:
236 StorageLocation *create(const IR::Type *type, cstring name) const;
237
238 static const cstring validFieldName;
239};
240
243class LocationSet : public IHasDbPrint {
244 using LocationsStorage = ordered_set<const StorageLocation *>;
245 LocationsStorage locations;
246
247 class canonical_iterator {
248 absl::InlinedVector<const StorageLocation *, 8> workList;
249
250 void unwrapTop() {
251 if (workList.empty()) return;
252
253 const auto *location = workList.back();
254 if (location->is<BaseLocation>()) return;
255
256 if (const auto *wfl = location->to<WithFieldsLocation>()) {
257 workList.pop_back();
258 for (const auto *f : Util::iterator_range(wfl->fields()).reverse())
259 workList.push_back(f);
260 unwrapTop();
261 return;
262 }
263
264 if (const auto *a = location->to<IndexedLocation>()) {
265 workList.pop_back();
266 for (const auto *f : Util::iterator_range(*a).reverse()) workList.push_back(f);
267 unwrapTop();
268 return;
269 }
270
271 BUG("unexpected location");
272 }
273
274 public:
275 using iterator_category = std::forward_iterator_tag;
276 using value_type = const StorageLocation *;
277 using difference_type = ptrdiff_t;
278 using pointer = value_type;
279 using reference = value_type;
280
281 canonical_iterator() = default;
282
283 explicit canonical_iterator(const LocationsStorage &locations) {
284 for (const auto *loc : Util::iterator_range(locations).reverse())
285 workList.push_back(loc);
286 unwrapTop();
287 }
288 canonical_iterator &operator++() {
289 workList.pop_back();
290 unwrapTop();
291 return *this;
292 }
293 canonical_iterator operator++(int) {
294 auto copy = *this;
295 ++*this;
296 return copy;
297 }
298 bool operator==(const canonical_iterator &i) const { return workList == i.workList; }
299 bool operator!=(const canonical_iterator &i) const { return workList != i.workList; }
300 reference operator*() const { return workList.back(); }
301 pointer operator->() const { return workList.back(); }
302 };
303
304 public:
305 LocationSet() = default;
306 explicit LocationSet(const ordered_set<const StorageLocation *> &other) : locations(other) {}
307 explicit LocationSet(const StorageLocation *location) {
308 CHECK_NULL(location);
309 locations.emplace(location);
310 }
311 static const LocationSet *empty;
312
313 const LocationSet *getField(cstring field) const;
314 const LocationSet *getValidField() const;
315 const LocationSet *getIndex(unsigned index) const;
316 const LocationSet *allElements() const;
317 const LocationSet *getArrayLastIndex() const;
318
319 void add(const StorageLocation *location) {
320 CHECK_NULL(location);
321 locations.emplace(location);
322 }
323 const LocationSet *join(const LocationSet *other) const;
326 const LocationSet *canonicalize() const;
327 void addCanonical(const StorageLocation *location);
328 auto begin() const { return locations.cbegin(); }
329 auto end() const { return locations.cend(); }
330 auto canon_begin() const { return canonical_iterator(locations); }
331 auto canon_end() const { return canonical_iterator(); }
332 auto canonical() const { return Util::iterator_range(canon_begin(), canon_end()); }
333
334 void dbprint(std::ostream &out) const override {
335 if (locations.empty()) out << "LocationSet::empty";
336 for (auto l : locations) {
337 l->dbprint(out);
338 out << " ";
339 }
340 }
341 // only defined for canonical representations
342 bool overlaps(const LocationSet *other) const;
343 bool operator==(const LocationSet &other) const;
344 bool isEmpty() const { return locations.empty(); }
345};
346
348class StorageMap : public IHasDbPrint {
351 StorageFactory factory;
352
353 public:
354 ReferenceMap *refMap;
355 TypeMap *typeMap;
356
357 StorageMap(ReferenceMap *refMap, TypeMap *typeMap) : refMap(refMap), typeMap(typeMap) {
358 CHECK_NULL(refMap);
359 CHECK_NULL(typeMap);
360 }
361 const StorageLocation *add(const IR::IDeclaration *decl) {
362 CHECK_NULL(decl);
363 auto type = typeMap->getType(decl->getNode(), true);
364 auto loc = factory.create(type, decl->getName() + "/" + decl->externalName());
365 if (loc != nullptr) storage.emplace(decl, loc);
366 return loc;
367 }
368 const StorageLocation *getOrAdd(const IR::IDeclaration *decl) {
369 const auto *s = getStorage(decl);
370 if (s != nullptr) return s;
371 return add(decl);
372 }
373 const StorageLocation *getStorage(const IR::IDeclaration *decl) const {
374 CHECK_NULL(decl);
375 auto result = ::P4::get(storage, decl);
376 return result;
377 }
378 void dbprint(std::ostream &out) const override {
379 for (auto &it : storage) out << it.first << ": " << it.second << Log::endl;
380 }
381};
382
384class ProgramPoint : public IHasDbPrint {
392 absl::InlinedVector<const IR::Node *, 8> stack; // Has inline space for 8 nodes
393
394 public:
395 ProgramPoint() = default;
396 ProgramPoint(const ProgramPoint &other) : stack(other.stack) {}
397 explicit ProgramPoint(const IR::Node *node) {
398 CHECK_NULL(node);
399 assign(node);
400 }
401 ProgramPoint(const ProgramPoint &context, const IR::Node *node);
403 static ProgramPoint beforeStart;
405 ProgramPoint after() { return ProgramPoint(*this, nullptr); }
406 bool operator==(const ProgramPoint &other) const;
407 std::size_t hash() const;
408 void dbprint(std::ostream &out) const override {
409 if (isBeforeStart()) {
410 out << "<BeforeStart>";
411 } else {
412 bool first = true;
413 for (auto n : stack) {
414 if (!first) out << "//";
415 if (!n)
416 out << "After end";
417 else
418 out << dbp(n);
419 first = false;
420 }
421 auto l = stack.back();
422 if (l != nullptr &&
423 (l->is<IR::BaseAssignmentStatement>() || l->is<IR::MethodCallStatement>()))
424 out << "[[" << l << "]]";
425 }
426 }
427 void assign(const ProgramPoint &context, const IR::Node *node);
428 void assign(const IR::Node *node) { stack.assign({node}); }
429 void clear() { stack.clear(); }
430 const IR::Node *last() const { return stack.empty() ? nullptr : stack.back(); }
431 bool isBeforeStart() const { return stack.empty(); }
432 auto begin() const { return stack.begin(); }
433 auto end() const { return stack.end(); }
434 ProgramPoint &operator=(const ProgramPoint &) = default;
435 ProgramPoint &operator=(ProgramPoint &&) = default;
436};
437} // namespace P4
438
439// inject hash into std namespace so it is picked up by std::unordered_set
440namespace std {
441template <>
442struct hash<P4::ProgramPoint> {
443 std::size_t operator()(const P4::ProgramPoint &s) const { return s.hash(); }
444};
445
446template <>
447struct hash<P4::loc_t> {
448 std::size_t operator()(const P4::loc_t &loc) const { return loc.hash(); }
449};
450
451} // namespace std
452
453namespace P4::Util {
454template <>
456 size_t operator()(const P4::ProgramPoint &p) const { return p.hash(); }
457};
458
459template <>
460struct Hasher<P4::loc_t> {
461 size_t operator()(const P4::loc_t &loc) const { return loc.hash(); }
462};
463} // namespace P4::Util
464
465namespace P4 {
466class ProgramPoints : public IHasDbPrint {
467 typedef absl::flat_hash_set<ProgramPoint, Util::Hash> Points;
468 Points points;
469 explicit ProgramPoints(const Points &points) : points(points) {}
470
471 public:
472 ProgramPoints() = default;
473 explicit ProgramPoints(ProgramPoint point) { points.emplace(point); }
474 void add(const ProgramPoints *from);
475 const ProgramPoints *merge(const ProgramPoints *with) const;
476 bool operator==(const ProgramPoints &other) const;
477 void dbprint(std::ostream &out) const override {
478 out << "{";
479 for (auto p : points) out << p << " ";
480 out << "}";
481 }
482 size_t size() const { return points.size(); }
483 bool containsBeforeStart() const {
484 return points.find(ProgramPoint::beforeStart) != points.end();
485 }
486 Points::const_iterator begin() const { return points.cbegin(); }
487 Points::const_iterator end() const { return points.cend(); }
488};
489
491class Definitions : public IHasDbPrint {
496 bool unreachable = false;
497
498 public:
499 Definitions() = default;
500 Definitions(const Definitions &other)
501 : definitions(other.definitions), unreachable(other.unreachable) {}
502 Definitions *joinDefinitions(const Definitions *other) const;
504 Definitions *writes(ProgramPoint point, const LocationSet &locations) const;
505 void setDefintion(const BaseLocation *loc, const ProgramPoints *point) {
506 CHECK_NULL(loc);
507 CHECK_NULL(point);
508 definitions[loc] = point;
509 }
510 void setDefinition(const StorageLocation *loc, const ProgramPoints *point);
511 void setDefinition(const LocationSet &loc, const ProgramPoints *point);
512 Definitions *setUnreachable() {
513 unreachable = true;
514 return this;
515 }
516 bool isUnreachable() const { return unreachable; }
517 bool hasLocation(const BaseLocation *location) const {
518 return definitions.find(location) != definitions.end();
519 }
520 const ProgramPoints *getPoints(const BaseLocation *location) const {
521 auto r = ::P4::get(definitions, location);
522 BUG_CHECK(r != nullptr, "no definitions found for %1%", location);
523 return r;
524 }
525 const ProgramPoints *getPoints(const LocationSet &locations) const;
526 bool operator==(const Definitions &other) const;
527 void dbprint(std::ostream &out) const override {
528 if (unreachable) {
529 out << " Unreachable" << Log::endl;
530 }
531 if (definitions.empty()) out << " Empty definitions";
532 bool first = true;
533 for (auto d : definitions) {
534 if (!first) out << Log::endl;
535 out << " " << *d.first << "=>" << *d.second;
536 first = false;
537 }
538 }
539 Definitions *cloneDefinitions() const { return new Definitions(*this); }
540 void removeLocation(const StorageLocation *loc);
541 bool empty() const { return definitions.empty(); }
542 size_t size() const { return definitions.size(); }
543};
544
545class AllDefinitions : public IHasDbPrint {
551 StorageMap storageMap;
552
553 public:
554 AllDefinitions(ReferenceMap *refMap, TypeMap *typeMap) : storageMap(refMap, typeMap) {}
555
556 Definitions *getDefinitions(ProgramPoint point, bool emptyIfNotFound = false) {
557 auto it = atPoint.find(point);
558 if (it == atPoint.end()) {
559 if (emptyIfNotFound) {
560 auto defs = new Definitions();
561 setDefinitionsAt(point, defs, false);
562 return defs;
563 }
564 BUG("Unknown point %1% for definitions", &point);
565 }
566 return it->second;
567 }
568 void setDefinitionsAt(ProgramPoint point, Definitions *defs, bool overwrite) {
569 if (!overwrite) {
570 auto it = atPoint.find(point);
571 if (it != atPoint.end()) {
572 LOG2("Overwriting definitions at " << point << ": " << it->second << " with "
573 << defs);
574 BUG_CHECK(false, "Overwriting definitions at %1%", point);
575 }
576 }
577 atPoint[point] = defs;
578 }
579
580 const StorageLocation *getStorage(const IR::IDeclaration *decl) const {
581 return storageMap.getStorage(decl);
582 }
583
584 const StorageLocation *getOrAddStorage(const IR::IDeclaration *decl) {
585 return storageMap.getOrAdd(decl);
586 }
587
588 void dbprint(std::ostream &out) const override {
589 for (auto e : atPoint) out << e.first << " => " << e.second << Log::endl;
590 }
591};
592
603
604class ComputeWriteSet : public Inspector, public IHasDbPrint {
605 // We are using node_hash_set here as we need pointers to entries (loc_t) to be stable
606 using CachedLocs = absl::node_hash_set<loc_t, Util::Hash>;
607
608 public:
609 explicit ComputeWriteSet(AllDefinitions *allDefinitions, ReferenceMap *refMap, TypeMap *typeMap)
610 : refMap(refMap),
611 typeMap(typeMap),
612 allDefinitions(allDefinitions),
613 currentDefinitions(nullptr),
614 returnedDefinitions(nullptr),
616 lhs(false),
617 virtualMethod(false),
618 cached_locs(new CachedLocs) {
619 CHECK_NULL(allDefinitions);
620 CHECK_NULL(refMap);
621 CHECK_NULL(typeMap);
622 visitDagOnce = false;
623 }
624
625 // expressions
626 bool preorder(const IR::Literal *expression) override;
627 bool preorder(const IR::AbstractSlice *expression) override;
628 bool preorder(const IR::TypeNameExpression *expression) override;
629 bool preorder(const IR::PathExpression *expression) override;
630 bool preorder(const IR::Member *expression) override;
631 bool preorder(const IR::ArrayIndex *expression) override;
632 bool preorder(const IR::Operation_Binary *expression) override;
633 bool preorder(const IR::Mux *expression) override;
634 bool preorder(const IR::SelectExpression *expression) override;
635 bool preorder(const IR::ListExpression *expression) override;
636 bool preorder(const IR::Operation_Unary *expression) override;
637 bool preorder(const IR::MethodCallExpression *expression) override;
638 bool preorder(const IR::DefaultExpression *expression) override;
639 bool preorder(const IR::Expression *expression) override;
640 bool preorder(const IR::InvalidHeader *expression) override;
641 bool preorder(const IR::InvalidHeaderUnion *expression) override;
642 bool preorder(const IR::P4ListExpression *expression) override;
643 bool preorder(const IR::ArrayExpression *expression) override;
644 bool preorder(const IR::StructExpression *expression) override;
645 // statements
646 bool preorder(const IR::P4Parser *parser) override;
647 bool preorder(const IR::P4Control *control) override;
648 bool preorder(const IR::P4Action *action) override;
649 bool preorder(const IR::P4Table *table) override;
650 bool preorder(const IR::Function *function) override;
651 bool preorder(const IR::BaseAssignmentStatement *statement) override;
652 bool preorder(const IR::ReturnStatement *statement) override;
653 bool preorder(const IR::ExitStatement *statement) override;
654 bool preorder(const IR::BreakStatement *statement) override;
655 bool handleJump(const char *tok, Definitions *&defs);
656 bool preorder(const IR::ContinueStatement *statement) override;
657 bool preorder(const IR::IfStatement *statement) override;
658 bool preorder(const IR::ForStatement *statement) override;
659 bool preorder(const IR::ForInStatement *statement) override;
660 bool preorder(const IR::BlockStatement *statement) override;
661 bool preorder(const IR::SwitchStatement *statement) override;
662 bool preorder(const IR::EmptyStatement *statement) override;
663 bool preorder(const IR::MethodCallStatement *statement) override;
664
665 const LocationSet *writtenLocations(const IR::Expression *expression) {
666 expression->apply(*this);
667 return getWrites(expression);
668 }
669
670 protected:
671 ReferenceMap *refMap;
672 TypeMap *typeMap;
673 AllDefinitions *allDefinitions;
681 bool lhs;
684 bool virtualMethod;
686 alloc_trace_cb_t nested_trace;
687 static int nest_count;
688
691 ComputeWriteSet(const ComputeWriteSet *source, ProgramPoint context, Definitions *definitions,
692 std::shared_ptr<CachedLocs> cached_locs)
693 : refMap(source->refMap),
694 typeMap(source->typeMap),
695
696 allDefinitions(source->allDefinitions),
697 currentDefinitions(definitions),
698 returnedDefinitions(nullptr),
702 callingContext(context),
703 lhs(false),
704 virtualMethod(false),
705 cached_locs(cached_locs) {
706 visitDagOnce = false;
707 }
709 const loc_t *getLoc(const IR::Node *n, const loc_t *parentLoc);
710 const loc_t *getLoc(const Visitor::Context *ctxt);
711 const loc_t *getLoc(const IR::Node *n, const Visitor::Context *ctxt);
712 void enterScope(const IR::ParameterList *parameters,
713 const IR::IndexedVector<IR::Declaration> *locals, ProgramPoint startPoint,
714 bool clear = true);
715 void exitScope(const IR::ParameterList *parameters,
716 const IR::IndexedVector<IR::Declaration> *locals, ProgramPoint endPoint);
717 Definitions *getDefinitionsAfter(const IR::ParserState *state);
718 bool setDefinitions(Definitions *defs, const IR::Node *who = nullptr, bool overwrite = false);
719 ProgramPoint getProgramPoint(const IR::Node *node = nullptr) const;
720 // Get writes of a node that is a direct child of the currently being visited node.
721 const LocationSet *getWrites(const IR::Expression *expression) {
722 const loc_t &exprLoc = *getLoc(expression, getChildContext());
723 auto result = ::P4::get(writes, exprLoc);
724 BUG_CHECK(result != nullptr, "No location set known for %1%", expression);
725 return result;
726 }
727 // Get writes of a node that is not a direct child of the currently being visited node.
728 // In this case, parentLoc is the loc of expression's direct parent node.
729 const LocationSet *getWrites(const IR::Expression *expression, const loc_t *parentLoc) {
730 const loc_t &exprLoc = *getLoc(expression, parentLoc);
731 auto result = ::P4::get(writes, exprLoc);
732 BUG_CHECK(result != nullptr, "No location set known for %1%", expression);
733 return result;
734 }
735 // Register writes of expression, which is expected to be the currently visited node.
736 void expressionWrites(const IR::Expression *expression, const LocationSet *loc) {
737 CHECK_NULL(expression);
738 CHECK_NULL(loc);
739 LOG3(expression << dbp(expression) << " writes " << loc);
740 const Context *ctx = getChildContext();
741 BUG_CHECK(ctx->node == expression, "Expected ctx->node == expression.");
742 const loc_t &exprLoc = *getLoc(ctx);
743 if (auto it = writes.find(exprLoc); it != writes.end()) {
744 BUG_CHECK(*it->second == *loc || expression->is<IR::Literal>(),
745 "Expression %1% write set already set", expression);
746 } else {
747 writes.emplace(exprLoc, loc);
748 }
749 }
750 void dbprint(std::ostream &out) const override {
751 if (writes.empty()) out << "No writes";
752 for (auto &it : writes) out << it.first.node << " writes " << it.second << Log::endl;
753 }
754 profile_t init_apply(const IR::Node *root) override {
755 auto rv = Inspector::init_apply(root);
756 LOG1("starting ComputWriteSet" << Log::indent);
757 if (nest_count++ == 0 && LOGGING(2)) {
758 memuse.clear();
759 nested_trace = memuse.start();
760 }
761 return rv;
762 }
763 void end_apply() override {
764 LOG1("finished CWS" << Log::unindent);
765 if (--nest_count == 0 && LOGGING(2)) {
766 memuse.stop(nested_trace);
767 LOG2(memuse);
768 }
769 }
770
771 private:
772 std::shared_ptr<CachedLocs> cached_locs;
773};
774
775} // namespace P4
776
777#endif /* FRONTENDS_P4_DEF_USE_H_ */
Definition frontends/p4/def_use.h:545
Definition alloc_trace.h:20
Definition frontends/p4/def_use.h:91
Definition frontends/p4/def_use.h:604
bool lhs
if true we are processing an expression on the lhs of an assignment
Definition frontends/p4/def_use.h:681
AllocTrace memuse
True if we are analyzing a virtual method.
Definition frontends/p4/def_use.h:685
Definitions * breakDefinitions
Definitions after exit statements.
Definition frontends/p4/def_use.h:677
Definitions * returnedDefinitions
Before statement currently processed.
Definition frontends/p4/def_use.h:675
ComputeWriteSet(const ComputeWriteSet *source, ProgramPoint context, Definitions *definitions, std::shared_ptr< CachedLocs > cached_locs)
Definition frontends/p4/def_use.h:691
void visitVirtualMethods(const IR::IndexedVector< IR::Declaration > &locals)
Statements and other control structures.
Definition frontends/p4/def_use.cpp:760
Definitions * exitDefinitions
Definitions after return statements.
Definition frontends/p4/def_use.h:676
Definitions * currentDefinitions
Result computed by this pass.
Definition frontends/p4/def_use.h:674
Definitions * continueDefinitions
Definitions at break statements.
Definition frontends/p4/def_use.h:678
ProgramPoint callingContext
Definitions at continue statements.
Definition frontends/p4/def_use.h:679
hvec_map< loc_t, const LocationSet * > writes
For each program location the location set it writes.
Definition frontends/p4/def_use.h:683
List of definers for each base storage (at a specific program point).
Definition frontends/p4/def_use.h:491
Definitions * writes(ProgramPoint point, const LocationSet &locations) const
Point writes the specified LocationSet.
Definition frontends/p4/def_use.cpp:369
Definition castable.h:27
Definition stringify.h:33
The Declaration interface, representing objects with names.
Definition declaration.h:17
virtual ID getName() const =0
Definition indexed_vector.h:31
Definition node.h:53
Interface for locations that support an index operation.
Definition frontends/p4/def_use.h:163
Definition visitor.h:418
Definition frontends/p4/def_use.h:243
const LocationSet * canonicalize() const
Definition frontends/p4/def_use.cpp:232
Indicates a statement in the program.
Definition frontends/p4/def_use.h:384
static ProgramPoint beforeStart
A point logically before the function/control/action start.
Definition frontends/p4/def_use.h:403
ProgramPoint after()
We use a nullptr to indicate a point after the previous context.
Definition frontends/p4/def_use.h:405
Definition frontends/p4/def_use.h:466
Class used to encode maps from paths to declarations.
Definition referenceMap.h:67
Definition frontends/p4/def_use.h:226
Abstraction for something that is has a left value (variable, parameter)
Definition frontends/p4/def_use.h:48
LocationSet getValidBits() const
Definition frontends/p4/def_use.cpp:154
LocationSet removeHeaders() const
Definition frontends/p4/def_use.cpp:106
LocationSet getLastIndexField() const
Definition frontends/p4/def_use.cpp:160
Maps a declaration to its associated storage.
Definition frontends/p4/def_use.h:348
Definition typeMap.h:32
Definition iterator_range.h:44
Definition visitor.h:78
Base class for location sets that contain fields.
Definition frontends/p4/def_use.h:115
Definition cstring.h:85
Definition hvec_map.h:22
Definition ordered_set.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
STL namespace.
Definition hash.h:123
Definition flat_map.h:29
Definition frontends/p4/def_use.h:32
Definition gc.h:27