P4C
The P4 Compiler
Loading...
Searching...
No Matches
attached_info.h
1
19#ifndef BF_P4C_MAU_ATTACHED_INFO_H_
20#define BF_P4C_MAU_ATTACHED_INFO_H_
21
22#include "attached_entries.h"
23#include "backends/tofino/bf-p4c/mau/mau_visitor.h"
24#include "ir/pass_manager.h"
25#include "lib/ordered_map.h"
26#include "lib/ordered_set.h"
27
28namespace ActionData {
29
30using namespace P4;
31
33 // An "enum" that tracks the splitting of entries across stages for both the match table
34 // and all indirect attached tables. For each table (match and indirect attached), we
35 // need to know if there are entries in this stage, earlier stages, and later stages.
36 // That's 3 bits per table, but not all combinations make sense. We store these packed
37 // into a single uint32, with the bottom 3 bits for the match table and additional bits
38 // for up to 9 attached tables (in practice there are never more than 2 or 3).
39 //
40 // We need this to be an easily comparable "enum" as we use it as a key for caches of
41 // table layout formats, action data formats, and actions.
42 //
43 // A given table will end up with a different FormatType_t for each stage that it is
44 // split across, which summarizes the view of the table from that stage -- which parts
45 // of the table are allocated in the current stage and which other stages have parts that
46 // the parts in this stage need to communicate with. So for example, table with match(M),
47 // stateful(S) and counter(C) split across three stages as
48 // stage1 | stage2 | stage3
49 // FormatType_t M | M+S+C | S
50 // match (bits 0..2): -T- ET- E--
51 // stateful (bits 3..5): --L -TL ET-
52 // counter (bits 6..8): --L -T- E--
53 //
54 // Many combinations do not make sense, so should not occur. Attached table entries
55 // can never be in a stage before match table entries, so if there are match entries in
56 // later stages, all attached entries must also be in later stages.
57 // Currently we never set match LATER_STAGE as nothing depends on it -- FormatTypes
58 // that differ only in this bit will end up with the exact same possible table and
59 // action formats.
60
61 enum stage_t {
62 EARLIER_STAGE = 1,
63 THIS_STAGE = 2,
64 LATER_STAGE = 4,
65 MASK = 7,
66 ALL_ATTACHED = 01111111110,
67 };
68 uint32_t value;
69
70 public:
71 bool operator<(FormatType_t a) const { return value < a.value; }
72 bool operator==(const FormatType_t &a) const { return value == a.value; }
73 bool operator!=(const FormatType_t &a) const { return !(*this == a); }
74 bool valid() const { return value != 0; }
75 void invalidate() { value = 0; }
76 void check_valid(const IR::MAU::Table *tbl = nullptr) const; // sanity check for
77 // insane combinations
78 bool normal() const { // valid format that does not require any action changes
79 // either everything is in this stage OR there are no attached tabled
80 return (value & ~(ALL_ATTACHED * THIS_STAGE)) == THIS_STAGE || (value > 0 && value <= MASK);
81 }
82
83 bool matchEarlierStage() const { return value & EARLIER_STAGE; }
84 bool matchThisStage() const { return value & THIS_STAGE; }
85 bool matchLaterStage() const { return value & LATER_STAGE; }
86
87 int num_attached() const { return floor_log2(value) / 3; }
88 bool attachedEarlierStage(int idx) const { return (value >> 3 * (idx + 1)) & EARLIER_STAGE; }
89 bool attachedThisStage(int idx) const { return (value >> 3 * (idx + 1)) & THIS_STAGE; }
90 bool attachedLaterStage(int idx) const { return (value >> 3 * (idx + 1)) & LATER_STAGE; }
91 bool anyAttachedEarlierStage() const { return (value & (ALL_ATTACHED * EARLIER_STAGE)) != 0; }
92 bool anyAttachedThisStage() const { return (value & (ALL_ATTACHED * THIS_STAGE)) != 0; }
93 bool anyAttachedLaterStage() const { return (value & (ALL_ATTACHED * LATER_STAGE)) != 0; }
94
95 FormatType_t() : value(0) {}
96 void initialize(const IR::MAU::Table *tbl, int entries, bool prev_stages,
97 const attached_entries_t &attached);
98 // which attached tables are we tracking in the FormatType_t
99 static bool track(const IR::MAU::AttachedMemory *at);
100 static std::vector<const IR::MAU::AttachedMemory *> tracking(const IR::MAU::Table *);
101 static FormatType_t default_for_table(const IR::MAU::Table *);
102 friend std::ostream &operator<<(std::ostream &, FormatType_t);
103 std::string toString() const;
104};
105} // end namespace ActionData
106
108 public:
109 enum addr_type_t { STATS, METER, ACTIONDATA, TYPES };
110 using TypeToAddressMap = std::map<addr_type_t, IR::MAU::Table::IndirectAddress>;
111
112 private:
113 const IR::MAU::Table *tbl;
114 TypeToAddressMap &ind_addrs;
115
116 std::map<addr_type_t, const IR::MAU::BackendAttached *> users;
117
118 cstring addr_type_name(addr_type_t type) {
119 switch (type) {
120 case STATS:
121 return "stats"_cs;
122 case METER:
123 return "meter"_cs;
124 case ACTIONDATA:
125 return "action"_cs;
126 default:
127 return ""_cs;
128 }
129 }
130
131 bool compatible(const IR::MAU::BackendAttached *, const IR::MAU::BackendAttached *);
132 void free_address(const IR::MAU::AttachedMemory *am, addr_type_t type);
133
134 bool preorder(const IR::MAU::Counter *cnt) override;
135 bool preorder(const IR::MAU::Meter *mtr) override;
136 bool preorder(const IR::MAU::StatefulAlu *salu) override;
137 bool preorder(const IR::MAU::Selector *as) override;
138 bool preorder(const IR::MAU::TernaryIndirect *) override {
139 BUG("No ternary indirect should exist before table placement");
140 return false;
141 }
142 bool preorder(const IR::MAU::ActionData *ad) override;
143 bool preorder(const IR::MAU::IdleTime *) override { return false; }
144 bool preorder(const IR::Attached *att) override {
145 BUG("Unknown attached table type %s", typeid(*att).name());
146 }
147
148 public:
149 ValidateAttachedOfSingleTable(TypeToAddressMap &ia, const IR::MAU::Table *t)
150 : tbl(t), ind_addrs(ia) {}
151};
152
183class PhvInfo;
184
189 std::vector<unsigned> _found;
190 unsigned _found_all = 0U;
191
192 profile_t init_apply(const IR::Node *node) {
193 auto rv = MauInspector::init_apply(node);
194 _found_all = 0;
195 _found.clear();
196 _found.resize(am_match.size());
197 return rv;
198 }
199
200 bool preorder(const IR::MAU::AttachedMemory *am) {
201 unsigned mask = 1U;
202 const Visitor::Context *ctxt = nullptr;
203 if (findContext<IR::MAU::Primitive>(ctxt)) {
204 BUG_CHECK(ctxt->child_index >= 0 && ctxt->child_index < 32, "mask overflow");
205 mask <<= ctxt->child_index;
206 }
207 if (am_match.count(am)) {
208 _found[am_match.at(am)] |= mask;
209 _found_all |= mask;
210 }
211 return false;
212 }
213
214 public:
215 HasAttachedMemory() = default;
216 void add(const IR::MAU::AttachedMemory *am) {
217 if (!am_match.count(am)) {
218 unsigned idx = am_match.size();
219 am_match[am] = idx;
220 }
221 }
222 HasAttachedMemory(std::initializer_list<const IR::MAU::AttachedMemory *> am) {
223 for (auto *a : am) add(a);
224 }
225 unsigned found() const { return _found_all; }
226 unsigned found(const IR::MAU::AttachedMemory *am) const { return _found[am_match.at(am)]; }
227 auto begin() const -> decltype(Keys(am_match).begin()) { return Keys(am_match).begin(); }
228 auto end() const -> decltype(Keys(am_match).end()) { return Keys(am_match).end(); }
229};
230
237 PhvInfo &phv;
238
239 // Can't use IR::Node * as keys in a map, as they change in transforms. Names
240 // are unique and stable, so use them instead. However, the pointers in the
241 // sets may be out-of-date and not refer to the current IR. Turns out we only
242 // ever use this to get a count of the number of tables (to detect shared attached
243 // tables) so it doesn't matter for now...
245
246 struct IndexTemp {
247 const IR::TempVar *index = nullptr;
248 const IR::TempVar *enable = nullptr;
249 const IR::TempVar *type = nullptr;
250 };
251 std::map<cstring, IndexTemp> index_tempvars;
252
253 // Not linked via gateway with information
254 struct AddressInfo {
256 bool always_run_on_hit = true;
258 bool always_run_on_miss = true;
260 int address_bits = 0;
262 int hash_bits = 0;
266 bitvec types_on_hit;
268 bitvec types_on_miss;
269 };
270
272
273 profile_t init_apply(const IR::Node *node) {
274 auto rv = PassManager::init_apply(node);
275 attached_to_table_map.clear();
276 address_info_per_table.clear();
277 cache.clear(); // actions might have changed without renaming
278 return rv;
279 }
280
284 class BuildSplitMaps : public MauInspector {
285 SplitAttachedInfo &self;
286 bool preorder(const IR::MAU::Table *) override;
287
288 public:
289 explicit BuildSplitMaps(SplitAttachedInfo &s) : self(s) {}
290 };
291
297 class EnableAndTypesOnActions : public MauInspector {
298 SplitAttachedInfo &self;
299 bool preorder(const IR::MAU::Action *) override;
300
301 public:
302 explicit EnableAndTypesOnActions(SplitAttachedInfo &s) : self(s) {}
303 };
304
305 class ValidateAttachedOfAllTables : public MauInspector {
306 SplitAttachedInfo &self;
307 bool preorder(const IR::MAU::Table *) override;
308
309 public:
310 explicit ValidateAttachedOfAllTables(SplitAttachedInfo &s) : self(s) {}
311 };
312
313 public:
314 explicit SplitAttachedInfo(PhvInfo &phv) : phv(phv) {
315 addPasses({new BuildSplitMaps(*this), new ValidateAttachedOfAllTables(*this),
316 new EnableAndTypesOnActions(*this)});
317 }
318
319 const ordered_set<const IR::MAU::Table *> &tables_from_attached(const IR::Attached *att) const {
320 return attached_to_table_map.at(att->name);
321 }
322
323 private:
324 int addr_bits_to_phv_on_split(const IR::MAU::Table *tbl,
325 const IR::MAU::AttachedMemory *at) const;
326 bool enable_to_phv_on_split(const IR::MAU::Table *tbl, const IR::MAU::AttachedMemory *at) const;
327 int type_bits_to_phv_on_split(const IR::MAU::Table *tbl,
328 const IR::MAU::AttachedMemory *at) const;
329
330 const IR::MAU::Instruction *pre_split_addr_instr(const IR::MAU::Action *act,
331 const IR::MAU::Table *tbl,
332 const IR::MAU::AttachedMemory *at);
333 const IR::MAU::Instruction *pre_split_enable_instr(const IR::MAU::Action *act,
334 const IR::MAU::Table *tbl,
335 const IR::MAU::AttachedMemory *at);
336 const IR::MAU::Instruction *pre_split_type_instr(const IR::MAU::Action *act,
337 const IR::MAU::Table *tbl,
338 const IR::MAU::AttachedMemory *at);
339
340 // memoization cache for get/create_split_action
341 typedef std::tuple<cstring /* table name */, cstring /* action name */, FormatType_t> memo_key;
342 std::map<memo_key, const IR::MAU::Action *> cache;
343
344 public:
345 const IR::Expression *split_enable(const IR::MAU::AttachedMemory *, const IR::MAU::Table *);
346 const IR::Expression *split_index(const IR::MAU::AttachedMemory *, const IR::MAU::Table *);
347 const IR::Expression *split_type(const IR::MAU::AttachedMemory *, const IR::MAU::Table *);
348
349 const IR::MAU::Action *get_split_action(const IR::MAU::Action *act, const IR::MAU::Table *tbl,
350 FormatType_t format_type);
351
352 private:
353 const IR::MAU::Action *create_split_action(const IR::MAU::Action *act,
354 const IR::MAU::Table *tbl, FormatType_t format_type);
355};
356
357#endif /* BF_P4C_MAU_ATTACHED_INFO_H_ */
Definition attached_info.h:32
Definition attached_info.h:187
Definition mau_visitor.h:29
Definition node.h:94
Definition ir/pass_manager.h:40
Definition visitor.h:78
Definition bitvec.h:120
Definition cstring.h:85
Definition ordered_set.h:32
Definition phv_fields.h:1095
Definition attached_info.h:235
Definition attached_info.h:107
Definition action_format.cpp:30
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition visitor.h:47