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 "absl/container/node_hash_set.h"
23#include "frontends/common/resolveReferences/referenceMap.h"
25#include "lib/alloc_trace.h"
26#include "lib/flat_map.h"
28#include "lib/hvec_map.h"
29#include "lib/ordered_set.h"
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;
51 std::size_t hash()
const;
58#ifdef DEBUG_LOCATION_IDS
59 static unsigned crtid;
69#ifdef DEBUG_LOCATION_IDS
76 void dbprint(std::ostream &out)
const override {
77#ifdef DEBUG_LOCATION_IDS
78 out <<
id <<
" " << name;
80 out << dbp(type) <<
" " << name;
83 cstring toString()
const {
return name; }
87 virtual void addValidBits(
LocationSet *result)
const = 0;
93 virtual void addLastIndexField(
LocationSet *result)
const = 0;
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",
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);
117 void addLastIndexField(
LocationSet *)
const override {}
126 absl::InlinedVector<std::pair<cstring, const StorageLocation *>, 4>>
130 fieldLocations.emplace(name, field);
134 fieldLocations[field] = replacement;
145 auto fields()
const {
return Values(fieldLocations); }
146 void dbprint(std::ostream &out)
const override {
147 for (
auto f : fieldLocations) out << *f.second <<
" ";
157 BUG_CHECK(type->is<IR::Type_StructLike>(),
"%1%: unexpected type", type);
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>(); }
173 absl::InlinedVector<const StorageLocation *, 8> elements;
177 elements[index] = element;
183 const auto *it = type->to<IR::Type_Indexed>();
184 BUG_CHECK(it !=
nullptr,
"%1%: unexpected type", type);
185 elements.resize(it->getSize());
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) <<
" ";
197 size_t getSize()
const {
return elements.size(); }
211 void addLastIndexField(
LocationSet *)
const override {}
219 void setLastIndexField(
const StorageLocation *location) { lastIndexField = location; }
226 const StorageLocation *getLastIndexField()
const {
return lastIndexField; }
228 void addValidBits(
LocationSet *result)
const override;
230 void addLastIndexField(
LocationSet *result)
const override;
237 mutable std::vector<std::unique_ptr<StorageLocation>> storageLocations;
240 T *construct(
const IR::Type *type,
cstring name)
const;
242 static constexpr std::string_view indexFieldName =
"$last_index";
247 static const cstring validFieldName;
256 class canonical_iterator {
257 absl::InlinedVector<const StorageLocation *, 8> workList;
260 if (workList.empty())
return;
262 const auto *location = workList.back();
268 workList.push_back(f);
280 BUG(
"unexpected location");
284 using iterator_category = std::forward_iterator_tag;
286 using difference_type = ptrdiff_t;
287 using pointer = value_type;
288 using reference = value_type;
290 canonical_iterator() =
default;
294 workList.push_back(loc);
297 canonical_iterator &operator++() {
302 canonical_iterator operator++(
int) {
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(); }
317 CHECK_NULL(location);
318 locations.emplace(location);
329 CHECK_NULL(location);
330 locations.emplace(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(); }
343 void dbprint(std::ostream &out)
const override {
344 if (locations.empty()) out <<
"LocationSet::empty";
345 for (
auto l : locations) {
353 bool isEmpty()
const {
return locations.empty(); }
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);
378 const auto *s = getStorage(decl);
379 if (s !=
nullptr)
return s;
384 auto result = ::P4::get(storage, decl);
387 void dbprint(std::ostream &out)
const override {
388 for (
auto &it : storage) out << it.first <<
": " << it.second << Log::endl;
401 absl::InlinedVector<const IR::Node *, 8> stack;
416 std::size_t hash()
const;
417 void dbprint(std::ostream &out)
const override {
418 if (isBeforeStart()) {
419 out <<
"<BeforeStart>";
422 for (
auto n : stack) {
423 if (!first) out <<
"//";
430 auto l = stack.back();
432 (l->is<IR::AssignmentStatement>() || l->is<IR::MethodCallStatement>()))
433 out <<
"[[" << l <<
"]]";
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;
451struct hash<
P4::ProgramPoint> {
452 std::size_t operator()(
const P4::ProgramPoint &s)
const {
return s.hash(); }
456struct hash<
P4::loc_t> {
457 std::size_t operator()(
const P4::loc_t &loc)
const {
return loc.hash(); }
470 size_t operator()(
const P4::loc_t &loc)
const {
return loc.hash(); }
476 typedef absl::flat_hash_set<ProgramPoint, Util::Hash> Points;
478 explicit ProgramPoints(
const Points &points) : points(points) {}
486 void dbprint(std::ostream &out)
const override {
488 for (
auto p : points) out << p <<
" ";
491 size_t size()
const {
return points.size(); }
492 bool containsBeforeStart()
const {
495 Points::const_iterator begin()
const {
return points.cbegin(); }
496 Points::const_iterator end()
const {
return points.cend(); }
505 bool unreachable =
false;
510 : definitions(other.definitions), unreachable(other.unreachable) {}
517 definitions[loc] = point;
525 bool isUnreachable()
const {
return unreachable; }
527 return definitions.find(location) != definitions.end();
530 auto r = ::P4::get(definitions, location);
531 BUG_CHECK(r !=
nullptr,
"no definitions found for %1%", location);
536 void dbprint(std::ostream &out)
const override {
538 out <<
" Unreachable" << Log::endl;
540 if (definitions.empty()) out <<
" Empty definitions";
542 for (
auto d : definitions) {
543 if (!first) out << Log::endl;
544 out <<
" " << *d.first <<
"=>" << *d.second;
550 bool empty()
const {
return definitions.empty(); }
551 size_t size()
const {
return definitions.size(); }
566 auto it = atPoint.find(point);
567 if (it == atPoint.end()) {
568 if (emptyIfNotFound) {
570 setDefinitionsAt(point, defs,
false);
573 BUG(
"Unknown point %1% for definitions", &point);
579 auto it = atPoint.find(point);
580 if (it != atPoint.end()) {
581 LOG2(
"Overwriting definitions at " << point <<
": " << it->second <<
" with "
583 BUG_CHECK(
false,
"Overwriting definitions at %1%", point);
586 atPoint[point] = defs;
590 return storageMap.getStorage(decl);
594 return storageMap.getOrAdd(decl);
597 void dbprint(std::ostream &out)
const override {
598 for (
auto e : atPoint) out << e.first <<
" => " << e.second << Log::endl;
615 using CachedLocs = absl::node_hash_set<loc_t, Util::Hash>;
621 allDefinitions(allDefinitions),
626 virtualMethod(
false),
627 cached_locs(
new CachedLocs) {
628 CHECK_NULL(allDefinitions);
631 visitDagOnce =
false;
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;
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;
674 const LocationSet *writtenLocations(
const IR::Expression *expression) {
675 expression->apply(*
this);
676 return getWrites(expression);
696 static int nest_count;
701 std::shared_ptr<CachedLocs> cached_locs)
702 : refMap(source->refMap),
703 typeMap(source->typeMap),
705 allDefinitions(source->allDefinitions),
713 virtualMethod(false),
714 cached_locs(cached_locs) {
715 visitDagOnce =
false;
721 void enterScope(
const IR::ParameterList *parameters,
724 void exitScope(
const IR::ParameterList *parameters,
726 Definitions *getDefinitionsAfter(
const IR::ParserState *state);
727 bool setDefinitions(
Definitions *defs,
const IR::Node *who =
nullptr,
bool overwrite =
false);
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);
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);
745 void expressionWrites(
const IR::Expression *expression,
const LocationSet *loc) {
746 CHECK_NULL(expression);
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);
756 writes.emplace(exprLoc, loc);
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;
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)) {
768 nested_trace =
memuse.start();
772 void end_apply()
override {
773 LOG1(
"finished CWS" << Log::unindent);
774 if (--nest_count == 0 && LOGGING(2)) {
775 memuse.stop(nested_trace);
781 std::shared_ptr<CachedLocs> cached_locs;
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 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:172
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 iterator_range.h:44
Base class for location sets that contain fields.
Definition frontends/p4/def_use.h:124
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition frontends/p4/def_use.h:41