P4C
The P4 Compiler
Loading...
Searching...
No Matches
input_xbar.h
1
19#ifndef BF_P4C_MAU_INPUT_XBAR_H_
20#define BF_P4C_MAU_INPUT_XBAR_H_
21
22#include <array>
23#include <map>
24#include <random>
25#include <unordered_set>
26
27#include "backends/tofino/bf-p4c/bf-p4c-options.h"
28#include "backends/tofino/bf-p4c/common/alloc.h"
29#include "backends/tofino/bf-p4c/common/asm_output.h"
30#include "backends/tofino/bf-p4c/common/slice.h"
31#include "backends/tofino/bf-p4c/device.h"
32#include "backends/tofino/bf-p4c/lib/autoclone.h"
33#include "backends/tofino/bf-p4c/lib/dyn_vector.h"
34#include "backends/tofino/bf-p4c/mau/attached_entries.h"
35#include "backends/tofino/bf-p4c/mau/ixbar_expr.h"
36#include "backends/tofino/bf-p4c/mau/table_layout.h"
37#include "backends/tofino/bf-p4c/phv/phv_fields.h"
38#include "ir/ir.h"
39#include "lib/hex.h"
40#include "lib/safe_vector.h"
41
42using namespace P4;
43
44class IXBarRealign;
46class TableMatch;
47class MauAsmOutput;
48
49namespace BFN {
50namespace Resources {
51struct StageResources;
52}
53} // namespace BFN
54
57 static std::random_device seed_generator;
58 static unsigned seed;
59 static std::mt19937 mersenne_generator;
61 static std::uniform_int_distribution<unsigned> distribution10;
63 static std::uniform_int_distribution<unsigned> distribution1;
66 static unsigned nextRandomNumber(unsigned numBits = 1);
67};
68
69struct IXBar : public IHasDbPrint {
70 // these constants aren't realy target specific, but don't really belong here
71 static constexpr int LAMB_LINE_SELECT_BITS = 6;
72 static constexpr int RAM_LINE_SELECT_BITS = 10;
73
74 struct Loc {
75 enum type { BYTE = 0, WORD = 1, NONE = 2 };
76 int group = -1, byte = -1;
77 Loc() = default;
78 Loc(int g, int b) : group(g), byte(b) {}
79 Loc(const Loc &) = default;
80 explicit operator bool() const { return group >= 0 && byte >= 0; }
81 operator std::pair<int, int>() const { return std::make_pair(group, byte); }
83 bool operator==(const Loc &loc) const { return group == loc.group && byte == loc.byte; }
84 bool operator!=(const Loc &loc) const { return !(*this == loc); }
85 int getOrd(const bool isTernary = false) const {
86 if (*this) {
87 if (isTernary)
88 return Device::ixbarSpec().getTernaryOrdBase(group) + byte;
89 else
90 return Device::ixbarSpec().getExactOrdBase(group) + byte;
91 } else {
92 return -1;
93 }
94 }
95 bool allocated() const { return group >= 0 && byte >= 0; }
96 type group_type() const {
97 if (group == 1)
98 return WORD;
99 else if (group == 0)
100 return BYTE;
101 else
102 return NONE;
103 }
104 };
105
106 enum byte_speciality_t {
107 NONE,
108 // Byte has to appear twice in the match for S0Q1 and S1Q0, but only once on the IXBar
109 ATCAM_DOUBLE,
110 // Byte does not have to appear on the match, as it is the partition index
111 ATCAM_INDEX,
112 // TCAM byte encoded with the 4b_lo_range match
113 RANGE_LO,
114 // TCAM byte encoded with the 4b_hi_range match
115 RANGE_HI,
116 BYTE_SPECIALITIES
117 };
118
128 struct FieldInfo {
129 cstring field;
130 int lo;
131 int hi;
134 std::optional<cstring> aliasSource;
136
137 FieldInfo(cstring n, int l, int h, int cl, std::optional<cstring> a)
138 : field(n), lo(l), hi(h), cont_lo(cl) {
139 if (a)
140 aliasSource = *a;
141 else
142 aliasSource = std::nullopt;
143 }
144
145 cstring get_use_name() const {
146 if (aliasSource == std::nullopt)
147 return field;
148 else
149 return *aliasSource;
150 }
151
152 bool operator==(const FieldInfo &fi) const {
153 return field == fi.field && lo == fi.lo && hi == fi.hi;
154 }
155 bool operator<(const FieldInfo &fi) const {
156 if (field != fi.field) return field < fi.field;
157 if (lo != fi.lo) return lo < fi.lo;
158 if (hi != fi.hi) return hi < fi.hi;
159 return false;
160 }
161
162 bool operator!=(const FieldInfo &fi) const { return !((*this) == fi); }
163
164 int width() const { return hi - lo + 1; }
165
166 int cont_hi() const { return cont_lo + width() - 1; }
167
168 le_bitrange range() const { return {lo, hi}; }
169
170 bitvec cont_loc() const { return bitvec(cont_lo, width()); }
171
172 std::string visualization_detail() const;
173 // get the FieldSlice object corresponding to this
174 PHV::FieldSlice field_slice(const PhvInfo &phv) const;
175 };
176
177 enum byte_type_t { NO_BYTE_TYPE, ATCAM, PARTITION_INDEX, RANGE };
178 enum HashDistDest_t {
179 HD_IMMED_LO,
180 HD_IMMED_HI,
181 HD_STATS_ADR,
182 HD_METER_ADR,
183 HD_ACTIONDATA_ADR,
184 HD_PRECOLOR,
185 HD_HASHMOD,
186 HD_DESTS
187 };
188 enum parity_status_t { PARITY_NONE, PARITY_ENABLED, PARITY_DISABLED };
189
191 struct Use {
192 /* everything is public so anyone can read it, but only IXBar should write to this */
193 enum flags_t {
194 NeedRange = 1,
195 NeedXor = 2,
196 Align16lo = 4,
197 Align16hi = 8,
198 Align32lo = 16,
199 Align32hi = 32
200 };
201
202 virtual bool is_parity_enabled() const = 0;
203
204 // FIXME: Could be better created initialized through a constructor
205 // DANGER: .gdbinit should match up with this
206 enum type_t {
207 EXACT_MATCH,
208 ATCAM_MATCH,
209 TERNARY_MATCH,
210 TRIE_MATCH,
211 GATEWAY,
212 ACTION,
213 PROXY_HASH,
214 SELECTOR,
215 METER,
216 STATEFUL_ALU,
217 HASH_DIST,
218 TYPES
219 } type = TYPES;
220
221 virtual ~Use() {}
222 virtual Use *clone() const = 0;
223
224 std::string used_by;
225 std::string used_for() const;
226 virtual std::string hash_dist_used_for() const = 0;
227 virtual int hash_dist_hash_group() const = 0;
228
229 /* tracking individual bytes (or parts of bytes) placed on the ixbar */
230 struct Byte {
231 // the PHV container
232 PHV::Container container;
233 //
234 int lo;
235 Loc loc;
236 // the PHV container bits the match will be performed on
237 bitvec bit_use;
238 // the PHV container bits that are potentially non-zero valued
239 bitvec non_zero_bits;
240 // flags describing alignment and gateway use/requirements
241 int flags = 0;
242 unsigned specialities = 0;
243 safe_vector<FieldInfo> field_bytes;
244
245 void set_spec(byte_speciality_t bs) { specialities |= (1 << bs); }
246
247 void clear_spec(byte_speciality_t bs) { specialities &= ~(1 << bs); }
248
249 bool is_spec(byte_speciality_t bs) const { return specialities & (1 << bs); }
250
251 // Which search bus this byte belongs to. Used rather than groups in table format
252 // as the Byte can appear once on the input xbar
253 int search_bus = -1;
254 // Given a byte appearing multiple times within the match format, which one it is
255 int match_index = 0;
256 // A index given to each range index, as there are constraints on the multirange
257 // distribution that leads to some restrictions on range fields
258 int range_index = -1;
259 // When converting a byte to proxy hash, this is the byte in the table format
260 // in which the hash is provide
261 bool proxy_hash = false;
262 // Desired ixbar group as specified by the ixbar_group_num pragma
263 int ixbar_group_num = -1;
264
265 // Byte(cstring n, int l) : container(n), lo(l) {}
266 // Byte(cstring n, int l, int g, int gb) : container(n), lo(l), loc(g, gb) {}
267 Byte(PHV::Container c, int l) : container(c), lo(l) {}
268 Byte(PHV::Container c, int l, int g, int gb) : container(c), lo(l), loc(g, gb) {}
269 operator std::pair<PHV::Container, int>() const {
270 return std::make_pair(container, lo);
271 }
272 bool operator==(const std::pair<PHV::Container, int> &a) const {
273 return container == a.first && lo == a.second;
274 }
275 bool operator==(const Byte &b) const { return container == b.container && lo == b.lo; }
276 bool operator<(const Byte &b) const {
277 if (container != b.container) return container < b.container;
278 if (lo != b.lo) return lo < b.lo;
279 if (match_index != b.match_index) return match_index < b.match_index;
280 // Sort by specialities to prevent combining bytes that have different
281 // specialities in create_alloc
282 if (specialities != b.specialities) return specialities < b.specialities;
283 // Due to limitations in range fields being spread across multiple TCAM,
284 // only one range field is allowed per byte
285 if (range_index != b.range_index) return range_index < b.range_index;
286 if (field_bytes != b.field_bytes) return field_bytes < b.field_bytes;
287 return false;
288 }
289 bool is_range() const { return is_spec(RANGE_LO) || is_spec(RANGE_HI); }
290 void unallocate() {
291 search_bus = -1;
292 loc.group = -1;
293 loc.byte = -1;
294 }
295 std::string visualization_detail() const;
296 std::vector<FieldInfo> get_slices_for_visualization() const;
297 bool is_subset(const Byte &b) const;
298 bool only_one_nibble_in_use() const {
299 BUG_CHECK(!bit_use.empty(), "IXBar byte has no data");
300 if (is_range()) return false;
301 return bit_use.getslice(0, 4).empty() || bit_use.getslice(4, 4).empty();
302 }
303
304 bool can_add_info(const FieldInfo &fi) const;
305 void add_info(const FieldInfo &fi);
306 bool has_field_slice(const PHV::FieldSlice &sl) const {
307 for (auto &fi : field_bytes) {
308 if (fi.field == sl.field()->name && sl.range().overlaps(fi.lo, fi.hi))
309 return true;
310 }
311 return false;
312 }
313 };
315
316 /* hash tables used for way address computation */
317 struct Way {
318 int source; // source of hash bits (ixbar hash group or xmu hash)
319 le_bitrange index; // hash bits for index lookup
320 le_bitrange select; // hash bits for bank select;
321 unsigned select_mask; // mask for bank select;
322 Way() = delete;
323 Way(int s, le_bitrange i, le_bitrange sel, unsigned m)
324 : source(s), index(i), select(sel), select_mask(m) {}
325 };
326 safe_vector<Way> way_use;
327
328 bool allocated() { return !use.empty(); }
329
330#if 0
331 /* which of the 16 hash tables we are using (bitvec) */
332 dyn_vector<unsigned> hash_table_inputs;
333 /* hash seed for different hash groups */
334 dyn_vector<bitvec> hash_seed;
335#endif
336
337 virtual void clear() {
338 type = TYPES;
339 used_by.clear();
340 use.clear();
341 way_use.clear();
342#if 0
343 hash_table_inputs.clear();
344 hash_seed.clear();
345#endif
346 }
347 virtual bool empty() const { return type == TYPES && use.empty() && way_use.empty(); }
348 virtual void dbprint(std::ostream &) const;
349
350 typedef safe_vector<safe_vector<Byte> *> TotalBytes;
351
352 struct GroupInfo : public IHasDbPrint {
353 int search_bus;
354 int ixbar_group;
355 int bytes;
356 int bits;
357
358 GroupInfo(int sb, int ig, int by, int b)
359 : search_bus(sb), ixbar_group(ig), bytes(by), bits(b) {}
360
361 void dbprint(std::ostream &out) const {
362 out << "Search bus: " << search_bus << ", IXBar group: " << ixbar_group
363 << ", Bytes : " << bytes << ", Bits : " << bits;
364 }
365 };
366
367 struct TotalInfo {
368 int hash_group;
369 safe_vector<GroupInfo> all_group_info;
370
371 TotalInfo(int hg, safe_vector<GroupInfo> agi) : hash_group(hg), all_group_info(agi) {}
372 };
373
374 virtual void add(const Use &alloc);
375 virtual TotalBytes atcam_match() const;
376 virtual safe_vector<Byte> atcam_partition(int *hash_group = nullptr) const;
378 virtual unsigned compute_hash_tables();
379 virtual bool emit_gateway_asm(const MauAsmOutput &, std::ostream &, indent_t,
380 const IR::MAU::Table *) const = 0;
381 virtual void emit_ixbar_asm(const PhvInfo &phv, std::ostream &out, indent_t indent,
382 const TableMatch *fmt, const IR::MAU::Table *) const = 0;
383 virtual void emit_salu_bytemasks(std::ostream &out, indent_t indent) const = 0;
384 virtual void emit_ixbar_hash_table(int hash_table, safe_vector<Slice> &match_data,
385 safe_vector<Slice> &ghost, const TableMatch *fmt,
386 std::map<int, std::map<int, Slice>> &sort) const = 0;
387 virtual bitvec galois_matrix_bits() const = 0;
388 virtual int gateway_group() const;
389 virtual int groups() const; // how many different groups in this use
390 virtual const std::map<int, const IR::Expression *> &hash_computed_expressions() const = 0;
391 virtual int hash_groups() const = 0;
392 virtual TotalBytes match_hash(safe_vector<int> *hash_groups = nullptr) const;
393 virtual bitvec meter_bit_mask() const = 0;
394 virtual int search_buses_single() const;
395 virtual int ternary_align(const Loc &) const = 0;
396 virtual int total_input_bits() const = 0;
397 virtual void update_resources(int, BFN::Resources::StageResources &) const;
398 virtual const char *way_source_kind() const = 0;
399 int findBytesOnIxbar(const PHV::FieldSlice &sl) const {
400 int bytesOnIxbar = 0;
401 for (auto &u : use) {
402 for (auto &fi : u.field_bytes) {
403 if (fi.field == sl.field()->name && sl.range().overlaps(fi.lo, fi.hi))
404 ++bytesOnIxbar;
405 }
406 }
407 return bytesOnIxbar;
408 }
409 };
410
411 static HashDistDest_t dest_location(const IR::Node *node, bool precolor = false);
412 static std::string hash_dist_name(HashDistDest_t dest);
413
414 cstring failure_reason;
415
416 /* A problem occurred with the way the IXBar was allocated that requires backtracking
417 * and trying something else */
418 struct failure : public Backtrack::trigger {
419 int stage = -1, group = -1;
420 failure(int stg, int grp) : trigger(OTHER), stage(stg), group(grp) {}
421
422 DECLARE_TYPEINFO(failure);
423 };
424
425 protected:
427
434 typedef std::map<Use::Byte, safe_vector<FieldInfo>> ContByteConversion;
435 static void add_use(ContByteConversion &map_alloc, const PHV::Field *field, const PhvInfo &phv,
436 const IR::MAU::Table *ctxt, std::optional<cstring> aliasSourceName,
437 const le_bitrange *bits = nullptr, int flags = 0,
438 byte_type_t byte_type = NO_BYTE_TYPE, unsigned extra_align = 0,
439 int range_index = 0, int pragma_forced_ixbar_group = -1);
440 void create_alloc(ContByteConversion &map_alloc, IXBar::Use &alloc);
441 void create_alloc(ContByteConversion &map_alloc, safe_vector<Use::Byte> &bytes);
442
443 struct KeyInfo {
444 bool hash_dist = false;
445 bool is_atcam = false;
446 bool partition = false;
447 int partition_bits = 0;
448 int range_index = 0;
449 bool repeats_allowed = true;
450 KeyInfo() {}
451 };
452
453 /* This is for adding fields to be allocated in the ixbar allocation scheme. Used by
454 match tables, selectors, and hash distribution */
455 class FieldManagement : public Inspector {
456 ContByteConversion *map_alloc;
457 safe_vector<const IR::Expression *> &field_list_order;
458 std::map<cstring, bitvec> *fields_needed;
459 const PhvInfo &phv;
460 KeyInfo &ki;
461 const IR::MAU::Table *tbl;
462
463 bool preorder(const IR::ListExpression *) override;
464 bool preorder(const IR::StructExpression *) override;
465 bool preorder(const IR::Mask *) override;
466 bool preorder(const IR::MAU::TableKey *read) override;
467 bool preorder(const IR::Constant *c) override;
468 bool preorder(const IR::MAU::ActionArg *aa) override;
469 bool preorder(const IR::Expression *e) override;
470 void postorder(const IR::BFN::SignExtend *c) override;
471 void end_apply() override;
472
473 public:
475 safe_vector<const IR::Expression *> &field_list_order,
476 const IR::Expression *field, std::map<cstring, bitvec> *fields_needed,
477 const PhvInfo &phv, KeyInfo &ki, const IR::MAU::Table *t)
478 : map_alloc(map_alloc),
479 field_list_order(field_list_order),
480 fields_needed(fields_needed),
481 phv(phv),
482 ki(ki),
483 tbl(t) {
484 field->apply(*this);
485 }
486 };
487
488 public:
489 virtual bool allocTable(const IR::MAU::Table *tbl, const IR::MAU::Table *gw, const PhvInfo &,
491 const ActionData::Format::Use *, const attached_entries_t &) = 0;
492 virtual void update(cstring name, const Use &alloc) = 0;
493 virtual void update(const IR::MAU::Table *tbl, const TableResourceAlloc *rsrc);
494 // virtual void update(cstring name, const TableResourceAlloc *alloc) = 0;
495 virtual void update(const IR::MAU::Table *tbl);
496 virtual void add_collisions() = 0;
497 virtual void verify_hash_matrix() const = 0;
498 virtual void dbprint(std::ostream &) const = 0;
499 virtual ~IXBar() {}
500
501 static IXBar *create();
502
503 protected:
504 // helper functions for dbprint
505 static void add_names(cstring n, std::map<cstring, char> &names);
506 static void add_names(const std::pair<PHV::Container, int> &c, std::map<cstring, char> &names);
507 static void add_names(PHV::Container c, std::map<cstring, char> &names);
508 template <class T>
509 static void add_names(const T &n, std::map<cstring, char> &names) {
510 for (auto &a : n) add_names(a, names);
511 }
512 // FIXME -- should not be needed, but Alloc2D is missing begin/end
513 template <class T, int R, int C>
514 static void add_names(const BFN::Alloc2D<T, R, C> &n, std::map<cstring, char> &names) {
515 for (int r = 0; r < R; r++) add_names(n[r], names);
516 }
517 // FIXME -- should not be needed, but Alloc1D is missing const begin/end
518 template <class T, int S>
519 static void add_names(const BFN::Alloc1D<T, S> &n, std::map<cstring, char> &names) {
520 for (int i = 0; i < S; i++) add_names(n[i], names);
521 }
522 static void sort_names(std::map<cstring, char> &names);
523 static void write_one(std::ostream &out, const std::pair<cstring, int> &f,
524 std::map<cstring, char> &fields);
525 static void write_one(std::ostream &out, cstring n, std::map<cstring, char> &names);
526 static void write_one(std::ostream &out, const std::pair<PHV::Container, int> &f,
527 std::map<cstring, char> &fields);
528 static void write_one(std::ostream &out, PHV::Container f, std::map<cstring, char> &fields);
529 template <class T>
530 static void write_group(std::ostream &out, const T &grp, std::map<cstring, char> &fields) {
531 for (auto &a : grp) write_one(out, a, fields);
532 }
533};
534
535inline std::ostream &operator<<(std::ostream &out, const IXBar::Loc &l) {
536 return out << '(' << l.group << ',' << l.byte << ')';
537}
538inline std::ostream &operator<<(std::ostream &out, const IXBar::Use &u) {
539 u.dbprint(out);
540 return out;
541}
542
543inline std::ostream &operator<<(std::ostream &out, const IXBar::FieldInfo &fi) {
544 out << fi.visualization_detail();
545 return out;
546}
547
548std::ostream &operator<<(std::ostream &, IXBar::Use::type_t);
549inline std::ostream &operator<<(std::ostream &out, const IXBar::Use::Byte &b) {
550 out << b.container << '[' << b.lo << ".." << (b.lo + 7) << ']';
551 if (b.loc) out << b.loc;
552 out << " 0x" << b.bit_use;
553 if (b.flags) out << " flags=" << P4::hex(b.flags);
554 out << " " << b.visualization_detail();
555 return out;
556}
557
558inline std::ostream &operator<<(std::ostream &out, const IXBar &i) {
559 i.dbprint(out);
560 return out;
561}
562
563#endif /* BF_P4C_MAU_INPUT_XBAR_H_ */
Definition alloc.h:65
Definition alloc.h:152
Definition input_xbar.h:455
Definition table_layout.h:34
Definition mau/asm_output.h:85
Definition stringify.h:33
Definition node.h:94
Definition visitor.h:400
Definition bitvec.h:120
Definition cstring.h:85
Definition hex.h:27
Definition indent.h:26
Definition ordered_map.h:32
Definition safe_vector.h:27
Definition phv.h:176
Definition phv_fields.h:154
cstring name
Definition phv_fields.h:161
Definition phv_fields.h:898
const PHV::Field * field() const override
Definition phv_fields.h:977
const le_bitrange & range() const override
Definition phv_fields.h:980
Definition phv_fields.h:1095
Definition mau/asm_output.h:223
Definition dyn_vector.h:27
The namespace encapsulating Barefoot/Intel-specific stuff.
Definition add_t2na_meta.cpp:21
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition action_format.h:979
Definition resources.h:125
Definition input_xbar.h:128
FieldInfo(cstring n, int l, int h, int cl, std::optional< cstring > a)
Definition input_xbar.h:137
int cont_lo
Definition input_xbar.h:132
int pragma_forced_ixbar_group
Definition input_xbar.h:133
int hi
Definition input_xbar.h:131
int lo
Definition input_xbar.h:130
Definition input_xbar.h:443
Definition input_xbar.h:74
bool operator==(const Loc &loc) const
return the byte number in the total order
Definition input_xbar.h:83
Definition input_xbar.h:230
std::string visualization_detail() const
Definition mau/input_xbar.cpp:334
Definition input_xbar.h:352
Definition input_xbar.h:367
Definition input_xbar.h:317
Definition input_xbar.h:191
virtual safe_vector< Byte > atcam_partition(int *hash_group=nullptr) const
Definition mau/input_xbar.cpp:146
std::string used_for() const
Definition mau/input_xbar.cpp:226
virtual int gateway_group() const
Definition mau/input_xbar.cpp:174
virtual TotalBytes match_hash(safe_vector< int > *hash_groups=nullptr) const
Definition mau/input_xbar.cpp:113
virtual TotalBytes atcam_match() const
Definition mau/input_xbar.cpp:129
virtual int search_buses_single() const
Definition mau/input_xbar.cpp:158
virtual safe_vector< TotalInfo > bits_per_search_bus() const
Definition mau/input_xbar.cpp:190
Definition input_xbar.h:418
Definition input_xbar.h:69
std::map< Use::Byte, safe_vector< FieldInfo > > ContByteConversion
Definition input_xbar.h:434
Compiler generated random number function for use as hash seed on the input crossbar.
Definition input_xbar.h:56
static unsigned seed
Definition input_xbar.h:58
static std::uniform_int_distribution< unsigned > distribution1
Uniform distribution producing either a 0 or a 1.
Definition input_xbar.h:63
static std::uniform_int_distribution< unsigned > distribution10
Uniform distribution producing a 10-bit random number.
Definition input_xbar.h:61
static unsigned nextRandomNumber(unsigned numBits=1)
Definition mau/input_xbar.cpp:43
Definition visitor.h:768
bool overlaps(ClosedRange a) const
Definition lib/bitrange.h:603
Definition resource.h:37