P4C
The P4 Compiler
Loading...
Searching...
No Matches
table_format.h
1
19#ifndef BF_P4C_MAU_TABLE_FORMAT_H_
20#define BF_P4C_MAU_TABLE_FORMAT_H_
21
22#include <map>
23#include <ostream>
24
25#include "backends/tofino/bf-p4c/mau/input_xbar.h"
26#include "backends/tofino/bf-p4c/mau/resource_estimate.h"
27#include "ir/ir.h"
28#include "lib/bitops.h"
29#include "lib/bitvec.h"
30#include "lib/safe_vector.h"
31
32using namespace P4;
33
34// Info for the allocation scheme for individual byte off of the input crossbar
35struct ByteInfo : public IHasDbPrint {
36 public:
37 IXBar::Use::Byte byte; // Obviously the byte
38 bitvec bit_use; // Relevant bits of the byte
39 int byte_location = -1;
40
41 explicit ByteInfo(const IXBar::Use::Byte b, bitvec bu) : byte(b), bit_use(bu) {}
42
43 void dbprint(std::ostream &out) const;
44
45 // Where the hole is in the byte, i.e. at the LSB or the MSB or in the middle
46 enum HoleType_t { LSB, MIDDLE, MSB, INVALID };
47 bool is_better_for_overhead(const ByteInfo &bi, int overhead_bits) const;
48 int hole_size(HoleType_t hole_type, int *hole_start_pos = nullptr) const;
49 bool better_hole_type(int hole, int comp_hole, int overhead_bits) const;
50 void set_interleave_info(int overhead_bits);
51
52 struct InterleaveInfo : public IHasDbPrint {
53 bool interleaved = false;
54 HoleType_t hole_type = INVALID;
55 // How many bytes the combination of the match byte and overhead take
56 int byte_cycle = 0;
57 // The first bit position of the overhead in this byte cycle
58 int overhead_start = 0;
59 // The first bit position of the match byte in this byte cycle (always % 8 == 0)
60 int match_byte_start = 0;
61 void dbprint(std::ostream &out) const;
62 };
63
64 InterleaveInfo il_info;
65};
66
68 static constexpr int OVERHEAD_BITS = 64;
69 static constexpr int SINGLE_RAM_BITS = 128;
70 static constexpr int SINGLE_RAM_BYTES = 16;
71 static constexpr int MAX_GROUPS_PER_LAMB = 4;
72 static constexpr int RAM_GHOST_BITS = IXBar::RAM_LINE_SELECT_BITS;
73 static constexpr int GATEWAY_BYTES = 4;
74 static constexpr int VERSION_BYTES = 14;
75 static constexpr int VERSION_BITS = 4;
76 static constexpr int VERSION_NIBBLES = 4;
77 static constexpr int MID_BYTE_LO = 0;
78 static constexpr int MID_BYTE_HI = 1;
79 static constexpr int MID_BYTE_VERS = 3;
80 static constexpr int MAX_SHARED_GROUPS = 2;
81 static constexpr int MAX_GROUPS_PER_RAM = 5;
82 static constexpr int FULL_IMEM_ADDRESS_BITS = 6;
83 static constexpr int FULL_NEXT_TABLE_BITS = 8;
84 static constexpr int NEXT_MAP_TABLE_ENTRIES = 8;
85 static constexpr int IMEM_MAP_TABLE_ENTRIES = 8;
86 // MSB bit of the selector length
87 static constexpr int SELECTOR_LENGTH_MAX_BIT = 16;
88
89 enum type_t {
90 MATCH,
91 NEXT,
92 ACTION,
93 IMMEDIATE,
94 VERS,
95 COUNTER,
96 COUNTER_PFE,
97 METER,
98 METER_PFE,
99 METER_TYPE,
100 INDIRECT_ACTION,
101 SEL_LEN_MOD,
102 SEL_LEN_SHIFT,
103 VALID,
104 ENTRY_TYPES,
105 INTERLEAVED_MATCH
106 };
107
108 struct Use {
110 // int is the number of bits in allocation
111 // bitvec is the mask, if bitvec.popcount() < Byte.hi - Byte.lo then it is
112 // an 8 bit field that's partially ghosted,
113 // if bitvec.popcount() > byte.hi - byte.lo then it is
114 // a misaligned field where the mask was not known until PHV allocation
115
117 std::map<IXBar::Use::Byte, bitvec> match;
118 bitvec mask[ENTRY_TYPES];
119 bitvec match_byte_mask; // The bytes that are allocated for matching
120 bitvec allocated_bytes;
121
122 void clear_match() {
123 match.clear();
124 mask[MATCH].clear();
125 mask[VERS].clear();
126 match_byte_mask.clear();
127 }
128
129 void clear() {
130 clear_match();
131 allocated_bytes.clear();
132 for (int i = 0; i < ENTRY_TYPES; i++) mask[i].clear();
133 }
134
135 bitvec match_bit_mask() const { return mask[MATCH] | mask[VERS]; }
136
137 bitvec entry_info_bit_mask() const {
138 bitvec rv;
139 for (int i = 0; i < ENTRY_TYPES; i++) rv |= mask[i];
140 return rv;
141 }
142
143 int entry_min_word() const {
144 return entry_info_bit_mask().min().index() / SINGLE_RAM_BITS;
145 }
146
147 int entry_max_word() const {
148 return entry_info_bit_mask().max().index() / SINGLE_RAM_BITS;
149 }
150
151 bitvec overhead_mask() const { return entry_info_bit_mask() - match_bit_mask(); }
152
153 bool overhead_in_RAM_word(int RAM_word) const {
154 bitvec bv = overhead_mask();
155 bv = bv & bitvec(RAM_word * SINGLE_RAM_BITS, SINGLE_RAM_BITS);
156 return !bv.empty();
157 }
158
159 bool match_data_in_RAM_word(int RAM_word) const {
160 bitvec bv = match_bit_mask();
161 bv = bv & bitvec(RAM_word * SINGLE_RAM_BITS, SINGLE_RAM_BITS);
162 return !bv.empty();
163 }
164 };
165
166 struct TCAM_use {
167 int group = -1;
168 int byte_group = -1;
169 int byte_config = -1;
170 bitvec dirtcam;
171
172 void set_group(int _group, bitvec _dirtcam);
173 void set_midbyte(int _byte_group, int _byte_config);
174
175 int range_index = -1;
176 TCAM_use() {}
177 };
178
179 bool only_one_result_bus = false;
180 safe_vector<match_group_use> match_groups;
181 safe_vector<safe_vector<int>> match_group_map;
182 safe_vector<TCAM_use> tcam_use;
183 int split_midbyte = -1;
184
185 std::map<int, safe_vector<int>> ixbar_group_per_width;
186 safe_vector<bool> result_bus_needed;
187 bitvec avail_sb_bytes;
188 int proxy_hash_group = -1;
189 bool identity_hash = false;
190
193 std::map<IXBar::Use::Byte, bitvec> ghost_bits;
194 bitvec immed_mask;
195
196 IR::MAU::PfeLocation stats_pfe_loc = IR::MAU::PfeLocation::NOT_SET;
197 IR::MAU::PfeLocation meter_pfe_loc = IR::MAU::PfeLocation::NOT_SET;
198 IR::MAU::TypeLocation meter_type_loc = IR::MAU::TypeLocation::NOT_SET;
199
200 std::map<int, int> payload_map;
201
202 void clear() {
203 ghost_bits.clear();
204 match_groups.clear();
205 match_group_map.clear();
206 tcam_use.clear();
207
208 ixbar_group_per_width.clear();
209 result_bus_needed.clear();
210 avail_sb_bytes.clear();
211 immed_mask.clear();
212 stats_pfe_loc = IR::MAU::PfeLocation::NOT_SET;
213 meter_pfe_loc = IR::MAU::PfeLocation::NOT_SET;
214 meter_type_loc = IR::MAU::TypeLocation::NOT_SET;
215 payload_map.clear();
216 }
217
218 bool has_overhead() const {
219 if (match_groups.empty()) return false;
220 return !match_groups[0].overhead_mask().empty();
221 }
222
223 bitvec overhead() const {
224 bitvec rv;
225 for (auto &match_group : match_groups) rv |= match_group.overhead_mask();
226 return rv;
227 }
228
229 bool instr_in_overhead() const {
230 if (match_groups.empty()) return false;
231 return !match_groups[0].mask[ACTION].empty();
232 }
233
234 int next_table_bits() const {
235 if (match_groups.empty()) return false;
236 return match_groups[0].mask[NEXT].popcount();
237 }
238
240 bitvec result_bus_words() const;
241 };
242
243 protected:
244 bitvec total_use; // Total bitvec for all entries in table format
245 bitvec interleaved_match_byte_use;
246 bitvec match_byte_use; // Bytes used by all match byte masks
247
248 Use *use = nullptr;
249 const LayoutOption &layout_option;
250 const IXBar::Use *match_ixbar;
251 // Size of the following vectors is the layout_option.way->width
252
254 // safe_vector<int> match_groups_per_RAM;
257
258 safe_vector<int> shared_groups_per_RAM;
259 safe_vector<int> full_match_groups_per_RAM;
260 safe_vector<ByteInfo> match_bytes;
261 safe_vector<ByteInfo> ghost_bytes;
264
265 // Vector for a hash group, as large tables could potentially use multiple hash groups
267 int ghost_bits_count = 0;
268
269 const IR::MAU::Table *tbl;
270
271 private:
272 const IXBar::Use *proxy_hash_ixbar;
273
274 std::set<int> fully_ghosted_search_buses;
275 safe_vector<int> ghost_bit_buses;
276
277 bitvec pre_match_total_use;
278
279 bitvec interleaved_bit_use;
280
281 enum packing_algorithm_t { SAVE_GW_SPACE, PACK_TIGHT, PACKING_ALGORITHMS };
282
283 packing_algorithm_t pa = PACKING_ALGORITHMS;
284
285 bitvec version_allocated;
286
287 // Match group index in use coordinate to whenever they are found in the match_groups_per_RAM
288 // i.e. if the match_groups_per_RAM looks like [2, 2], then use->match_groups[0] and
289 // use->match_groups[1] are in the first RAM, etc. Same thing applies for overhead groups
290
291 // Size of outer vector is layout_option.way->match_groups. Essentially which RAMs does
292 // each match group use, for allocating version bits.
293 // safe_vector<safe_vector<int>> match_group_info;
294
295 const bitvec immediate_mask;
296 bool gw_linked;
298
299 const PhvInfo &phv;
300
301 bool skinny = false;
302 void clear_match_state();
303 void clear_pre_allocation_state();
304
305 bitvec bitvec_necessary(type_t type) const;
306 int overhead_bits_necessary() const;
307 bool allocate_overhead_field(type_t type, int lsb_mem_word_offset, int bit_width, int entry,
308 int RAM_word);
309 bool allocate_overhead_entry(int entry, int RAM_word, int lsb_mem_word_offset);
310 void setup_pfes_and_types();
311 bool allocate_all_indirect_ptrs();
312 bool allocate_all_immediate();
313 bool allocate_all_instr_selection();
314 bool allocate_match();
315 bool allocate_match_with_algorithm();
316 bool is_match_entry_wide() const;
317
318 bool allocate_all_ternary_match();
319 void initialize_dirtcam_value(bitvec &dirtcam, const IXBar::Use::Byte &byte);
320 void ternary_midbyte(int midbyte, size_t &index, bool lo_midbyte);
321 void ternary_version(size_t &index);
322
323 bool analyze_skinny_layout_option(int per_RAM, safe_vector<IXBar::Use::GroupInfo> &sizes);
324 bool analyze_wide_layout_option(safe_vector<IXBar::Use::GroupInfo> &sizes);
325 void analyze_proxy_hash_option(int per_RAM);
326
327 int hit_actions() const;
328 bool allocate_next_table();
329 bool allocate_selector_length();
330 bool allocate_indirect_ptr(int total, type_t type, int group, int RAM);
331
332 bool allocate_interleaved_byte(const ByteInfo &info, safe_vector<ByteInfo> &alloced,
333 int width_sect, int entry, bitvec &byte_attempt,
334 bitvec &bit_attempt);
335 bool allocate_version(int width_sect, const safe_vector<ByteInfo> &alloced, bitvec &version_loc,
336 bitvec &byte_attempt, bitvec &bit_attempt);
337
338 int determine_group(int width_sect, int groups_allocated);
339 void allocate_share(int width_sect, int group, safe_vector<ByteInfo> &unalloced_group,
340 safe_vector<ByteInfo> &alloced, bitvec &version_loc, bitvec &byte_attempt,
341 bitvec &bit_attempt, bool overhead_section);
342 bool attempt_allocate_shares();
343 bool allocate_shares();
344 bool redistribute_entry_priority();
345 void redistribute_next_table();
346 bool build_match_group_map();
347 bool build_payload_map();
348 bool interleave_match_and_overhead();
349
350 virtual void classify_match_bits();
351 virtual bool allocate_sram_match();
352 virtual bool allocate_match_byte(const ByteInfo &info, safe_vector<ByteInfo> &alloced,
353 int width_sect, bitvec &byte_attempt, bitvec &bit_attempt);
354 virtual bool requires_versioning() const { return layout_option.layout.requires_versioning; }
355 virtual bool requires_valid_bit() const { return false; }
356 virtual void find_bytes_to_allocate(int width_sect, safe_vector<ByteInfo> &unalloced);
357
358 protected:
359 virtual bool allocate_overhead(bool alloc_match = false);
360 virtual void get_potential_ghost_byte(
361 const IXBar::Use::Byte byte, const std::map<cstring, bitvec> &hash_masks,
362 safe_vector<std::pair<IXBar::Use::Byte, bitvec>> &potential_ghost);
363 virtual void choose_ghost_bits(
364 safe_vector<std::pair<IXBar::Use::Byte, bitvec>> &potential_ghost);
365 int bits_necessary(type_t type) const;
366 bool initialize_byte(int byte_offset, int width_sect, const ByteInfo &info,
367 safe_vector<ByteInfo> &alloced, bitvec &byte_attempt,
368 bitvec &bit_attempted);
369 virtual void allocate_full_fits(int width_sect, int group = -1);
370 virtual bool analyze_layout_option();
371 void fill_out_use(int group, const safe_vector<ByteInfo> &alloced, bitvec &version_loc);
372
373 public:
374 TableFormat(const LayoutOption &l, const IXBar::Use *mi, const IXBar::Use *phi,
375 const IR::MAU::Table *t, const bitvec im, bool gl, FindPayloadCandidates &fpc,
376 const PhvInfo &phv)
377 : layout_option(l),
378 match_ixbar(mi),
379 tbl(t),
380 proxy_hash_ixbar(phi),
381 immediate_mask(im),
382 gw_linked(gl),
383 fpc(fpc),
384 phv(phv) {}
385 bool find_format(Use *u);
386 void verify();
387 static TableFormat *create(const LayoutOption &l, const IXBar::Use *mi, const IXBar::Use *phi,
388 const IR::MAU::Table *t, const bitvec im, bool gl,
389 FindPayloadCandidates &fpc, const PhvInfo &phv);
390};
391
392std::ostream &operator<<(std::ostream &out, const TableFormat::Use::match_group_use &m);
393#endif /* BF_P4C_MAU_TABLE_FORMAT_H_ */
Definition payload_gateway.h:31
Definition table_layout.h:34
Definition stringify.h:33
Definition bitvec.h:120
Definition safe_vector.h:27
Definition phv_fields.h:1095
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
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 table_format.h:52
void dbprint(std::ostream &out) const
Definition table_format.cpp:27
Definition table_format.h:35
void set_interleave_info(int overhead_bits)
Definition table_format.cpp:2650
bool better_hole_type(int hole, int comp_hole, int overhead_bits) const
Definition table_format.cpp:2602
bool is_better_for_overhead(const ByteInfo &bi, int overhead_bits) const
Definition table_format.cpp:2624
Definition input_xbar.h:230
Definition input_xbar.h:191
Definition table_format.h:166
Definition table_format.h:109
std::map< IXBar::Use::Byte, bitvec > match
The byte and byte_mask location in the format.
Definition table_format.h:117
Definition table_format.h:108
bitvec no_overhead_atcam_result_bus_words() const
Definition table_format.cpp:60
bitvec result_bus_words() const
Definition table_format.cpp:113
std::map< IXBar::Use::Byte, bitvec > ghost_bits
Definition table_format.h:193
Definition table_format.h:67
bool find_format(Use *u)
Definition table_format.cpp:505
virtual void allocate_full_fits(int width_sect, int group=-1)
Definition table_format.cpp:1580
virtual bool allocate_overhead(bool alloc_match=false)
Definition table_format.cpp:576
bool initialize_byte(int byte_offset, int width_sect, const ByteInfo &info, safe_vector< ByteInfo > &alloced, bitvec &byte_attempt, bitvec &bit_attempted)
Definition table_format.cpp:1137
safe_vector< int > overhead_groups_per_RAM
Which RAM sections contain the match groups.
Definition table_format.h:256
virtual void choose_ghost_bits(safe_vector< std::pair< IXBar::Use::Byte, bitvec > > &potential_ghost)
Definition table_format.cpp:1438
void fill_out_use(int group, const safe_vector< ByteInfo > &alloced, bitvec &version_loc)
Definition table_format.cpp:1547
virtual bool analyze_layout_option()
Definition table_format.cpp:183
virtual void get_potential_ghost_byte(const IXBar::Use::Byte byte, const std::map< cstring, bitvec > &hash_masks, safe_vector< std::pair< IXBar::Use::Byte, bitvec > > &potential_ghost)
Definition table_format.cpp:1339
safe_vector< int > search_bus_per_width
Specifically which search bus coordinates to which RAM.
Definition table_format.h:263