P4C
The P4 Compiler
Loading...
Searching...
No Matches
midend/def_use.h
1/*
2Copyright 2024 Intel Corp.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef MIDEND_DEF_USE_H_
18#define MIDEND_DEF_USE_H_
19
20#include "frontends/common/resolveReferences/resolveReferences.h"
21#include "ir/ir.h"
22#include "lib/bitrange.h"
23#include "lib/hvec_map.h"
24#include "lib/hvec_set.h"
25
26namespace P4 {
27
44class ComputeDefUse : public Inspector,
45 public ControlFlowVisitor,
46 public P4WriteContext,
48 static int uid_ctr;
49 int uid = 0;
50 ComputeDefUse *clone() const override {
51 auto *rv = new ComputeDefUse(*this);
52 rv->uid = ++uid_ctr;
53 LOG8("ComputeDefUse::clone " << rv->uid);
54 return rv;
55 }
56 void flow_merge(Visitor &) override;
57 void flow_copy(ControlFlowVisitor &) override;
58 bool operator==(const ControlFlowVisitor &) const override;
59
60 enum { SKIPPING, NORMAL, READ_ONLY, WRITE_ONLY } state = SKIPPING;
61
62 public:
63 // a location in the program. Includes the context from the visitor, which needs to
64 // be copied out of the Visitor::Context objects, as they are allocated on the stack and
65 // will become invalid as the IR traversal continues
66 struct loc_t {
67 const IR::Node *node;
68 const loc_t *parent;
69 mutable size_t computedHash = 0;
70 bool operator<(const loc_t &a) const {
71 if (node != a.node) return node->id < a.node->id;
72 if (!parent || !a.parent) return parent != nullptr;
73 return *parent < *a.parent;
74 }
75 bool operator==(const loc_t &a) const {
76 if (node != a.node) return false;
77 if (parent == a.parent) return true;
78 if (!parent || !a.parent) return false;
79 return *parent == *a.parent;
80 }
81 std::size_t hash() const {
82 if (!computedHash) {
83 if (!parent)
84 computedHash = Util::Hash{}(node->id);
85 else
86 computedHash = Util::Hash{}(node->id, parent->hash());
87 }
88 return computedHash;
89 }
90
91 template <class T>
92 const T *find() const {
93 for (auto *p = this; p; p = p->parent) {
94 if (auto *t = p->node->to<T>()) return t;
95 }
96 return nullptr;
97 }
98 };
100
101 private:
102 // DANGER -- pointers to elements of this set must be stable
103 std::unordered_set<loc_t> &cached_locs;
104 const loc_t *getLoc(const Visitor::Context *ctxt);
105 const loc_t *getLoc() { return getLoc(getChildContext()); }
106 const loc_t *getLoc(const IR::Node *, const Visitor::Context *);
107 const loc_t *getLoc(const IR::Node *n) { return getLoc(n, getChildContext()); }
108
109 // flow tracking info about defs live at the point we are currently visiting
110 struct def_info_t {
111 // definitions of a symbol (or part of a symbol) visible at this point in the
112 // program. `defs` will be empty if `live` is; if not those defs are visible only
113 // for those bits/elements/fields where live is set.
114 locset_t defs;
115 bitvec live;
116 // FIXME -- this parent field is never used and is not set consistently, so
117 // appears to be useless?
118 def_info_t *parent = nullptr;
119 // track valid bit access for headers separate from the rest of the header
120 locset_t valid_bit_defs;
121 // one of these maps will always be empty.
122 std::map<cstring, def_info_t> fields;
123 std::map<le_bitrange, def_info_t> slices; // also used for arrays
124 // keys in slices are always non-overlapping (checked by slices_sanity)
125 void slices_sanity();
126 std::map<le_bitrange, def_info_t>::iterator slices_overlap_begin(le_bitrange);
127 void erase_slice(le_bitrange);
128 void split_slice(le_bitrange);
129 void flow_merge(def_info_t &);
130 bool operator==(const def_info_t &) const;
131 bool operator!=(const def_info_t &a) const { return !(*this == a); }
132 def_info_t() = default;
133 def_info_t(const def_info_t &);
134 def_info_t(def_info_t &&);
135 def_info_t &operator=(const def_info_t &);
136 def_info_t &operator=(def_info_t &&);
137 };
138 hvec_map<const IR::IDeclaration *, def_info_t> def_info;
139 void add_uses(const loc_t *, def_info_t &);
140 void set_live_from_type(def_info_t &di, const IR::Type *type);
141
142 // computed defuse info for all uses and defs in the program
143 struct defuse_t {
144 // defs maps from all uses to their definitions
145 // uses maps from all definitions to their uses
146 // uses/defs are lvalue expressions, or param declarations.
147 hvec_map<const IR::Node *, locset_t> defs;
148 hvec_map<const IR::Node *, locset_t> uses;
149 } & defuse;
150 static const locset_t empty;
151
152 profile_t init_apply(const IR::Node *root) override {
153 auto rv = Inspector::init_apply(root);
154 LOG3("## Midend ComputeDefUse");
155 uid_ctr = 0;
156 state = SKIPPING;
157 clear();
158 return rv;
159 }
160 bool preorder(const IR::P4Control *) override;
161 bool preorder(const IR::P4Table *) override;
162 bool preorder(const IR::P4Action *) override;
163 bool preorder(const IR::P4Parser *) override;
164 bool preorder(const IR::Function *) override;
165 bool preorder(const IR::ParserState *) override;
166 void revisit(const IR::ParserState *) override;
167 void loop_revisit(const IR::ParserState *) override;
168 void postorder(const IR::ParserState *) override;
169 bool preorder(const IR::Type *) override { return false; }
170 bool preorder(const IR::Annotations *) override { return false; }
171 bool preorder(const IR::KeyElement *) override;
172 bool preorder(const IR::AssignmentStatement *) override;
173 const IR::Expression *do_read(def_info_t &, const IR::Expression *, const Context *);
174 const IR::Expression *do_write(def_info_t &, const IR::Expression *, const Context *);
175 bool preorder(const IR::PathExpression *) override;
176 void loop_revisit(const IR::PathExpression *) override;
177 bool preorder(const IR::MethodCallExpression *) override;
178 void end_apply() override;
179
180 class SetupJoinPoints;
181 void applySetupJoinPoints(const IR::Node *root) override;
182 bool filter_join_point(const IR::Node *) override;
183
184 public:
185 ComputeDefUse();
186 void clear();
187
188 const locset_t &getDefs(const IR::Node *n) const {
189 auto it = defuse.defs.find(n);
190 return it == defuse.defs.end() ? empty : it->second;
191 }
192 const locset_t &getUses(const IR::Node *n) const {
193 auto it = defuse.uses.find(n);
194 return it == defuse.uses.end() ? empty : it->second;
195 }
196
197 // for debugging
198 friend std::ostream &operator<<(std::ostream &, const loc_t &);
199 friend std::ostream &operator<<(std::ostream &, const defuse_t &);
200 friend std::ostream &operator<<(std::ostream &out, const ComputeDefUse &cdu) {
201 return out << cdu.defuse;
202 }
203};
204
205} // namespace P4
206
207namespace std {
208template <>
209struct hash<P4::ComputeDefUse::loc_t> {
210 std::size_t operator()(const P4::ComputeDefUse::loc_t &loc) const { return loc.hash(); }
211};
212
213} // namespace std
214
215#endif /* MIDEND_DEF_USE_H_ */
Compute defuse info within P4Parser and P4Control blocks in the midend.
Definition midend/def_use.h:47
Definition visitor.h:463
Definition node.h:95
Definition visitor.h:400
Definition visitor.h:788
Visitor mixin for looking up names in enclosing scopes from the Visitor::Context.
Definition resolveReferences.h:33
Definition visitor.h:75
Definition hvec_set.h:31
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
STL namespace.
Definition midend/def_use.h:66
Definition hash.h:125
Definition visitor.h:47
Definition frontends/p4/def_use.h:40