P4C
The P4 Compiler
Loading...
Searching...
No Matches
rewrite_egress_intrinsic_metadata_header.h
1
19#ifndef BF_P4C_MIDEND_REWRITE_EGRESS_INTRINSIC_METADATA_HEADER_H_
20#define BF_P4C_MIDEND_REWRITE_EGRESS_INTRINSIC_METADATA_HEADER_H_
21
22#include "backends/tofino/bf-p4c/device.h"
23
24namespace P4 {
25class TypeMap;
26class ReferenceMap;
27} // namespace P4
28
29namespace BFN {
30
36 struct CollectUsedFields : public Inspector {
37 std::set<cstring> used_fields;
38 const IR::Type_Header *eg_intr_md = nullptr;
39
40 bool preorder(const IR::Type_Header *type) override {
41 if (type->name == "egress_intrinsic_metadata_t") {
42 if (!eg_intr_md) eg_intr_md = type;
43 }
44 return false;
45 }
46
47 bool preorder(const IR::Member *member) override {
48 if (auto hdr = member->expr->to<IR::PathExpression>()) {
49 if (auto type = hdr->type->to<IR::Type_Header>()) {
50 if (type->name == "egress_intrinsic_metadata_t") {
51 used_fields.insert(member->member);
52 }
53 }
54 }
55
56 return true;
57 }
58 };
59
60 struct RewriteHeader : public Transform {
61 const CollectUsedFields &used_fields;
62 P4::TypeMap *typeMap;
63
65
66 profile_t init_apply(const IR::Node *root) override {
67 BUG_CHECK(used_fields.eg_intr_md, "egress_intrinsic_metadata_t not found?");
68
69 const IR::StructField *prev = nullptr;
70 const IR::Type *prev_type = nullptr;
71 for (auto field : used_fields.eg_intr_md->fields) {
72 if (used_fields.used_fields.count(field->name) || field->name == "egress_port") {
73 // "egress_port" is always there (not optional)
74 // we need to preserve each field's byte alignment as in original header
75 const IR::Type *canonicalType = nullptr;
76 if (field->type->is<IR::Type_Name>())
77 canonicalType = typeMap->getTypeType(field->type, true);
78 else
79 canonicalType = field->type;
80 if (canonicalType->width_bits() % 8) {
81 BUG_CHECK(
82 prev &&
83 (canonicalType->width_bits() + prev_type->width_bits()) % 8 == 0,
84 "%1% not padded to be byte-aligned in %2%", field->name,
85 "egress_intrinsic_metadata_t");
86 new_fields.push_back(prev);
87 }
88 new_fields.push_back(field);
89 }
90 prev = field;
91 if (field->type->is<IR::Type_Name>())
92 prev_type = typeMap->getTypeType(field->type, true);
93 else
94 prev_type = field->type;
95 }
96
97 unsigned total_size_in_bits = 0;
98 for (auto field : new_fields) {
99 const IR::Type *canonicalType;
100 if (field->type->is<IR::Type_Name>())
101 canonicalType = typeMap->getTypeType(field->type, true);
102 else
103 canonicalType = field->type;
104 auto bits = canonicalType->to<IR::Type_Bits>();
105 total_size_in_bits += bits->size;
106 }
107
108 BUG_CHECK(total_size_in_bits % 8 == 0,
109 "rewritten egress_intrinsic_metadata_t not byte-aligned?");
110
111 // JBay requires the egress intrinsic metadata to be padded to 4-byte aligned
112 // Minimum metadata lengh is 8B (JBay EPB uarch sec 6.1).
113 if (Device::currentDevice() == Device::JBAY) {
114 unsigned total_size_in_byte = total_size_in_bits / 8;
115 unsigned tofino2_pad = ((total_size_in_byte + 3) / 4) * 4 - total_size_in_byte;
116 if (total_size_in_byte + tofino2_pad < Device::egressIntrinsicMetadataMinLen())
117 tofino2_pad += Device::egressIntrinsicMetadataMinLen() -
118 (total_size_in_byte + tofino2_pad);
119
120 if (tofino2_pad) {
121 LOG4("tofino2 needs " << tofino2_pad << " bytes of padding");
122
123 auto *annots = new IR::Annotations({new IR::Annotation(IR::ID("padding"), {})});
124
125 const IR::StructField *tofino2_pad_field = new IR::StructField(
126 "__tofino2_pad_", annots, IR::Type::Bits::get(tofino2_pad * 8));
127
128 new_fields.push_back(tofino2_pad_field);
129 }
130 }
131
132 return Transform::init_apply(root);
133 }
134
135 IR::Node *preorder(IR::Type_Header *type) override {
136 if (type->name == "egress_intrinsic_metadata_t") {
137 auto clone = type->clone();
138 clone->fields = new_fields;
139 LOG4("rewrite egress_intrinsic_metadata_t as:");
140 LOG4(clone);
141 return clone;
142 }
143
144 return type;
145 }
146
147 explicit RewriteHeader(const CollectUsedFields &used, P4::TypeMap *typeMap)
148 : used_fields(used), typeMap(typeMap) {}
149 };
150
151 public:
153 auto collectUsedFields = new CollectUsedFields;
154
155 addPasses({
156 collectUsedFields,
157 new RewriteHeader(*collectUsedFields, typeMap),
158 new P4::ClearTypeMap(typeMap),
159 new BFN::TypeChecking(refMap, typeMap, true),
160 });
161 }
162};
163
164} // namespace BFN
165
166#endif /* BF_P4C_MIDEND_REWRITE_EGRESS_INTRINSIC_METADATA_HEADER_H_ */
Definition typeChecker.h:32
Definition node.h:52
Definition node.h:94
Definition visitor.h:400
Definition ir/pass_manager.h:40
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition visitor.h:424
Definition typeChecker.h:55
Definition typeMap.h:41
Definition visitor.h:78
Pass that updates egress intrinsic metadata.
Definition rewrite_egress_intrinsic_metadata_header.h:35
The namespace encapsulating Barefoot/Intel-specific stuff.
Definition add_t2na_meta.cpp:21
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition id.h:28