P4C
The P4 Compiler
Loading...
Searching...
No Matches
table_placement.h
1
26#ifndef BF_P4C_MAU_TABLE_PLACEMENT_H_
27#define BF_P4C_MAU_TABLE_PLACEMENT_H_
28
29#include <map>
30
31#include "backends/tofino/bf-p4c/backend.h"
32#include "backends/tofino/bf-p4c/mau/dynamic_dep_metrics.h"
33#include "backends/tofino/bf-p4c/mau/mau_visitor.h"
34#include "backends/tofino/bf-p4c/mau/resource.h"
35#include "backends/tofino/bf-p4c/mau/resource_estimate.h"
36#include "backends/tofino/bf-p4c/mau/table_flow_graph.h"
37#include "backends/tofino/bf-p4c/mau/table_mutex.h"
38#include "backends/tofino/bf-p4c/mau/table_summary.h"
39#include "lib/ordered_set.h"
40
41using namespace P4;
42
43struct DependencyGraph;
45struct StageUseEstimate;
46class PhvInfo;
47class LayoutChoices;
50
52 public:
53 const BFN_Options &options;
54 DependencyGraph &deps;
55 const TablesMutuallyExclusive &mutex;
56 PhvInfo &phv;
57 LayoutChoices &lc;
60 ControlPathwaysToTable con_paths;
62 SplitAttachedInfo &att_info;
63 TableSummary &summary;
64 MauBacktracker &mau_backtracker;
65 bool success = false;
66
67 struct Placed;
69 const TablePlacement::Placed *placement = nullptr;
70
71 struct TableInfo {
72 int uid = -1;
73 const IR::MAU::Table *table;
75 bitvec parents; // Tables that invoke seqs containing this table
76 bitvec tables; // this table and all tables control dependent on it
77 };
78
79 struct TableSeqInfo {
80 bool root = false;
81 int uid = -1;
82 bitvec parents; // same as 'refs', as a bitvec
83 bitvec immed_tables; // the tables directly in the sequence
84 bitvec tables; // the tables in the seqence and their control dependent children
85 ordered_set<const IR::MAU::Table *> refs; // parent tables of this seq
86 };
87
88 static int placement_round;
89 static bool can_duplicate(const IR::MAU::AttachedMemory *);
90 bool can_split(const IR::MAU::Table *, const IR::MAU::AttachedMemory *);
91
92 std::map<const IR::MAU::Table *, struct TableInfo> tblInfo;
93 std::vector<struct TableInfo *> tblByUid;
94 std::map<cstring, struct TableInfo *> tblByName;
95 std::map<const IR::MAU::TableSeq *, struct TableSeqInfo> seqInfo;
96 std::map<const IR::MAU::AttachedMemory *, ordered_set<const IR::MAU::Table *>> attached_to;
97 std::set<const IR::MAU::Table *> not_eligible;
98 int uid(const IR::MAU::Table *t) { return tblInfo.at(t).uid; }
99 int uid(cstring t) { return tblByName.at(t)->uid; }
100 int uid(const IR::MAU::TableSeq *t) {
101 if (seqInfo.count(t) == 0) return -1;
102 return seqInfo.at(t).uid;
103 }
104 const IR::MAU::Table *getTblByName(cstring t) {
105 if (auto *ti = get(tblByName, t)) {
106 return ti->table;
107 }
108 LOG5("No tbl info found for table : " << t);
109 return nullptr;
110 }
111 class SetupInfo;
112
116
118 bool limit_tmp_creation;
119 explicit FinalRerunTablePlacementTrigger(bool l)
120 : Backtrack::trigger(OK), limit_tmp_creation(l) {}
121
122 DECLARE_TYPEINFO(FinalRerunTablePlacementTrigger);
123 };
124
126 GatewayMergeChoices gateway_merge_choices(const IR::MAU::Table *table);
127
128 typedef enum {
129 CALC_STAGE,
130 PROV_STAGE,
131 NEED_MORE,
132 SHARED_TABLES,
133 PRIORITY,
134 DOWNWARD_PROP_DSC,
135 LOCAL_DSC,
136 LOCAL_DS,
137 LOCAL_TD,
138 DOWNWARD_DOM_FRONTIER,
139 DOWNWARD_TD,
140 NEXT_TABLE_OPEN,
141 CDS_PLACEABLE,
142 CDS_PLACE_COUNT,
143 AVERAGE_CDS_CHAIN,
144 DEFAULT
145 } choice_t;
146 bool backtrack(trigger &) override;
147
148 // tracking reasons tables were passed up for logging. Currently not backtracking
149 // friendly
151 choice_t reason;
152 int stage;
153 int entries;
154 attached_entries_t attached_entries;
155 };
156 std::map<cstring, std::map<cstring, RejectReason>> rejected_placements;
157 void reject_placement(const Placed *of, choice_t reason, const Placed *better);
158
159 // In both in class. Remove
160 std::array<bool, 3> table_in_gress = {{false, false, false}};
161 cstring error_message;
162 bool ignoreContainerConflicts = false;
163 bool limit_tmp_creation = false;
164 std::array<const IR::MAU::Table *, 2> starter_pistol = {{nullptr, nullptr}};
165 bool alloc_done = false;
166
167 profile_t init_apply(const IR::Node *root) override;
168 void end_apply() override { placement_round++; };
169
170 bool try_pick_layout(const gress_t &gress, std::vector<Placed *> tables_to_allocate,
171 std::vector<Placed *> tables_placed);
172 bool try_alloc_adb(const gress_t &gress, std::vector<Placed *> tables_to_allocate,
173 std::vector<Placed *> tables_placed);
174 bool try_alloc_imem(const gress_t &gress, std::vector<Placed *> tables_to_allocate,
175 std::vector<Placed *> tables_placed);
176
177 bool try_alloc_ixbar(Placed *next, std::vector<Placed *> allocated_layout);
178 bool try_alloc_format(Placed *next, bool gw_linked);
179 bool try_alloc_mem(Placed *next, std::vector<Placed *> whole_stage);
180 void setup_detached_gateway(IR::MAU::Table *tbl, const Placed *placed);
181 void filter_layout_options(Placed *pl);
182 bool disable_split_layout(const IR::MAU::Table *tbl);
183 bool pick_layout_option(Placed *next, std::vector<Placed *> allocated_layout);
184 bool shrink_attached_tbl(Placed *next, bool first_time, bool &done_shrink);
185 bool shrink_estimate(Placed *next, int &srams_left, int &tcams_left, int min_entries);
186 bool shrink_preferred_lo(Placed *next);
187 TableSummary::PlacementResult try_alloc_all(Placed *next, std::vector<Placed *> whole_stage,
188 const char *what, bool no_memory = false);
189 bool initial_stage_and_entries(TablePlacement::Placed *rv, int &furthest_stage);
190 Placed *try_place_table(Placed *rv, const StageUseEstimate &current,
191 const TableSummary::PlacedTable *pt = nullptr);
192 safe_vector<Placed *> try_place_table(const IR::MAU::Table *t, const Placed *done,
193 const StageUseEstimate &current, GatewayMergeChoices &gmc,
194 const TableSummary::PlacedTable *pt = nullptr);
195
196 friend std::ostream &operator<<(std::ostream &out, choice_t choice);
197
198 const Placed *add_starter_pistols(const Placed *done, const Placed **best,
199 const StageUseEstimate &current);
200
201 std::multimap<cstring, const Placed *> table_placed;
202 std::multimap<cstring, const Placed *>::const_iterator find_placed(cstring name) const;
203 void find_dependency_stages(
204 const IR::MAU::Table *tbl,
206
207 template <class... Args>
208 void error(Args... args) {
209 auto &ctxt = BaseCompileContext::get();
210 auto msg = ctxt.errorReporter().format_message(args...);
211 LOG5(" defer error: " << msg);
212 summary.addPlacementError(msg);
213 }
214 int errorCount() const { return P4::errorCount() + summary.placementErrorCount(); }
215};
216
218 TablePlacement &self;
220
221 public:
222 struct GroupPlace;
223 class Backfill;
224 class BacktrackPlacement;
225 class PlacementScore;
226 class ResourceBasedAlloc;
227 class FinalPlacement;
228#ifdef MULTITHREAD
229 class TryPlacedPool;
230#endif
232 explicit DecidePlacement(TablePlacement &s);
233
234 private:
235#ifdef MULTITHREAD
236 // Arbitrary number of worker threads that should be exposed as compiler option, e.g. "-j4"
237 int jobs = 4;
238#endif
239 struct save_placement_t;
240 std::map<cstring, save_placement_t> saved_placements;
241 int backtrack_count = 0; // number of times backtracked in this pipe
242 int MaxBacktracksPerPipe = 32;
243 bool resource_mode = false;
244 std::map<cstring, std::set<int>> bt_attempts;
245 void savePlacement(const Placed *, const ordered_set<const GroupPlace *> &, bool);
246 void recomputePartlyPlaced(const Placed *, ordered_set<const IR::MAU::Table *> &);
247 std::optional<BacktrackPlacement *> find_previous_placement(const Placed *best, int offset,
248 bool local_bt, int process_stage);
249 std::optional<BacktrackPlacement *> find_backtrack_point(const Placed *, int, bool);
250 bool is_better(const Placed *, const Placed *, TablePlacement::choice_t &);
251 int get_control_anti_split_adj_score(const Placed *) const;
252 int longBranchTagsNeeded(const Placed *, const ordered_set<const GroupPlace *> &,
254
255 void initForPipe(const IR::BFN::Pipe *, ordered_set<const GroupPlace *> &);
256 bool preorder(const IR::BFN::Pipe *) override;
260 bool are_metadata_deps_satisfied(const Placed *placed, const IR::MAU::Table *t) const;
261 Placed *try_backfill_table(const Placed *done, const IR::MAU::Table *tbl, cstring before);
262 bool can_place_with_partly_placed(const IR::MAU::Table *tbl,
263 const ordered_set<const IR::MAU::Table *> &partly_placed,
264 const Placed *placed);
265 bool gateway_thread_can_start(const IR::MAU::Table *, const Placed *placed);
266 IR::MAU::Table *create_starter_table(gress_t gress);
267 const Placed *place_table(ordered_set<const GroupPlace *> &work, const Placed *pl);
268 template <class... Args>
269 void error(Args... args) {
270 self.error(args...);
271 }
272 int errorCount() const { return self.errorCount(); }
273 std::pair<bool, const Placed *> alt_table_placement(const IR::BFN::Pipe *pipe);
274 const Placed *default_table_placement(const IR::BFN::Pipe *pipe);
275};
276
278 TablePlacement &self;
279 ordered_set<const IR::MAU::Table *> always_run_actions; // always run actions to be
280 // moved to the top-level TableSeq. A
281 // set so we avoid duplicate references
282
283 public:
284 explicit TransformTables(TablePlacement &s) : self(s) {}
285
286 private:
287 IR::Node *preorder(IR::MAU::TableSeq *) override;
288 IR::Node *postorder(IR::MAU::TableSeq *) override;
289 IR::Node *preorder(IR::MAU::Table *) override;
290 IR::Node *postorder(IR::MAU::Table *) override;
291 IR::Node *preorder(IR::MAU::BackendAttached *) override;
292 IR::Node *preorder(IR::BFN::Pipe *pipe) override;
293 IR::Node *postorder(IR::BFN::Pipe *pipe) override;
294 void merge_match_and_gateway(IR::MAU::Table *tbl, const TablePlacement::Placed *placed,
295 IR::MAU::Table::Layout &gw_layout);
296 IR::MAU::Table *break_up_atcam(IR::MAU::Table *tbl, const TablePlacement::Placed *placed,
297 int stage_table = -1, IR::MAU::Table **last = nullptr);
298 IR::Vector<IR::MAU::Table> *break_up_dleft(IR::MAU::Table *tbl,
299 const TablePlacement::Placed *placed,
300 int stage_table = -1);
301 void table_set_resources(IR::MAU::Table *tbl, const TableResourceAlloc *res, const int entries);
302 template <class... Args>
303 void error(Args... args) {
304 self.error(args...);
305 }
306 int errorCount() const { return self.errorCount(); }
307};
308
309std::ostream &operator<<(std::ostream &out, TablePlacement::choice_t choice);
310
312 TablePlacement &self;
313
314 using TableFieldSlices = std::map<IR::MAU::Table *, PHV::FieldSlice>;
315
316 struct AlwaysRunKey {
317 int stage;
318 gress_t gress;
319
320 bool operator<(const AlwaysRunKey &ark) const {
321 if (stage != ark.stage) return stage < ark.stage;
322 return gress < ark.gress;
323 }
324
325 AlwaysRunKey(int s, gress_t g) : stage(s), gress(g) {}
326 };
327
328 std::map<AlwaysRunKey, ordered_set<const IR::MAU::Table *>> ar_tables_per_stage;
329 std::map<AlwaysRunKey, const IR::MAU::Table *> merge_per_stage;
330 std::map<AlwaysRunKey, std::set<int>> merged_ar_minStages;
333
334 // Keep the original start and end of AllocSlice liveranges that have
335 // shifted due to table merging
336 typedef std::map<const IR::MAU::Table *, int> premerge_table_stg_t;
339
340 bool mergedARAwitNewStage;
341
342 profile_t init_apply(const IR::Node *node) override {
343 auto rv = PassManager::init_apply(node);
344 ar_tables_per_stage.clear();
345 merge_per_stage.clear();
346 merged_ar_minStages.clear();
347 written_fldSlice.clear();
348 read_fldSlice.clear();
349 premergeLRstart.clear();
350 premergeLRend.clear();
351 mergedARAwitNewStage = false;
352
353 // MinSTage status before updating slice liveranges and merged table minStage
354 LOG7("MIN STAGE DEPARSER stage: " << self.phv.getDeparserStage());
355 LOG7(PhvInfo::reportMinStages());
356 LOG7("DG DEPARSER stage: " << (self.deps.max_min_stage + 1));
357 LOG7(self.deps);
358
359 return rv;
360 }
361
362 class Scan : public MauInspector {
364 bool preorder(const IR::MAU::Table *) override;
365 bool preorder(const IR::MAU::Primitive *) override;
366 void end_apply() override;
367
368 public:
369 explicit Scan(MergeAlwaysRunActions &s) : self(s) {}
370 };
371
372 class Update : public MauTransform {
374 const IR::MAU::Table *preorder(IR::MAU::Table *) override;
375 void end_apply() override;
376
377 public:
378 explicit Update(MergeAlwaysRunActions &s) : self(s) {}
379 };
380
381 // After merging of ARA tables and updating the dependency graph
382 // this class updates the minStage info of tables that have dependence
383 // relationship to the merged tables that have changed stage. In
384 // addition the liveranges of the affected allocated slices (AllocSlice)
385 // are also updated.
386 class UpdateAffectedTableMinStage : public MauInspector, public TofinoWriteContext {
388 // Map affected tables to pair of <old, new> minStages
391 std::map<PHV::AllocSlice *, std::pair<bool, bool>> sliceLRmodifies;
392
393 bool preorder(const IR::MAU::Table *) override;
394 bool preorder(const IR::Expression *) override;
395 void end_apply() override;
396
397 public:
398 explicit UpdateAffectedTableMinStage(MergeAlwaysRunActions &s) : self(s) {}
399 };
400
401 const IR::MAU::Table *ar_replacement(int st, gress_t gress) {
402 AlwaysRunKey ark(st, gress);
403 if (ar_tables_per_stage.count(ark) == 0)
404 BUG("MergeAlwaysRunActions cannot find stage of an always run table");
405 auto set = ar_tables_per_stage.at(ark);
406 return *(set.begin());
407 }
408
409 template <class... Args>
410 void error(Args... args) {
411 self.error(args...);
412 }
413 int errorCount() const { return self.errorCount(); }
414
415 public:
416 explicit MergeAlwaysRunActions(TablePlacement &s) : self(s) {
417 addPasses({new Scan(*this), new Update(*this), new FindDependencyGraph(self.phv, self.deps),
418 new UpdateAffectedTableMinStage(*this)});
419 }
420};
421
422#endif /* BF_P4C_MAU_TABLE_PLACEMENT_H_ */
Definition bf-p4c-options.h:28
Definition table_dependency_graph.h:938
Definition table_dependency_graph.h:972
Definition table_placement.cpp:1525
Definition table_placement.cpp:4032
Definition table_placement.cpp:855
Definition table_placement.cpp:1427
Definition table_placement.cpp:1056
Definition table_placement.cpp:1288
Definition table_placement.h:217
Definition table_placement.cpp:953
Definition dynamic_dep_metrics.h:28
Definition table_dependency_graph.h:1033
Definition payload_gateway.h:31
Definition table_layout.h:83
Definition mau_backtracker.h:29
Definition mau_visitor.h:29
Definition mau_visitor.h:55
Definition table_placement.h:311
static BaseCompileContext & get()
Definition compile_context.cpp:61
Definition node.h:94
Definition vector.h:59
Definition ir/pass_manager.h:40
Definition visitor.h:78
Definition bitvec.h:120
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:27
Definition phv_fields.h:1095
Definition mau/table_mutex.h:160
Definition attached_info.h:235
Definition table_placement.h:51
static bool can_duplicate(const IR::MAU::AttachedMemory *)
Definition table_placement.cpp:2378
const Placed * add_starter_pistols(const Placed *done, const Placed **best, const StageUseEstimate &current)
Definition table_placement.cpp:3076
bool can_split(const IR::MAU::Table *, const IR::MAU::AttachedMemory *)
Check if an indirect attached table can be split acorss stages.
Definition table_placement.cpp:2388
Definition table_placement.h:150
Definition table_placement.h:71
Definition table_placement.h:79
Definition table_summary.h:158
Definition mau/table_mutex.h:110
Definition tofino_write_context.h:24
Definition table_placement.h:277
bool pick_layout_option(Placed *next, std::vector< Placed * > allocated_layout)
Definition table_placement.cpp:1736
Definition table_placement.cpp:1964
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:51
unsigned errorCount()
Definition lib/error.h:35
Definition table_placement.cpp:474
Definition table_dependency_graph.h:52
Definition visitor.h:768
Definition resource_estimate.h:29
Definition table_placement.h:117
Definition table_placement.cpp:553
Definition resource.h:37
Definition table_summary.h:168