17#ifndef FRONTENDS_P4_DEF_USE_H_
18#define FRONTENDS_P4_DEF_USE_H_
20#include "absl/container/flat_hash_set.h"
21#include "absl/container/inlined_vector.h"
22#include "frontends/common/resolveReferences/referenceMap.h"
24#include "lib/alloc_trace.h"
25#include "lib/flat_map.h"
27#include "lib/hvec_map.h"
28#include "lib/ordered_set.h"
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;
50 std::size_t hash()
const;
57#ifdef DEBUG_LOCATION_IDS
58 static unsigned crtid;
68#ifdef DEBUG_LOCATION_IDS
75 void dbprint(std::ostream &out)
const override {
76#ifdef DEBUG_LOCATION_IDS
77 out <<
id <<
" " << name;
79 out << dbp(type) <<
" " << name;
82 cstring toString()
const {
return name; }
86 virtual void addValidBits(
LocationSet *result)
const = 0;
92 virtual void addLastIndexField(
LocationSet *result)
const = 0;
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",
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);
116 void addLastIndexField(
LocationSet *)
const override {}
125 absl::InlinedVector<std::pair<cstring, const StorageLocation *>, 4>>
129 fieldLocations.emplace(name, field);
133 fieldLocations[field] = replacement;
144 auto fields()
const {
return Values(fieldLocations); }
145 void dbprint(std::ostream &out)
const override {
146 for (
auto f : fieldLocations) out << *f.second <<
" ";
156 BUG_CHECK(type->is<IR::Type_StructLike>(),
"%1%: unexpected type", type);
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>(); }
172 absl::InlinedVector<const StorageLocation *, 8> elements;
176 elements[index] = element;
182 const auto *it = type->to<IR::Type_Indexed>();
183 BUG_CHECK(it !=
nullptr,
"%1%: unexpected type", type);
184 elements.resize(it->getSize());
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) <<
" ";
196 size_t getSize()
const {
return elements.size(); }
210 void addLastIndexField(
LocationSet *)
const override {}
218 void setLastIndexField(
const StorageLocation *location) { lastIndexField = location; }
225 const StorageLocation *getLastIndexField()
const {
return lastIndexField; }
227 void addValidBits(
LocationSet *result)
const override;
229 void addLastIndexField(
LocationSet *result)
const override;
236 mutable std::vector<std::unique_ptr<StorageLocation>> storageLocations;
239 T *construct(
const IR::Type *type,
cstring name)
const;
241 static constexpr std::string_view indexFieldName =
"$last_index";
246 static const cstring validFieldName;
255 class canonical_iterator {
256 absl::InlinedVector<const StorageLocation *, 8> workList;
259 if (workList.empty())
return;
261 const auto *location = workList.back();
267 workList.push_back(f);
279 BUG(
"unexpected location");
283 using iterator_category = std::forward_iterator_tag;
285 using difference_type = ptrdiff_t;
286 using pointer = value_type;
287 using reference = value_type;
289 canonical_iterator() =
default;
293 workList.push_back(loc);
296 canonical_iterator &operator++() {
301 canonical_iterator operator++(
int) {
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(); }
316 CHECK_NULL(location);
317 locations.emplace(location);
328 CHECK_NULL(location);
329 locations.emplace(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(); }
342 void dbprint(std::ostream &out)
const override {
343 if (locations.empty()) out <<
"LocationSet::empty";
344 for (
auto l : locations) {
352 bool isEmpty()
const {
return locations.empty(); }
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);
377 const auto *s = getStorage(decl);
378 if (s !=
nullptr)
return s;
383 auto result = ::P4::get(storage, decl);
386 void dbprint(std::ostream &out)
const override {
387 for (
auto &it : storage) out << it.first <<
": " << it.second << Log::endl;
400 absl::InlinedVector<const IR::Node *, 8> stack;
415 std::size_t hash()
const;
416 void dbprint(std::ostream &out)
const override {
417 if (isBeforeStart()) {
418 out <<
"<BeforeStart>";
421 for (
auto n : stack) {
422 if (!first) out <<
"//";
429 auto l = stack.back();
431 (l->is<IR::AssignmentStatement>() || l->is<IR::MethodCallStatement>()))
432 out <<
"[[" << l <<
"]]";
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;
450struct hash<
P4::ProgramPoint> {
451 std::size_t operator()(
const P4::ProgramPoint &s)
const {
return s.hash(); }
455struct hash<
P4::loc_t> {
456 std::size_t operator()(
const P4::loc_t &loc)
const {
return loc.hash(); }
470 typedef absl::flat_hash_set<ProgramPoint, Util::Hash> Points;
472 explicit ProgramPoints(
const Points &points) : points(points) {}
480 void dbprint(std::ostream &out)
const override {
482 for (
auto p : points) out << p <<
" ";
485 size_t size()
const {
return points.size(); }
486 bool containsBeforeStart()
const {
489 Points::const_iterator begin()
const {
return points.cbegin(); }
490 Points::const_iterator end()
const {
return points.cend(); }
499 bool unreachable =
false;
504 : definitions(other.definitions), unreachable(other.unreachable) {}
511 definitions[loc] = point;
519 bool isUnreachable()
const {
return unreachable; }
521 return definitions.find(location) != definitions.end();
524 auto r = ::P4::get(definitions, location);
525 BUG_CHECK(r !=
nullptr,
"no definitions found for %1%", location);
530 void dbprint(std::ostream &out)
const override {
532 out <<
" Unreachable" << Log::endl;
534 if (definitions.empty()) out <<
" Empty definitions";
536 for (
auto d : definitions) {
537 if (!first) out << Log::endl;
538 out <<
" " << *d.first <<
"=>" << *d.second;
544 bool empty()
const {
return definitions.empty(); }
545 size_t size()
const {
return definitions.size(); }
560 auto it = atPoint.find(point);
561 if (it == atPoint.end()) {
562 if (emptyIfNotFound) {
564 setDefinitionsAt(point, defs,
false);
567 BUG(
"Unknown point %1% for definitions", &point);
573 auto it = atPoint.find(point);
574 if (it != atPoint.end()) {
575 LOG2(
"Overwriting definitions at " << point <<
": " << it->second <<
" with "
577 BUG_CHECK(
false,
"Overwriting definitions at %1%", point);
580 atPoint[point] = defs;
584 return storageMap.getStorage(decl);
588 return storageMap.getOrAdd(decl);
591 void dbprint(std::ostream &out)
const override {
592 for (
auto e : atPoint) out << e.first <<
" => " << e.second << Log::endl;
612 allDefinitions(allDefinitions),
617 virtualMethod(
false),
618 cached_locs(*
new std::unordered_set<loc_t>) {
619 CHECK_NULL(allDefinitions);
622 visitDagOnce =
false;
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;
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;
665 const LocationSet *writtenLocations(
const IR::Expression *expression) {
666 expression->apply(*
this);
667 return getWrites(expression);
687 static int nest_count;
692 std::unordered_set<loc_t> &cached_locs)
693 : refMap(source->refMap),
694 typeMap(source->typeMap),
696 allDefinitions(source->allDefinitions),
704 virtualMethod(false),
705 cached_locs(cached_locs) {
706 visitDagOnce =
false;
712 void enterScope(
const IR::ParameterList *parameters,
715 void exitScope(
const IR::ParameterList *parameters,
717 Definitions *getDefinitionsAfter(
const IR::ParserState *state);
718 bool setDefinitions(
Definitions *defs,
const IR::Node *who =
nullptr,
bool overwrite =
false);
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);
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);
736 void expressionWrites(
const IR::Expression *expression,
const LocationSet *loc) {
737 CHECK_NULL(expression);
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);
747 writes.emplace(exprLoc, loc);
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;
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)) {
759 nested_trace =
memuse.start();
763 void end_apply()
override {
764 LOG1(
"finished CWS" << Log::unindent);
765 if (--nest_count == 0 && LOGGING(2)) {
766 memuse.stop(nested_trace);
773 std::unordered_set<loc_t> &cached_locs;
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 stringify.h:33
The Declaration interface, representing objects with names.
Definition declaration.h:26
virtual ID getName() const =0
Interface for locations that support an index operation.
Definition frontends/p4/def_use.h:171
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 iterator_range.h:44
Base class for location sets that contain fields.
Definition frontends/p4/def_use.h:123
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition frontends/p4/def_use.h:40