P4C
The P4 Compiler
Loading...
Searching...
No Matches
intrinsic_metadata.h
1
19#ifndef BF_P4C_ARCH_INTRINSIC_METADATA_H_
20#define BF_P4C_ARCH_INTRINSIC_METADATA_H_
21
22#include "backends/tofino/bf-p4c/arch/bridge_metadata.h"
23#include "backends/tofino/bf-p4c/device.h"
24#include "backends/tofino/bf-p4c/midend/type_checker.h"
25#include "frontends/p4/cloner.h"
26#include "frontends/p4/typeChecking/typeChecker.h"
27#include "ir/ir.h"
28
29namespace BFN {
30
31const IR::ParserState *convertStartStateToNormalState(const IR::ParserState *state,
32 cstring newName);
33
34const IR::ParserState *convertStartStateToNormalState(IR::P4Parser *parser, cstring newName);
35
36const IR::ParserState *addNewStartState(cstring name, cstring nextState);
37void addNewStartState(IR::P4Parser *parser, cstring name, cstring nextState);
38
39const IR::ParserState *createGeneratedParserState(cstring name,
40 IR::IndexedVector<IR::StatOrDecl> &&statements,
41 const IR::Expression *selectExpression);
42const IR::ParserState *createGeneratedParserState(cstring name,
43 IR::IndexedVector<IR::StatOrDecl> &&statements,
44 cstring nextState);
45const IR::Statement *createAdvanceCall(cstring pkt, int bits);
46const IR::SelectCase *createSelectCase(unsigned bitWidth, unsigned value, unsigned mask,
47 const IR::ParserState *nextState);
48const IR::Statement *createSetMetadata(cstring header, cstring field, int bitWidth, int constant);
49const IR::Statement *createSetMetadata(cstring param, cstring header, cstring field, int bitWidth,
50 int constant);
51const IR::Statement *createSetMetadata(const IR::Expression *dest, cstring header, cstring field);
52const IR::Statement *createSetValid(const Util::SourceInfo &, cstring header, cstring field);
53const IR::Statement *createExtractCall(cstring pkt, cstring type, cstring hdr);
54const IR::Statement *createExtractCall(cstring pkt, IR::Expression *member);
55const IR::Statement *createExtractCall(cstring pkt, cstring typeName, IR::Expression *member);
56const IR::Expression *createLookaheadExpr(cstring pkt, int bits);
57
60static void addIngressMetadata(IR::BFN::TnaParser *parser) {
61 auto *p4EntryPointState = convertStartStateToNormalState(parser, "ingress_p4_entry_point"_cs);
62
63 // Add a state that skips over any padding between the phase 0 data and the
64 // beginning of the packet.
65 const auto bitSkip = Device::pardeSpec().bitIngressPrePacketPaddingSize();
66 auto packetInParam = parser->tnaParams.at("pkt"_cs);
67 auto *skipToPacketState = createGeneratedParserState(
68 "skip_to_packet"_cs, {createAdvanceCall(packetInParam, bitSkip)}, p4EntryPointState->name);
69 parser->states.push_back(skipToPacketState);
70
71 // Add a state that parses the phase 0 data. This is a placeholder that
72 // just skips it; if we find a phase 0 table, it'll be replaced later.
73 const auto bitPhase0Size = Device::pardeSpec().bitPhase0Size();
74 auto *phase0State = createGeneratedParserState(
75 "phase0"_cs, {createAdvanceCall(packetInParam, bitPhase0Size)}, skipToPacketState->name);
76 parser->states.push_back(phase0State);
77
78 // This state parses resubmit data. Just like phase 0, the version we're
79 // generating here is a placeholder that just skips the data; we'll replace
80 // it later with an actual implementation.
81 const auto bitResubmitSize = Device::pardeSpec().bitResubmitSize();
82 auto *resubmitState = createGeneratedParserState(
83 "resubmit"_cs, {createAdvanceCall(packetInParam, bitResubmitSize)},
84 skipToPacketState->name);
85 parser->states.push_back(resubmitState);
86
87 // If this is a resubmitted packet, the initial intrinsic metadata will be
88 // followed by the resubmit data; otherwise, it's followed by the phase 0
89 // data. This state checks the resubmit flag and branches accordingly.
90 auto igIntrMd = parser->tnaParams.at("ig_intr_md"_cs);
91 IR::Vector<IR::Expression> selectOn = {
92 new IR::Member(new IR::PathExpression(igIntrMd), "resubmit_flag"_cs)};
93 auto *checkResubmitState = createGeneratedParserState(
94 "check_resubmit"_cs, {},
95 new IR::SelectExpression(new IR::ListExpression(selectOn),
96 {createSelectCase(1, 0x0, 0x1, phase0State),
97 createSelectCase(1, 0x1, 0x1, resubmitState)}));
98 parser->states.push_back(checkResubmitState);
99
100 // This state handles the extraction of ingress intrinsic metadata.
101 auto *igMetadataState = createGeneratedParserState(
102 "ingress_metadata"_cs,
103 {createSetMetadata("ig_intr_md_from_prsr"_cs, "parser_err"_cs, 16, 0),
104 createExtractCall(packetInParam, "ingress_intrinsic_metadata_t"_cs,
105 parser->tnaParams.at("ig_intr_md"_cs))},
106 checkResubmitState->name);
107 parser->states.push_back(igMetadataState);
108
109 addNewStartState(parser, "ingress_tna_entry_point"_cs, igMetadataState->name);
110}
111
114static void addEgressMetadata(IR::BFN::TnaParser *parser, const IR::ParserState *start_i2e_mirrored,
115 const IR::ParserState *start_e2e_mirrored,
116 const IR::ParserState *start_coalesced,
117 const IR::ParserState *start_egress,
118 std::map<cstring, const IR::SelectCase *> selMap) {
119 auto *p4EntryPointState = convertStartStateToNormalState(parser, "egress_p4_entry_point"_cs);
120
121 // Add a state that parses bridged metadata. This is just a placeholder;
122 // we'll replace it once we know which metadata need to be bridged.
123 auto *bridgedMetadataState = createGeneratedParserState(
124 "bridged_metadata"_cs, {},
125 ((start_egress) ? "start_egress"_cs : p4EntryPointState->name.name));
126 parser->states.push_back(bridgedMetadataState);
127
128 // Similarly, this state is a placeholder which will eventually hold the
129 // parser for mirrored data.
130 IR::Vector<IR::Expression> selectOn;
131 IR::Vector<IR::SelectCase> branchTo;
132 if (start_i2e_mirrored || start_e2e_mirrored || start_coalesced)
133 selectOn.push_back(new IR::Member(new IR::PathExpression(new IR::Path(COMPILER_META)),
134 "instance_type"_cs));
135 if (start_i2e_mirrored) {
136 BUG_CHECK(selMap.count("start_i2e_mirrored"_cs) != 0,
137 "Couldn't find the start_i2e_mirrored state?");
138 branchTo.push_back(selMap.at("start_i2e_mirrored"_cs));
139 }
140 if (start_e2e_mirrored) {
141 BUG_CHECK(selMap.count("start_e2e_mirrored"_cs) != 0,
142 "Couldn't find the start_e2e_mirrored state?");
143 branchTo.push_back(selMap.at("start_e2e_mirrored"_cs));
144 }
145 if (start_coalesced) {
146 BUG_CHECK(selMap.count("start_coalesced"_cs) != 0,
147 "Couldn't find the start_coalesced state?");
148 branchTo.push_back(selMap.at("start_coalesced"_cs));
149 }
150
151 const IR::ParserState *mirroredState = nullptr;
152 if (branchTo.size()) {
153 mirroredState = createGeneratedParserState(
154 "mirrored"_cs, {},
155 new IR::SelectExpression(new IR::ListExpression(selectOn), branchTo));
156 } else {
157 mirroredState = createGeneratedParserState("mirrored"_cs, {}, p4EntryPointState->name);
158 }
159 parser->states.push_back(mirroredState);
160
161 // If this is a mirrored packet, the hardware will have prepended the
162 // contents of the mirror buffer to the actual packet data. To detect this
163 // data, we add a byte to the beginning of the mirror buffer that contains a
164 // flag indicating that it's a mirrored packet. We can use this flag to
165 // distinguish a mirrored packet from a normal packet because we always
166 // begin the bridged metadata we attach to normal packet with an extra byte
167 // which has the mirror indicator flag set to zero.
168 auto packetInParam = parser->tnaParams.at("pkt"_cs);
169 selectOn = {createLookaheadExpr(packetInParam, 8)};
170 auto *checkMirroredState = createGeneratedParserState(
171 "check_mirrored"_cs, {},
172 new IR::SelectExpression(new IR::ListExpression(selectOn),
173 {createSelectCase(8, 0, 1 << 3, bridgedMetadataState),
174 createSelectCase(8, 1 << 3, 1 << 3, mirroredState)}));
175 parser->states.push_back(checkMirroredState);
176
177 // This state handles the extraction of egress intrinsic metadata.
178 // auto headerParam = parser->tnaParams.at("hdr");
179 auto *egMetadataState = createGeneratedParserState(
180 "egress_metadata"_cs,
181 {createSetMetadata("eg_intr_md_from_prsr"_cs, "parser_err"_cs, 16, 0),
182 // createSetMetadata(parser, "eg_intr_md_from_prsr"_cs, "coalesce_sample_count"_cs, 8, 0),
183 createExtractCall(packetInParam, "egress_intrinsic_metadata_t"_cs,
184 parser->tnaParams.at("eg_intr_md"_cs))},
185 checkMirroredState->name);
186 parser->states.push_back(egMetadataState);
187
188 addNewStartState(parser, "egress_tna_entry_point"_cs, egMetadataState->name);
189}
190
195 bool found_start = false;
196
197 public:
198 IR::ParserState *preorder(IR::ParserState *state) override {
199 auto anno = state->getAnnotation("name"_cs);
200 if (!anno) return state;
201 auto name = anno->getExpr(0)->to<IR::StringLiteral>();
202 // We want to check if the .start was found, which indicates that
203 // the p4c indeed added start_0 and .$start and we should
204 // therefore rename the generated start state
205 if (name->value == ".$start") {
206 LOG1("Found p4c added start state for @packet_entry");
207 found_start = true;
208 }
209 return state;
210 }
211
212 IR::BFN::TnaParser *postorder(IR::BFN::TnaParser *parser) override {
213 if (found_start) {
214 LOG1("Renaming p4c generated start state for @packet_entry");
215 convertStartStateToNormalState(parser, "old_p4_start_point_to_be_removed"_cs);
216 }
217 return parser;
218 }
219};
220
221// Add parser code to extract the standard TNA intrinsic metadata.
222// This pass is used by the P4-14 to V1model translation path.
224 const IR::ParserState *start_i2e_mirrored = nullptr;
225 const IR::ParserState *start_e2e_mirrored = nullptr;
226 const IR::ParserState *start_coalesced = nullptr;
227 const IR::ParserState *start_egress = nullptr;
228 // map the name of 'start_i2e_mirrored' ... to the IR::SelectCase
229 // that is used to transit to these state. Used to support extra
230 // entry point to P4-14 parser.
231 std::map<cstring, const IR::SelectCase *> selectCaseMap;
232 cstring p4c_start = nullptr;
233
234 public:
235 AddMetadataFields() { setName("AddMetadataFields"); }
236
237 IR::ParserState *preorder(IR::ParserState *state) override {
238 auto anno = state->getAnnotation("packet_entry"_cs);
239 if (!anno) return state;
240 anno = state->getAnnotation("name"_cs);
241 auto name = anno->getExpr(0)->to<IR::StringLiteral>();
242 if (name->value == ".start_i2e_mirrored") {
243 start_i2e_mirrored = state;
244 } else if (name->value == ".start_e2e_mirrored") {
245 start_e2e_mirrored = state;
246 } else if (name->value == ".start_coalesced") {
247 start_coalesced = state;
248 } else if (name->value == ".start_egress") {
249 start_egress = state;
250 }
251 return state;
252 }
253
254 // Delete the compiler-generated start state from frontend.
255 IR::ParserState *postorder(IR::ParserState *state) override {
256 auto anno = state->getAnnotation("name"_cs);
257 if (!anno) return state;
258 auto name = anno->getExpr(0)->to<IR::StringLiteral>();
259 if (name->value == ".start") {
260 LOG1("found start state ");
261 // Frontend renames 'start' to 'start_0' if the '@packet_entry' pragma is used.
262 // The renamed 'start' state has a "@name('.start')" annotation.
263 // The translation is introduced at frontends/p4/fromv1.0/converters.cpp#L1121
264 // As we will create Tofino-specific start state in this pass, we will need to ensure
265 // that the frontend-generated start state is removed and the original start
266 // state is restored before the logic in this pass modifies the start state.
267 // Basically, the invariant here is to ensure the start state is unmodified,
268 // with or w/o the @packet_entry pragma.
269 p4c_start = state->name;
270 state->name = IR::ParserState::start;
271 return state;
272 } else if (name->value == ".$start") {
273 auto selExpr = state->selectExpression->to<IR::SelectExpression>();
274 BUG_CHECK(selExpr != nullptr, "Couldn't find the select expression?");
275 for (auto c : selExpr->selectCases) {
276 if (c->state->path->name == "start_i2e_mirrored") {
277 selectCaseMap.emplace("start_i2e_mirrored"_cs, c);
278 } else if (c->state->path->name == "start_e2e_mirrored") {
279 selectCaseMap.emplace("start_e2e_mirrored"_cs, c);
280 } else if (c->state->path->name == "start_coalesced") {
281 selectCaseMap.emplace("start_coalesced"_cs, c);
282 } else if (c->state->path->name == "start_egress") {
283 selectCaseMap.emplace("start_egress"_cs, c);
284 }
285 }
286 return nullptr;
287 }
288 return state;
289 }
290
291 // Also rename paths to start_0
292 IR::Path *postorder(IR::Path *path) override {
293 if (path->name.name == p4c_start) path->name = IR::ParserState::start;
294 return path;
295 }
296
297 IR::BFN::TnaParser *postorder(IR::BFN::TnaParser *parser) override {
298 if (parser->thread == INGRESS)
299 addIngressMetadata(parser);
300 else
301 addEgressMetadata(parser, start_i2e_mirrored, start_e2e_mirrored, start_coalesced,
302 start_egress, selectCaseMap);
303 return parser;
304 }
305};
306
308 public:
310 setName("AddIntrinsicMetadata");
311 addPasses({
312 new RenameP4StartState(),
313 new AddMetadataFields(),
315 new P4::ClearTypeMap(typeMap),
316 new BFN::TypeChecking(refMap, typeMap, true),
317 });
318 }
319};
320
321} // namespace BFN
322
323#endif /* BF_P4C_ARCH_INTRINSIC_METADATA_H_ */
Definition intrinsic_metadata.h:307
Definition intrinsic_metadata.h:223
Definition intrinsic_metadata.h:194
Definition typeChecker.h:32
Definition cloner.h:26
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 source_file.h:131
Definition cstring.h:85
size_t bitResubmitSize() const
Definition parde_spec.h:395
The namespace encapsulating Barefoot/Intel-specific stuff.
Definition add_t2na_meta.cpp:21
const IR::Statement * createSetMetadata(cstring header, cstring field, int bitWidth, int constant)
Definition intrinsic_metadata.cpp:120
const IR::Statement * createExtractCall(cstring pkt, cstring type, cstring hdr)
Definition intrinsic_metadata.cpp:151
const IR::ParserState * createGeneratedParserState(cstring name, IR::IndexedVector< IR::StatOrDecl > &&statements, const IR::Expression *selectExpression)
Definition intrinsic_metadata.cpp:82
const IR::Statement * createAdvanceCall(cstring pkt, int bits)
Definition intrinsic_metadata.cpp:100
const IR::Expression * createLookaheadExpr(cstring pkt, int bits)
Definition intrinsic_metadata.cpp:180
const IR::Statement * createSetValid(const Util::SourceInfo &si, cstring header, cstring field)
Definition intrinsic_metadata.cpp:142
const IR::SelectCase * createSelectCase(unsigned bitWidth, unsigned value, unsigned mask, const IR::ParserState *nextState)
Definition intrinsic_metadata.cpp:110