P4C
The P4 Compiler
Loading...
Searching...
No Matches
slice_alloc.h
1
19#ifndef BF_P4C_PHV_UTILS_SLICE_ALLOC_H_
20#define BF_P4C_PHV_UTILS_SLICE_ALLOC_H_
21
22#include <optional>
23
24#include "backends/tofino/bf-p4c/ir/bitrange.h"
25#include "backends/tofino/bf-p4c/phv/phv.h"
26#include "ir/ir.h"
27#include "lib/bitvec.h"
28#include "lib/symbitmatrix.h"
29
30namespace PHV {
31
32using namespace P4;
33
36using RefsMap = ordered_map<cstring, FieldUse>;
37
38class DarkInitPrimitive;
39class DarkInitEntry;
40class Field;
41class AllocContext;
42class AllocSlice;
43// Enum for selecting how to match AllocSlices
44enum class SliceMatch {
45 DFLT = 0, // Use min/max_stage_i
46 REF = 1, // Use refs
47 REF_DG_LR = 2, // Use d-graph stage of refs
48 REF_PHYS_LR = 4
49}; // Use physical stage of refs
50
52 private:
53 bool assignZeroToDestination;
54 bool nop;
55 std::unique_ptr<AllocSlice> sourceSlice;
56 bool alwaysInitInLastMAUStage;
57 bool alwaysRunActionPrim;
58 ActionSet actions;
59 UnitSet priorUnits; // Hold units of prior overlay slice
60 UnitSet postUnits; // Hold units of post overlay slice
61 std::vector<DarkInitEntry *> priorPrims; // Hold prior ARA prims
62 std::vector<DarkInitEntry *> postPrims; // Hold post ARA prims
63
64 public:
66 : assignZeroToDestination(false),
67 nop(false),
68 sourceSlice(),
69 alwaysInitInLastMAUStage(false),
70 alwaysRunActionPrim(false) {}
71
72 explicit DarkInitPrimitive(const ActionSet &initPoints);
73 explicit DarkInitPrimitive(AllocSlice &src);
74 explicit DarkInitPrimitive(AllocSlice &src, const ActionSet &initPoints);
75 explicit DarkInitPrimitive(const DarkInitPrimitive &other);
76 DarkInitPrimitive &operator=(const DarkInitPrimitive &other);
77
78 bool operator==(const DarkInitPrimitive &other) const;
79
80 bool isEmpty() const {
81 if (!nop && !sourceSlice && !assignZeroToDestination) return true;
82 return false;
83 }
84
85 void addSource(const AllocSlice &sl);
86
87 void setNop() {
88 nop = true;
89 sourceSlice.reset();
90 assignZeroToDestination = false;
91 }
92
93 void addPriorUnits(const UnitSet &units, bool append = true) {
94 if (!append) {
95 priorUnits.clear();
96 }
97 priorUnits.insert(units.begin(), units.end());
98 }
99
100 void addPostUnits(const UnitSet &units, bool append = true) {
101 if (!append) {
102 postUnits.clear();
103 }
104 postUnits.insert(units.begin(), units.end());
105 }
106
107 void addPriorPrims(DarkInitEntry *prims, bool append = true) {
108 if (!append) {
109 priorPrims.clear();
110 }
111 priorPrims.push_back(prims);
112 }
113 void addPostPrims(DarkInitEntry *prims, bool append = true) {
114 if (!append) {
115 postPrims.clear();
116 }
117 postPrims.push_back(prims);
118 }
119
120 void setLastStageAlwaysInit() { alwaysInitInLastMAUStage = alwaysRunActionPrim = true; }
121 void setAlwaysRunActionPrim() { alwaysRunActionPrim = true; }
122 void setAssignZeroToDest();
123 bool isNOP() const { return nop; }
124 bool destAssignedToZero() const { return assignZeroToDestination; }
125 bool mustInitInLastMAUStage() const { return alwaysInitInLastMAUStage; }
126 bool isAlwaysRunActionPrim() const { return alwaysRunActionPrim; }
127 AllocSlice *getSourceSlice() const { return sourceSlice.get(); }
128 bool setSourceLatestLiveness(StageAndAccess max);
129 const ActionSet &getInitPoints() const { return actions; }
130 const UnitSet &getARApriorUnits() const { return priorUnits; }
131 const UnitSet &getARApostUnits() const { return postUnits; }
132 const std::vector<DarkInitEntry *> getARApriorPrims() const { return priorPrims; }
133 const std::vector<DarkInitEntry *> getARApostPrims() const { return postPrims; }
134};
135
137 const Field *field_i;
138 Container container_i;
139 int field_bit_lo_i;
140 int container_bit_lo_i;
141 int width_i;
142 ActionSet init_points_i;
143 StageAndAccess min_stage_i;
144 StageAndAccess max_stage_i;
145 mutable RefsMap refs;
146 DarkInitPrimitive init_i;
147
148 // Is true if the alloc is copied from an alias destination alloc that requires an always run
149 // in the final stage.
150 bool shadow_always_run_i = false;
151
152 // Is true if the alloc is copied from an alias destination alloc that is zero-initialized
153 bool shadow_init_i = false;
154
155 bool has_meta_init_i = false;
156
157 // Is true if all stageAndAccess vars are generated from physical_live_range, i.e.,
158 // min_stage_i and max_stage_i are based on physical stage info instead of min_stages.
159 bool is_physical_stage_based_i = false;
160
161 // After FinalizeStageAllocation set to true for assembly generation
162 bool physical_deparser_stage_i = false;
163
164 // Set to true to enable assembly generation for profile exceeding allowed stages
165 bool physical_deparser_stage_exceeded_i = false;
166
167 public:
168 AllocSlice(const Field *f, Container c, int f_bit_lo, int container_bit_lo, int width);
169 AllocSlice(const Field *f, Container c, int f_bit_lo, int container_bit_lo, int width,
170 const ActionSet &action);
171 AllocSlice(const Field *f, Container c, le_bitrange f_slice, le_bitrange container_slice);
172
173 static const int NOTSET = -2;
174
175 AllocSlice(const AllocSlice &a);
176 AllocSlice &operator=(const AllocSlice &a);
177 AllocSlice(AllocSlice &&) = default;
178 AllocSlice &operator=(AllocSlice &&) = default;
179
180 bool operator==(const AllocSlice &other) const;
181 bool operator!=(const AllocSlice &other) const;
182 bool operator<(const AllocSlice &other) const;
183 bool isEarlierFieldslice(const AllocSlice &other) const;
184 bool same_alloc_fieldslice(const AllocSlice &other) const;
185
186 // returns a cloned AllocSlice split by field[start:start+ len - 1].
187 // by_field indicates that @p start and @p len are applied on field.
188 // e.g.
189 // alloc_slice: container[5:28] <= f1[0:23]
190 // ^^^.sub_alloc_by_field(3,6) returns
191 // alloc_slice: container[8:13] <= f1[3:8]
192 std::optional<AllocSlice> sub_alloc_by_field(int start, int len) const;
193
194 const Field *field() const { return field_i; }
195 Container container() const { return container_i; }
196 le_bitrange field_slice() const { return StartLen(field_bit_lo_i, width_i); }
197 le_bitrange container_slice() const { return StartLen(container_bit_lo_i, width_i); }
198 le_bitrange container_bytes() const;
199 bool is_initialized() const;
200 int width() const { return width_i; }
201 const DarkInitPrimitive &getInitPrimitive() const { return init_i; }
202 DarkInitPrimitive &getInitPrimitive() { return init_i; }
203 const StageAndAccess &getEarliestLiveness() const { return min_stage_i; }
204 const StageAndAccess &getLatestLiveness() const { return max_stage_i; }
205 std::pair<Container, int> container_byte() const {
206 BUG_CHECK(container_bit_lo_i % 8U + width_i <= 8U, "%s is not in one container byte",
207 *this);
208 return std::make_pair(container_i, container_bit_lo_i & ~7);
209 }
210
211 bool hasInitPrimitive() const;
212
213 // Get the physical liverange of a slice based on its refs
214 void get_ref_lr(StageAndAccess &minStg, StageAndAccess &maxStg) const;
215
216 // @returns true is this alloc slice is live at @p stage for @p use.
217 bool isLiveAt(int stage, const FieldUse &use) const;
218
219 // @returns true if @p other and this AllocSlice have disjoint live ranges.
220 bool isLiveRangeDisjoint(const AllocSlice &other, int gap = 0) const;
221
222 bool representsSameFieldSlice(const AllocSlice &other) const {
223 if (field_i != other.field()) return false;
224 if (field_slice() != other.field_slice()) return false;
225 if (width_i != other.width()) return false;
226 return true;
227 }
228
229 bool extends_live_range(const AllocSlice &other) const {
230 if ((min_stage_i.first < other.getEarliestLiveness().first) ||
231 (max_stage_i.first > other.getLatestLiveness().first) ||
232 ((min_stage_i.first == other.getEarliestLiveness().first) &&
233 (min_stage_i.second < other.getEarliestLiveness().second)) ||
234 ((max_stage_i.first == other.getLatestLiveness().first) &&
235 (max_stage_i.second > other.getLatestLiveness().second)))
236 return true;
237 return false;
238 }
239
240 void setLiveness(const StageAndAccess &min, const StageAndAccess &max) {
241 min_stage_i = std::make_pair(min.first, min.second);
242 max_stage_i = std::make_pair(max.first, max.second);
243 }
244
245 void setLatestLiveness(const StageAndAccess &max) {
246 max_stage_i = std::make_pair(max.first, max.second);
247 }
248
249 void setEarliestLiveness(const StageAndAccess &min) {
250 min_stage_i = std::make_pair(min.first, min.second);
251 }
252
253 void setInitPrimitive(const DarkInitPrimitive *prim);
254
255 bool hasMetaInit() const { return has_meta_init_i; }
256 void setMetaInit() { has_meta_init_i = true; }
257 const ActionSet &getInitPoints() const { return init_points_i; }
258 void setInitPoints(const ActionSet &init_points) { init_points_i = init_points; }
259 void setShadowAlwaysRun(bool val) { shadow_always_run_i = val; }
260 bool getShadowAlwaysRun() const { return shadow_always_run_i; }
261 void setShadowInit(bool val) { shadow_init_i = val; }
262 bool getShadowInit() const { return shadow_init_i; }
263 const RefsMap &getRefs() const { return refs; }
264 void clearRefs() { refs.clear(); }
265 void addRefs(const RefsMap &sl_refs, bool clear_refs = false) {
266 if (clear_refs) refs.clear();
267 for (auto ref_entry : sl_refs) addRef(ref_entry.first, ref_entry.second);
268 }
269
270 bool addRef(cstring, FieldUse f_use) const;
271
272 bool isUsedDeparser() const;
273 bool isUsedParser() const;
274
275 bool isPhysicalStageBased() const { return is_physical_stage_based_i; }
276 void setIsPhysicalStageBased(bool v) { is_physical_stage_based_i = v; }
277
278 bool isPhysicalDeparserStage() const { return physical_deparser_stage_i; }
279 void setPhysicalDeparserStage(bool v) { physical_deparser_stage_i = v; }
280
281 bool isPhysicalDeparserStageExceeded() const { return physical_deparser_stage_exceeded_i; }
282 void setPhysicalDeparserStageExceeded(bool v) { physical_deparser_stage_exceeded_i = v; }
283
284 bool isUninitializedRead() const {
285 return (getEarliestLiveness().second.isRead() && getLatestLiveness().second.isRead());
286 }
287
288 // @returns true if this alloc slice is referenced within @p ctxt for @p use.
289 bool isReferenced(const AllocContext *ctxt, const FieldUse *use,
290 SliceMatch match = SliceMatch::DFLT) const;
291 std::string toString() const;
292
293 private:
294 // helpers to get id of parde units for StageAndAccess. Depending on is_physical_live_i,
295 // stage indexes of parser and deparser are different.
296 int parser_stage_idx() const;
297 int deparser_stage_idx() const;
298};
299
301 private:
302 AllocSlice destinationSlice;
303 DarkInitPrimitive initInfo;
304
305 public:
306 explicit DarkInitEntry(AllocSlice &dest) : destinationSlice(dest) {}
307 explicit DarkInitEntry(AllocSlice &dest, const ActionSet &initPoints)
308 : destinationSlice(dest), initInfo(initPoints) {}
309 explicit DarkInitEntry(AllocSlice &dest, AllocSlice &src)
310 : destinationSlice(dest), initInfo(src) {}
311 explicit DarkInitEntry(AllocSlice &dest, AllocSlice &src, const ActionSet &init)
312 : destinationSlice(dest), initInfo(src, init) {}
313 explicit DarkInitEntry(const AllocSlice &dest, const DarkInitPrimitive &src)
314 : destinationSlice(dest), initInfo(src) {}
315
316 void addSource(AllocSlice sl) { initInfo.addSource(sl); }
317 void setNop() { initInfo.setNop(); }
318 void setLastStageAlwaysInit() { initInfo.setLastStageAlwaysInit(); }
319 void setAlwaysRunInit() { initInfo.setAlwaysRunActionPrim(); }
320 bool isNOP() const { return initInfo.isNOP(); }
321 bool destAssignedToZero() const { return initInfo.destAssignedToZero(); }
322 bool mustInitInLastMAUStage() const { return initInfo.mustInitInLastMAUStage(); }
323 AllocSlice *getSourceSlice() const { return initInfo.getSourceSlice(); }
324
325 void addPriorUnits(const UnitSet &units, bool append = true) {
326 initInfo.addPriorUnits(units, append);
327 }
328 void addPostUnits(const UnitSet &units, bool append = true) {
329 initInfo.addPostUnits(units, append);
330 }
331
332 void addPriorPrims(DarkInitEntry *prims, bool append = true) {
333 initInfo.addPriorPrims(prims, append);
334 }
335 void addPostPrims(DarkInitEntry *prims, bool append = true) {
336 initInfo.addPostPrims(prims, append);
337 }
338
339 const ActionSet &getInitPoints() const { return initInfo.getInitPoints(); }
340 const AllocSlice &getDestinationSlice() const { return destinationSlice; }
341 AllocSlice getDestinationSlice() { return destinationSlice; }
342 const DarkInitPrimitive &getInitPrimitive() const { return initInfo; }
343 DarkInitPrimitive &getInitPrimitive() { return initInfo; }
344 void setDestinationLatestLiveness(const StageAndAccess &max) {
345 destinationSlice.setLatestLiveness(max);
346 }
347 void setDestinationEarliestLiveness(const StageAndAccess &min) {
348 destinationSlice.setEarliestLiveness(min);
349 }
350
351 void addRefs(const RefsMap &sl_refs, bool clear_refs = false) {
352 destinationSlice.addRefs(sl_refs, clear_refs);
353 }
354
355 void addDestinationUnit(cstring tName, FieldUse tRef) { destinationSlice.addRef(tName, tRef); }
356
357 bool operator<(const DarkInitEntry &other) const {
358 if (destinationSlice != other.getDestinationSlice())
359 return destinationSlice < other.getDestinationSlice();
360 if (getSourceSlice() && other.getSourceSlice() &&
361 *(getSourceSlice()) != *(other.getSourceSlice()))
362 return *(getSourceSlice()) < *(other.getSourceSlice());
363 if (getSourceSlice() && !other.getSourceSlice()) return true;
364 return false;
365 }
366
367 bool operator==(const DarkInitEntry &other) const {
368 LOG4("DarkInitEntry == : " << &destinationSlice << " <-> ");
369
370 return (destinationSlice == other.getDestinationSlice()) &&
371 (initInfo == other.getInitPrimitive());
372 }
373
374 bool operator!=(const DarkInitEntry &other) const { return !this->operator==(other); }
375};
376
377std::ostream &operator<<(std::ostream &out, const AllocSlice &);
378std::ostream &operator<<(std::ostream &out, const AllocSlice *);
379std::ostream &operator<<(std::ostream &out, const std::vector<AllocSlice> &);
380std::ostream &operator<<(std::ostream &out, const DarkInitEntry &);
381std::ostream &operator<<(std::ostream &out, const DarkInitPrimitive &);
382
383} // namespace PHV
384
385std::ostream &operator<<(std::ostream &, const safe_vector<PHV::AllocSlice> &);
386
387#endif /* BF_P4C_PHV_UTILS_SLICE_ALLOC_H_ */
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:27
Represents a PHV-allocation context: a parser, a table, or a deparser.
Definition phv_fields.h:83
Definition slice_alloc.h:136
bool isEarlierFieldslice(const AllocSlice &other) const
Check if the references of the slice are earlier than the @other refs.
Definition slice_alloc.cpp:127
Definition phv.h:176
Definition slice_alloc.h:300
Definition slice_alloc.h:51
Definition phv_fields.h:154
Definition phv.h:248
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
The namespace encapsulating PHV-related stuff.
Definition gateway.h:32
Definition lib/bitrange.h:158