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