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