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