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