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 "frontends/common/resolveReferences/referenceMap.h"
23#include "ir/ir.h"
24#include "lib/alloc_trace.h"
25#include "lib/flat_map.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 ComputeWriteSet;
34class StorageFactory;
35class LocationSet;
36
37// A location in the program. Includes the context from the visitor, which needs to
38// be copied out of the Visitor::Context objects, as they are allocated on the stack and
39// will become invalid as the IR traversal continues
40struct loc_t {
41 const IR::Node *node;
42 const loc_t *parent;
43 mutable std::size_t computedHash = 0;
44 bool operator==(const loc_t &a) const {
45 if (node != a.node) return false;
46 if (parent == a.parent) return true;
47 if (!parent || !a.parent) return false;
48 return *parent == *a.parent;
49 }
50 std::size_t hash() const;
51};
52
53// #define DEBUG_LOCATION_IDS
54
56class StorageLocation : public IHasDbPrint, public ICastable {
57#ifdef DEBUG_LOCATION_IDS
58 static unsigned crtid;
59 unsigned id;
60#endif
61
62 public:
63 virtual ~StorageLocation() {}
64 const IR::Type *type;
65 const cstring name;
66 StorageLocation(const IR::Type *type, cstring name)
67 :
68#ifdef DEBUG_LOCATION_IDS
69 id(crtid++),
70#endif
71 type(type),
72 name(name) {
73 CHECK_NULL(type);
74 }
75 void dbprint(std::ostream &out) const override {
76#ifdef DEBUG_LOCATION_IDS
77 out << id << " " << name;
78#else
79 out << dbp(type) << " " << name;
80#endif
81 }
82 cstring toString() const { return name; }
83
86 virtual void addValidBits(LocationSet *result) const = 0;
89 virtual void removeHeaders(LocationSet *result) const = 0;
92 virtual void addLastIndexField(LocationSet *result) const = 0;
93
94 DECLARE_TYPEINFO(StorageLocation);
95};
96
100 public:
101 BaseLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {
102 if (auto tt = type->to<IR::Type_Tuple>())
103 BUG_CHECK(tt->getSize() == 0, "%1%: tuples with fields are not base locations", tt);
104 else if (auto ts = type->to<IR::Type_StructLike>())
105 BUG_CHECK(ts->fields.size() == 0, "%1%: structs with fields are not base locations",
106 tt);
107 else
108 BUG_CHECK(type->is<IR::Type_Bits>() || type->is<IR::Type_Enum>() ||
109 type->is<IR::Type_Boolean>() || type->is<IR::Type_Var>() ||
110 type->is<IR::Type_Error>() || type->is<IR::Type_Varbits>() ||
111 type->is<IR::Type_Newtype>() || type->is<IR::Type_SerEnum>() ||
112 type->is<IR::Type_List>(),
113 "%1%: unexpected type", type);
114 }
115 void addValidBits(LocationSet *) const override {}
116 void addLastIndexField(LocationSet *) const override {}
117 void removeHeaders(LocationSet *result) const override;
118
119 DECLARE_TYPEINFO(BaseLocation, StorageLocation);
120};
121
125 absl::InlinedVector<std::pair<cstring, const StorageLocation *>, 4>>
126 fieldLocations;
127
128 void createField(cstring name, StorageLocation *field) {
129 fieldLocations.emplace(name, field);
130 CHECK_NULL(field);
131 }
132 void replaceField(cstring field, StorageLocation *replacement) {
133 fieldLocations[field] = replacement;
134 }
135
136 friend class StorageFactory;
137
138 protected:
139 WithFieldsLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {}
140
141 public:
142 void addField(cstring field, LocationSet *addTo) const;
143 void removeHeaders(LocationSet *result) const override;
144 auto fields() const { return Values(fieldLocations); }
145 void dbprint(std::ostream &out) const override {
146 for (auto f : fieldLocations) out << *f.second << " ";
147 }
148
149 DECLARE_TYPEINFO(WithFieldsLocation, StorageLocation);
150};
151
154 protected:
155 StructLocation(const IR::Type *type, cstring name) : WithFieldsLocation(type, name) {
156 BUG_CHECK(type->is<IR::Type_StructLike>(), "%1%: unexpected type", type);
157 }
158 friend class StorageFactory;
159
160 public:
161 void addValidBits(LocationSet *result) const override;
162 void addLastIndexField(LocationSet *result) const override;
163 bool isHeader() const { return type->is<IR::Type_Header>(); }
164 bool isHeaderUnion() const { return type->is<IR::Type_HeaderUnion>(); }
165 bool isStruct() const { return type->is<IR::Type_Struct>(); }
166
167 DECLARE_TYPEINFO(StructLocation, WithFieldsLocation);
168};
169
172 absl::InlinedVector<const StorageLocation *, 8> elements;
173
174 protected:
175 void createElement(unsigned index, StorageLocation *element) {
176 elements[index] = element;
177 CHECK_NULL(element);
178 }
179
180 IndexedLocation(const IR::Type *type, cstring name) : StorageLocation(type, name) {
181 CHECK_NULL(type);
182 const auto *it = type->to<IR::Type_Indexed>();
183 BUG_CHECK(it != nullptr, "%1%: unexpected type", type);
184 elements.resize(it->getSize());
185 }
186
187 friend class StorageFactory;
188
189 public:
190 void addElement(unsigned index, LocationSet *result) const;
191 auto begin() const { return elements.cbegin(); }
192 auto end() const { return elements.cend(); }
193 void dbprint(std::ostream &out) const override {
194 for (unsigned i = 0; i < elements.size(); i++) out << *elements.at(i) << " ";
195 }
196 size_t getSize() const { return elements.size(); }
197 void removeHeaders(LocationSet *result) const override;
198
199 DECLARE_TYPEINFO(IndexedLocation, StorageLocation);
200};
201
204 protected:
205 TupleLocation(const IR::Type *type, cstring name) : IndexedLocation(type, name) {}
206 friend class StorageFactory;
207
208 public:
209 void addValidBits(LocationSet *) const override {}
210 void addLastIndexField(LocationSet *) const override {}
211
212 DECLARE_TYPEINFO(TupleLocation, IndexedLocation);
213};
214
216 const StorageLocation *lastIndexField = nullptr; // accessed by lastIndex
217
218 void setLastIndexField(const StorageLocation *location) { lastIndexField = location; }
219
220 protected:
221 ArrayLocation(const IR::Type *type, cstring name) : IndexedLocation(type, name) {}
222 friend class StorageFactory;
223
224 public:
225 const StorageLocation *getLastIndexField() const { return lastIndexField; }
226
227 void addValidBits(LocationSet *result) const override;
228 void removeHeaders(LocationSet *) const override {} // no results added
229 void addLastIndexField(LocationSet *result) const override;
230
231 DECLARE_TYPEINFO(ArrayLocation, IndexedLocation);
232};
233
235 // FIXME: Allocate StorageLocations from an arena, not global allocator
236 mutable std::vector<std::unique_ptr<StorageLocation>> storageLocations;
237
238 template <class T>
239 T *construct(const IR::Type *type, cstring name) const;
240
241 static constexpr std::string_view indexFieldName = "$last_index";
242
243 public:
244 StorageLocation *create(const IR::Type *type, cstring name) const;
245
246 static const cstring validFieldName;
247};
248
251class LocationSet : public IHasDbPrint {
253 LocationsStorage locations;
254
255 class canonical_iterator {
256 absl::InlinedVector<const StorageLocation *, 8> workList;
257
258 void unwrapTop() {
259 if (workList.empty()) return;
260
261 const auto *location = workList.back();
262 if (location->is<BaseLocation>()) return;
263
264 if (const auto *wfl = location->to<WithFieldsLocation>()) {
265 workList.pop_back();
266 for (const auto *f : Util::iterator_range(wfl->fields()).reverse())
267 workList.push_back(f);
268 unwrapTop();
269 return;
270 }
271
272 if (const auto *a = location->to<IndexedLocation>()) {
273 workList.pop_back();
274 for (const auto *f : Util::iterator_range(*a).reverse()) workList.push_back(f);
275 unwrapTop();
276 return;
277 }
278
279 BUG("unexpected location");
280 }
281
282 public:
283 using iterator_category = std::forward_iterator_tag;
284 using value_type = const StorageLocation *;
285 using difference_type = ptrdiff_t;
286 using pointer = value_type;
287 using reference = value_type;
288
289 canonical_iterator() = default;
290
291 explicit canonical_iterator(const LocationsStorage &locations) {
292 for (const auto *loc : Util::iterator_range(locations).reverse())
293 workList.push_back(loc);
294 unwrapTop();
295 }
296 canonical_iterator &operator++() {
297 workList.pop_back();
298 unwrapTop();
299 return *this;
300 }
301 canonical_iterator operator++(int) {
302 auto copy = *this;
303 ++*this;
304 return copy;
305 }
306 bool operator==(const canonical_iterator &i) const { return workList == i.workList; }
307 bool operator!=(const canonical_iterator &i) const { return workList != i.workList; }
308 reference operator*() const { return workList.back(); }
309 pointer operator->() const { return workList.back(); }
310 };
311
312 public:
313 LocationSet() = default;
314 explicit LocationSet(const ordered_set<const StorageLocation *> &other) : locations(other) {}
315 explicit LocationSet(const StorageLocation *location) {
316 CHECK_NULL(location);
317 locations.emplace(location);
318 }
319 static const LocationSet *empty;
320
321 const LocationSet *getField(cstring field) const;
322 const LocationSet *getValidField() const;
323 const LocationSet *getIndex(unsigned index) const;
324 const LocationSet *allElements() const;
325 const LocationSet *getArrayLastIndex() const;
326
327 void add(const StorageLocation *location) {
328 CHECK_NULL(location);
329 locations.emplace(location);
330 }
331 const LocationSet *join(const LocationSet *other) const;
334 const LocationSet *canonicalize() const;
335 void addCanonical(const StorageLocation *location);
336 auto begin() const { return locations.cbegin(); }
337 auto end() const { return locations.cend(); }
338 auto canon_begin() const { return canonical_iterator(locations); }
339 auto canon_end() const { return canonical_iterator(); }
340 auto canonical() const { return Util::iterator_range(canon_begin(), canon_end()); }
341
342 void dbprint(std::ostream &out) const override {
343 if (locations.empty()) out << "LocationSet::empty";
344 for (auto l : locations) {
345 l->dbprint(out);
346 out << " ";
347 }
348 }
349 // only defined for canonical representations
350 bool overlaps(const LocationSet *other) const;
351 bool operator==(const LocationSet &other) const;
352 bool isEmpty() const { return locations.empty(); }
353};
354
356class StorageMap : public IHasDbPrint {
359 StorageFactory factory;
360
361 public:
362 ReferenceMap *refMap;
363 TypeMap *typeMap;
364
365 StorageMap(ReferenceMap *refMap, TypeMap *typeMap) : refMap(refMap), typeMap(typeMap) {
366 CHECK_NULL(refMap);
367 CHECK_NULL(typeMap);
368 }
369 const StorageLocation *add(const IR::IDeclaration *decl) {
370 CHECK_NULL(decl);
371 auto type = typeMap->getType(decl->getNode(), true);
372 auto loc = factory.create(type, decl->getName() + "/" + decl->externalName());
373 if (loc != nullptr) storage.emplace(decl, loc);
374 return loc;
375 }
376 const StorageLocation *getOrAdd(const IR::IDeclaration *decl) {
377 const auto *s = getStorage(decl);
378 if (s != nullptr) return s;
379 return add(decl);
380 }
381 const StorageLocation *getStorage(const IR::IDeclaration *decl) const {
382 CHECK_NULL(decl);
383 auto result = ::P4::get(storage, decl);
384 return result;
385 }
386 void dbprint(std::ostream &out) const override {
387 for (auto &it : storage) out << it.first << ": " << it.second << Log::endl;
388 }
389};
390
392class ProgramPoint : public IHasDbPrint {
400 absl::InlinedVector<const IR::Node *, 8> stack; // Has inline space for 8 nodes
401
402 public:
403 ProgramPoint() = default;
404 ProgramPoint(const ProgramPoint &other) : stack(other.stack) {}
405 explicit ProgramPoint(const IR::Node *node) {
406 CHECK_NULL(node);
407 assign(node);
408 }
409 ProgramPoint(const ProgramPoint &context, const IR::Node *node);
413 ProgramPoint after() { return ProgramPoint(*this, nullptr); }
414 bool operator==(const ProgramPoint &other) const;
415 std::size_t hash() const;
416 void dbprint(std::ostream &out) const override {
417 if (isBeforeStart()) {
418 out << "<BeforeStart>";
419 } else {
420 bool first = true;
421 for (auto n : stack) {
422 if (!first) out << "//";
423 if (!n)
424 out << "After end";
425 else
426 out << dbp(n);
427 first = false;
428 }
429 auto l = stack.back();
430 if (l != nullptr &&
431 (l->is<IR::AssignmentStatement>() || l->is<IR::MethodCallStatement>()))
432 out << "[[" << l << "]]";
433 }
434 }
435 void assign(const ProgramPoint &context, const IR::Node *node);
436 void assign(const IR::Node *node) { stack.assign({node}); }
437 void clear() { stack.clear(); }
438 const IR::Node *last() const { return stack.empty() ? nullptr : stack.back(); }
439 bool isBeforeStart() const { return stack.empty(); }
440 auto begin() const { return stack.begin(); }
441 auto end() const { return stack.end(); }
442 ProgramPoint &operator=(const ProgramPoint &) = default;
443 ProgramPoint &operator=(ProgramPoint &&) = default;
444};
445} // namespace P4
446
447// inject hash into std namespace so it is picked up by std::unordered_set
448namespace std {
449template <>
450struct hash<P4::ProgramPoint> {
451 std::size_t operator()(const P4::ProgramPoint &s) const { return s.hash(); }
452};
453
454template <>
455struct hash<P4::loc_t> {
456 std::size_t operator()(const P4::loc_t &loc) const { return loc.hash(); }
457};
458
459} // namespace std
460
461namespace P4::Util {
462template <>
464 size_t operator()(const P4::ProgramPoint &p) const { return p.hash(); }
465};
466} // namespace P4::Util
467
468namespace P4 {
470 typedef absl::flat_hash_set<ProgramPoint, Util::Hash> Points;
471 Points points;
472 explicit ProgramPoints(const Points &points) : points(points) {}
473
474 public:
475 ProgramPoints() = default;
476 explicit ProgramPoints(ProgramPoint point) { points.emplace(point); }
477 void add(const ProgramPoints *from);
478 const ProgramPoints *merge(const ProgramPoints *with) const;
479 bool operator==(const ProgramPoints &other) const;
480 void dbprint(std::ostream &out) const override {
481 out << "{";
482 for (auto p : points) out << p << " ";
483 out << "}";
484 }
485 size_t size() const { return points.size(); }
486 bool containsBeforeStart() const {
487 return points.find(ProgramPoint::beforeStart) != points.end();
488 }
489 Points::const_iterator begin() const { return points.cbegin(); }
490 Points::const_iterator end() const { return points.cend(); }
491};
492
494class Definitions : public IHasDbPrint {
499 bool unreachable = false;
500
501 public:
502 Definitions() = default;
503 Definitions(const Definitions &other)
504 : definitions(other.definitions), unreachable(other.unreachable) {}
505 Definitions *joinDefinitions(const Definitions *other) const;
507 Definitions *writes(ProgramPoint point, const LocationSet &locations) const;
508 void setDefintion(const BaseLocation *loc, const ProgramPoints *point) {
509 CHECK_NULL(loc);
510 CHECK_NULL(point);
511 definitions[loc] = point;
512 }
513 void setDefinition(const StorageLocation *loc, const ProgramPoints *point);
514 void setDefinition(const LocationSet &loc, const ProgramPoints *point);
515 Definitions *setUnreachable() {
516 unreachable = true;
517 return this;
518 }
519 bool isUnreachable() const { return unreachable; }
520 bool hasLocation(const BaseLocation *location) const {
521 return definitions.find(location) != definitions.end();
522 }
523 const ProgramPoints *getPoints(const BaseLocation *location) const {
524 auto r = ::P4::get(definitions, location);
525 BUG_CHECK(r != nullptr, "no definitions found for %1%", location);
526 return r;
527 }
528 const ProgramPoints *getPoints(const LocationSet &locations) const;
529 bool operator==(const Definitions &other) const;
530 void dbprint(std::ostream &out) const override {
531 if (unreachable) {
532 out << " Unreachable" << Log::endl;
533 }
534 if (definitions.empty()) out << " Empty definitions";
535 bool first = true;
536 for (auto d : definitions) {
537 if (!first) out << Log::endl;
538 out << " " << *d.first << "=>" << *d.second;
539 first = false;
540 }
541 }
542 Definitions *cloneDefinitions() const { return new Definitions(*this); }
543 void removeLocation(const StorageLocation *loc);
544 bool empty() const { return definitions.empty(); }
545 size_t size() const { return definitions.size(); }
546};
547
554 StorageMap storageMap;
555
556 public:
557 AllDefinitions(ReferenceMap *refMap, TypeMap *typeMap) : storageMap(refMap, typeMap) {}
558
559 Definitions *getDefinitions(ProgramPoint point, bool emptyIfNotFound = false) {
560 auto it = atPoint.find(point);
561 if (it == atPoint.end()) {
562 if (emptyIfNotFound) {
563 auto defs = new Definitions();
564 setDefinitionsAt(point, defs, false);
565 return defs;
566 }
567 BUG("Unknown point %1% for definitions", &point);
568 }
569 return it->second;
570 }
571 void setDefinitionsAt(ProgramPoint point, Definitions *defs, bool overwrite) {
572 if (!overwrite) {
573 auto it = atPoint.find(point);
574 if (it != atPoint.end()) {
575 LOG2("Overwriting definitions at " << point << ": " << it->second << " with "
576 << defs);
577 BUG_CHECK(false, "Overwriting definitions at %1%", point);
578 }
579 }
580 atPoint[point] = defs;
581 }
582
583 const StorageLocation *getStorage(const IR::IDeclaration *decl) const {
584 return storageMap.getStorage(decl);
585 }
586
587 const StorageLocation *getOrAddStorage(const IR::IDeclaration *decl) {
588 return storageMap.getOrAdd(decl);
589 }
590
591 void dbprint(std::ostream &out) const override {
592 for (auto e : atPoint) out << e.first << " => " << e.second << Log::endl;
593 }
594};
595
607class ComputeWriteSet : public Inspector, public IHasDbPrint {
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 std::unordered_set<loc_t>) {
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::HeaderStackExpression *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::AssignmentStatement *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::unordered_set<loc_t> &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 // TODO: Make absl::node_hash_set instead?
773 std::unordered_set<loc_t> &cached_locs;
774};
775
776} // namespace P4
777
778#endif /* FRONTENDS_P4_DEF_USE_H_ */
Definition frontends/p4/def_use.h:548
Definition alloc_trace.h:29
Definition frontends/p4/def_use.h:215
Definition frontends/p4/def_use.h:99
Definition frontends/p4/def_use.h:607
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
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:676
Definitions * currentDefinitions
Result computed by this pass.
Definition frontends/p4/def_use.h:674
ComputeWriteSet(const ComputeWriteSet *source, ProgramPoint context, Definitions *definitions, std::unordered_set< loc_t > &cached_locs)
Definition frontends/p4/def_use.h:691
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:494
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:171
Definition visitor.h:400
Definition frontends/p4/def_use.h:251
const LocationSet * canonicalize() const
Definition frontends/p4/def_use.cpp:243
Indicates a statement in the program.
Definition frontends/p4/def_use.h:392
static ProgramPoint beforeStart
A point logically before the function/control/action start.
Definition frontends/p4/def_use.h:411
ProgramPoint after()
We use a nullptr to indicate a point after the previous context.
Definition frontends/p4/def_use.h:413
Definition frontends/p4/def_use.h:469
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition frontends/p4/def_use.h:234
Abstraction for something that is has a left value (variable, parameter)
Definition frontends/p4/def_use.h:56
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:356
Definition frontends/p4/def_use.h:153
Definition frontends/p4/def_use.h:203
Definition typeMap.h:41
Definition iterator_range.h:44
Base class for location sets that contain fields.
Definition frontends/p4/def_use.h:123
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:40
Definition gc.h:27