P4C
The P4 Compiler
Loading...
Searching...
No Matches
defuse.h
1
19#ifndef BF_P4C_MIDEND_DEFUSE_H_
20#define BF_P4C_MIDEND_DEFUSE_H_
21
22#include "frontends/common/resolveReferences/resolveReferences.h"
23#include "ir/ir.h"
24
43class ComputeDefUse : public Inspector,
44 public ControlFlowVisitor,
45 public P4WriteContext,
47 ComputeDefUse *clone() const { return new ComputeDefUse(*this); }
48 void flow_merge(Visitor &) override;
49 void flow_copy(ControlFlowVisitor &) override;
50 enum { SKIPPING, NORMAL, READ_ONLY, WRITE_ONLY } state = SKIPPING;
51
52 public:
53 // a location in the program. Includes the context from the visitor, which needs to
54 // be copied out of the Visitor::Context objects, as they are allocated on the stack and
55 // will become invalid as the IR traversal continues
56 struct loc_t {
57 const IR::Node *node;
58 const loc_t *parent;
59 bool operator<(const loc_t &a) const {
60 if (node != a.node) return node->id < a.node->id;
61 if (!a.parent) return parent != nullptr;
62 return *parent < *a.parent;
63 }
64 template <class T>
65 const T *find() const {
66 for (auto *p = this; p; p = p->parent) {
67 if (auto *t = p->node->to<T>()) return t;
68 }
69 return nullptr;
70 }
71 };
72
73 private:
74 std::set<loc_t> &cached_locs;
75 const loc_t *getLoc(const Visitor::Context *ctxt);
76 const loc_t *getLoc() { return getLoc(getChildContext()); }
77 const loc_t *getLoc(const IR::Node *, const Visitor::Context *);
78 const loc_t *getLoc(const IR::Node *n) { return getLoc(n, getChildContext()); }
79
80 // flow tracking info about defs live at the point we are currently visiting
81 struct def_info_t {
82 // definitions of a symbol (or part of a symbol) visible at this point in the
83 // program. `defs` will be empty if `live` is; if not those defs are visible only
84 // for those bits/elements/fields where live is set.
85 ordered_set<const loc_t *> defs;
86 bitvec live;
87 def_info_t *parent = nullptr;
88 // track valid bit access for headers separate from the rest of the header
89 ordered_set<const loc_t *> valid_bit_defs;
90 // one of these maps will always be empty.
91 std::map<cstring, def_info_t> fields;
92 std::map<le_bitrange, def_info_t> slices; // also used for arrays
93 // keys in slices are always non-overlapping (checked by slices_sanity)
94 void slices_sanity();
95 std::map<le_bitrange, def_info_t>::iterator slices_overlap_begin(le_bitrange);
96 void erase_slice(le_bitrange);
97 void split_slice(le_bitrange);
98 void flow_merge(def_info_t &);
99 def_info_t() = default;
100 def_info_t(const def_info_t &);
101 def_info_t(def_info_t &&);
102 };
103 ordered_map<const IR::IDeclaration *, def_info_t> def_info;
104 void add_uses(const loc_t *, def_info_t &);
105
106 // computed defuse info for all uses and defs in the program
107 struct defuse_t {
108 // defs maps from all uses to their definitions
109 // uses maps from all definitions to their uses
110 // uses/defs are lvalue expressions, or param declarations.
111 ordered_map<const IR::Node *, ordered_set<const loc_t *>> defs;
112 ordered_map<const IR::Node *, ordered_set<const loc_t *>> uses;
113 } & defuse;
114 static const ordered_set<const loc_t *> empty;
115
116 profile_t init_apply(const IR::Node *root) override {
117 auto rv = Inspector::init_apply(root);
118 state = SKIPPING;
119 clear();
120 return rv;
121 }
122 bool preorder(const IR::P4Control *) override;
123 bool preorder(const IR::P4Table *) override;
124 bool preorder(const IR::P4Action *) override;
125 bool preorder(const IR::P4Parser *) override;
126 bool preorder(const IR::ParserState *) override;
127 void revisit(const IR::ParserState *) override;
128 void loop_revisit(const IR::ParserState *) override;
129 void postorder(const IR::ParserState *) override;
130 bool preorder(const IR::Type *) override { return false; }
131 bool preorder(const IR::Annotations *) override { return false; }
132 bool preorder(const IR::KeyElement *) override;
133 const IR::Expression *do_read(def_info_t &, const IR::Expression *, const Context *);
134 const IR::Expression *do_write(def_info_t &, const IR::Expression *, const Context *);
135 bool preorder(const IR::PathExpression *) override;
136 void loop_revisit(const IR::PathExpression *) override;
137 bool preorder(const IR::MethodCallExpression *) override;
138 void end_apply() override;
139
140 class SetupJoinPoints;
141 void applySetupJoinPoints(const IR::Node *root) override;
142 bool filter_join_point(const IR::Node *) override;
143
144 public:
146 : ResolutionContext(true), cached_locs(*new std::set<loc_t>), defuse(*new defuse_t) {
147 joinFlows = true;
148 }
149 void clear() {
150 cached_locs.clear();
151 def_info.clear();
152 defuse.defs.clear();
153 defuse.uses.clear();
154 }
155
156 const ordered_set<const loc_t *> &getDefs(const IR::Node *n) const {
157 auto it = defuse.defs.find(n);
158 return it == defuse.defs.end() ? empty : it->second;
159 }
160 const ordered_set<const loc_t *> &getUses(const IR::Node *n) const {
161 auto it = defuse.uses.find(n);
162 return it == defuse.uses.end() ? empty : it->second;
163 }
164
165 // for debugging
166 friend std::ostream &operator<<(std::ostream &, const defuse_t &);
167 friend std::ostream &operator<<(std::ostream &out, const ComputeDefUse &cdu) {
168 return out << cdu.defuse;
169 }
170#if BAREFOOT_INTERNAL
171 friend void dump(const def_info_t &);
172 friend void dump(const ordered_map<const IR::IDeclaration *, def_info_t> &);
173 friend void dump(const ComputeDefUse &);
174#endif /* BAREFOOT_INTERNAL */
175};
176
177#endif /* BF_P4C_MIDEND_DEFUSE_H_ */
Visitor mixin for looking up names in enclosing scopes from the Visitor::Context.
Definition resolveReferences.h:35
Compute defuse info within P4Parser and P4Control blocks in the midend.
Definition defuse.h:46
STL namespace.
Definition defuse.h:56