P4C
The P4 Compiler
Loading...
Searching...
No Matches
phv_fields.h
1
19#ifndef BF_P4C_PHV_PHV_FIELDS_H_
20#define BF_P4C_PHV_PHV_FIELDS_H_
21
22#include <functional>
23#include <limits>
24#include <optional>
25
26#include <boost/range/irange.hpp>
27
28#include "backends/tofino/bf-p4c/bf-p4c-options.h"
29#include "backends/tofino/bf-p4c/device.h"
30#include "backends/tofino/bf-p4c/ir/bitrange.h"
31#include "backends/tofino/bf-p4c/ir/thread_visitor.h"
32#include "backends/tofino/bf-p4c/ir/tofino_write_context.h"
33#include "backends/tofino/bf-p4c/lib/assoc.h"
34#include "backends/tofino/bf-p4c/lib/cmp.h"
35#include "backends/tofino/bf-p4c/lib/union_find.hpp"
36#include "backends/tofino/bf-p4c/phv/constraints/constraints.h"
37#include "backends/tofino/bf-p4c/phv/phv.h"
38#include "backends/tofino/bf-p4c/phv/phv_parde_mau_use.h"
39#include "backends/tofino/bf-p4c/phv/utils/slice_alloc.h"
40#include "ir/ir.h"
41#include "lib/algorithm.h"
42#include "lib/map.h"
43#include "lib/ordered_map.h"
44#include "lib/ordered_set.h"
45#include "lib/range.h"
46#include "lib/safe_vector.h"
47#include "lib/symbitmatrix.h"
48
49using namespace P4;
50
52 explicit FieldAlignment(nw_bitrange bitLayout);
53 explicit FieldAlignment(le_bitrange bitLayout);
54
55 bool operator==(const FieldAlignment &other) const;
56 bool operator!=(const FieldAlignment &other) const;
57
58 bool isByteAligned() const { return align == 0; }
59
61 unsigned align;
62};
63
64std::ostream &operator<<(std::ostream &, const FieldAlignment &);
65
66namespace PHV {
67
68using SolitaryReason = Constraints::SolitaryConstraint::SolitaryReason;
69using DigestType = Constraints::DigestConstraint::DigestType;
70using AlignmentReason = Constraints::AlignmentConstraint::AlignmentReason;
71
72class FieldSlice;
73
74enum class FieldKind : unsigned short {
75 header = 0, // header fields
76 metadata = 1, // metadata fields
77 pov = 2 // POV fields, eg. $valid
78};
79
80enum class FieldAccessType { NONE = 0, R = 1, W = 2, RW = 3 };
81
84 public:
85 enum class Type { PARSER, TABLE, DEPARSER };
86 Type type;
87
89 const IR::MAU::Table *table;
90
91 private:
93 explicit AllocContext(Type type) : type(type), table(nullptr) {
94 BUG_CHECK(type != Type::TABLE, "Improper usage of PHV::AllocContext interface");
95 }
96
98 explicit AllocContext(const IR::MAU::Table *table) : type(Type::TABLE), table(table) {
99 BUG_CHECK(table, "Improper usage of PHV::AllocContext interface");
100 }
101
102 public:
103 bool is_parser() const { return type == Type::PARSER; }
104 bool is_deparser() const { return type == Type::DEPARSER; }
105 bool is_table() const { return type == Type::TABLE; }
106 cstring typeStr() const {
107 if (is_parser())
108 return "PARSER"_cs;
109 else if (is_deparser())
110 return "DEPARSER"_cs;
111 else if (is_table())
112 return "TABLE"_cs;
113 return "NONE"_cs;
114 }
115
116 static const AllocContext *PARSER;
117 static const AllocContext *DEPARSER;
118
123 static const AllocContext *of_unit(const IR::BFN::Unit *unit) {
124 if (!unit) return nullptr;
125 if (unit->is<IR::BFN::ParserState>() || unit->is<IR::BFN::Parser>() ||
126 unit->is<IR::BFN::GhostParser>())
127 return PARSER;
128 if (unit->to<IR::BFN::Deparser>()) return DEPARSER;
129 if (auto table = unit->to<IR::MAU::Table>()) return new AllocContext(table);
130 BUG("Improper usage of PHV::AllocContext interface. Not a parser, deparser, or table: %1%",
131 unit);
132 }
133};
134std::ostream &operator<<(std::ostream &, const AllocContext &);
135
137 bool is_bitwise_op;
138 bool is_salu_inst;
139 const IR::MAU::Instruction *inst;
140 FieldAccessType rw_type;
141 le_bitrange range; // If range.size() == this->size, then the operation is
142 // over the whole field.
143 FieldOperation(bool is_bitwise_op, bool is_salu_inst, const IR::MAU::Instruction *inst,
144 FieldAccessType rw_type, le_bitrange range)
145 : is_bitwise_op(is_bitwise_op),
146 is_salu_inst(is_salu_inst),
147 inst(inst),
148 rw_type(rw_type),
149 range(range) {}
150};
151
152class Field;
153
154class Field : public LiftLess<Field> {
155 public:
162
164 int id = 0;
165
167 gress_t gress = INGRESS;
168
173 bool isGhostField() const {
174 if (BackendOptions().arch == "tna") {
175 return name.startsWith("ghost::");
176 }
177 if (name.startsWith("ghost::")) return true;
178 // A field valid in both ingress && ghost e.g. ping pong reg does not
179 // have a 'ghost::" prefix and above check is not sufficient to identify
180 // it to be valid ghost field.
181 if (name.startsWith("ingress::")) return false;
182 if (name.startsWith("egress::")) return false;
183 // FIXME: For no prefix we assume this to be valid in ghost field. Needs
184 // to be fixed by relying on 'gress' field rather than prefix
185 return true;
186 }
187
190 return name.startsWith("__phv_dummy_padding__");
191 }
192
194 int size = 0;
195
198 std::optional<FieldAlignment> alignment;
200 std::list<std::pair<FieldAlignment, Util::SourceInfo>> alignmentSources;
201
204
206 int offset = 0;
207
209 bool metadata = false;
210
212 bool intrinsic_i = false;
213
217
219 bool bridged = false;
220
222 bool padding = false;
223
226 bool overlayable = false;
227
229 bool emitted_i = false;
230
231 // Define field allocation status.
232 enum alloc_code_t {
233 EMPTY = 0,
234 REFERENCED = 1 << 0, // Field is referenced
235 HAS_PHV_ALLOCATION = 1 << 1, // Field is at least partially PHV-allocated
236 FULLY_PHV_ALLOCATED = 1 << 2, // Field is fully PHV-allocated
237 HAS_CLOT_ALLOCATION = 1 << 3, // Field is at least partially CLOT-allocated
238 };
239
240 typedef unsigned AllocState;
241
244 Field *member_field;
245 int field_list;
246 bool operator==(const mirror_field_list_t &rhs) const {
247 return rhs.member_field == this->member_field && rhs.field_list == this->field_list;
248 }
249 bool operator!=(const mirror_field_list_t &rhs) const { return !(*this == rhs); }
250 } mirror_field_list = {nullptr, -1};
251
253 bool pov = false;
254
270 const PHV::Field *aliasSource = nullptr;
271
273 std::optional<Util::SourceInfo> srcInfo;
274
278 void setStartBits(PHV::Size size, bitvec startPositions);
279
283
285 cstring header() const { return name.before(strrchr(name.c_str(), '.')); }
286
287 private:
290 std::optional<cstring> externalName_i;
291
292 // constraints on this field
293 //
295 bool flexible_i = false;
296 bool parsed_i = false;
297 bool deparsed_i = false;
301 // Solitary Constraint: This field cannot be packed with any other field (although it may share
302 // a container with another field through overlay).
304
305 // Digest Constraint: This field is used in a digest. This constraint also contains the type of
306 // digest this field is used in.
308
309 // Alignment Constraint: This field must be aligned at given offset within a container.
311
312 bool deparsed_bottom_bits_i = false;
313 bool deparsed_top_bits_i = false;
315 bool exact_containers_i = false;
316
317 bool deparsed_to_tm_i = false;
318 size_t numNoPack = 0;
320
321 bool is_checksummed_i = false;
322 bool mocha_i = false;
324 bool dark_i = false;
326 bool deparser_zero_i = false;
328 bool write_force_immediate_i = false;
330 ordered_set<int> wide_arith_start_bit_;
335 bool ignore_alloc_i = false;
336
337 // true if the field is part of Type_FixedSizeHeader, used to represent resubmit/phase0 data.
338 bool fixed_size_i = false;
339
340 bool same_container_group_i = false;
343
345 PHV::Size prefer_container_size_i = PHV::Size::null;
346
353 bool no_holes_i = false;
354
355 bool upcasted_i = false;
357
363 int maxContainerBytes_i = -1;
364
369 std::vector<le_bitrange> no_split_ranges_i;
370
382 bool is_marshaled_i = false;
383
386 std::optional<bitvec> limited_container_ids_i = std::nullopt;
387
388 // Maximum field size in the same SuperCluster with no_split constraint.
389 // Used by bridged metadata packing to insert padding after the 'no_split'
390 // bridged field, if the bridged field is smaller than the related
391 // 'no_split' field.
392 int no_split_container_size_i = -1;
393
395 safe_vector<FieldOperation> operations_i;
396
397 // Do not allocate this field in phv or clots. Use for local parser variables.
398 bool avoid_alloc_i = false;
399
402 safe_vector<PHV::AllocSlice> alloc_slice_i;
403
404 friend std::ostream &operator<<(std::ostream &out, const Field &field);
405
406 public:
407 bool is_flexible() const { return flexible_i; }
408 void set_flexible(bool b) { flexible_i = b; }
410 bool is_tphv_candidate(const PhvUse &uses) const;
411 bool is_mocha_candidate() const { return mocha_i; }
412 bool is_dark_candidate() const { return dark_i; }
413 bool is_deparser_zero_candidate() const { return deparser_zero_i; }
414 void set_mocha_candidate(bool c) { mocha_i = c; }
415 void set_dark_candidate(bool c) { dark_i = c; }
416 void set_deparser_zero_candidate(bool c) { deparser_zero_i = c; }
417
418 bool is_ignore_alloc() const { return ignore_alloc_i; }
419 void set_ignore_alloc(bool b) { ignore_alloc_i = b; }
420
421 bool is_avoid_alloc() const { return avoid_alloc_i; }
422 void set_avoid_alloc(bool a) { avoid_alloc_i = a; }
423
424 bool is_padding() const { return padding; }
425 void set_padding(bool p) { padding = p; }
426 bool is_overlayable() const { return overlayable; }
427 void set_overlayable(bool p) { overlayable = p; }
428 bool is_fixed_size_header() const { return fixed_size_i; }
429 void set_fixed_size_header(bool f) { fixed_size_i = f; }
430
431 bool emitted() const { return emitted_i; }
432 void set_emitted(bool b) { emitted_i = b; }
433
434 bool is_upcasted() const { return upcasted_i; }
435 void set_upcasted(bool c) { upcasted_i = c; }
436
437 //
438 // constraints
439 //
440 bool parsed() const { return parsed_i; }
441 void set_parsed(bool b) { parsed_i = b; }
444 bool deparsed() const { return deparsed_i; }
445 void set_deparsed(bool b) { deparsed_i = b; }
446
447 bool is_solitary() const { return solitary_i.hasConstraint(); }
448 void set_solitary(uint32_t reason) { solitary_i.addConstraint(reason); }
449
450 const Constraints::SolitaryConstraint &getSolitaryConstraint() const { return solitary_i; }
451
452 bool is_digest() const { return digest_i.hasConstraint(); }
453 void set_digest(uint32_t source) { digest_i.addConstraint(source); }
454
455 const Constraints::DigestConstraint &getDigestConstraint() const { return digest_i; }
456
457 // only update the alignment constraint used by bridged packing
458 void set_alignment(Constraints::AlignmentConstraint &c) { alignment_i = c; }
459 void set_alignment(unsigned r, unsigned v) { alignment_i.addConstraint(r, v); }
460 void erase_alignment() { alignment_i.eraseConstraint(); }
461 const Constraints::AlignmentConstraint &getAlignmentConstraint() const { return alignment_i; }
462
463 bool deparsed_bottom_bits() const { return deparsed_bottom_bits_i; }
464 void set_deparsed_bottom_bits(bool b) { deparsed_bottom_bits_i = b; }
465 bool deparsed_top_bits() const { return deparsed_top_bits_i; }
466 void set_deparsed_top_bits(bool b) { deparsed_top_bits_i = b; }
467 bool exact_containers() const { return exact_containers_i; }
468 void set_exact_containers(bool b) { exact_containers_i = b; }
469 void set_written_in_force_immediate(bool b) { write_force_immediate_i = b; }
470 bool written_in_force_immediate_table() const { return write_force_immediate_i; }
471
472 void set_no_split_container_size(int size) { no_split_container_size_i = size; }
473 int no_split_container_size() const { return no_split_container_size_i; }
474 bool no_split() const;
475 void set_no_split(bool b);
476 bool no_split_at(int pos) const;
477 bool has_no_split_at_pos() const;
478 void set_no_split_at(le_bitrange range); // The indicated slice cannot be split.
479
480 bool same_container_group() const { return same_container_group_i; }
481 void set_same_container_group(bool b) { same_container_group_i = b; }
482
483 bool no_holes() const { return no_holes_i; }
484 void set_no_holes(bool b) { no_holes_i = b; }
485
486 void set_prefer_container_size(PHV::Size cnt_size) { prefer_container_size_i = cnt_size; }
487 PHV::Size prefer_container_size() const { return prefer_container_size_i; }
488
489 bool used_in_wide_arith() const { return wide_arith_start_bit_.size() > 0; }
490
491 bool bit_used_in_wide_arith(int slice_bit) const {
492 for (auto bit : wide_arith_start_bit_) {
493 if (slice_bit >= bit && slice_bit < (bit + 64)) return true;
494 }
495 return false;
496 }
497 bool bit_is_wide_arith_lo(int slice_bit) const {
498 for (auto bit : wide_arith_start_bit_) {
499 if (slice_bit < (bit + 32)) return true;
500 }
501 return false;
502 }
503
504 // Only called for least signficant bit of wide arith operation.
505 // Returns true if could successfully add constraint.
506 bool add_wide_arith_start_bit(int start_bit) {
507 for (auto bit : wide_arith_start_bit_) {
508 if (bit != start_bit) {
509 // conflicting constraint if start bit has to go to both
510 // odd and even container locations
511 if (bit < start_bit && start_bit < (bit + 64)) return false;
512 if (start_bit < bit && bit < (start_bit + 64)) return false;
513 }
514 }
515 wide_arith_start_bit_.insert(start_bit);
516 return true;
517 }
518 std::vector<le_bitrange> no_split_ranges() const { return no_split_ranges_i; }
519
520 bool deparsed_to_tm() const { return deparsed_to_tm_i; }
521 void set_deparsed_to_tm(bool b) { deparsed_to_tm_i = b; }
522
523 bool is_marshaled() const { return is_marshaled_i; }
524 void set_is_marshaled(bool b) { is_marshaled_i = b; }
525
526 bool is_checksummed() const { return is_checksummed_i; }
527 void set_is_checksummed(bool b) { is_checksummed_i = b; }
528 bool is_intrinsic() const { return intrinsic_i; }
529 void set_intrinsic(bool b) { intrinsic_i = b; }
530 bool is_invalidate_from_arch() const { return invalidate_from_arch_i; }
531 void set_invalidate_from_arch(bool b) { invalidate_from_arch_i = b; }
532
533 void set_limited_container_ids(const std::optional<bitvec> &ids) {
534 limited_container_ids_i = ids;
535 }
536 const std::optional<bitvec> &limited_container_ids() const { return limited_container_ids_i; }
537
538 // @returns the set of MAU operations on this field.
539 const safe_vector<FieldOperation> &operations() const { return operations_i; }
540
541 // @returns the set of MAU operations on this field.
542 safe_vector<FieldOperation> &operations() { return operations_i; }
543
544 void set_num_pack_conflicts(size_t no) { numNoPack = no; }
545
546 size_t num_pack_conflicts() const { return numNoPack; }
547
548 bool hasMaxContainerBytesConstraint() const { return maxContainerBytes_i != -1; }
549
550 int getMaxContainerBytes() const { return maxContainerBytes_i; }
551
552 void setMaxContainerBytes(int size) { maxContainerBytes_i = size; }
553
555 bool isPacketField() const { return (!metadata && !pov); }
556
561 const PHV::AllocSlice &for_bit(int bit) const;
562
584 void foreach_byte(le_bitrange r, const PHV::AllocContext *ctxt, const PHV::FieldUse *use,
585 std::function<void(const PHV::AllocSlice &)> fn,
586 SliceMatch useTblRefs = SliceMatch::DFLT) const;
587 void foreach_byte(le_bitrange r, const IR::MAU::Table *ctxt, const PHV::FieldUse *use,
588 std::function<void(const PHV::AllocSlice &)> fn,
589 SliceMatch useTblRefs = SliceMatch::DFLT) const {
590 foreach_byte(r, PHV::AllocContext::of_unit(ctxt), use, fn, useTblRefs);
591 }
592
593 void foreach_byte(const PHV::AllocContext *ctxt, const PHV::FieldUse *use,
594 std::function<void(const PHV::AllocSlice &)> fn,
595 SliceMatch useTblRefs = SliceMatch::DFLT) const {
596 foreach_byte(StartLen(0, this->size), ctxt, use, fn, useTblRefs);
597 }
598 void foreach_byte(const IR::MAU::Table *ctxt, const PHV::FieldUse *use,
599 std::function<void(const PHV::AllocSlice &)> fn,
600 SliceMatch useTblRefs = SliceMatch::DFLT) const {
601 foreach_byte(PHV::AllocContext::of_unit(ctxt), use, fn, useTblRefs);
602 }
603
610 void foreach_byte(const le_bitrange *r, const PHV::AllocContext *ctxt, const PHV::FieldUse *use,
611 std::function<void(const PHV::AllocSlice &)> fn,
612 SliceMatch useTblRefs = SliceMatch::DFLT) const {
613 foreach_byte(r ? *r : StartLen(0, this->size), ctxt, use, fn, useTblRefs);
614 }
615 void foreach_byte(const le_bitrange *r, const IR::MAU::Table *ctxt, const PHV::FieldUse *use,
616 std::function<void(const PHV::AllocSlice &)> fn,
617 SliceMatch useTblRefs = SliceMatch::DFLT) const {
618 foreach_byte(r, PHV::AllocContext::of_unit(ctxt), use, fn, useTblRefs);
619 }
620
625 const std::vector<PHV::AllocSlice> get_combined_alloc_bytes(
626 const PHV::AllocContext *ctxt, const PHV::FieldUse *use,
627 SliceMatch useTblRefs = SliceMatch::DFLT) const;
628
633 const std::vector<PHV::AllocSlice> get_combined_alloc_slices(le_bitrange bits,
634 const PHV::AllocContext *ctxt,
635 const PHV::FieldUse *use) const;
636
641 void foreach_alloc(le_bitrange r, const PHV::AllocContext *ctxt, const PHV::FieldUse *use,
642 std::function<void(const PHV::AllocSlice &)> fn,
643 SliceMatch useTblRefs = SliceMatch::DFLT) const;
644
645 void foreach_alloc(le_bitrange r, const IR::MAU::Table *ctxt, const PHV::FieldUse *use,
646 std::function<void(const PHV::AllocSlice &)> fn,
647 SliceMatch useTblRefs = SliceMatch::DFLT) const {
648 foreach_alloc(r, PHV::AllocContext::of_unit(ctxt), use, fn, useTblRefs);
649 }
650
651 void foreach_alloc(le_bitrange r, std::function<void(const PHV::AllocSlice &)> fn,
652 SliceMatch useTblRefs = SliceMatch::DFLT) const {
653 foreach_alloc(r, (PHV::AllocContext *)nullptr, nullptr, fn, useTblRefs);
654 }
655
661 void foreach_alloc(const PHV::AllocContext *ctxt, const PHV::FieldUse *use,
662 std::function<void(const PHV::AllocSlice &)> fn,
663 SliceMatch useTblRefs = SliceMatch::DFLT) const {
664 foreach_alloc(StartLen(0, this->size), ctxt, use, fn, useTblRefs);
665 }
666
667 void foreach_alloc(const IR::MAU::Table *ctxt, const PHV::FieldUse *use,
668 std::function<void(const PHV::AllocSlice &)> fn,
669 SliceMatch useTblRefs = SliceMatch::DFLT) const {
670 foreach_alloc(PHV::AllocContext::of_unit(ctxt), use, fn, useTblRefs);
671 }
672
673 void foreach_alloc(std::function<void(const PHV::AllocSlice &)> fn,
674 SliceMatch useTblRefs = SliceMatch::DFLT) const {
675 foreach_alloc((PHV::AllocContext *)nullptr, nullptr, fn, useTblRefs);
676 }
677
684 void foreach_alloc(const le_bitrange *r, const PHV::AllocContext *ctxt,
685 const PHV::FieldUse *use, std::function<void(const PHV::AllocSlice &)> fn,
686 SliceMatch useTblRefs = SliceMatch::DFLT) const {
687 foreach_alloc(r ? *r : StartLen(0, this->size), ctxt, use, fn, useTblRefs);
688 }
689
690 void foreach_alloc(const le_bitrange *r, const IR::MAU::Table *ctxt, const PHV::FieldUse *use,
691 std::function<void(const PHV::AllocSlice &)> fn,
692 SliceMatch useTblRefs = SliceMatch::DFLT) const {
693 foreach_alloc(r, PHV::AllocContext::of_unit(ctxt), use, fn, useTblRefs);
694 }
695
698 int container_bytes(std::optional<le_bitrange> bits = std::nullopt) const;
699
701 void clear_alloc() { alloc_slice_i.clear(); }
702
704 void add_alloc(const PHV::AllocSlice &alloc) { alloc_slice_i.push_back(alloc); }
705
706 PHV::AllocSlice *add_and_return_alloc(const Field *f, PHV::Container c, int fb, int cb, int w,
707 const ActionSet &a) {
708 alloc_slice_i.emplace_back(f, c, fb, cb, w, a);
709 unsigned size = alloc_slice_i.size();
710 return &(alloc_slice_i[size - 1]);
711 }
712
714 void set_alloc(const safe_vector<PHV::AllocSlice> &alloc) { alloc_slice_i = alloc; }
715
717 const safe_vector<PHV::AllocSlice> &get_alloc() const { return alloc_slice_i; }
718
719 safe_vector<PHV::AllocSlice> &get_alloc() { return alloc_slice_i; }
720
722 size_t alloc_size() const { return alloc_slice_i.size(); }
723
725 bool is_unallocated() const { return alloc_slice_i.empty(); }
726
728 void sort_alloc() {
729 std::sort(alloc_slice_i.begin(), alloc_slice_i.end(),
731 if (l.field_slice().lo != r.field_slice().lo)
732 return l.field_slice().lo > r.field_slice().lo;
733 return l.getEarliestLiveness().first > r.getEarliestLiveness().first;
734 });
735 }
736
739 void updateAlignment(PHV::AlignmentReason, const FieldAlignment &newAlignment,
740 const Util::SourceInfo &newAlignmentSource);
741
743 void eraseAlignment();
744
755 void updateValidContainerRange(nw_bitrange newValidRange);
756
759 cstring externalName() const { return externalName_i ? *externalName_i : name; }
760
763 bool hasExternalName() const { return externalName_i != std::nullopt; }
764
767 void setExternalName(cstring name) { externalName_i = name; }
768
770 void clearExternalName() { externalName_i = std::nullopt; }
771
798
802 int start = 8 * (offset / 8);
803 int len = (8 * ROUNDUP(offset + size, 8)) - start;
804 return StartLen(start, len);
805 }
806
808 bool hasPhvAllocation(AllocState s) const {
809 return (s & HAS_PHV_ALLOCATION) || (s & FULLY_PHV_ALLOCATED);
810 }
811 bool hasClotAllocation(AllocState s) const { return s & HAS_CLOT_ALLOCATION; }
812
814 bool hasAllocation(AllocState s) const { return hasPhvAllocation(s) || hasClotAllocation(s); }
815
816 bool fullyPhvAllocated(AllocState s) const { return s & FULLY_PHV_ALLOCATED; }
817 bool partiallyPhvAllocated(AllocState s) const {
818 return hasPhvAllocation(s) && !fullyPhvAllocated(s);
819 }
820 bool isReferenced(AllocState s) const { return (s & REFERENCED) || hasAllocation(s); }
821
822 private:
825
826 // TODO: This is currently only used for SALU operands. However,
827 // it's general enough to support bit-in-byte alignment requirements
828 // (alignment_i), valid container range requirements, and deparsed_to_tm.
829 std::map<PHV::Size, bitvec> startBitsByContainerSize_i;
830
831 public:
832 Field() {
833 for (auto size : Device::phvSpec().containerSizes())
834 startBitsByContainerSize_i[size] = bitvec(0, int(size));
835 }
836
838 //
839 // The precise ordering here is unimportant, as long as it is stable across different compiler
840 // runs.
841 bool operator<(const Field &other) const { return name < other.name; }
842
849};
850
856 public:
857 AbstractField() {}
858 virtual ~AbstractField() {}
859 virtual int size() const = 0;
860 virtual const PHV::Field *field() const = 0;
861 virtual const le_bitrange &range() const = 0;
862 template <typename T>
863 const T &as() const {
864 return dynamic_cast<const T &>(this);
865 }
866 template <typename T>
867 const T *to() const {
868 return dynamic_cast<const T *>(this);
869 }
870 template <typename T>
871 bool is() const {
872 return to<T>() != nullptr;
873 }
874 static AbstractField *create(const PhvInfo &, const IR::Expression *);
875};
876
880class Constant : public AbstractField {
881 le_bitrange range_i;
882
883 public:
884 explicit Constant(const IR::Constant *value) : value(value) {
885 range_i = {0, value->type->width_bits() - 1};
886 }
887
888 int size() const override { return value->type->width_bits(); }
889 const PHV::Field *field() const override { return nullptr; }
890 const le_bitrange &range() const override { return range_i; }
891 const IR::Constant *value;
892};
893
898class FieldSlice : public AbstractField, public LiftCompare<FieldSlice> {
899 // There is no reason for a FieldSlice to change the field it is representing, so make this
900 // const (also used in ActionPhvConstraints)
901 const PHV::Field *field_i;
902 le_bitrange range_i;
903 std::optional<FieldAlignment> alignment_i = std::nullopt;
904 nw_bitrange validContainerRange_i = ZeroToMax();
905
906 public:
907 FieldSlice() : field_i(nullptr), range_i(StartLen(0, 0)) {}
908
910
914
917 BUG_CHECK(slice.range().contains(range),
918 "Trying to create field sub-slice larger than the original slice");
919 }
920
921 explicit operator bool() const { return field_i != nullptr; }
922
928 int start = 8 * ((field_i->offset + range_i.lo) / 8);
929 int len = (8 * ROUNDUP(field_i->offset + range_i.hi + 1, 8)) - start;
930 return StartLen(start, len);
931 }
932
933 cstring shortString() const {
934 if (is_whole_field()) return field_i->name;
935
936 std::stringstream ss;
937 ss << field_i->name << "[" << range_i.hi << ":" << range_i.lo << "]";
938 return ss.str();
939 }
940
941 bool operator==(const FieldSlice &other) const override {
942 return field_i == other.field() && range_i == other.range();
943 }
944
945 bool operator<(const FieldSlice &other) const override {
946 if (field_i != other.field()) return Field::less(field_i, other.field());
947 if (range_i.lo != other.range().lo) return range_i.lo < other.range().lo;
948 return range_i.hi < other.range().hi;
949 }
950
952 gress_t gress() const { return field_i->gress; }
953
955 int size() const override { return range_i.size(); }
956
959 std::optional<FieldAlignment> alignment() const { return alignment_i; }
960
962 nw_bitrange validContainerRange() const { return validContainerRange_i; }
963
965 FieldKind kind() const {
966 // TODO: PHV::Field::metadata and PHV::Field::pov should be
967 // replaced by FieldKind.
968 if (field_i->pov)
969 return FieldKind::pov;
970 else if (field_i->metadata)
971 return FieldKind::metadata;
972 else
973 return FieldKind::header;
974 }
975
977 const PHV::Field *field() const override { return field_i; }
978
980 const le_bitrange &range() const override { return range_i; }
981
983 bool is_whole_field() const { return range_i == StartLen(0, field_i->size); }
984
988
990 bool is_tphv_candidate(const PhvUse &uses) const;
991
992 // methods that just forward to the underlying PHV::Field method
993 int container_bytes() const { return field_i->container_bytes(range_i); }
994 template <class FN>
995 void foreach_byte(const PHV::AllocContext *ctxt, const PHV::FieldUse *use, FN fn) const {
996 field_i->foreach_byte(range_i, ctxt, use, fn);
997 }
998 template <class FN>
999 void foreach_byte(const IR::MAU::Table *ctxt, const PHV::FieldUse *use, FN fn) const {
1000 field_i->foreach_byte(range_i, PHV::AllocContext::of_unit(ctxt), use, fn);
1001 }
1002
1003 bool is_unallocated() const { return field_i->is_unallocated(); }
1004
1005 friend size_t hash_value(const FieldSlice &fs) {
1006 size_t h = 0;
1007 boost::hash_combine(h, fs.field()->id);
1008 boost::hash_combine(h, fs.range().lo);
1009 boost::hash_combine(h, fs.range().hi);
1010 return h;
1011 }
1012};
1013
1015 cstring field_name;
1016 le_bitrange range;
1017 ordered_set<FieldRange> conflicts;
1018
1019 bool operator==(const FieldRange &other) const {
1020 return (field_name == other.field_name) && range == other.range;
1021 }
1022
1023 bool operator<(const FieldRange &other) const {
1024 if (field_name != other.field_name) return (field_name < other.field_name);
1025 if (range.lo != other.range.lo) return range.lo < other.range.lo;
1026 return range.hi < other.range.hi;
1027 }
1028
1029 bool has_conflict(const FieldRange fld_range) const { return (conflicts.count(fld_range) > 0); }
1030};
1031
1035 using FieldRange = std::pair<const PHV::Field *, le_bitrange>;
1039 std::optional<FieldRange> slice;
1040 int padding = 0;
1041
1042 public:
1043 explicit FieldRangeOrPadding(const FieldRange &fs) : slice(fs) {}
1044 explicit FieldRangeOrPadding(int n_padding_bits) : padding(n_padding_bits) {}
1045 bool is_fs() const { return slice.has_value(); }
1046 const FieldRange &fs() const { return *slice; }
1047 int size() const {
1048 if (is_fs())
1049 return slice->second.size();
1050 else
1051 return padding;
1052 }
1053 };
1054
1058 gress_t gress;
1059};
1060
1061std::ostream &operator<<(std::ostream &out, const Field &);
1062std::ostream &operator<<(std::ostream &out, const Field *);
1063std::ostream &operator<<(std::ostream &out, const PackingLayout &);
1064std::ostream &operator<<(std::ostream &out, const PackingLayout *);
1065
1066} // namespace PHV
1067
1072using InsertionConstraints = std::pair<std::set<UniqueId>, std::set<UniqueId>>;
1073
1076
1095class PhvInfo {
1096 public:
1097 // min-stage-based mapping from table to stages.
1098 static ordered_map<cstring, std::set<int>> table_to_min_stages;
1099 // physical-stage-based mapping from table to physical stages of the last table placement.
1100 static ordered_map<cstring, std::set<int>> table_to_physical_stages;
1101 static int deparser_stage;
1102 static bool darkSpillARA;
1103 static const bool DARK_SPILL_ARA_DEFAULT = true;
1104
1106 struct DumpPhvFields : public Visitor {
1107 const PhvInfo &phv;
1108 const PhvUse &uses;
1109
1110 explicit DumpPhvFields(const PhvInfo &phv, const PhvUse &uses) : phv(phv), uses(uses) {}
1111
1112 const IR::Node *apply_visitor(const IR::Node *n, const char *) override;
1116 void generate_field_histogram(gress_t) const;
1117 };
1118
1120 struct StructInfo {
1123
1125 gress_t gress;
1126
1131
1134 int size;
1135
1136 StructInfo(bool metadata, gress_t gress)
1138 StructInfo(bool metadata, gress_t gress, int first_field_id, int size)
1140 BUG_CHECK(0 <= size, "PhvInfo::StructInfo with negative size");
1141 BUG_CHECK(size == 0 || 0 <= first_field_id,
1142 "PhvInfo::StructInfo with negative first field offset");
1143 }
1144
1146 boost::integer_range<int> field_ids() const {
1147 return boost::irange(first_field_id, first_field_id + size);
1148 }
1149 };
1150
1154 using FieldBit = std::pair<const PHV::Field *, int>;
1155 UnionFind<FieldBit> same_byte_bits;
1156
1157 // return true if the two field slice must share a container.
1158 bool same_container(const PHV::FieldSlice &a, const PHV::FieldSlice &b) const;
1159 void clear() { same_byte_bits.clear(); }
1160 };
1161
1162 const SymBitMatrix &field_mutex() const { return field_mutex_i; }
1163 const SymBitMatrix &metadata_mutex() const { return metadata_mutex_i; }
1164 const SymBitMatrix &dark_mutex() const { return dark_mutex_i; }
1165 const SymBitMatrix &deparser_no_pack_mutex() const { return deparser_no_pack_i; }
1166 const SymBitMatrix &digest_no_pack_mutex() const { return digest_no_pack_i; }
1167 const SameContainerAllocConstraint &same_container_alloc_constraint() const {
1168 return same_container_alloc_i;
1169 }
1170 SymBitMatrix &field_mutex() { return field_mutex_i; }
1171 SymBitMatrix &metadata_mutex() { return metadata_mutex_i; }
1172 SymBitMatrix &dark_mutex() { return dark_mutex_i; }
1173 SymBitMatrix &deparser_no_pack_mutex() { return deparser_no_pack_i; }
1174 SymBitMatrix &digest_no_pack_mutex() { return digest_no_pack_i; }
1175
1176 SymBitMatrix &getBridgedExtractedTogether() { return bridged_extracted_together_i; }
1177 const SymBitMatrix &getBridgedExtractedTogether() const { return bridged_extracted_together_i; }
1178 SameContainerAllocConstraint &same_container_alloc_constraint() {
1179 return same_container_alloc_i;
1180 }
1181
1182 bool are_bridged_extracted_together(const PHV::Field *f1, const PHV::Field *f2) const {
1183 BUG_CHECK(f1 && f2, "No PHV field");
1184 return bridged_extracted_together_i(f1->id, f2->id);
1185 }
1186
1187 SymBitMatrix &getMutuallyAligned() { return mutually_aligned_i; }
1188 const SymBitMatrix &getMutuallyAligned() const { return mutually_aligned_i; }
1189 bool are_mutually_aligned(const PHV::Field *f1, const PHV::Field *f2) const {
1190 BUG_CHECK(f1 && f2, "No PHV field");
1191 return mutually_aligned_i(f1->id, f2->id);
1192 }
1193
1194 void addMutuallyAligned(const PHV::Field *f1, const PHV::Field *f2) {
1195 BUG_CHECK(f1 && f2, "No PHV field");
1196 mutually_aligned_i(f1->id, f2->id) = true;
1197 }
1198
1199 void addDeparserNoPack(const PHV::Field *f1, const PHV::Field *f2) {
1200 BUG_CHECK(f1 && f2, "No PHV field");
1201 deparser_no_pack_i(f1->id, f2->id) = true;
1202 }
1203
1204 void addFieldNoPack(const PHV::Field *f1, const PHV::Field *f2) {
1205 BUG_CHECK(f1 && f2, "No PHV field");
1206 field_no_pack_i(f1->id, f2->id) = true;
1207 }
1208
1209 void removeFieldNoPack(const PHV::Field *f1, const PHV::Field *f2) {
1210 BUG_CHECK(f1 && f2, "No PHV field");
1211 field_no_pack_i(f1->id, f2->id) = false;
1212 }
1213
1214 void addDigestNoPack(const PHV::Field *f1, const PHV::Field *f2) {
1215 BUG_CHECK(f1 && f2, "No PHV field");
1216 digest_no_pack_i(f1->id, f2->id) = true;
1217 }
1218
1219 void removeDigestNoPack(const PHV::Field *f1, const PHV::Field *f2) {
1220 BUG_CHECK(f1 && f2, "No PHV field");
1221 digest_no_pack_i(f1->id, f2->id) = false;
1222 }
1223
1224 void addFieldMutex(const PHV::Field *f1, const PHV::Field *f2) {
1225 BUG_CHECK(f1 && f2, "No PHV field");
1226 field_mutex_i(f1->id, f2->id) = true;
1227 }
1228
1229 void removeFieldMutex(const PHV::Field *f1, const PHV::Field *f2) {
1230 BUG_CHECK(f1 && f2, "No PHV field");
1231 field_mutex_i(f1->id, f2->id) = false;
1232 }
1233
1234 void addMetadataMutex(const PHV::Field *f1, const PHV::Field *f2) {
1235 BUG_CHECK(f1 && f2, "No PHV field");
1236 metadata_mutex_i(f1->id, f2->id) = true;
1237 }
1238
1239 void addDarkMutex(const PHV::Field *f1, const PHV::Field *f2) {
1240 BUG_CHECK(f1 && f2, "No PHV field");
1241 dark_mutex_i(f1->id, f2->id) = true;
1242 }
1243
1244 bool isFieldMutex(const PHV::Field *f1, const PHV::Field *f2) const {
1245 BUG_CHECK(f1 && f2, "No PHV field");
1246 return field_mutex_i(f1->id, f2->id);
1247 }
1248
1249 bool isMetadataMutex(const PHV::Field *f1, const PHV::Field *f2) const {
1250 BUG_CHECK(f1 && f2, "No PHV field");
1251 return metadata_mutex_i(f1->id, f2->id);
1252 }
1253
1254 bool isDarkMutex(const PHV::Field *f1, const PHV::Field *f2) const {
1255 BUG_CHECK(f1 && f2, "No PHV field");
1256 return dark_mutex_i(f1->id, f2->id);
1257 }
1258
1259 bool isDeparserNoPack(const PHV::Field *f1, const PHV::Field *f2) const {
1260 BUG_CHECK(f1 && f2, "No PHV field");
1261 return deparser_no_pack_i(f1->id, f2->id);
1262 }
1263
1264 bool isFieldNoPack(const PHV::Field *f1, const PHV::Field *f2) const {
1265 BUG_CHECK(f1 && f2, "No PHV field");
1266 return field_no_pack_i(f1->id, f2->id);
1267 }
1268
1269 bool isDigestNoPack(const PHV::Field *f1, const PHV::Field *f2) const {
1270 BUG_CHECK(f1 && f2, "No PHV field");
1271 return digest_no_pack_i(f1->id, f2->id);
1272 }
1273
1274 unsigned sizeFieldNoPack() { return field_no_pack_i.size(); }
1275
1278 constantExtractedInSameState.clear();
1279 sameStateConstantExtraction.clear();
1280 }
1281
1284 void insertConstantExtractField(PHV::Field *f) { sameStateConstantExtraction.insert(f); }
1285
1289 sameStateConstantExtraction.makeUnion(f, g);
1290 constantExtractedInSameState[f->id] = true;
1291 constantExtractedInSameState[g->id] = true;
1292 }
1293
1294 const UnionFind<PHV::Field *> &getSameSetConstantExtraction() const {
1295 return sameStateConstantExtraction;
1296 }
1297
1298 UnionFind<PHV::Field *> &getSameSetConstantExtraction() { return sameStateConstantExtraction; }
1299
1300 bool hasParserConstantExtract(const PHV::Field *f) const {
1301 return constantExtractedInSameState[f->id];
1302 }
1303
1304 // Return the insertion constraints for the AlwaysRunAction tables
1305 const ordered_map<gress_t, ConstraintMap> &getARAConstraints() const { return alwaysRunTables; }
1306
1307 // Add insertion constraints for table @tbl in gress @grs
1308 bool add_table_constraints(gress_t grs, IR::MAU::Table *tbl, InsertionConstraints cnstrs) {
1309 bool has_constrs =
1310 (alwaysRunTables.count(grs) ? (alwaysRunTables[grs].count(tbl) ? true : false) : false);
1311
1312 if (!has_constrs) {
1313 (alwaysRunTables[grs])[tbl] = cnstrs;
1314 } else {
1315 (alwaysRunTables[grs])[tbl].first.insert(cnstrs.first.begin(), cnstrs.first.end());
1316 (alwaysRunTables[grs])[tbl].second.insert(cnstrs.second.begin(), cnstrs.second.end());
1317 }
1318
1319 return !has_constrs;
1320 }
1321
1322 // Clear insertion constraints
1323 void clearARAconstraints() { alwaysRunTables.clear(); }
1324
1325 static void clearMinStageInfo() { PhvInfo::table_to_min_stages.clear(); }
1326 static void clearPhysicalStageInfo() { PhvInfo::table_to_physical_stages.clear(); }
1327
1328 static void resetDeparserStage() { PhvInfo::deparser_stage = -1; }
1329
1330 static void setDeparserStage(int stage) { PhvInfo::deparser_stage = stage; }
1331
1332 static int getDeparserStage() { return PhvInfo::deparser_stage; }
1333
1334 static std::set<int> minStages(const IR::MAU::Table *tbl);
1335 static std::set<int> physicalStages(const IR::MAU::Table *tbl);
1336
1337 static void addMinStageEntry(const IR::MAU::Table *tbl, int stage,
1338 bool remove_prev_stages = false);
1339 static void setPhysicalStages(const IR::MAU::Table *tbl, const std::set<int> &stage);
1340
1341 static bool hasMinStageEntry(const IR::MAU::Table *tbl);
1342
1343 static cstring reportMinStages();
1344
1345 static void resetDarkSpillARA() { darkSpillARA = DARK_SPILL_ARA_DEFAULT; }
1346
1347 // When a gateway and a table is merged together, we need to make sure that the slices used in
1348 // the gateway are alive at the table with which it is merged. @returns true if the liveness
1349 // check allows the merging of the gateway with the table.
1350 bool darkLivenessOkay(const IR::MAU::Table *gateway, const IR::MAU::Table *t) const;
1351
1352 // return true if some bit of two fieldslice will share the same container after allocation.
1353 bool must_alloc_same_container(const PHV::FieldSlice &a, const PHV::FieldSlice &b) const {
1354 return same_container_alloc_i.same_container(a, b);
1355 }
1356
1357 private: // class PhvInfo
1358 //
1359 std::map<cstring, PHV::Field> all_fields;
1362
1364 std::map<cstring, StructInfo> all_structs;
1365
1367 // TODO: what about header unions?
1368 ordered_map<cstring, StructInfo> simple_headers;
1369
1372
1374 ordered_set<cstring> dummyPaddingNames;
1375
1379
1382 ordered_map<cstring, PHV::Field *> externalNameMap;
1383
1386
1387 bool alloc_done_ = false;
1388 bool pov_alloc_done = false;
1389 bool trivial_alloc_ = false; // MAU group constraints not met
1390
1392 SymBitMatrix field_mutex_i;
1393
1396 SymBitMatrix metadata_mutex_i;
1397
1398 SymBitMatrix dark_mutex_i;
1399
1402 SymBitMatrix deparser_no_pack_i;
1403
1406 SymBitMatrix field_no_pack_i;
1407
1411 SymBitMatrix digest_no_pack_i;
1412
1415 SymBitMatrix bridged_extracted_together_i;
1416
1419 SymBitMatrix mutually_aligned_i;
1420
1424
1427 SameContainerAllocConstraint same_container_alloc_i;
1428
1431 std::set<PHV::Container> zeroContainers[2]; // per gress
1432
1438
1439 // reverseMetadataDeps[t1] = { t_n }, means that all tables in t_n must be placed before we
1440 // place table t1.
1441 ordered_map<cstring, ordered_set<cstring>> reverseMetadataDeps;
1442
1443 // For each of the table pairs in above 'metadataDeps' map, below map holds
1444 // the corresponding slice causing the dependency
1445 typedef std::pair<cstring, cstring> tpair;
1447
1448 // UnionFind struct in PhvInfo for all fields that are written in the same parser state using
1449 // constants.
1450 UnionFind<PHV::Field *> sameStateConstantExtraction;
1451
1452 // Structure to quickly check membership in sameStateConstantExtraction.
1453 bitvec constantExtractedInSameState;
1454
1455 void clear();
1456
1457 void add_hdr(cstring headerName, const IR::Type_StructLike *type, gress_t gress,
1458 bool isMetadata);
1459 void add_struct(cstring structName, const IR::Type_StructLike *type, gress_t gress, bool meta,
1460 bool bridged, int offset);
1461 void addPadding(const IR::Padding *padding, gress_t gress);
1462
1463 template <typename Iter>
1464 class iterator {
1465 Iter it;
1466
1467 public:
1468 iterator(Iter i) : it(i) {} // NOLINT(runtime/explicit)
1469 bool operator==(iterator a) { return it == a.it; }
1470 bool operator!=(iterator a) { return it != a.it; }
1471 iterator &operator++() {
1472 ++it;
1473 return *this;
1474 }
1475 iterator &operator--() {
1476 --it;
1477 return *this;
1478 }
1479 decltype(**it) operator*() { return **it; }
1480 decltype(*it) operator->() { return *it; }
1481 };
1482
1483 friend class ClearPhvInfo;
1484 friend class CollectPhvFields;
1485 friend struct AllocatePOVBits;
1486 friend struct MarkBridgedMetadataFields;
1487
1497 void allocatePOV(const BFN::HeaderStackInfo &);
1498
1499 public: // class PhvInfo
1500 PhvInfo() {}
1501 void addTempVar(const IR::TempVar *tempVar, gress_t gress);
1502 bool isTempVar(const PHV::Field *f) const { return fields_to_tempvars_i.count(f) > 0; }
1503 const PHV::Field *field(int idx) const {
1504 return size_t(idx) < by_id.size() ? by_id.at(idx) : 0;
1505 }
1506 const PHV::Field *field(const cstring &) const;
1507 const PHV::Field *field(const IR::Expression *, le_bitrange *bits = 0) const;
1508 const PHV::Field *field(const IR::Member *, le_bitrange *bits = 0) const;
1509 PHV::Field *field(int idx) { return (size_t)idx < by_id.size() ? by_id.at(idx) : 0; }
1510 PHV::Field *field(const cstring &name) {
1511 return const_cast<PHV::Field *>(const_cast<const PhvInfo *>(this)->field(name));
1512 }
1513 PHV::Field *field(const IR::Expression *e, le_bitrange *bits = 0) {
1514 return const_cast<PHV::Field *>(const_cast<const PhvInfo *>(this)->field(e, bits));
1515 }
1516 PHV::Field *field(const IR::Member *fr, le_bitrange *bits = 0) {
1517 return const_cast<PHV::Field *>(const_cast<const PhvInfo *>(this)->field(fr, bits));
1518 }
1519 bool has_struct_info(cstring name) const;
1521 cstring full_hdr_name(const cstring &name) const;
1522 const PhvInfo::StructInfo *hdr(const cstring &name_) const;
1523
1524 const StructInfo struct_info(cstring name) const;
1525 const StructInfo struct_info(const IR::HeaderRef *hr) const {
1526 return struct_info(hr->toString());
1527 }
1528 const std::map<cstring, PHV::Field> &get_all_fields() const { return all_fields; }
1529 size_t num_fields() const { return all_fields.size(); }
1532 const IR::TempVar *getTempVar(const PHV::Field *f) const;
1533
1534 PHV::Field *add(cstring fieldName, gress_t gress, int size, int offset, bool isMetadata,
1535 bool isPOV, bool bridged = false, bool isPad = false,
1536 bool isOverlayable = false, bool isFlexible = false,
1537 bool isFixedSizeHeader = false,
1538 std::optional<Util::SourceInfo> srcInfo = std::nullopt);
1539
1540 PHV::Field *create_dummy_padding(size_t sz, gress_t gress, bool overlayable = true);
1541
1542 std::vector<PHV::AllocSlice> get_alloc(const IR::Expression *f,
1543 const PHV::AllocContext *ctxt = nullptr,
1544 const PHV::FieldUse *use = nullptr) const;
1545
1546 std::vector<PHV::AllocSlice> get_alloc(const PHV::Field *phv_field, le_bitrange *bits = nullptr,
1547 const PHV::AllocContext *ctxt = nullptr,
1548 const PHV::FieldUse *use = nullptr) const;
1549
1550 iterator<safe_vector<PHV::Field *>::iterator> begin() { return by_id.begin(); }
1551 iterator<safe_vector<PHV::Field *>::iterator> end() { return by_id.end(); }
1552 iterator<safe_vector<PHV::Field *>::const_iterator> begin() const { return by_id.begin(); }
1553 iterator<safe_vector<PHV::Field *>::const_iterator> end() const { return by_id.end(); }
1554
1555 bool alloc_done() const { return alloc_done_; }
1556 bool trivial_alloc() const { return trivial_alloc_; }
1557 void set_done(bool trivial = false) {
1558 alloc_done_ = true;
1559 trivial_alloc_ = trivial;
1560 }
1561
1564 void clear_container_to_fields() { container_to_fields.clear(); }
1570
1573
1575 std::vector<PHV::AllocSlice> get_slices_in_container(const PHV::Container c) const;
1576
1581 std::vector<PHV::AllocSlice> get_slices_in_container(const PHV::Container c,
1582 const PHV::AllocContext *ctxt,
1583 const PHV::FieldUse *use) const;
1584
1590 bitvec bits_allocated(const PHV::Container, const PHV::AllocContext *ctxt = nullptr,
1591 const PHV::FieldUse *use = nullptr) const;
1592
1593 bitvec bits_allocated(const PHV::Container container, const IR::MAU::Table *ctxt,
1594 const PHV::FieldUse *use = nullptr) const {
1595 return bits_allocated(container, PHV::AllocContext::of_unit(ctxt), use);
1596 }
1597
1601 bitvec bits_allocated(const PHV::Container, const PHV::Field *field,
1602 const PHV::AllocContext *ctxt = nullptr,
1603 const PHV::FieldUse *use = nullptr) const;
1604
1605 bitvec bits_allocated(const PHV::Container container, const PHV::Field *field,
1606 const IR::MAU::Table *ctxt, const PHV::FieldUse *use = nullptr) const {
1607 return bits_allocated(container, field, PHV::AllocContext::of_unit(ctxt), use);
1608 }
1609
1618 const PHV::AllocContext *ctxt = nullptr,
1619 const PHV::FieldUse *use = nullptr) const;
1620
1621 bitvec bits_allocated(const PHV::Container container,
1622 const ordered_set<const PHV::Field *> &fields, const IR::MAU::Table *ctxt,
1623 const PHV::FieldUse *use = nullptr) const {
1624 return bits_allocated(container, fields, PHV::AllocContext::of_unit(ctxt), use);
1625 }
1626
1631 std::optional<cstring> get_alias_name(const IR::Expression *expr) const;
1632
1634 void addAliasMapEntry(const PHV::Field *f1, const PHV::Field *f2) {
1635 if (aliasMap.count(f1))
1636 BUG_CHECK(aliasMap[f1] == f2, "Multiple aliases with the same field found");
1637 aliasMap[f1] = f2;
1638 }
1639
1642 externalNameMap[externalName] = f;
1643 }
1644
1647 return aliasMap;
1648 }
1649
1653 if (aliasMap.count(f)) return aliasMap.at(f);
1654 return nullptr;
1655 }
1656
1658 const std::set<PHV::Container> &getZeroContainers(gress_t gr) const {
1659 return zeroContainers[gr];
1660 }
1661
1663 void addZeroContainer(gress_t gr, PHV::Container c) {
1664 zeroContainers[gr].insert(c);
1665 BUG_CHECK(zeroContainers[gr].size() <= 1,
1666 "Only two zero containers allowed: one for each gress");
1667 }
1668
1672 void addMetadataDependency(const IR::MAU::Table *t1, const IR::MAU::Table *t2,
1673 const PHV::FieldSlice *slice = nullptr) {
1674 metadataDeps[t1->name].insert(t2->name);
1675 reverseMetadataDeps[t2->name].insert(t1->name);
1676 if (slice) {
1677 auto table_pair = std::make_pair(t1->name, t2->name);
1678 if (metadataDepFields.emplace(table_pair, slice).second) {
1679 LOG5(" Adding tables " << t1->name << " --> " << t2->name
1680 << " with metadata dependent field " << slice);
1681 }
1682 }
1683 }
1684
1686 const ordered_set<cstring> getReverseMetadataDeps(const IR::MAU::Table *t) const {
1687 static ordered_set<cstring> emptySet;
1688 if (!reverseMetadataDeps.count(t->name)) return emptySet;
1689 return reverseMetadataDeps.at(t->name);
1690 }
1691
1694 return metadataDeps;
1695 }
1696
1699 return reverseMetadataDeps;
1700 }
1701
1704 return metadataDepFields;
1705 }
1706
1709 ContainterToSliceMap getContainerToSlicesMap(
1710 std::function<bool(const PHV::Field *)> *f = nullptr,
1711 std::function<bool(const PHV::AllocSlice *)> *s = nullptr) const;
1712};
1713
1736 explicit CollectPhvInfo(PhvInfo &phv);
1737};
1738
1746 private:
1747 PhvInfo &phv_i;
1748 bool preorder(const IR::BFN::ParserState *state) override;
1749
1750 public:
1751 explicit CollectExtractedTogetherFields(PhvInfo &p) : phv_i(p) {}
1752};
1753
1756 const PhvInfo &phv_i;
1757
1759 field_to_parser_states;
1760
1762
1764 container_to_parser_states;
1765
1767
1769
1770 std::map<const IR::BFN::ParserState *, const IR::BFN::Parser *> state_to_parser;
1771
1773 state_to_writes;
1774
1775 explicit MapFieldToParserStates(const PhvInfo &phv) : phv_i(phv) {}
1776
1777 profile_t init_apply(const IR::Node *root) override {
1778 field_to_parser_states.clear();
1779 field_to_writes.clear();
1780 container_to_parser_states.clear();
1781 container_to_writes.clear();
1782 write_to_state.clear();
1783 state_to_parser.clear();
1784 state_to_writes.clear();
1785 return Inspector::init_apply(root);
1786 }
1787
1788 bool preorder(const IR::BFN::ParserChecksumWritePrimitive *checksum) override {
1789 if (auto dest = checksum->getWriteDest()) add_field(dest->field, checksum);
1790 return true;
1791 }
1792
1793 bool preorder(const IR::BFN::Extract *extract) override {
1794 if (auto lval = extract->dest->to<IR::BFN::FieldLVal>()) add_field(lval->field, extract);
1795 return true;
1796 }
1797
1798 private:
1799 void add_field(const IR::Expression *field, const IR::BFN::ParserPrimitive *prim) {
1800 if (auto *f = phv_i.field(field)) {
1801 auto state = findContext<IR::BFN::ParserState>();
1802 auto parser = findContext<IR::BFN::Parser>();
1803
1804 field_to_parser_states[f].insert(state);
1805 state_to_parser[state] = parser;
1806
1807 field_to_writes[f].insert(prim);
1808 write_to_state[prim] = state;
1809 state_to_writes[state].insert(prim);
1810
1811 if (phv_i.alloc_done()) {
1812 PHV::FieldUse use(PHV::FieldUse::WRITE);
1813 for (auto &alloc : phv_i.get_alloc(field, PHV::AllocContext::PARSER, &use)) {
1814 auto cont = alloc.container();
1815 container_to_parser_states[cont].insert(state);
1816 container_to_writes[cont].insert(prim);
1817 }
1818 }
1819 }
1820 }
1821};
1822
1823void dump(const PhvInfo *);
1824void dump(const PHV::Field *);
1825
1826std::ostream &operator<<(std::ostream &, const ordered_set<PHV::Field *> &);
1827std::ostream &operator<<(std::ostream &, const ordered_set<const PHV::Field *> &);
1828std::ostream &operator<<(std::ostream &, const PhvInfo &);
1829std::ostream &operator<<(std::ostream &, const PHV::FieldAccessType &);
1830std::ostream &operator<<(std::ostream &, const PhvInfo::SameContainerAllocConstraint &);
1831std::ostream &operator<<(std::ostream &, const PhvInfo::SameContainerAllocConstraint::FieldBit &);
1832
1833namespace PHV {
1834
1835std::ostream &operator<<(std::ostream &, const PHV::FieldSlice &sl);
1836std::ostream &operator<<(std::ostream &, const PHV::FieldSlice *sl);
1837
1838} // namespace PHV
1839
1840// These overloads must be declared directly in `namespace std` to work around
1841// ADL limitations for lookup of names in sibling namespaces.
1842namespace std {
1843ostream &operator<<(ostream &, const list<::PHV::Field *> &);
1844ostream &operator<<(ostream &, const set<const ::PHV::Field *> &);
1845} // namespace std
1846//
1847#endif /* BF_P4C_PHV_PHV_FIELDS_H_ */
Definition phv_fields.cpp:1247
Definition phv_fields.h:1745
Definition phv_fields.cpp:1267
Definition constraints.h:149
Definition constraints.h:90
Definition constraints.h:56
Definition cmp.h:84
Definition cmp.h:55
Definition node.h:94
Definition visitor.h:400
Definition ir/pass_manager.h:40
Definition symbitmatrix.h:27
Definition source_file.h:131
Definition visitor.h:78
Definition visitor.h:75
Definition bitvec.h:120
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:27
Definition phv_fields.h:855
Represents a PHV-allocation context: a parser, a table, or a deparser.
Definition phv_fields.h:83
const IR::MAU::Table * table
Populated iff type is TABLE.
Definition phv_fields.h:89
static const AllocContext * of_unit(const IR::BFN::Unit *unit)
Definition phv_fields.h:123
Definition slice_alloc.h:136
Definition phv_fields.h:880
Definition phv.h:176
Definition phv_fields.h:154
void eraseAlignment()
Erase the alignment requirement for this field.
Definition phv_fields.cpp:1072
nw_bitrange validContainerRange_i
Definition phv_fields.h:203
const safe_vector< PHV::AllocSlice > & get_alloc() const
Definition phv_fields.h:717
const PHV::AllocSlice & for_bit(int bit) const
Definition phv_fields.cpp:800
size_t alloc_size() const
Definition phv_fields.h:722
std::optional< FieldAlignment > alignment
Definition phv_fields.h:198
void updateValidContainerRange(nw_bitrange newValidRange)
Definition phv_fields.cpp:1194
int size
Total size of Field in bits.
Definition phv_fields.h:194
int id
Unique field ID.
Definition phv_fields.h:164
bool overlayable
Definition phv_fields.h:226
bool isCompilerGeneratedPaddingField() const
Definition phv_fields.h:189
void setExternalName(cstring name)
Definition phv_fields.h:767
void foreach_alloc(const le_bitrange *r, const PHV::AllocContext *ctxt, const PHV::FieldUse *use, std::function< void(const PHV::AllocSlice &)> fn, SliceMatch useTblRefs=SliceMatch::DFLT) const
Definition phv_fields.h:684
bool hasPhvAllocation(AllocState s) const
Utility functions to get field allocation status.
Definition phv_fields.h:808
int offset
Offset of lsb from lsb (last) bit of containing header.
Definition phv_fields.h:206
void sort_alloc()
Sort by field MSB.
Definition phv_fields.h:728
bool padding
True if this Field is a padding field.
Definition phv_fields.h:222
bitvec getStartBits(PHV::Size size) const
Definition phv_fields.cpp:1087
bool invalidate_from_arch_i
Definition phv_fields.h:216
const std::vector< PHV::AllocSlice > get_combined_alloc_bytes(const PHV::AllocContext *ctxt, const PHV::FieldUse *use, SliceMatch useTblRefs=SliceMatch::DFLT) const
Definition phv_fields.cpp:808
bool deparsed() const
Definition phv_fields.h:444
bool operator<(const Field &other) const
Orders by name.
Definition phv_fields.h:841
le_bitrange byteAlignedRangeInBits() const
Definition phv_fields.h:801
cstring externalName() const
Definition phv_fields.h:759
cstring name
Definition phv_fields.h:161
void set_alloc(const safe_vector< PHV::AllocSlice > &alloc)
Set all allocated slices of this field.
Definition phv_fields.h:714
void setStartBits(PHV::Size size, bitvec startPositions)
Definition phv_fields.cpp:1080
std::optional< Util::SourceInfo > srcInfo
Associate source info to each field.
Definition phv_fields.h:273
bool intrinsic_i
True if this Field is intrinsic.
Definition phv_fields.h:212
void add_alloc(const PHV::AllocSlice &alloc)
Allocate a slice of this field.
Definition phv_fields.h:704
bool pov
True if this Field is a validity bit.
Definition phv_fields.h:253
cstring header() const
Definition phv_fields.h:285
bool isPacketField() const
Definition phv_fields.h:555
void foreach_alloc(const PHV::AllocContext *ctxt, const PHV::FieldUse *use, std::function< void(const PHV::AllocSlice &)> fn, SliceMatch useTblRefs=SliceMatch::DFLT) const
Definition phv_fields.h:661
bool bridged
True if this Field is metadata bridged from ingress to egress.
Definition phv_fields.h:219
bool is_tphv_candidate(const PhvUse &uses) const
Definition phv_fields.cpp:1002
const PHV::Field * aliasSource
Definition phv_fields.h:270
int container_bytes(std::optional< le_bitrange > bits=std::nullopt) const
Definition phv_fields.cpp:777
const std::vector< PHV::AllocSlice > get_combined_alloc_slices(le_bitrange bits, const PHV::AllocContext *ctxt, const PHV::FieldUse *use) const
Definition phv_fields.cpp:866
bool hasAllocation(AllocState s) const
Determines whether s has a PHV allocation or a CLOT allocation.
Definition phv_fields.h:814
bool is_unallocated() const
Definition phv_fields.h:725
bool hasExternalName() const
Definition phv_fields.h:763
bool isGhostField() const
Definition phv_fields.h:173
void clear_alloc()
Clear any PHV allocation for this field.
Definition phv_fields.h:701
void setStartBitsToLowerBitsOfBottomByte()
Definition phv_fields.cpp:1092
void updateAlignment(PHV::AlignmentReason, const FieldAlignment &newAlignment, const Util::SourceInfo &newAlignmentSource)
Definition phv_fields.cpp:1017
void foreach_byte(const le_bitrange *r, const PHV::AllocContext *ctxt, const PHV::FieldUse *use, std::function< void(const PHV::AllocSlice &)> fn, SliceMatch useTblRefs=SliceMatch::DFLT) const
Definition phv_fields.h:610
std::list< std::pair< FieldAlignment, Util::SourceInfo > > alignmentSources
List of alignment sources for this field (mainly for error printing)
Definition phv_fields.h:200
nw_bitrange validContainerRange() const
Definition phv_fields.h:797
void foreach_byte(le_bitrange r, const PHV::AllocContext *ctxt, const PHV::FieldUse *use, std::function< void(const PHV::AllocSlice &)> fn, SliceMatch useTblRefs=SliceMatch::DFLT) const
Definition phv_fields.cpp:901
gress_t gress
Whether the Field is ingress or egress.
Definition phv_fields.h:167
void foreach_alloc(le_bitrange r, const PHV::AllocContext *ctxt, const PHV::FieldUse *use, std::function< void(const PHV::AllocSlice &)> fn, SliceMatch useTblRefs=SliceMatch::DFLT) const
Definition phv_fields.cpp:961
bool metadata
True if this Field is metadata.
Definition phv_fields.h:209
void clearExternalName()
Clear the external name, if any has been set.
Definition phv_fields.h:770
bool emitted_i
True if this field is emitted by the deparser onto the wire.
Definition phv_fields.h:229
Definition phv_fields.h:898
const PHV::Field * field() const override
Definition phv_fields.h:977
FieldSlice(const Field *field)
Create a slice that holds the entirety of field.
Definition phv_fields.h:912
le_bitrange byteAlignedRangeInBits() const
Definition phv_fields.h:927
const le_bitrange & range() const override
Definition phv_fields.h:980
bool is_tphv_candidate(const PhvUse &uses) const
Definition phv_fields.cpp:1007
bool is_whole_field() const
Definition phv_fields.h:983
FieldSlice(FieldSlice slice, le_bitrange range)
Creates a subslice of the field of slice from range.lo to range.hi.
Definition phv_fields.h:916
FieldKind kind() const
Kind of field of this slice.
Definition phv_fields.h:965
int size() const override
Total size of FieldSlice in bits.
Definition phv_fields.h:955
bitvec getStartBits(PHV::Size size) const
Definition phv_fields.cpp:1175
std::optional< FieldAlignment > alignment() const
Definition phv_fields.h:959
nw_bitrange validContainerRange() const
See documentation for Field::validContainerRange().
Definition phv_fields.h:962
gress_t gress() const
Whether the Field is ingress or egress.
Definition phv_fields.h:952
Definition phv.h:248
Definition phv_fields.h:1038
Definition phv.h:114
Definition phv_fields.h:1095
const std::set< PHV::Container > & getZeroContainers(gress_t gr) const
Definition phv_fields.h:1658
const PHV::Field * getAliasDestination(const PHV::Field *f) const
Definition phv_fields.h:1652
void clear_container_to_fields()
Definition phv_fields.h:1564
std::optional< cstring > get_alias_name(const IR::Expression *expr) const
Definition phv_fields.cpp:651
const ordered_set< cstring > getReverseMetadataDeps(const IR::MAU::Table *t) const
Definition phv_fields.h:1686
const IR::TempVar * getTempVar(const PHV::Field *f) const
Definition phv_fields.cpp:197
void addExternalNameMapEntry(PHV::Field *f, cstring externalName)
Adds an entry to the externalNameMap.
Definition phv_fields.h:1641
void addAliasMapEntry(const PHV::Field *f1, const PHV::Field *f2)
Adds an entry to the aliasMap.
Definition phv_fields.h:1634
const ordered_map< tpair, const PHV::FieldSlice * > & getMetadataDepFields() const
Definition phv_fields.h:1703
void clearConstantExtractionState()
Clear the state maintained corresponding to constant extractors.
Definition phv_fields.h:1277
bitvec bits_allocated(const PHV::Container, const PHV::AllocContext *ctxt=nullptr, const PHV::FieldUse *use=nullptr) const
Definition phv_fields.cpp:538
void addZeroContainer(gress_t gr, PHV::Container c)
adds container to the set of deparsed zero containers.
Definition phv_fields.h:1663
cstring full_hdr_name(const cstring &name) const
Definition phv_fields.cpp:214
void add_container_to_field_entry(const PHV::Container c, const PHV::Field *f)
Definition phv_fields.cpp:503
const PhvInfo::StructInfo * hdr(const cstring &name_) const
Get information about a collection of header or metadata fields, based on the partial or complete nam...
Definition phv_fields.cpp:272
std::vector< PHV::AllocSlice > get_slices_in_container(const PHV::Container c) const
Definition phv_fields.cpp:514
ordered_map< PHV::Container, std::vector< PHV::AllocSlice > > ContainterToSliceMap
Definition phv_fields.h:1708
void addMetadataDependency(const IR::MAU::Table *t1, const IR::MAU::Table *t2, const PHV::FieldSlice *slice=nullptr)
Definition phv_fields.h:1672
void get_hdr_fields(cstring name_, ordered_set< const PHV::Field * > &flds) const
Definition phv_fields.cpp:251
const ordered_set< const PHV::Field * > & fields_in_container(const PHV::Container c) const
Definition phv_fields.cpp:508
void mergeConstantExtracts(PHV::Field *f, PHV::Field *g)
Definition phv_fields.h:1288
void insertConstantExtractField(PHV::Field *f)
Definition phv_fields.h:1284
const ordered_map< const PHV::Field *, const PHV::Field * > & getAliasMap() const
Definition phv_fields.h:1646
const ordered_map< cstring, ordered_set< cstring > > & getReverseMetadataDeps() const
Definition phv_fields.h:1698
const ordered_map< cstring, ordered_set< cstring > > & getMetadataDeps() const
Definition phv_fields.h:1693
Definition phv_parde_mau_use.h:154
Definition assoc.h:403
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
The namespace encapsulating PHV-related stuff.
Definition gateway.h:32
gress_t gress
gress
Definition phv_fields.h:1058
Size
all possible PHV container sizes in BFN devices
Definition phv.h:110
safe_vector< FieldRangeOrPadding > layout
actual layout
Definition phv_fields.h:1056
Definition phv_fields.h:1034
STL namespace.
Definition phv_fields.cpp:1439
Metadata about how header stacks are used in the program.
Definition header_stack.h:94
Create and store a PHV::Field for each header and metadata field, and for TempVars....
Definition phv_fields.h:1735
Definition phv_fields.h:51
unsigned align
bit in byte alignment of the field in little endian order
Definition phv_fields.h:61
Map field to the parser states in which they are extracted or assigned from checksums.
Definition phv_fields.h:1755
Definition lib/bitrange.h:158
Definition lib/bitrange.h:190
int lo
Definition lib/bitrange.h:694
ssize_t size() const
Definition lib/bitrange.h:539
int hi
Definition lib/bitrange.h:700
bool contains(int index) const
Definition lib/bitrange.h:594
A mirror field points to its field list (one of eight)
Definition phv_fields.h:243
Definition phv_fields.h:136
Definition phv_fields.h:1014
Pretty-print all fields.
Definition phv_fields.h:1106
void generate_field_histogram(gress_t) const
Definition phv_fields.cpp:2551
Definition phv_fields.h:1153
PHV-related info about structs, i.e. collections of header or metadata fields.
Definition phv_fields.h:1120
bool metadata
True if this is a metadata struct; false for headers.
Definition phv_fields.h:1122
boost::integer_range< int > field_ids() const
Returns the half-open range of field IDs for this struct.
Definition phv_fields.h:1146
int size
Definition phv_fields.h:1134
int first_field_id
Definition phv_fields.h:1130
gress_t gress
Gress of this struct.
Definition phv_fields.h:1125