P4C
The P4 Compiler
Loading...
Searching...
No Matches
jbay_next_table.h
1
19#ifndef BACKENDS_TOFINO_BF_P4C_MAU_JBAY_NEXT_TABLE_H_
20#define BACKENDS_TOFINO_BF_P4C_MAU_JBAY_NEXT_TABLE_H_
21
22#include "backends/tofino/bf-p4c/lib/dyn_vector.h"
23#include "backends/tofino/bf-p4c/mau/memories.h"
24#include "backends/tofino/bf-p4c/mau/table_layout.h"
25#include "mau_visitor.h"
26#include "next_table.h"
27#include "table_control_deps.h"
28#include "table_mutex.h"
29
30using namespace P4;
31
32/* This pass determines next table propagation in tofino2. It minimizes the use of long branches
33 * whenever possible by "pushing down" next table propagation to tables in the table sequence and
34 * using global_exec/local_exec instead. This pass must be run after modifications to IR graph are
35 * done, otherwise its data will be invalidated.
36 */
37class JbayNextTable : public PassRepeated, public NextTable, public IHasDbPrint {
38 public:
39 // Map from tables->condition (tseq names)->sets of tables that need to occur next
40 using next_map_t = std::map<UniqueId, std::unordered_map<cstring, std::set<UniqueId>>>;
41 next_map_t props;
42 // Map from table to tag # to set of tables
43 std::map<UniqueId, std::unordered_map<int, std::set<UniqueId>>> lbs;
44 size_t get_num_lbs() { return size_t(max_tag + 1); } // For metrics
45 size_t get_num_dts() { return num_dts; }
51 std::pair<ssize_t, ssize_t> get_live_range_for_lb_with_dest(UniqueId dest) const;
52 explicit JbayNextTable(bool disableNextTableUse = false);
53 friend std::ostream &operator<<(std::ostream &out, const JbayNextTable &nt) {
54 out << "Long Branches:" << std::endl;
55 for (auto id_tag : nt.lbs) {
56 out << " " << id_tag.first << " has long branch mapping:" << std::endl;
57 for (auto tag_tbls : id_tag.second) {
58 out << " " << tag_tbls.first << ":" << std::endl;
59 for (auto t : tag_tbls.second) {
60 out << " " << t << std::endl;
61 }
62 }
63 }
64 if (nt.lbs.size() == 0) out << " unused" << std::endl;
65 out << "Liveness:" << std::endl;
66 for (auto luse : nt.lbus) {
67 out << " " << luse << std::endl;
68 }
69 return out;
70 }
71 void dbprint(std::ostream &out) const { out << *this; }
72 ordered_set<UniqueId> next_for(const IR::MAU::Table *tbl, cstring what) const;
73 const std::unordered_map<int, std::set<UniqueId>> &long_branches(UniqueId tbl) const {
74 if (!lbs.count(tbl)) return NextTable::long_branches(tbl);
75 return lbs.at(tbl);
76 }
77
78 private:
79 // Represents a long branch targeting a single destination (unique on destination)
80 class LBUse {
81 public:
82 ssize_t fst, lst; // First and last stages this tag is used on
83 const IR::MAU::Table *dest; // The destination related with this use
84 explicit LBUse(const IR::MAU::Table *d) // Dummy constructor for lookup by destination
85 : fst(-1), lst(-1), dest(d) {}
86 LBUse(const IR::MAU::Table *d, size_t f, size_t l) // Construct a LBUse for a dest
87 : fst(f), lst(l), dest(d) {}
88 // Always unique on dest, ensure that the < is deterministic
89 bool operator<(const LBUse &r) const { return dest->unique_id() < r.dest->unique_id(); }
90 bool operator&(const LBUse &a) const; // Returns true if tags do have unmergeable overlap
91 void extend(const IR::MAU::Table *); // Extends this LB to a new source table
92 // Returns true if on the same gress, false o.w.
93 inline bool same_gress(const LBUse &r) const { return dest->thread() == r.dest->thread(); }
94 // Returns true if this LB is targetable for DT, false o.w.
95 inline gress_t thread() const { return dest->thread(); }
96 friend std::ostream &operator<<(std::ostream &out, const LBUse &u) {
97 out << "dest: " << u.dest->name << ", rng: " << u.fst << "->" << u.lst;
98 return out;
99 }
100 };
101
102 class LocalizeSeqs : public PassManager {
103 using TableToSeqSet =
105 using TableToTableSet =
107 using SeqToThreads = ordered_map<const IR::MAU::TableSeq *,
109
110 TableToSeqSet table_to_seqs;
111 TableToTableSet can_localize_prop_to;
112 SeqToThreads seq_to_threads;
113
114 profile_t init_apply(const IR::Node *node) override {
115 auto rv = PassManager::init_apply(node);
116 table_to_seqs.clear();
117 can_localize_prop_to.clear();
118 seq_to_threads.clear();
119 return rv;
120 }
121
122 class BuildTableToSeqs : public MauTableInspector {
123 LocalizeSeqs &self;
124 profile_t init_apply(const IR::Node *node) override {
125 auto rv = MauInspector::init_apply(node);
126 self.table_to_seqs.clear();
127 return rv;
128 }
129 bool preorder(const IR::MAU::Table *) override;
130
131 public:
132 explicit BuildTableToSeqs(LocalizeSeqs &s) : self(s) { visitDagOnce = false; }
133 };
134
135 class BuildCanLocalizeMaps : public MauTableInspector {
136 LocalizeSeqs &self;
137 profile_t init_apply(const IR::Node *node) override {
138 auto rv = MauInspector::init_apply(node);
139 self.can_localize_prop_to.clear();
140 return rv;
141 }
142 bool preorder(const IR::MAU::Table *) override;
143
144 public:
145 explicit BuildCanLocalizeMaps(LocalizeSeqs &s) : self(s) {}
146 };
147
148 public:
149 LocalizeSeqs() {
150 addPasses({new BuildTableToSeqs(*this), new BuildCanLocalizeMaps(*this)});
151 }
152
153 bool can_propagate_to(const IR::MAU::Table *src, const IR::MAU::Table *dst) const {
154 auto src_pos = can_localize_prop_to.find(src);
155 if (src_pos == can_localize_prop_to.end()) return false;
156 return src_pos->second.count(dst) > 0;
157 }
158 };
159
160 LocalizeSeqs localize_seqs;
161
162 // Represents a single wire with multiple LBUses in it
163 class Tag {
164 std::vector<LBUse> uses; // Live ranges of this tag
165 public:
166 // Attempts to add a tag. Returns true if successful, false otherwise
167 bool add_use(const LBUse &);
168 std::vector<LBUse>::iterator begin() { return uses.begin(); }
169 std::vector<LBUse>::iterator end() { return uses.end(); }
170 size_t size() const { return uses.size(); }
171 };
172
173 // Gets the unique id for a table, depending on whether the table is placed or not
174 static inline UniqueId get_uid(const IR::MAU::Table *t) {
175 return t->is_placed() ? t->unique_id() : t->pp_unique_id();
176 }
177
178 /*===================================Data for next_table use ================================*/
180 TableControlDeps control_dep;
182 class FindNextTableUse;
183 bool uses_next_table(const IR::MAU::Table *tbl) const { return use_next_table.count(tbl) > 0; }
184
185 /*===================================Data gathered by Prop===================================*/
186 std::map<int, std::unique_ptr<Memories>> mems; // Map from stage to tables
187 std::map<int, int> stage_id; // Map from stage to next open LID
188 ordered_set<LBUse> lbus; // Long branches that are needed
189 ordered_map<UniqueId, ordered_set<UniqueId>> dest_src; // Map from dest. to set of srcs
190 // Map from dest. to containing seqs
191 std::map<UniqueId, ordered_set<const IR::MAU::TableSeq *>> dest_ts;
192 std::set<UniqueId> al_runs; // Set of tables that always run
193 int max_stage; // The last stage seen
194
195 // Computes a minimal scheme for how to propagate next tables and records long branches for
196 // allocation. Also gathers information for dumb table allocation/addition.
197 class Prop : public MauInspector {
198 JbayNextTable &self;
199
200 // Holds information for propagating a single table sequence
201 struct NTInfo;
202 // Adds a table and corresponding table sequence to props map
203 void add_table_seq(const IR::MAU::Table *, std::pair<cstring, const IR::MAU::TableSeq *>);
204 void local_prop(const NTInfo &nti, std::map<int, bitvec> &executed_paths);
205 void cross_prop(const NTInfo &nti, std::map<int, bitvec> &executed_paths);
206 void next_table_prop(const NTInfo &nti, std::map<int, bitvec> &executed_paths);
207 bool preorder(const IR::MAU::Table *) override;
208
209 profile_t init_apply(const IR::Node *root) override;
210 void end_apply() override;
211
212 public:
213 explicit Prop(JbayNextTable &ntp) : self(ntp) {}
214 };
215
216 /*==================================Data gathered by LBAlloc==================================*/
217 dyn_vector<Tag> stage_tags; // Track usage of tags x stages so far
218 size_t max_tag; // Largest tag allocated (number of lbs)
219 std::map<LBUse, int> use_tags; // Map from uses to tags
220 // Allocates long branches into tags
221 class LBAlloc : public MauInspector {
222 JbayNextTable &self;
223 profile_t init_apply(const IR::Node *root) override; // Allocates long branches to tags
224 bool preorder(const IR::BFN::Pipe *) override; // Early abort
225 int alloc_lb(const LBUse &); // Finds a tag in self.stage_tags to fit the LBUse
226
227 std::stringstream log; // Log that captures pretty printing
228 void pretty_tags(); // Print tags nice
229 void pretty_srcs(); // Print src info nice
230 void end_apply() override; // Pretty print
231
232 public:
233 explicit LBAlloc(JbayNextTable &ntp) : self(ntp) {}
234 };
235
236 size_t num_dts = 0;
237 // Attempts to reduce the number of tags in use to the max supported by the device
238 class TagReduce : public MauTransform {
239 JbayNextTable &self;
240
241 template <class T>
242 class sym_matrix; // Symmetric matrix for merging
243 struct merge_t; // Represents an "in-progress" merge of two tags
244 sym_matrix<merge_t> find_merges() const; // Finds all possible merges given current tags
245 merge_t merge(Tag l, Tag r) const; // Merges two tags, creating list of dummy tables
246 bool merge_tags(); // Merge tags by adding DTs to fit. Returns false if failed
247 std::map<int, std::vector<IR::MAU::Table *>> stage_dts; // Map from stage # to DTs
248 void alloc_dt_mems(); // Allocates memories for DTs in stage_dts
249
250 // Map from table sequences to dumb tables to add to sequence
251 std::map<const IR::MAU::TableSeq *, std::vector<IR::MAU::Table *>> dumb_tbls;
252
253 profile_t init_apply(const IR::Node *root) override;
254 // Early abort if push-down is sufficient. Adds DTs and allocates them memories
255 IR::Node *preorder(IR::BFN::Pipe *) override;
256 IR::Node *preorder(IR::MAU::Table *) override; // Set always run tags
257 IR::Node *preorder(
258 IR::MAU::TableSeq *) override; // Add specified tables to table sequences
259 public:
260 explicit TagReduce(JbayNextTable &ntp) : self(ntp) { visitDagOnce = false; }
261 };
262};
263
265 LongBranchAllocFailed() : trigger(OK) {}
266};
267
268#endif /* BACKENDS_TOFINO_BF_P4C_MAU_JBAY_NEXT_TABLE_H_ */
Definition mau/jbay_next_table.cpp:332
Definition jbay_next_table.h:37
std::pair< ssize_t, ssize_t > get_live_range_for_lb_with_dest(UniqueId dest) const
Definition mau/jbay_next_table.cpp:440
Definition mau_visitor.h:29
Definition mau_visitor.h:39
Definition mau_visitor.h:55
Definition next_table.h:26
Definition stringify.h:33
Definition node.h:94
Definition ir/pass_manager.h:40
Definition ir/pass_manager.h:145
Definition unique_id.h:168
Definition visitor.h:78
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:27
Definition table_control_deps.h:33
Definition mau/table_mutex.h:110
Definition dyn_vector.h:27
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition jbay_next_table.h:264
Definition visitor.h:768