P4C
The P4 Compiler
Loading...
Searching...
No Matches
dark_live_range.h
1
19#ifndef BF_P4C_PHV_ANALYSIS_DARK_LIVE_RANGE_H_
20#define BF_P4C_PHV_ANALYSIS_DARK_LIVE_RANGE_H_
21
22#include "backends/tofino/bf-p4c/common/field_defuse.h"
23#include "backends/tofino/bf-p4c/common/map_tables_to_actions.h"
24#include "backends/tofino/bf-p4c/logging/event_logger.h"
25#include "backends/tofino/bf-p4c/mau/table_dependency_graph.h"
26#include "backends/tofino/bf-p4c/mau/table_mutex.h"
27#include "backends/tofino/bf-p4c/parde/clot/clot_info.h"
28#include "backends/tofino/bf-p4c/phv/action_phv_constraints.h"
29#include "backends/tofino/bf-p4c/phv/analysis/dominator_tree.h"
30#include "backends/tofino/bf-p4c/phv/analysis/non_mocha_dark_fields.h"
31#include "backends/tofino/bf-p4c/phv/mau_backtracker.h"
32#include "backends/tofino/bf-p4c/phv/phv.h"
33#include "backends/tofino/bf-p4c/phv/phv_fields.h"
34#include "backends/tofino/bf-p4c/phv/phv_parde_mau_use.h"
35#include "backends/tofino/bf-p4c/phv/pragma/phv_pragmas.h"
36#include "backends/tofino/bf-p4c/phv/utils/live_range_report.h"
37#include "lib/symbitmatrix.h"
38
39// Structure that represents the live range map.
41 public:
42 using StageAndAccess = PHV::StageAndAccess;
43 using ReadWritePair = std::pair<const PHV::AllocSlice *, const PHV::AllocSlice *>;
44 // Pair of sets of units in which the field has been used, and a bool set to true, if all those
45 // units use the field such that it can be sourced/written to a dark container.
46 using AccessInfo = std::pair<ordered_set<const IR::BFN::Unit *>, bool>;
47 // Single entry in live range map.
49
50 private:
51 static constexpr unsigned READ = PHV::FieldUse::READ;
52 static constexpr unsigned WRITE = PHV::FieldUse::WRITE;
53
55 int DEPARSER = -1;
56
57 public:
60
61 void setDeparserStageValue(int dep) { DEPARSER = dep; }
62
63 int getDeparserStageValue() const { return DEPARSER; }
64
65 std::optional<Entry> getDarkLiveRange(const PHV::Field *f) const {
66 if (livemap.count(f)) return livemap.at(f);
67 return std::nullopt;
68 }
69
70 void addAccess(const PHV::Field *f, int stage, unsigned access, const IR::BFN::Unit *unit,
71 bool dark) {
72 StageAndAccess key = std::make_pair(stage, PHV::FieldUse(access));
73 bool fieldEntryPresent = livemap.count(f);
74 bool accessEntryPresent = fieldEntryPresent && livemap.at(f).count(key);
75 if (!fieldEntryPresent || !accessEntryPresent) {
77 units.insert(unit);
78 AccessInfo val = std::make_pair(units, dark);
79 livemap[f][key] = val;
80 return;
81 }
82 livemap[f][key].first.insert(unit);
83 livemap[f][key].second &= dark;
84 }
85
86 void clear() { livemap.clear(); }
87
88 bool count(const PHV::Field *f) const { return livemap.count(f); }
89
90 const Entry &at(const PHV::Field *f) const { return livemap.at(f); }
91
92 const AccessInfo &at(const PHV::Field *f, int stage, unsigned access) const {
93 StageAndAccess key = std::make_pair(stage, PHV::FieldUse(access));
94 return livemap.at(f).at(key);
95 }
96
97 bool hasAccess(const PHV::Field *f, StageAndAccess sa) const {
98 return livemap.count(f) && livemap.at(f).count(sa);
99 }
100
101 bool hasAccess(const PHV::Field *f, int stage, unsigned access) const {
102 return hasAccess(f, std::make_pair(stage, PHV::FieldUse(access)));
103 }
104
105 std::optional<StageAndAccess> getEarliestAccess(const PHV::Field *f) const;
106 std::optional<StageAndAccess> getLatestAccess(const PHV::Field *f) const;
107};
108
115class DarkLiveRange : public Inspector {
116 private:
117 static constexpr unsigned READ = PHV::FieldUse::READ;
118 static constexpr unsigned WRITE = PHV::FieldUse::WRITE;
119 static constexpr int PARSER = -1;
120 using StageAndAccess = PHV::StageAndAccess;
121
122 using AccessInfo = DarkLiveRangeMap::AccessInfo;
124 using ReadWritePair = std::pair<const PHV::AllocSlice *, const PHV::AllocSlice *>;
125
126 public:
128 PHV::AllocSlice field;
129 StageAndAccess minStage;
130 StageAndAccess maxStage;
131 PHV::UnitSet units;
132
133 explicit OrderedFieldInfo(const PHV::AllocSlice &f, const StageAndAccess acc,
134 const AccessInfo &a)
135 : field(f) {
136 // Initial access means that minStage = maxStage.
137 minStage = std::make_pair(acc.first, acc.second);
138 maxStage = std::make_pair(acc.first, acc.second);
139 field.clearRefs();
140 for (const auto *u : a.first) {
141 units.insert(u);
142 const auto *tbl = u->to<IR::MAU::Table>();
143 if (!tbl) continue;
144 LOG_DEBUG5("\t D. Add unit " << tbl->name.c_str() << " to slice " << field);
145 field.addRef(tbl->name, acc.second);
146 }
147 }
148
149 void addAccess(StageAndAccess s, const AccessInfo &a) {
150 // Check that the access is not the same as the min access.
151 BUG_CHECK(minStage != s, "New access cannot be the same as the min access.");
152 // Check that the access is not the same as the max access recorded so far.
153 BUG_CHECK(maxStage != s, "New access cannot be the same as the max access.");
154 // Check that the access to be added represents a stage after the max access recorded so
155 // far.
156 BUG_CHECK(maxStage.first < s.first ||
157 (maxStage.first == s.first && maxStage.second < s.second),
158 "New access must be greater than max access.");
159 maxStage.first = s.first;
160 maxStage.second = s.second;
161 for (const auto *u : a.first) {
162 units.insert(u);
163 const auto *tbl = u->to<IR::MAU::Table>();
164 if (!tbl) continue;
165 LOG_DEBUG5("\t E. Add unit " << tbl->name.c_str() << " to slice " << field);
166 field.addRef(tbl->name, s.second);
167 }
168 }
169
170 bool operator==(const OrderedFieldInfo &other) const {
171 if (field != other.field) return false;
172 if (minStage != other.minStage) return false;
173 if (maxStage != other.maxStage) return false;
174 if (units.size() != other.units.size()) return false;
175 for (const auto *u : units)
176 if (!other.units.count(u)) return false;
177 for (const auto *u : other.units)
178 if (!units.count(u)) return false;
179 return true;
180 }
181
182 bool operator!=(const OrderedFieldInfo &other) const { return !(*this == other); }
183
184 // Return min unit stage for tables in units; Return -1 if no tables found
185 int get_min_stage(const DependencyGraph &dg) const {
186 int stage = -1;
187 int dg_stage = -1;
188
189 for (auto unit : units) {
190 const auto *tbl = unit->to<IR::MAU::Table>();
191 if (!tbl) continue;
192 for (auto stg_val : PhvInfo::minStages(tbl)) {
193 if (stage < 0)
194 stage = stg_val;
195 else
196 stage = std::min(stage, stg_val);
197 }
198 if (dg_stage < 0)
199 dg_stage = dg.min_stage(tbl);
200 else
201 dg_stage = std::min(dg_stage, dg.min_stage(tbl));
202
203 LOG_DEBUG6(TAB3 "Table: " << tbl->externalName()
204 << ", phvInfo min-stage: " << stage);
205 LOG_DEBUG6(TAB3 "Table: " << tbl->externalName() << ", DG min-stage: " << dg_stage);
206 }
207
208 return std::min(stage, dg_stage);
209 }
210 };
211
212 using OrderedFieldSummary = std::vector<OrderedFieldInfo>;
213
214 public:
218 static bool overlaps(const int num_max_min_stages, const DarkLiveRangeEntry &range1,
219 const DarkLiveRangeEntry &range2);
220
221 private:
222 PhvInfo &phv;
223 const ClotInfo &clot;
224 const DependencyGraph &dg;
225 FieldDefUse &defuse;
226 const PragmaNoOverlay &noOverlay;
227 const PhvUse &uses;
228 const BuildDominatorTree &domTree;
229 const ActionPhvConstraints &actionConstraints;
230 const MauBacktracker &tableAlloc;
231
234 const ordered_set<const PHV::Field *> &noInitFields;
236 const ordered_set<const PHV::Field *> &notParsedFields;
238 const ordered_set<const PHV::Field *> &notDeparsedFields;
239
243 SymBitMatrix &overlay;
244
245 const TablesMutuallyExclusive &tableMutex;
246 const MapTablesToActions &tablesToActions;
247 const NonMochaDarkFields &nonMochaDark;
248
249 int DEPARSER = -1;
250
252 DarkLiveRangeMap livemap;
253 ordered_set<const PHV::Field *> doNotInitToDark;
256
257 profile_t init_apply(const IR::Node *root) override;
258 bool preorder(const IR::MAU::Table *tbl) override;
259 bool preorder(const IR::MAU::Action *act) override;
260 void end_apply() override;
261
263 void setFieldLiveMap(const PHV::Field *f);
264
265 std::optional<OrderedFieldSummary> produceFieldsInOrder(
266 const ordered_set<PHV::AllocSlice> &fields, bool &onlyReadRefs) const;
267
268 std::optional<ReadWritePair> getFieldsLiveAtStage(const ordered_set<PHV::AllocSlice> &fields,
269 const int stage) const;
270
271 bool validateLiveness(const OrderedFieldSummary &slices) const;
272
273 const IR::MAU::Table *getGroupDominator(const PHV::Field *f, const PHV::UnitSet &f_units,
274 gress_t gress) const;
275
276 bool increasesDependenceCriticalPath(const IR::MAU::Table *use,
277 const IR::MAU::Table *init) const;
278
279 std::optional<PHV::ActionSet> getInitActions(const PHV::Container &c,
280 const OrderedFieldInfo &field,
281 const IR::MAU::Table *t,
282 const PHV::Transaction &alloc) const;
283
284 std::optional<PHV::DarkInitMap> getInitPointsForTable(
285 const PHV::ContainerGroup &group, const PHV::Container &c, const IR::MAU::Table *t,
286 const OrderedFieldInfo &lastField, const OrderedFieldInfo &currentField,
287 PHV::DarkInitMap &initMap, bool moveLastFieldToDark, bool initializeCurrentField,
288 bool initializeFromDark, const PHV::Transaction &alloc, bool useARA) const;
289
290 const PHV::Container getBestDarkContainer(const ordered_set<PHV::Container> &darkContainers,
291 const OrderedFieldInfo &field,
292 const PHV::Transaction &alloc) const;
293
294 bool mustMoveToDark(const OrderedFieldInfo &field,
295 const OrderedFieldSummary &fieldsInOrder) const;
296
297 bool mustInitializeCurrentField(const OrderedFieldInfo &field,
298 const PHV::UnitSet &fieldUses) const;
299
300 bool mustInitializeFromDarkContainer(const OrderedFieldInfo &field,
301 const OrderedFieldSummary &fieldsInOrder) const;
302
303 bool mutexSatisfied(const OrderedFieldInfo &info, const IR::MAU::Table *t) const;
304
305 bool cannotInitInAction(const PHV::Container &c, const IR::MAU::Action *action,
306 const PHV::Transaction &alloc) const;
307
308 std::optional<PHV::DarkInitEntry *> getInitForLastFieldToDark(
309 const PHV::Container &c, const PHV::ContainerGroup &group, const IR::MAU::Table *t,
310 const OrderedFieldInfo &field, const PHV::Transaction &alloc,
311 const OrderedFieldInfo &nxtField, bool useARA) const;
312
313 std::optional<PHV::DarkInitEntry *> getInitForCurrentFieldFromDark(
314 const PHV::Container &c, const IR::MAU::Table *t, const OrderedFieldInfo &field,
315 PHV::DarkInitMap &initMap, const PHV::Transaction &alloc) const;
316
317 std::optional<PHV::DarkInitEntry *> getInitForCurrentFieldWithZero(
318 const PHV::Container &c, const IR::MAU::Table *t, const OrderedFieldInfo &field,
319 const PHV::Transaction &alloc, std::optional<PHV::DarkInitEntry *>, bool useARA) const;
320
321 bool ignoreReachCondition(
322 const OrderedFieldInfo &currentField, const OrderedFieldInfo &lastField,
323 const ordered_set<std::pair<const IR::BFN::Unit *, const IR::BFN::Unit *>> &conflicts)
324 const;
325
326 bool isGroupDominatorEarlierThanFirstUseOfCurrentField(
327 const OrderedFieldInfo &currentField, const PHV::UnitSet &doms,
328 const IR::MAU::Table *groupDominator) const;
329
330 bool nonOverlaidWrites(const ordered_set<PHV::AllocSlice> &fields,
331 const PHV::Transaction &alloc, const PHV::Container c,
332 bool onlyReadCandidates) const;
333
334 std::optional<PHV::DarkInitEntry> generateInitForLastStageAlwaysInit(
335 const OrderedFieldInfo &field, const OrderedFieldInfo *previousField,
336 PHV::DarkInitMap &darkInitMap) const;
337
338 std::optional<PHV::DarkInitEntry> generateARAzeroInit(const OrderedFieldInfo &field,
339 const OrderedFieldInfo *previousField,
340 const PHV::Transaction &alloc,
341 bool onlyDeparserUse,
342 bool onlyReadCandidates) const;
343
344 public:
345 std::optional<PHV::DarkInitMap> findInitializationNodes(
346 const PHV::ContainerGroup &group, const PHV::Container &c,
347 const ordered_set<PHV::AllocSlice> &fields, const PHV::Transaction &alloc, bool canUseARA,
348 bool prioritizeARAinits) const;
349
350 explicit DarkLiveRange(PhvInfo &p, const ClotInfo &c, const DependencyGraph &g, FieldDefUse &f,
351 const PHV::Pragmas &pragmas, const PhvUse &u,
352 const BuildDominatorTree &d, const ActionPhvConstraints &actions,
353 const MauBacktracker &a, const TablesMutuallyExclusive &t,
354 const MapTablesToActions &m, const NonMochaDarkFields &nmd)
355 : phv(p),
356 clot(c),
357 dg(g),
358 defuse(f),
359 noOverlay(pragmas.pa_no_overlay()),
360 uses(u),
361 domTree(d),
362 actionConstraints(actions),
363 tableAlloc(a),
364 noInitFields(pragmas.pa_no_init().getFields()),
365 notParsedFields(pragmas.pa_deparser_zero().getNotParsedFields()),
366 notDeparsedFields(pragmas.pa_deparser_zero().getNotDeparsedFields()),
367 overlay(phv.dark_mutex()),
368 tableMutex(t),
369 tablesToActions(m),
370 nonMochaDark(nmd) {}
371
372 const DarkLiveRangeMap &getLiveMap() const { return livemap; }
373};
374
375static inline std::ostream &operator<<(std::ostream &out,
377 out << " Field : " << i.field << " [ " << i.minStage << ", " << i.maxStage << " ]";
378 out << " Units [ ";
379 for (auto u : i.units) {
380 out << DBPrint::Brief << u << ", ";
381 }
382 out << " ] " << std::endl;
383 return out;
384}
385
389class DarkOverlay : public PassManager {
390 private:
391 TablesMutuallyExclusive tableMutex;
392 DarkLiveRange initNode;
393
394 public:
395 bool suitableForDarkOverlay(const PHV::AllocSlice &slice) const;
396
397 std::optional<PHV::DarkInitMap> findInitializationNodes(
398 const PHV::ContainerGroup &group, const ordered_set<PHV::AllocSlice> &alloced,
399 const PHV::AllocSlice &slice, const PHV::Transaction &alloc, bool canUseARA,
400 bool prioritizeARAinits) const {
401 if (!suitableForDarkOverlay(slice)) {
402 LOG_FEATURE("alloc_progress", 5,
403 TAB2 "Dark overlay candidate " << slice << " not a good fit for container "
404 << slice.container());
405 return std::nullopt;
406 }
407
410 for (auto &sl : alloced) {
411 fields.insert(PHV::AllocSlice(sl));
412 if (c == PHV::Container())
413 c = sl.container();
414 else
415 BUG_CHECK(c == sl.container(),
416 "Containers for dark overlay candidates are different.");
417 }
418 BUG_CHECK(c != PHV::Container(), "Container candidate for dark overlay cannot be NULL.");
419 BUG_CHECK(c == slice.container(), "Needs to be the same container");
420 fields.insert(PHV::AllocSlice(slice));
421 return initNode.findInitializationNodes(group, c, fields, alloc, canUseARA,
422 prioritizeARAinits);
423 }
424
425 const DarkLiveRangeMap &getLiveMap() const { return initNode.getLiveMap(); }
426
427 explicit DarkOverlay(PhvInfo &p, const ClotInfo &c, const DependencyGraph &g, FieldDefUse &f,
428 const PHV::Pragmas &pragmas, const PhvUse &u,
429 const ActionPhvConstraints &actions, const BuildDominatorTree &d,
430 const MapTablesToActions &m, const MauBacktracker &a,
431 const NonMochaDarkFields &nmd);
432};
433
434#endif /* BF_P4C_PHV_ANALYSIS_DARK_LIVE_RANGE_H_ */
Definition action_phv_constraints.h:107
Definition dominator_tree.h:32
Definition clot_info.h:41
Definition dark_live_range.h:115
static bool overlaps(const int num_max_min_stages, const DarkLiveRangeEntry &range1, const DarkLiveRangeEntry &range2)
Definition dark_live_range.cpp:29
Definition dark_live_range.h:40
cstring printDarkLiveRanges() const
Pretty print the live ranges of all metadata fields.
Definition dark_live_range.cpp:1680
Definition dark_live_range.h:389
Definition map_tables_to_actions.h:29
Definition mau_backtracker.h:29
Definition non_mocha_dark_fields.h:29
Definition node.h:94
Definition visitor.h:400
Definition ir/pass_manager.h:40
Definition symbitmatrix.h:27
Definition visitor.h:78
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition slice_alloc.h:136
Definition phv/utils/utils.h:37
Definition phv.h:176
Definition phv_fields.h:154
Definition phv.h:248
Definition phv_pragmas.h:46
Definition phv/utils/utils.h:561
Definition phv_fields.h:1095
Definition phv_parde_mau_use.h:154
Definition pa_no_overlay.h:33
Definition mau/table_mutex.h:110
Definition field_defuse.h:77
void info(const int kind, const char *format, const T *node, Args &&...args)
Report info messages of type kind. Requires that the node argument have source info.
Definition lib/error.h:148
Definition dark_live_range.h:127
Definition table_dependency_graph.h:52