P4C
The P4 Compiler
Loading...
Searching...
No Matches
action_format.h
1
19#ifndef BACKENDS_TOFINO_BF_P4C_MAU_ACTION_FORMAT_H_
20#define BACKENDS_TOFINO_BF_P4C_MAU_ACTION_FORMAT_H_
21
22#include <array>
23#include <iterator>
24#include <map>
25
26#include "bf-p4c/ir/bitrange.h"
27#include "bf-p4c/mau/action_analysis.h"
28#include "bf-p4c/mau/attached_info.h"
29#include "bf-p4c/mau/ixbar_expr.h"
30#include "bf-p4c/phv/phv.h"
31#include "ir/ir.h"
32#include "lib/bitops.h"
33#include "lib/bitvec.h"
34#include "lib/log.h"
35#include "lib/ordered_set.h"
36#include "lib/safe_vector.h"
37
38namespace ActionData {
39
40using namespace P4;
41using ::P4::operator<<; // avoid overload hiding issues
42
43// MASK is currently not used, but maybe will be in order to reduce the size of the JSON
44// If MASK is used, then the equiv_cond will have to change
45enum ModConditionally_t { NONE, VALUE, /* MASK */ };
46
53class Parameter : public IHasDbPrint {
86 protected:
87 // Whether the value is controlled by a condition, or is part of conditional mask
88 ModConditionally_t _cond_type = NONE;
89 // The conditional that controls this value
90 cstring _cond_name;
91
92 public:
93 // virtual const Parameter *shared_param(const Parameter *, int &start_bit) = 0;
94 virtual ~Parameter() {}
95 virtual int size() const = 0;
96 virtual bool from_p4_program() const = 0;
97 virtual cstring name() const = 0;
98 virtual const Parameter *split(int lo, int hi) const = 0;
99 virtual bool only_one_overlap_solution() const = 0;
100
101 virtual bool is_next_bit_of_param(const Parameter *, bool same_alias) const = 0;
102 virtual const Parameter *get_extended_param(uint32_t extension, const Parameter *) const = 0;
103 virtual const Parameter *overlap(const Parameter *ad, bool guaranteed_one_overlap,
104 le_bitrange *my_overlap, le_bitrange *ad_overlap) const = 0;
105 virtual void dbprint(std::ostream &out) const = 0;
106
107 virtual bool equiv_value(const Parameter *, bool check_cond = true) const = 0;
108 virtual bool can_merge(const Parameter *param) const { return equiv_value(param); }
109 virtual bool is_subset_of(const Parameter *param) const { return equiv_value(param); }
110 virtual const Parameter *merge(const Parameter *param) const {
111 if (param != nullptr) BUG_CHECK(can_merge(param), "Merging parameters that cannot merge");
112 return this;
113 }
114
115 template <typename T>
116 const T *to() const {
117 return dynamic_cast<const T *>(this);
118 }
119 template <typename T>
120 bool is() const {
121 return to<T>() != nullptr;
122 }
123
124 bool is_cond_type(ModConditionally_t type) const { return type == _cond_type; }
125 cstring cond_name() const { return _cond_name; }
126
127 void set_cond(ModConditionally_t ct, cstring n) {
128 _cond_type = ct;
129 _cond_name = n;
130 }
131
132 void set_cond(const Parameter *p) {
133 _cond_type = p->_cond_type;
134 _cond_name = p->_cond_name;
135 }
136
137 bool equiv_cond(const Parameter *p) const {
138 return _cond_type == p->_cond_type && _cond_name == p->_cond_name;
139 }
140
141 bool can_overlap_ranges(le_bitrange my_range, le_bitrange ad_range, le_bitrange &overlap,
142 le_bitrange *my_overlap, le_bitrange *ad_overlap) const;
143};
144
160class Argument : public Parameter {
161 IR::ID _name;
162 le_bitrange _param_field;
163
164 public:
165 cstring name() const override { return _name.name; }
166 cstring originalName() const { return _name.originalName; }
167 le_bitrange param_field() const { return _param_field; }
168
169 Argument(IR::ID n, le_bitrange pf) : _name(n), _param_field(pf) {}
170 virtual ~Argument() {}
171
172 bool from_p4_program() const override { return true; }
173 const Parameter *split(int lo, int hi) const override {
174 le_bitrange split_range = {_param_field.lo + lo, _param_field.lo + hi};
175 BUG_CHECK(_param_field.contains(split_range),
176 "Illegally splitting a parameter, as the "
177 "split contains bits outside of the range");
178 auto *rv = new Argument(_name, split_range);
179 rv->set_cond(this);
180 return rv;
181 }
182
183 bool only_one_overlap_solution() const override { return true; }
184
185 bool is_next_bit_of_param(const Parameter *ad, bool) const override;
186
187 const Parameter *get_extended_param(uint32_t extension, const Parameter *) const override {
188 auto rv = new Argument(*this);
189 rv->_param_field.hi += extension;
190 return rv;
191 }
192
193 const Parameter *overlap(const Parameter *ad, bool guaranteed_one_overlap,
194 le_bitrange *my_overlap, le_bitrange *ad_overlap) const override;
195 bool equiv_value(const Parameter *ad, bool check_cond = true) const override {
196 const Argument *arg = ad->to<Argument>();
197 if (arg == nullptr) return false;
198 if (check_cond && !equiv_cond(ad)) return false;
199 return _name == arg->_name && _param_field == arg->_param_field;
200 }
201 int size() const override { return _param_field.size(); }
202 void dbprint(std::ostream &out) const override {
203 out << "Arg:" << _name << " " << _param_field;
204 }
205};
206
216class Constant : public Parameter {
217 bitvec _value;
218 size_t _size;
219 cstring _alias;
220 le_bitrange range() const { return {0, static_cast<int>(_size) - 1}; }
221
222 public:
223 Constant(int v, size_t sz) : _value(v), _size(sz) {}
224 Constant(bitvec v, size_t sz) : _value(v), _size(sz) {}
225
226 const Parameter *split(int lo, int hi) const override;
227 bool only_one_overlap_solution() const override { return false; }
228 bool from_p4_program() const override { return !_alias.isNull(); }
229 bool is_next_bit_of_param(const Parameter *ad, bool same_alias) const override;
230 const Parameter *get_extended_param(uint32_t extension, const Parameter *ad) const override;
231 const Parameter *overlap(const Parameter *ad, bool only_one_overlap_solution,
232 le_bitrange *my_overlap, le_bitrange *ad_overlap) const override;
233 bool equiv_value(const Parameter *ad, bool check_cond = true) const override;
234 bitvec value() const { return _value; }
235 int size() const override { return _size; }
236 cstring name() const override {
237 if (_alias) return _alias;
238 return "$constant"_cs;
239 }
240 cstring alias() const { return _alias; }
241 void set_alias(cstring a) { _alias = a; }
242 void dbprint(std::ostream &out) const override {
243 out << "Const: 0x" << _value << " : " << _size << " bits";
244 }
245};
246
247class Hash : public Parameter {
248 P4HashFunction _func;
249
250 public:
251 explicit Hash(const P4HashFunction &f) : _func(f) {}
252
253 int size() const override { return _func.size(); }
254 cstring name() const override { return _func.name(); }
255 const Parameter *split(int lo, int hi) const override;
256 bool only_one_overlap_solution() const override { return false; }
257 bool from_p4_program() const override { return true; }
258 bool is_next_bit_of_param(const Parameter *ad, bool same_alias) const override;
259 const Parameter *get_extended_param(uint32_t extension, const Parameter *ad) const override;
260 const Parameter *overlap(const Parameter *ad, bool only_one_overlap_solution,
261 le_bitrange *my_overlap, le_bitrange *ad_overlap) const override;
262 bool equiv_value(const Parameter *ad, bool check_cond = true) const override;
263 void dbprint(std::ostream &out) const override { out << "Hash: " << _func; }
264 P4HashFunction func() const { return _func; }
265};
266
275class RandomNumber : public Parameter {
276 class UniqueAlloc {
277 cstring _random;
278 cstring _action;
279
280 public:
281 bool operator<(const UniqueAlloc &ua) const {
282 if (_random != ua._random) return _random < ua._random;
283 return _action < ua._action;
284 }
285
286 bool operator==(const UniqueAlloc &ua) const {
287 return _random == ua._random && _action == ua._action;
288 }
289
290 bool operator!=(const UniqueAlloc &ua) const { return !(*this == ua); }
291
292 cstring random() const { return _random; }
293 cstring action() const { return _action; }
294 UniqueAlloc(cstring rand, cstring act) : _random(rand), _action(act) {}
295 };
296
297 std::map<UniqueAlloc, le_bitrange> _rand_nums;
298 std::string rand_num_names() const {
299 std::stringstream str;
300 str << "{ ";
301 std::string sep = "";
302 for (auto ua : _rand_nums) {
303 str << sep << ua.first.random() << "$" << ua.first.action() << ua.second;
304 sep = ", ";
305 }
306 str << " }";
307 return str.str();
308 }
309
310 RandomNumber() {}
311 void add_alloc(cstring rand, cstring act, le_bitrange range) {
312 UniqueAlloc ua(rand, act);
313 _rand_nums.emplace(ua, range);
314 }
315
316 public:
317 int size() const override;
318 cstring name() const override { return "random"_cs; }
319 const Parameter *split(int lo, int hi) const override;
320 bool from_p4_program() const override { return true; }
321 bool only_one_overlap_solution() const override { return false; }
322 bool is_next_bit_of_param(const Parameter *ad, bool same_alias) const override;
323 const Parameter *get_extended_param(uint32_t extension, const Parameter *ad) const override;
324 const Parameter *overlap(const Parameter *ad, bool only_one_overlap_solution,
325 le_bitrange *my_overlap, le_bitrange *ad_overlap) const override;
326 bool equiv_value(const Parameter *ad, bool check_cond = true) const override;
327 bool rand_nums_overlap_into(const RandomNumber *rn) const;
328
329 bool is_subset_of(const Parameter *ad) const override;
330 bool can_merge(const Parameter *ad) const override;
331 const Parameter *merge(const Parameter *ad) const override;
332 void dbprint(std::ostream &out) const override { out << "Random: " << rand_num_names(); }
333
334 RandomNumber(cstring rand, cstring act, le_bitrange range) {
335 UniqueAlloc ua(rand, act);
336 _rand_nums.emplace(ua, range);
337 }
338};
339
340class RandomPadding : public Parameter {
341 int _size;
342
343 public:
344 int size() const override { return _size; }
345 cstring name() const override { return "rand_padding"_cs; }
346 const Parameter *split(int lo, int hi) const override;
347 bool from_p4_program() const override { return false; }
348 bool only_one_overlap_solution() const override { return false; }
349 bool is_next_bit_of_param(const Parameter *ad, bool same_alias) const override;
350 const Parameter *get_extended_param(uint32_t extensions, const Parameter *ad) const override;
351 const Parameter *overlap(const Parameter *ad, bool only_one_overlap_solution,
352 le_bitrange *my_overlap, le_bitrange *ad_overlap) const override;
353 bool equiv_value(const Parameter *ad, bool check_cond = true) const override;
354 bool is_subset_of(const Parameter *ad) const override;
355 bool can_merge(const Parameter *ad) const override;
356 const Parameter *merge(const Parameter *ad) const override;
357 void dbprint(std::ostream &out) const override {
358 out << "RndPad: " << name() << " : " << size();
359 }
360 explicit RandomPadding(int s) : _size(s) {}
361};
362
372class MeterColor : public Parameter {
373 cstring _meter_name;
374 le_bitrange _range;
375
376 public:
377 le_bitrange range() const { return _range; }
378 int size() const override { return _range.size(); }
379 bool from_p4_program() const override { return true; }
380 cstring name() const override { return _meter_name; }
381 const Parameter *split(int lo, int hi) const override;
382 bool only_one_overlap_solution() const override { return true; }
383 bool is_next_bit_of_param(const Parameter *, bool same_alias) const override;
384 const Parameter *get_extended_param(uint32_t extension, const Parameter *) const override;
385 const Parameter *overlap(const Parameter *ad, bool only_one_overlap_solution,
386 le_bitrange *my_overlap, le_bitrange *ad_overlap) const override;
387 void dbprint(std::ostream &out) const override {
388 out << "MeterColor: " << _meter_name << _range;
389 }
390 bool equiv_value(const Parameter *, bool check_cond = true) const override;
391 bool is_padding() const { return _meter_name == "$padding"; }
392
393 bool is_subset_of(const Parameter *ad) const override;
394 bool can_merge(const Parameter *ad) const override;
395 const Parameter *merge(const Parameter *ad) const override;
396 MeterColor(cstring mn, le_bitrange r) : _meter_name(mn), _range(r) {}
397};
398
410class MeterALU : public Parameter {
411 cstring _alu_user;
412 le_bitrange _range;
413
414 public:
415 le_bitrange range() const { return _range; }
416 int size() const override { return _range.size(); }
417 bool from_p4_program() const override { return true; }
418 cstring name() const override { return _alu_user; }
419 bool only_one_overlap_solution() const override { return true; }
420 const Parameter *split(int lo, int hi) const override;
421 bool is_next_bit_of_param(const Parameter *, bool) const override;
422 const Parameter *get_extended_param(uint32_t extension, const Parameter *) const override;
423 const Parameter *overlap(const Parameter *ad, bool only_one_overlap_solution,
424 le_bitrange *my_overlap, le_bitrange *ad_overlap) const override;
425 void dbprint(std::ostream &out) const override { out << "MeterALU: " << _alu_user << _range; }
426 bool equiv_value(const Parameter *, bool check_cond = true) const override;
427 MeterALU(cstring au, le_bitrange r) : _alu_user(au), _range(r) {}
428};
429
431 const Parameter *param;
432 le_bitrange phv_bits;
433 // @seealso ALUOperation::read_bits
434
435 /* actually a rotate, not a shift -- the number of bits the destination PHV needs to
436 * be rotated by to match up with this source. So it turns out to be the number of bits
437 * this parameter needs to left-rotate */
438 int right_shift;
439
441 bool is_wrapped(PHV::Container cont) const { return slot_bits_brs(cont).size() > 1; }
442
443 ALUParameter(const Parameter *p, le_bitrange pb) : param(p), phv_bits(pb), right_shift(0) {}
444
445 friend std::ostream &operator<<(std::ostream &out, const ALUParameter &p) {
446 return out << "ALU Param { " << p.param << ", phv bits : 0x" << p.phv_bits
447 << ", rotate_right_shift : " << p.right_shift << " } ";
448 }
449};
450
451enum ALUOPConstraint_t { ISOLATED, BITMASKED_SET, DEPOSIT_FIELD, BYTE_ROTATE_MERGE };
452std::ostream &operator<<(std::ostream &out, ALUOPConstraint_t c);
453
455 cstring action_name;
456 const Parameter *param = nullptr;
457 PHV::Container container;
458 le_bitrange phv_bits;
459
460 public:
462
464 : action_name(an), param(p), container(cont), phv_bits(pb) {}
465};
466
467class RamSection;
468
469using ParameterPositions = std::map<int, const Parameter *>;
470
486 // The location of the P4 parameters, i.e. what bits contain particular bitranges. This
487 // is knowledge required for the driver to pack the RAM
489 // The bits that are to be written in the PHV Container
490 bitvec _phv_bits;
491 // The amount to barrel-shift right the phv_bits in order to know the associated slot_bits. One
492 // can think of the phv_bits as the write_bits and the slot_bits as the read_bits. In a
493 // deposit-field instruction, the right rotate is actually the reverse, i.e. the right rotation
494 // of the read bits in order to align them to the write bits
495 int _right_shift;
496 bool _right_shift_set = false;
497 PHV::Container _container;
498 // Information on how the data is used, in order to potentially pack in RAM space other
499 // ALUOperations
500 ALUOPConstraint_t _constraint;
501 // Alias name for the assembly language
502 cstring _alias;
503 // Mask alias for the assembly language
504 cstring _mask_alias;
505 // Used for modify field conditionally
506 safe_vector<ALUParameter> _mask_params;
507 bitvec _mask_bits;
508 // Explicitly needed for action parameters shared between actions, i.e. hash, rng
509 cstring _action_name;
510
511 public:
512 void add_param(ALUParameter &ap) {
513 _params.push_back(ap);
514 _phv_bits.setrange(ap.phv_bits.lo, ap.phv_bits.size());
515 }
516
517 void add_mask_param(ALUParameter &ap) {
518 _mask_params.push_back(ap);
519 _mask_bits.setrange(ap.phv_bits.lo, ap.phv_bits.size());
520 }
521
522 bool contains_only_one_overlap_solution() const {
523 for (auto param : _params) {
524 if (param.param->only_one_overlap_solution()) return true;
525 }
526 return false;
527 }
528
529 bitvec phv_bits() const { return _phv_bits; }
530 bitvec phv_bytes() const;
531 bitvec mask_bits() const { return _mask_bits; }
532 bitvec slot_bits() const {
533 BUG_CHECK(_right_shift_set, "Unsafe call of slot bits in action format");
534 if (_container)
535 return _phv_bits.rotate_right_copy(0, _right_shift, _container.size());
536 else
537 return _phv_bits >> _right_shift;
538 }
539
540 bool valid() const { return static_cast<bool>(_container); }
541 size_t size() const {
542 return valid() ? _container.size() : static_cast<size_t>(PHV::Size::b32);
543 }
544 bool is_constrained(ALUOPConstraint_t cons) const { return _constraint == cons; }
545 size_t index() const {
546 BUG_CHECK(valid(), "Cannot call index on an invalid ALU operation");
547 return ceil_log2(size()) - 3;
548 }
549 ALUOPConstraint_t constraint() const { return _constraint; }
550
551 ALUOperation(PHV::Container cont, ALUOPConstraint_t cons)
552 : _right_shift(0), _container(cont), _constraint(cons) {}
553
554 const RamSection *create_RamSection(bool shift_to_lsb) const;
555 const ALUOperation *add_right_shift(int right_shift, int *rot_alias_idx) const;
556 cstring alias() const { return _alias; }
557 cstring mask_alias() const { return _mask_alias; }
558 cstring action_name() const { return _action_name; }
559 void set_alias(cstring a) { _alias = a; }
560 void set_mask_alias(cstring ma) { _mask_alias = ma; }
561 void set_action_name(cstring an) { _action_name = an; }
562 PHV::Container container() const { return _container; }
563 const ALUParameter *find_param_alloc(UniqueLocationKey &key) const;
564 ParameterPositions parameter_positions() const;
565 std::string parameter_positions_to_string() const;
566 cstring wrapped_constant() const;
567 bitvec static_entry_of_arg(const Argument *arg, bitvec value) const;
569
571 template <typename T>
572 bool has_param() const {
573 for (auto param : _params) {
574 if (param.param->is<T>()) return true;
575 }
576 return false;
577 }
578 int hw_right_shift() const;
581 bool is_right_shift_from_hw() const { return has_param<MeterColor>() || has_param<MeterALU>(); }
582 bool right_shift_set() const { return _right_shift_set; }
583
584 friend std::ostream &operator<<(std::ostream &out, const ALUOperation &op) {
585 Log::TempIndent indent;
586 out << "ALU Operation { " << indent << Log::endl;
587 out << "params:" << indent;
588 for (auto &p : op._params) out << Log::endl << p;
589 out << indent.pop_back() << Log::endl;
590 out << "phv bits: " << op._phv_bits << ", right_shift : " << op._right_shift
591 << ", right_shift_set: " << op._right_shift_set << ", container: " << op._container
592 << ", op constraint: " << op._constraint << Log::endl;
593 if (op._alias) out << "alias: " << op._alias << Log::endl;
594 if (op._mask_alias) out << "mask alias: " << op._mask_alias << Log::endl;
595 if (op._mask_params.size() > 0) {
596 out << "mask params: " << Log::indent;
597 for (auto &p : op._mask_params) out << Log::endl << p;
598 out << Log::unindent << Log::endl;
599 }
600 out << "mask bits: " << op._mask_bits << ", action name: " << op._action_name;
601 out << " }";
602 return out;
603 }
604 friend std::ostream &operator<<(std::ostream &out, const ALUOperation *op) {
605 if (op) out << *op;
606 return out;
607 }
608 void dbprint_multiline() const {}
609};
610
612 const Parameter *param;
613 int a_start_bit;
614 int b_start_bit;
615
616 SharedParameter(const Parameter *p, int a, int b) : param(p), a_start_bit(a), b_start_bit(b) {}
617 friend std::ostream &operator<<(std::ostream &out, const SharedParameter &op) {
618 out << "Param: " << *op.param << "A :" << op.a_start_bit << " B:" << op.b_start_bit;
619 return out;
620 }
621};
622
624
631 private:
632 bits_iter_t bits_begin;
633 bits_iter_t bits_end;
634
635 public:
638 : bits_begin(bb), bits_end(be) {}
639
640 int size() const { return bits_end - bits_begin; }
641 void rotate(int bit_rotation);
642 RotationInfo split(int first_bit, int sz) const;
643};
644
650
651 bool empty() const { return bits_in_use.empty(); }
652 le_bitrange max_br_in_use() const {
653 return {bits_in_use.min().index(), bits_in_use.max().index()};
654 }
655 LocalPacking(int bw, bitvec b) : bit_width(bw), bits_in_use(b) {}
656 LocalPacking split(int first_bit, int sz) const;
657
658 void dbprint(std::ostream &out) const { out << "bits: " << bit_width << " 0x" << bits_in_use; }
659};
660
669 int rotational_granularity = -1;
670
673 safe_vector<PackingConstraint> recursive_constraints;
674
675 bool under_rotate(LocalPacking &lp, le_bitrange open_range, int &final_bit,
676 int right_shift) const;
677 bool over_rotate(LocalPacking &lp, le_bitrange open_range, int &final_bit,
678 int right_shift) const;
679
680 public:
681 PackingConstraint expand(int current_size, int expand_size) const;
682 bool is_rotational() const { return rotational_granularity > 0; }
683 bool can_rotate(int bit_width, int init_bit, int final_bit) const;
684 void rotate(RotationInfo &ri, int init_bit, int final_bit);
685 bool can_rotate_in_range(LocalPacking &lp, le_bitrange open_range, int &final_bit) const;
686 int get_granularity() const { return rotational_granularity; }
687 int bit_rotation_position(int bit_width, int init_bit, int final_bit, int init_bit_comp) const;
688 safe_vector<PackingConstraint> get_recursive_constraints() const {
689 return recursive_constraints;
690 }
691
693 const LocalPacking &pc_lp) const;
694
697 : rotational_granularity(rg), recursive_constraints(pc) {}
698 friend std::ostream &operator<<(std::ostream &out, const PackingConstraint &pc) {
699 out << "Packing Constraint {" << " Rotational Granularity: " << pc.rotational_granularity
700 << " Recursive Constraint (size): " << pc.recursive_constraints.size() << " } ";
701 return out;
702 }
703};
704
705enum SlotType_t { BYTE, HALF, FULL, SLOT_TYPES, DOUBLE_FULL = SLOT_TYPES, SECT_TYPES = 4 };
706std::ostream &operator<<(std::ostream &, SlotType_t);
707size_t slot_type_to_bits(SlotType_t type);
708SlotType_t bits_to_slot_type(size_t bits);
709
710using BusInputs = std::array<bitvec, SLOT_TYPES>;
711
759 safe_vector<const Parameter *> action_data_bits;
761 PackingConstraint pack_info;
762
763 bool is_better_merge_than(const RamSection *comp) const;
764
765 public:
769 // Made public for unit tests. Not sure if there is a way around this
770 bitvec bits_in_use() const;
772 const RamSection *expand_to_size(size_t expand_size) const;
773 const RamSection *can_rotate(int init_bit, int final_bit) const;
774 const RamSection *rotate_in_range(le_bitrange range) const;
775 const RamSection *no_overlap_merge(const RamSection *ad) const;
776 const RamSection *merge(const RamSection *ad) const;
777 const RamSection *condense(const RamSection *) const;
778 const RamSection *better_merge_cand(const RamSection *) const;
779 void gather_shared_params(const RamSection *ad, safe_vector<SharedParameter> &shared_params,
780 bool only_one_overlap_solution) const;
781 PackingConstraint get_pack_info() const { return pack_info; }
782
783 bool is_data_subset_of(const RamSection *ad) const;
784 bool contains(const RamSection *ad_small, int init_bit_pos, int *final_bit_pos) const;
785 bool contains_any_rotation_from_0(const RamSection *ad_small, int init_bit_pos,
786 int *final_bit_pos) const;
787 bool contains(const ALUOperation *ad_alu, int *first_phv_bit_pos = nullptr) const;
788
789 size_t size() const { return action_data_bits.size(); }
790 size_t index() const { return ceil_log2(size()) - 3; }
791 size_t byte_sz() const { return size() / 8; }
792 ParameterPositions parameter_positions(bool same_alias = false) const;
793 std::string parameter_positions_to_string(bool from_p4_program) const;
794 explicit RamSection(int s) : action_data_bits(s, nullptr) {}
795 RamSection(int s, PackingConstraint &pc) : action_data_bits(s, nullptr), pack_info(pc) {}
796 void add_param(int bit, const Parameter *);
797 void add_alu_req(const ALUOperation *rv) { alu_requirements.push_back(rv); }
798 BusInputs bus_inputs() const;
799 std::string get_action_data_bits_str() const {
800 std::stringstream rv;
801 // Merge action data bits to a slice if possible
802 std::vector<std::pair<cstring, le_bitrange>> adb_params;
803 for (auto *adb_param : action_data_bits) {
804 if (!adb_param) continue;
805 if (auto *arg_param = adb_param->to<Argument>()) {
806 if (adb_params.size() != 0) {
807 auto &last_param = adb_params.back();
808 if (last_param.first == adb_param->name()) {
809 last_param.second |= arg_param->param_field();
810 continue;
811 }
812 }
813 adb_params.push_back(std::make_pair(adb_param->name(), arg_param->param_field()));
814 }
815 }
816 rv << "Action Data : " << size() << "'b{";
817 for (auto &a : adb_params) rv << " " << a.first << " : " << a.second;
818 rv << " }";
819 return rv.str();
820 }
821
822 friend std::ostream &operator<<(std::ostream &out, const RamSection &rs) {
823 Log::TempIndent indent;
824 out << Log::endl;
825 out << "Ram Section {" << indent << Log::endl;
826 out << rs.get_action_data_bits_str() << Log::endl;
827 out << "Pack Info: " << indent << rs.pack_info << indent.pop_back() << Log::endl;
828 out << "Alu Req: " << indent << rs.alu_requirements;
829 out << " }";
830 return out;
831 }
832 void dbprint_multiline() const {}
833};
834
835// Actual locations are ACTION_DATA_TABLE, IMMEDIATE & METER_ALU
836// AD_LOCATIONS / ALL_LOCATIONS provide a way to loop over desired locations
837// for (loc = 0; loc < AD_LOCATIONS; ++loc) to iterate over action data locations or
838// for (loc = 0; loc < ALL_LOCATIONS; ++loc) to iterate over all location types
839enum Location_t { ACTION_DATA_TABLE, IMMEDIATE, AD_LOCATIONS, METER_ALU = 2, ALL_LOCATIONS = 3 };
840std::ostream &operator<<(std::ostream &, Location_t);
841
847 const RamSection *section;
848 int byte_offset = -1;
849 explicit RamSectionPosition(const RamSection *sect) : section(sect) {}
850 size_t total_slots_of_type(SlotType_t slot_type) const;
851 friend std::ostream &operator<<(std::ostream &out, const RamSectionPosition &rsp) {
852 if (rsp.section)
853 out << "Ram Section Position { " << *rsp.section << ", byte_offset: " << rsp.byte_offset
854 << " } ";
855 return out;
856 }
857 void dbprint_multiline() const {}
858};
859
868 cstring action_name;
870
872 : action_name(an), all_inputs(ai) {}
873
874 size_t total_slots_of_type(SlotType_t slot_type) const;
875 size_t bits_required() const;
876 size_t adt_bits_required() const;
877 std::array<int, SECT_TYPES> sections_of_size() const;
878 std::array<int, SECT_TYPES> minmax_bit_req() const;
879 std::array<int, SECT_TYPES> min_bit_of_contiguous_sect() const;
880 std::array<bool, SECT_TYPES> can_be_immed_msb(int bits_to_move) const;
881 void move_to_immed_from_adt(safe_vector<RamSectionPosition> &rv, size_t slot_sz,
882 bool move_min_max_bit_req);
883 void move_other_sections_to_immed(int bits_to_move, SlotType_t minmax_sz,
886 friend std::ostream &operator<<(std::ostream &out, const SingleActionPositions &sap) {
887 out << "Single Action Position { name: " << sap.action_name
888 << ", all_inputs: " << Log::TempIndent() << sap.all_inputs << " } ";
889 return out;
890 }
891};
892
894
909 // The information on the P4 parameters within this region
910 const ALUOperation *alu_op;
911 // Whether the data is in ActionData, Immmediate, or a from a Meter ALU operation
912 Location_t loc;
913 // The byte offset within the allocation
914 size_t start_byte;
915
916 public:
917 ALUPosition(const ALUOperation *ao, Location_t l, size_t sb)
918 : alu_op(ao), loc(l), start_byte(sb) {}
919
920 friend std::ostream &operator<<(std::ostream &out, const ALUPosition &pos) {
921 out << "ALU Position" << Log::indent << Log::endl
922 << "op: " << *pos.alu_op << Log::endl
923 << "loc: " << pos.loc << Log::endl
924 << "start_byte: " << pos.start_byte << Log::unindent;
925 return out;
926 }
927};
928
931
938 SingleActionPositions *positions;
939 BusInputs *all_action_inputs;
940 BusInputs current_action_inputs = {{bitvec(), bitvec(), bitvec()}};
943
944 void clear_inputs() {
945 orig_inputs.clear();
946 alloc_inputs.clear();
947 }
948 void build_orig_inputs() {
949 clear_inputs();
950 orig_inputs.insert(orig_inputs.end(), positions->all_inputs.begin(),
951 positions->all_inputs.end());
952 }
953
954 void set_positions() {
955 BUG_CHECK(orig_inputs.empty() && alloc_inputs.size() == positions->all_inputs.size(),
956 "Cannot set the positions of the action as not all have been assigned positions");
957 positions->all_inputs.clear();
958 positions->all_inputs.insert(positions->all_inputs.end(), alloc_inputs.begin(),
959 alloc_inputs.end());
960 }
961 cstring action_name() const { return positions->action_name; }
962
964 : positions(sap), all_action_inputs(aai) {
965 build_orig_inputs();
966 }
967};
968
969// Really could be an Alloc1D of bitvec of size 2, but Alloc1D couldn't hold bitvecs?
970using ModCondMap = std::map<cstring, safe_vector<bitvec>>;
971
972class Format {
973 public:
974 static constexpr int IMMEDIATE_BITS = 32;
975 static constexpr int ACTION_RAM_BYTES = 16;
976 static constexpr int METER_COLOR_SIZE = 8;
977 static constexpr int METER_COLOR_START_BIT = IMMEDIATE_BITS - METER_COLOR_SIZE;
978
979 struct Use {
980 std::map<cstring, safe_vector<ALUPosition>> alu_positions;
983 std::array<BusInputs, AD_LOCATIONS> bus_inputs = {
984 {{{bitvec(), bitvec(), bitvec()}}, {{bitvec(), bitvec(), bitvec()}}}};
985 std::array<int, AD_LOCATIONS> bytes_per_loc = {{0, 0}};
993
994 std::map<cstring, ModCondMap> mod_cond_values;
995
996 safe_vector<ALUPosition> locked_in_all_actions_alu_positions;
997 BusInputs locked_in_all_actions_bus_inputs = {{bitvec(), bitvec(), bitvec()}};
998
1001 int immediate_bits() const { return immediate_mask.max().index() + 1; }
1003 UniqueLocationKey &loc, const ALUPosition **alu_pos_p) const;
1005 const ALUPosition **alu_pos_p) const;
1006
1007 cstring get_format_name(const ALUPosition &alu_pos, bool bitmasked_set = false,
1008 le_bitrange *slot_bits = nullptr,
1009 le_bitrange *postpone_range = nullptr) const;
1010 cstring get_format_name(SlotType_t slot_type, Location_t loc, int byte_offset,
1011 le_bitrange *slot_bits = nullptr,
1012 le_bitrange *postpone_range = nullptr) const;
1013
1014 void clear() {
1015 alu_positions.clear();
1016 bus_inputs = {{{{bitvec(), bitvec(), bitvec()}}, {{bitvec(), bitvec(), bitvec()}}}};
1017 immediate_mask.clear();
1018 full_words_bitmasked.clear();
1019 mod_cond_values.clear();
1020 locked_in_all_actions_alu_positions.clear();
1021 locked_in_all_actions_bus_inputs = {{bitvec(), bitvec(), bitvec()}};
1022 }
1023 bool if_action_has_action_data(cstring action_name) const;
1024 bool if_action_has_action_data_table(cstring action_name) const;
1025
1026 // For templated methods, the declaration has to be in the same location as the
1027 // implementation? C++ is weird
1028 template <typename T>
1029 bool is_byte_offset(int byte_offset) const {
1030 bool found = false;
1031 bool is_template = false;
1032 for (auto &alu_position : locked_in_all_actions_alu_positions) {
1033 if (alu_position.start_byte != static_cast<unsigned>(byte_offset)) continue;
1034 auto param_positions = alu_position.alu_op->parameter_positions();
1035 BUG_CHECK(!param_positions.empty(), "An ALU operation somehow has no parameters");
1036 for (auto &param_pos : param_positions) {
1037 bool template_param = param_pos.second->is<T>();
1038 if (!found) {
1039 found = true;
1040 is_template = template_param;
1041 } else {
1042 BUG_CHECK(is_template == template_param,
1043 "A special parameter, i.e. "
1044 "HashDist, shares its packing with a different speciality");
1045 }
1046 }
1047 }
1048 return is_template;
1049 }
1050 const RamSection *build_locked_in_sect() const;
1051
1052 safe_vector<const ALUPosition *> all_alu_positions() const {
1054 for (auto &act : alu_positions)
1055 for (auto &pos : act.second) rv.push_back(&pos);
1056 return rv;
1057 }
1058 friend std::ostream &operator<<(std::ostream &out, const Use &use);
1059 };
1060
1061 private:
1062 PhvInfo &phv;
1063 const IR::MAU::Table *tbl;
1064 const ReductionOrInfo &red_info;
1065 safe_vector<Use> *uses = nullptr;
1066 SplitAttachedInfo &att_info;
1067 int calc_max_size = 0;
1068 std::map<cstring, RamSec_vec_t> init_ram_sections;
1069
1070 std::array<int, AD_LOCATIONS> bytes_per_loc = {{0, 0}};
1071 safe_vector<BusInputs> action_bus_input_bitvecs;
1072 safe_vector<AllActionPositions> action_bus_inputs;
1073
1074 // Responsible for holding hash, (eventually rng, meter color, stateful counters)
1075 RamSec_vec_t locked_in_all_actions_sects;
1076 BusInputs locked_in_all_actions_input_bitvecs;
1077 AllActionPositions locked_in_all_actions_inputs;
1078
1079 void create_argument(ALUOperation &alu, ActionAnalysis::ActionParam &read,
1080 le_bitrange container_bits, const IR::MAU::ConditionalArg *ca);
1081 void create_constant(ALUOperation &alu, const IR::Expression *read, le_bitrange container_bits,
1082 int &constant_alias_index, const IR::MAU::ConditionalArg *ca);
1083 void create_hash(ALUOperation &alu, ActionAnalysis::ActionParam &read,
1084 le_bitrange container_bits);
1085 void create_hash_constant(ALUOperation &alu, ActionAnalysis::ActionParam &read,
1086 le_bitrange container_bits);
1087 void create_random_number(ALUOperation &alu, ActionAnalysis::ActionParam &read,
1088 le_bitrange container_bits, cstring action_name);
1089 void create_random_padding(ALUOperation &alu, le_bitrange padding_bits);
1090 void create_meter_color(ALUOperation &alu, ActionAnalysis::ActionParam &read,
1091 le_bitrange container_bits);
1092 void create_mask_argument(ALUOperation &alu, ActionAnalysis::ActionParam &read,
1093 le_bitrange container_bits);
1094 void create_mask_constant(ALUOperation &alu, bitvec value, le_bitrange container_bits,
1095 int &constant_alias_index);
1096
1097 bool fix_bitwise_overwrite(ALUOperation &alu,
1098 const ActionAnalysis::ContainerAction &cont_action,
1099 const size_t container_size, const bitvec &total_write_bits,
1100 int &constant_alias_index, int &alias_required_reads);
1101
1102 void create_alu_ops_for_action(ActionAnalysis::ContainerActionsMap &ca_map,
1103 cstring action_name);
1104 bool analyze_actions(FormatType_t format_type);
1105
1106 void initial_possible_condenses(PossibleCondenses &condenses, const RamSec_vec_t &ram_sects);
1107 void incremental_possible_condenses(PossibleCondenses &condense, const RamSec_vec_t &ram_sects);
1108
1109 bitvec bytes_in_use(BusInputs &all_inputs) const {
1110 return all_inputs[BYTE] | all_inputs[HALF] | all_inputs[FULL];
1111 }
1112 bool is_better_condense(RamSec_vec_t &ram_sects, const RamSection *best, size_t best_skip1,
1113 size_t best_skip2, const RamSection *comp, size_t comp_skip1,
1114 size_t comp_skip2);
1115 void condense_action(cstring action_name, RamSec_vec_t &ram_sects);
1116 void shrink_possible_condenses(PossibleCondenses &pc, RamSec_vec_t &ram_sects,
1117 const RamSection *ad, size_t i_pos, size_t j_pos);
1118 void set_ram_sect_byte(SingleActionAllocation &single_action_alloc,
1119 bitvec &allocated_slots_in_action, RamSectionPosition &ram_sect,
1120 int byte_position);
1121 bitvec adt_iteration(SlotType_t slot_type, int &iteration);
1122 void alloc_adt_slots_of_size(SlotType_t slot_size, SingleActionAllocation &single_action_alloc,
1123 int max_bytes_required);
1124 void alloc_immed_slots_of_size(SlotType_t size, SingleActionAllocation &single_action_alloc,
1125 int max_bytes_required);
1126 void verify_placement(SingleActionAllocation &single_action_alloc);
1127
1128 void determine_single_action_input(SingleActionAllocation &single_action_alloc,
1129 int max_bytes_required);
1130 bool determine_next_immediate_bytes(bool immediate_forced);
1131 bool determine_bytes_per_loc(bool &initialized, IR::MAU::Table::ImmediateControl_t imm_ctrl);
1132
1133 void assign_action_data_table_bytes(AllActionPositions &all_bus_inputs,
1134 BusInputs &total_inputs);
1135 void assign_immediate_bytes(AllActionPositions &all_bus_inputs, BusInputs &total_inputs,
1136 int max_bytes_needed);
1137 void assign_RamSections_to_bytes();
1138
1139 const ALUOperation *finalize_locked_shift_alu_operation(const RamSection *ram_sect,
1140 const ALUOperation *init_ad_alu,
1141 int right_shift);
1142 const ALUOperation *finalize_alu_operation(const RamSection *ram_sect,
1143 const ALUOperation *init_ad_alu, int right_shift,
1144 int section_byte_offset, int *rot_alias_idx);
1145 void build_single_ram_sect(RamSectionPosition &ram_sect, Location_t loc,
1146 safe_vector<ALUPosition> &alu_positions, BusInputs &verify_inputs,
1147 int *rot_alias_idx);
1148 void build_locked_in_format(Use &use);
1149 void build_potential_format(bool immediate_forced);
1150
1151 public:
1152 void set_uses(safe_vector<Use> *u) { uses = u; }
1153 void allocate_format(IR::MAU::Table::ImmediateControl_t imm_ctrl, FormatType_t format_type);
1154 Format(PhvInfo &p, const IR::MAU::Table *t, const ReductionOrInfo &ri, SplitAttachedInfo &sai)
1155 : phv(p), tbl(t), red_info(ri), att_info(sai) {}
1156};
1157
1158} // namespace ActionData
1159
1160#endif /* BACKENDS_TOFINO_BF_P4C_MAU_ACTION_FORMAT_H_ */
Definition action_format.h:485
bool has_param() const
Definition action_format.h:572
bitvec static_entry_of_constants() const
Definition action_format.cpp:1124
const RamSection * create_meter_alu_RamSection() const
Definition action_format.cpp:1229
bitvec static_entry_of_arg(const Argument *arg, bitvec value) const
Definition action_format.cpp:1091
const RamSection * create_RamSection(bool shift_to_lsb) const
Definition action_format.cpp:944
const RamSection * create_meter_color_RamSection() const
Definition action_format.cpp:1178
bitvec phv_bytes() const
Definition action_format.cpp:931
const ALUOperation * add_right_shift(int right_shift, int *rot_alias_idx) const
Definition action_format.cpp:1029
Definition action_format.h:160
const Parameter * overlap(const Parameter *ad, bool guaranteed_one_overlap, le_bitrange *my_overlap, le_bitrange *ad_overlap) const override
Definition action_format.cpp:77
Definition action_format.h:216
const Parameter * get_extended_param(uint32_t extension, const Parameter *ad) const override
Definition action_format.cpp:145
const Parameter * overlap(const Parameter *ad, bool only_one_overlap_solution, le_bitrange *my_overlap, le_bitrange *ad_overlap) const override
Definition action_format.cpp:173
bool is_next_bit_of_param(const Parameter *ad, bool same_alias) const override
Definition action_format.cpp:131
Definition action_format.h:972
void allocate_format(IR::MAU::Table::ImmediateControl_t imm_ctrl, FormatType_t format_type)
Definition action_format.cpp:3660
Definition action_format.h:247
const Parameter * overlap(const Parameter *ad, bool only_one_overlap_solution, le_bitrange *my_overlap, le_bitrange *ad_overlap) const override
Definition action_format.cpp:229
const Parameter * overlap(const Parameter *ad, bool only_one_overlap_solution, le_bitrange *my_overlap, le_bitrange *ad_overlap) const override
Definition action_format.cpp:585
Definition action_format.h:372
Definition action_format.h:666
bool can_rotate(int bit_width, int init_bit, int final_bit) const
Definition action_format.cpp:628
PackingConstraint merge(const PackingConstraint &pc, const LocalPacking &lp, const LocalPacking &pc_lp) const
Definition action_format.cpp:797
int bit_rotation_position(int bit_width, int init_bit, int final_bit, int init_bit_comp) const
Definition action_format.cpp:852
void rotate(RotationInfo &ri, int init_bit, int final_bit)
Definition action_format.cpp:755
bool can_rotate_in_range(LocalPacking &lp, le_bitrange open_range, int &final_bit) const
Definition action_format.cpp:716
Definition action_format.h:53
ModConditionally_t _cond_type
Definition action_format.h:88
Definition action_format.h:757
ParameterPositions parameter_positions(bool same_alias=false) const
Definition action_format.cpp:1294
void gather_shared_params(const RamSection *ad, safe_vector< SharedParameter > &shared_params, bool only_one_overlap_solution) const
Definition action_format.cpp:1345
safe_vector< le_bitrange > open_holes() const
Definition action_format.cpp:1375
safe_vector< const ALUOperation * > alu_requirements
Definition action_format.h:768
bool is_data_subset_of(const RamSection *ad) const
Definition action_format.cpp:1595
BusInputs bus_inputs() const
Definition action_format.cpp:1706
const RamSection * rotate_in_range(le_bitrange range) const
Definition action_format.cpp:1439
bool contains(const RamSection *ad_small, int init_bit_pos, int *final_bit_pos) const
Definition action_format.cpp:1610
const RamSection * condense(const RamSection *) const
Definition action_format.cpp:1514
bool contains_any_rotation_from_0(const RamSection *ad_small, int init_bit_pos, int *final_bit_pos) const
Definition action_format.cpp:1639
const RamSection * no_overlap_merge(const RamSection *ad) const
Definition action_format.cpp:1454
const RamSection * expand_to_size(size_t expand_size) const
Definition action_format.cpp:1263
Definition action_format.h:275
bool rand_nums_overlap_into(const RandomNumber *rn) const
Definition action_format.cpp:368
const Parameter * overlap(const Parameter *ad, bool only_one_overlap_solution, le_bitrange *my_overlap, le_bitrange *ad_overlap) const override
Definition action_format.cpp:335
Definition action_format.h:340
Definition stringify.h:33
Definition bitvec.h:120
Definition cstring.h:85
Definition safe_vector.h:27
Definition phv.h:176
Definition phv_fields.h:1095
Definition attached_info.h:235
Definition action_format.cpp:30
Definition attached_output.cpp:24
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition action_analysis.h:65
Definition action_analysis.h:346
Definition action_format.h:430
safe_vector< le_bitrange > slot_bits_brs(PHV::Container cont) const
Definition action_format.cpp:906
Definition action_format.h:908
Definition action_format.h:979
bitvec immediate_mask
Definition action_format.h:988
void determine_mod_cond_maps()
Definition action_format.cpp:2015
bitvec full_words_bitmasked
Definition action_format.h:992
void determine_immediate_mask()
Definition action_format.cpp:1982
std::array< BusInputs, AD_LOCATIONS > bus_inputs
Definition action_format.h:983
const ALUParameter * find_locked_in_all_actions_param_alloc(UniqueLocationKey &loc, const ALUPosition **alu_pos_p) const
Definition action_format.cpp:2060
const ALUParameter * find_param_alloc(UniqueLocationKey &loc, const ALUPosition **alu_pos_p) const
Definition action_format.cpp:2094
Definition action_format.h:645
bitvec bits_in_use
Definition action_format.h:649
int bit_width
Definition action_format.h:647
Definition action_format.h:846
Definition action_format.h:630
Definition action_format.h:611
Definition action_format.h:937
Definition action_format.h:867
std::array< bool, SECT_TYPES > can_be_immed_msb(int bits_to_move) const
Definition action_format.cpp:1863
safe_vector< RamSectionPosition > best_inputs_to_move(int bits_to_move)
Definition action_format.cpp:1953
std::array< int, SECT_TYPES > sections_of_size() const
Definition action_format.cpp:1794
size_t total_slots_of_type(SlotType_t slot_type) const
Definition action_format.cpp:1761
void move_other_sections_to_immed(int bits_to_move, SlotType_t minmax_sz, safe_vector< RamSectionPosition > &immed_vec)
Definition action_format.cpp:1897
size_t adt_bits_required() const
Definition action_format.cpp:1781
std::array< int, SECT_TYPES > minmax_bit_req() const
Definition action_format.cpp:1810
std::array< int, SECT_TYPES > min_bit_of_contiguous_sect() const
Definition action_format.cpp:1823
Definition action_format.h:454
int lo
Definition lib/bitrange.h:694
ssize_t size() const
Definition lib/bitrange.h:539
bool contains(int index) const
Definition lib/bitrange.h:594
Definition id.h:28
Definition ixbar_expr.h:209
Definition reduction_or.h:47