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"
26#include "lib/hvec_map.h"
27#include "lib/ordered_set.h"
42 mutable std::size_t computedHash = 0;
43 bool operator==(
const loc_t &a)
const {
44 if (node != a.node)
return false;
45 if (parent == a.parent)
return true;
46 if (!parent || !a.parent)
return false;
47 return *parent == *a.parent;
49 std::size_t hash()
const;
54 static unsigned crtid;
57 virtual ~StorageLocation() {}
61 StorageLocation(
const IR::Type *type,
cstring name) : id(crtid++), type(type), name(name) {
64 void dbprint(std::ostream &out)
const override { out <<
id <<
" " << name; }
65 cstring toString()
const {
return name; }
69 virtual void addValidBits(
LocationSet *result)
const = 0;
75 virtual void addLastIndexField(
LocationSet *result)
const = 0;
77 DECLARE_TYPEINFO(StorageLocation);
82class BaseLocation :
public StorageLocation {
84 BaseLocation(
const IR::Type *type,
cstring name) : StorageLocation(type, name) {
85 if (
auto tt = type->to<IR::Type_Tuple>())
86 BUG_CHECK(tt->getSize() == 0,
"%1%: tuples with fields are not base locations", tt);
87 else if (
auto ts = type->to<IR::Type_StructLike>())
88 BUG_CHECK(ts->fields.size() == 0,
"%1%: structs with fields are not base locations",
91 BUG_CHECK(type->is<IR::Type_Bits>() || type->is<IR::Type_Enum>() ||
92 type->is<IR::Type_Boolean>() || type->is<IR::Type_Var>() ||
93 type->is<IR::Type_Error>() || type->is<IR::Type_Varbits>() ||
94 type->is<IR::Type_Newtype>() || type->is<IR::Type_SerEnum>() ||
95 type->is<IR::Type_List>(),
96 "%1%: unexpected type", type);
99 void addLastIndexField(
LocationSet *)
const override {}
102 DECLARE_TYPEINFO(BaseLocation, StorageLocation);
106class WithFieldsLocation :
public StorageLocation {
109 friend class StorageFactory;
110 WithFieldsLocation(
const IR::Type *type,
cstring name) : StorageLocation(type, name) {}
113 void createField(
cstring name, StorageLocation *field) {
114 fieldLocations.emplace(name, field);
117 void replaceField(
cstring field, StorageLocation *replacement) {
118 fieldLocations[field] = replacement;
121 return Values(fieldLocations);
123 void dbprint(std::ostream &out)
const override {
124 for (
auto f : fieldLocations) out << *f.second <<
" ";
127 DECLARE_TYPEINFO(WithFieldsLocation, StorageLocation);
131class StructLocation :
public WithFieldsLocation {
133 StructLocation(
const IR::Type *type,
cstring name) : WithFieldsLocation(type, name) {
134 BUG_CHECK(type->is<IR::Type_StructLike>(),
"%1%: unexpected type", type);
137 void addValidBits(
LocationSet *result)
const override;
139 void addLastIndexField(
LocationSet *result)
const override;
140 bool isHeader()
const {
return type->is<IR::Type_Header>(); }
141 bool isHeaderUnion()
const {
return type->is<IR::Type_HeaderUnion>(); }
142 bool isStruct()
const {
return type->is<IR::Type_Struct>(); }
144 DECLARE_TYPEINFO(StructLocation, WithFieldsLocation);
148class IndexedLocation :
public StorageLocation {
150 absl::InlinedVector<const StorageLocation *, 8> elements;
151 friend class StorageFactory;
153 void createElement(
unsigned index, StorageLocation *element) {
154 elements[index] = element;
159 IndexedLocation(
const IR::Type *type,
cstring name) : StorageLocation(type, name) {
161 auto it = type->to<IR::Type_Indexed>();
162 BUG_CHECK(it !=
nullptr,
"%1%: unexpected type", type);
163 elements.resize(it->getSize());
165 void addElement(
unsigned index,
LocationSet *result)
const;
166 auto begin()
const {
return elements.cbegin(); }
167 auto end()
const {
return elements.cend(); }
169 DECLARE_TYPEINFO(IndexedLocation, StorageLocation);
173class TupleLocation :
public IndexedLocation {
175 TupleLocation(
const IR::Type *type,
cstring name) : IndexedLocation(type, name) {}
176 size_t getSize()
const {
return elements.size(); }
178 void addLastIndexField(
LocationSet *)
const override {}
181 DECLARE_TYPEINFO(TupleLocation, IndexedLocation);
184class ArrayLocation :
public IndexedLocation {
187 ArrayLocation(
const IR::Type *type,
cstring name)
188 : IndexedLocation(type, name), lastIndexField(
nullptr) {}
189 void setLastIndexField(
const StorageLocation *location) { lastIndexField = location; }
190 const StorageLocation *getLastIndexField()
const {
return lastIndexField; }
191 void dbprint(std::ostream &out)
const override {
192 for (
unsigned i = 0; i < elements.size(); i++) out << *elements.at(i) <<
" ";
194 void addValidBits(
LocationSet *result)
const override;
196 void addLastIndexField(
LocationSet *result)
const override;
198 DECLARE_TYPEINFO(ArrayLocation, IndexedLocation);
205 static const cstring validFieldName;
206 static const cstring indexFieldName;
215 LocationSet() =
default;
218 CHECK_NULL(location);
219 locations.emplace(location);
221 static const LocationSet *empty;
223 const LocationSet *getField(
cstring field)
const;
224 const LocationSet *getValidField()
const;
225 const LocationSet *getIndex(
unsigned index)
const;
226 const LocationSet *allElements()
const;
227 const LocationSet *getArrayLastIndex()
const;
230 CHECK_NULL(location);
231 locations.emplace(location);
233 const LocationSet *join(
const LocationSet *other)
const;
238 ordered_set<const StorageLocation *>::const_iterator begin()
const {
239 return locations.cbegin();
241 ordered_set<const StorageLocation *>::const_iterator end()
const {
return locations.cend(); }
242 void dbprint(std::ostream &out)
const override {
243 if (locations.empty()) out <<
"LocationSet::empty";
244 for (
auto l : locations) {
250 bool overlaps(
const LocationSet *other)
const;
251 bool operator==(
const LocationSet &other)
const;
252 bool isEmpty()
const {
return locations.empty(); }
271 auto type = typeMap->getType(decl->getNode(),
true);
272 auto loc = factory.create(type, decl->
getName() +
"/" + decl->externalName());
273 if (loc !=
nullptr) storage.emplace(decl, loc);
277 auto s = getStorage(decl);
278 if (s !=
nullptr)
return s;
283 auto result = ::P4::get(storage, decl);
286 void dbprint(std::ostream &out)
const override {
287 for (
auto &it : storage) out << it.first <<
": " << it.second << Log::endl;
300 absl::InlinedVector<const IR::Node *, 8> stack;
303 ProgramPoint() =
default;
304 ProgramPoint(
const ProgramPoint &other) : stack(other.stack) {}
305 explicit ProgramPoint(
const IR::Node *node) {
309 ProgramPoint(
const ProgramPoint &context,
const IR::Node *node);
313 ProgramPoint
after() {
return ProgramPoint(*
this,
nullptr); }
315 std::size_t hash()
const;
316 void dbprint(std::ostream &out)
const override {
317 if (isBeforeStart()) {
318 out <<
"<BeforeStart>";
321 for (
auto n : stack) {
322 if (!first) out <<
"//";
329 auto l = stack.back();
331 (l->is<IR::AssignmentStatement>() || l->is<IR::MethodCallStatement>()))
332 out <<
"[[" << l <<
"]]";
335 void assign(
const ProgramPoint &context,
const IR::Node *node);
336 void assign(
const IR::Node *node) { stack.assign({node}); }
337 void clear() { stack.clear(); }
338 const IR::Node *last()
const {
return stack.empty() ? nullptr : stack.back(); }
339 bool isBeforeStart()
const {
return stack.empty(); }
340 auto begin()
const {
return stack.begin(); }
341 auto end()
const {
return stack.end(); }
342 ProgramPoint &operator=(
const ProgramPoint &) =
default;
343 ProgramPoint &operator=(ProgramPoint &&) =
default;
350struct hash<
P4::ProgramPoint> {
351 std::size_t operator()(
const P4::ProgramPoint &s)
const {
return s.hash(); }
355struct hash<
P4::loc_t> {
356 std::size_t operator()(
const P4::loc_t &loc)
const {
return loc.hash(); }
370 typedef absl::flat_hash_set<ProgramPoint, Util::Hash> Points;
372 explicit ProgramPoints(
const Points &points) : points(points) {}
375 ProgramPoints() =
default;
376 explicit ProgramPoints(
ProgramPoint point) { points.emplace(point); }
378 void add(
const ProgramPoints *from);
379 const ProgramPoints *merge(
const ProgramPoints *with)
const;
380 bool operator==(
const ProgramPoints &other)
const;
381 void dbprint(std::ostream &out)
const override {
383 for (
auto p : points) out << p <<
" ";
386 size_t size()
const {
return points.size(); }
387 bool containsBeforeStart()
const {
390 Points::const_iterator begin()
const {
return points.cbegin(); }
391 Points::const_iterator end()
const {
return points.cend(); }
400 bool unreachable =
false;
403 Definitions() =
default;
404 Definitions(
const Definitions &other)
405 : definitions(other.definitions), unreachable(other.unreachable) {}
406 Definitions *joinDefinitions(
const Definitions *other)
const;
412 definitions[loc] = point;
416 Definitions *setUnreachable() {
420 bool isUnreachable()
const {
return unreachable; }
422 return definitions.find(location) != definitions.end();
425 auto r = ::P4::get(definitions, location);
426 BUG_CHECK(r !=
nullptr,
"no definitions found for %1%", location);
430 bool operator==(
const Definitions &other)
const;
431 void dbprint(std::ostream &out)
const override {
433 out <<
" Unreachable" << Log::endl;
435 if (definitions.empty()) out <<
" Empty definitions";
437 for (
auto d : definitions) {
438 if (!first) out << Log::endl;
439 out <<
" " << *d.first <<
"=>" << *d.second;
443 Definitions *cloneDefinitions()
const {
return new Definitions(*
this); }
445 bool empty()
const {
return definitions.empty(); }
446 size_t size()
const {
return definitions.size(); }
459 : storageMap(
new StorageMap(refMap, typeMap)) {}
461 auto it = atPoint.find(point);
462 if (it == atPoint.end()) {
463 if (emptyIfNotFound) {
465 setDefinitionsAt(point, defs,
false);
468 BUG(
"Unknown point %1% for definitions", &point);
474 auto it = atPoint.find(point);
475 if (it != atPoint.end()) {
476 LOG2(
"Overwriting definitions at " << point <<
": " << it->second <<
" with "
478 BUG_CHECK(
false,
"Overwriting definitions at %1%", point);
481 atPoint[point] = defs;
483 void dbprint(std::ostream &out)
const override {
484 for (
auto e : atPoint) out << e.first <<
" => " << e.second << Log::endl;
502 : allDefinitions(allDefinitions),
506 storageMap(allDefinitions->storageMap),
508 virtualMethod(
false),
509 cached_locs(*
new std::unordered_set<loc_t>) {
510 CHECK_NULL(allDefinitions);
511 visitDagOnce =
false;
515 bool preorder(
const IR::Literal *expression)
override;
516 bool preorder(
const IR::Slice *expression)
override;
517 bool preorder(
const IR::TypeNameExpression *expression)
override;
518 bool preorder(
const IR::PathExpression *expression)
override;
519 bool preorder(
const IR::Member *expression)
override;
520 bool preorder(
const IR::ArrayIndex *expression)
override;
521 bool preorder(
const IR::Operation_Binary *expression)
override;
522 bool preorder(
const IR::Mux *expression)
override;
523 bool preorder(
const IR::SelectExpression *expression)
override;
524 bool preorder(
const IR::ListExpression *expression)
override;
525 bool preorder(
const IR::Operation_Unary *expression)
override;
526 bool preorder(
const IR::MethodCallExpression *expression)
override;
527 bool preorder(
const IR::DefaultExpression *expression)
override;
528 bool preorder(
const IR::Expression *expression)
override;
529 bool preorder(
const IR::InvalidHeader *expression)
override;
530 bool preorder(
const IR::InvalidHeaderUnion *expression)
override;
531 bool preorder(
const IR::P4ListExpression *expression)
override;
532 bool preorder(
const IR::HeaderStackExpression *expression)
override;
533 bool preorder(
const IR::StructExpression *expression)
override;
535 bool preorder(
const IR::P4Parser *parser)
override;
536 bool preorder(
const IR::P4Control *control)
override;
537 bool preorder(
const IR::P4Action *action)
override;
538 bool preorder(
const IR::P4Table *table)
override;
539 bool preorder(
const IR::Function *function)
override;
540 bool preorder(
const IR::AssignmentStatement *statement)
override;
541 bool preorder(
const IR::ReturnStatement *statement)
override;
542 bool preorder(
const IR::ExitStatement *statement)
override;
543 bool preorder(
const IR::BreakStatement *statement)
override;
544 bool handleJump(
const char *tok,
Definitions *&defs);
545 bool preorder(
const IR::ContinueStatement *statement)
override;
546 bool preorder(
const IR::IfStatement *statement)
override;
547 bool preorder(
const IR::ForStatement *statement)
override;
548 bool preorder(
const IR::ForInStatement *statement)
override;
549 bool preorder(
const IR::BlockStatement *statement)
override;
550 bool preorder(
const IR::SwitchStatement *statement)
override;
551 bool preorder(
const IR::EmptyStatement *statement)
override;
552 bool preorder(
const IR::MethodCallStatement *statement)
override;
554 const LocationSet *writtenLocations(
const IR::Expression *expression) {
555 expression->apply(*
this);
556 return getWrites(expression);
575 static int nest_count;
580 std::unordered_set<loc_t> &cached_locs)
581 : allDefinitions(source->allDefinitions),
588 storageMap(source->storageMap),
590 virtualMethod(false),
591 cached_locs(cached_locs) {
592 visitDagOnce =
false;
596 const loc_t *getLoc(
const Visitor::Context *ctxt);
597 const loc_t *getLoc(
const IR::Node *n,
const Visitor::Context *ctxt);
598 void enterScope(
const IR::ParameterList *parameters,
601 void exitScope(
const IR::ParameterList *parameters,
603 Definitions *getDefinitionsAfter(
const IR::ParserState *state);
604 bool setDefinitions(
Definitions *defs,
const IR::Node *who =
nullptr,
bool overwrite =
false);
607 const LocationSet *getWrites(
const IR::Expression *expression) {
608 const loc_t &exprLoc = *getLoc(expression, getChildContext());
609 auto result = ::P4::get(
writes, exprLoc);
610 BUG_CHECK(result !=
nullptr,
"No location set known for %1%", expression);
615 const LocationSet *getWrites(
const IR::Expression *expression,
const loc_t *parentLoc) {
616 const loc_t &exprLoc = *getLoc(expression, parentLoc);
617 auto result = ::P4::get(
writes, exprLoc);
618 BUG_CHECK(result !=
nullptr,
"No location set known for %1%", expression);
622 void expressionWrites(
const IR::Expression *expression,
const LocationSet *loc) {
623 CHECK_NULL(expression);
625 LOG3(expression << dbp(expression) <<
" writes " << loc);
626 const Context *ctx = getChildContext();
627 BUG_CHECK(ctx->node == expression,
"Expected ctx->node == expression.");
628 const loc_t &exprLoc = *getLoc(ctx);
629 if (
auto it =
writes.find(exprLoc); it !=
writes.end()) {
630 BUG_CHECK(*it->second == *loc || expression->is<IR::Literal>(),
631 "Expression %1% write set already set", expression);
633 writes.emplace(exprLoc, loc);
636 void dbprint(std::ostream &out)
const override {
637 if (
writes.empty()) out <<
"No writes";
638 for (
auto &it :
writes) out << it.first.node <<
" writes " << it.second << Log::endl;
640 profile_t init_apply(
const IR::Node *root)
override {
641 auto rv = Inspector::init_apply(root);
642 LOG1(
"starting ComputWriteSet" << Log::indent);
643 if (nest_count++ == 0 && LOGGING(2)) {
645 nested_trace =
memuse.start();
649 void end_apply()
override {
650 LOG1(
"finished CWS" << Log::unindent);
651 if (--nest_count == 0 && LOGGING(2)) {
652 memuse.stop(nested_trace);
659 std::unordered_set<loc_t> &cached_locs;
Definition frontends/p4/def_use.h:449
Definition alloc_trace.h:29
Definition frontends/p4/def_use.h:82
Definition frontends/p4/def_use.h:499
bool lhs
if true we are processing an expression on the lhs of an assignment
Definition frontends/p4/def_use.h:569
AllocTrace memuse
True if we are analyzing a virtual method.
Definition frontends/p4/def_use.h:573
Definitions * breakDefinitions
Definitions after exit statements.
Definition frontends/p4/def_use.h:564
Definitions * returnedDefinitions
Before statement currently processed.
Definition frontends/p4/def_use.h:562
void visitVirtualMethods(const IR::IndexedVector< IR::Declaration > &locals)
Statements and other control structures.
Definition frontends/p4/def_use.cpp:753
Definitions * exitDefinitions
Definitions after return statements.
Definition frontends/p4/def_use.h:563
Definitions * currentDefinitions
Result computed by this pass.
Definition frontends/p4/def_use.h:561
ComputeWriteSet(const ComputeWriteSet *source, ProgramPoint context, Definitions *definitions, std::unordered_set< loc_t > &cached_locs)
Definition frontends/p4/def_use.h:579
Definitions * continueDefinitions
Definitions at break statements.
Definition frontends/p4/def_use.h:565
ProgramPoint callingContext
Definitions at continue statements.
Definition frontends/p4/def_use.h:566
hvec_map< loc_t, const LocationSet * > writes
For each program location the location set it writes.
Definition frontends/p4/def_use.h:571
List of definers for each base storage (at a specific program point).
Definition frontends/p4/def_use.h:395
Definitions * writes(ProgramPoint point, const LocationSet *locations) const
Point writes the specified LocationSet.
Definition frontends/p4/def_use.cpp:355
Definition stringify.h:33
The Declaration interface, representing objects with names.
Definition declaration.h:26
virtual ID getName() const =0
Definition indexed_vector.h:40
Definition frontends/p4/def_use.h:211
const LocationSet * canonicalize() const
Definition frontends/p4/def_use.cpp:233
Indicates a statement in the program.
Definition frontends/p4/def_use.h:292
static ProgramPoint beforeStart
A point logically before the function/control/action start.
Definition frontends/p4/def_use.h:311
ProgramPoint after()
We use a nullptr to indicate a point after the previous context.
Definition frontends/p4/def_use.h:313
Definition frontends/p4/def_use.h:369
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition frontends/p4/def_use.h:201
Abstraction for something that is has a left value (variable, parameter)
Definition frontends/p4/def_use.h:53
const LocationSet * getLastIndexField() const
Definition frontends/p4/def_use.cpp:160
const LocationSet * removeHeaders() const
Definition frontends/p4/def_use.cpp:106
const LocationSet * getValidBits() const
Definition frontends/p4/def_use.cpp:154
Maps a declaration to its associated storage.
Definition frontends/p4/def_use.h:256
Definition ordered_set.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition frontends/p4/def_use.h:39