P4C
The P4 Compiler
Loading...
Searching...
No Matches
dpdkArch.h
1/*
2Copyright 2020 Intel Corp.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef BACKENDS_DPDK_DPDKARCH_H_
18#define BACKENDS_DPDK_DPDKARCH_H_
19
20#include "constants.h"
21#include "dpdkProgramStructure.h"
22#include "dpdkUtils.h"
23#include "frontends/common/resolveReferences/resolveReferences.h"
24#include "frontends/p4/evaluator/evaluator.h"
25#include "frontends/p4/sideEffects.h"
26#include "frontends/p4/typeMap.h"
27#include "lib/error.h"
28#include "lib/ordered_map.h"
29#include "midend/flattenInterfaceStructs.h"
30#include "midend/removeLeftSlices.h"
31
32namespace P4::DPDK {
33
34using namespace P4::literals;
35
36cstring TypeStruct2Name(const cstring *s);
37bool isSimpleExpression(const IR::Expression *e);
38bool isNonConstantSimpleExpression(const IR::Expression *e);
39void expressionUnrollSanityCheck(const IR::Expression *e);
40
41using UserMeta = std::set<cstring>;
42
43class CollectMetadataHeaderInfo;
44
45/* According to the implementation of DPDK backend, for a control block, there
46 * are only two parameters: header and metadata. Therefore, first we need to
47 * rewrite the declaration of PSA architecture included in psa.p4 in order to
48 * pass the type checking. In addition, this pass changes the definition of
49 * P4Control and P4Parser(parameter list) in the P4 program provided by the
50 * user.
51 *
52 * This pass also modifies all metadata references and header reference. For
53 * metadata, struct_name.field_name -> m.struct_name_field_name. For header
54 * headers.header_name.field_name -> h.header_name.field_name The parameter
55 * named for header and metadata are also updated to "h" and "m" respectively.
56 */
58 P4::ReferenceMap *refMap;
59 DpdkProgramStructure *structure;
60
61 const IR::Type_Control *rewriteControlType(const IR::Type_Control *, cstring);
62 const IR::Type_Parser *rewriteParserType(const IR::Type_Parser *, cstring);
63 const IR::Type_Control *rewriteDeparserType(const IR::Type_Control *, cstring);
64 const IR::Node *postorder(IR::Type_Control *c) override;
65 const IR::Node *postorder(IR::Type_Parser *p) override;
66 const IR::Node *preorder(IR::Member *m) override;
67 const IR::Node *preorder(IR::PathExpression *pe) override;
68
69 public:
71 : refMap(refMap), structure(structure) {
72 CHECK_NULL(structure);
73 }
74};
75
110 std::unordered_map<const IR::P4Program *, IR::IndexedVector<IR::Node>> newHeaderMap;
111 std::unordered_map<const IR::P4Parser *, IR::IndexedVector<IR::Declaration>> newLocalVarMap;
112 std::unordered_map<const IR::AssignmentStatement *, IR::IndexedVector<IR::StatOrDecl>>
113 newStatMap;
114
115 public:
116 void insertHeader(const IR::P4Program *p, const IR::Type_Header *h) {
117 if (newHeaderMap.count(p)) {
118 newHeaderMap.at(p).push_back(h);
119 } else {
120 newHeaderMap.emplace(p, IR::IndexedVector<IR::Node>(h));
121 }
122 LOG5("Program: " << dbp(p));
123 LOG2("Adding new header:" << std::endl << " " << h);
124 }
125 IR::IndexedVector<IR::Node> *getHeaders(const IR::P4Program *p) {
126 if (newHeaderMap.count(p)) {
127 return new IR::IndexedVector<IR::Node>(newHeaderMap.at(p));
128 }
129 return nullptr;
130 }
131 void insertVar(const IR::P4Parser *p, const IR::Declaration_Variable *v) {
132 if (newLocalVarMap.count(p)) {
133 newLocalVarMap.at(p).push_back(v);
134 } else {
135 newLocalVarMap.emplace(p, IR::IndexedVector<IR::Declaration>(v));
136 }
137 LOG5("Parser: " << dbp(p));
138 LOG2("Adding new local variable:" << std::endl << " " << v);
139 }
140 IR::IndexedVector<IR::Declaration> *getVars(const IR::P4Parser *p) {
141 if (newLocalVarMap.count(p)) {
142 return new IR::IndexedVector<IR::Declaration>(newLocalVarMap.at(p));
143 }
144 return nullptr;
145 }
146 void insertStatements(const IR::AssignmentStatement *as,
148 BUG_CHECK(newStatMap.count(as) == 0,
149 "Unexpectedly converting statement %1% multiple times!", as);
150 newStatMap.emplace(as, *vec);
151 LOG5("AssignmentStatement: " << dbp(as));
152 LOG2("Adding new statements:");
153 for (auto s : *vec) {
154 LOG2(" " << s);
155 }
156 }
157 IR::IndexedVector<IR::StatOrDecl> *getStatements(const IR::AssignmentStatement *as) {
158 if (newStatMap.count(as)) {
159 return new IR::IndexedVector<IR::StatOrDecl>(newStatMap.at(as));
160 }
161 return nullptr;
162 }
163 };
164
165 ReplacementMap repl;
166
167 class Collect : public Inspector {
168 P4::ReferenceMap *refMap;
169 P4::TypeMap *typeMap;
170 ReplacementMap *repl;
171
172 public:
173 Collect(P4::ReferenceMap *refMap, P4::TypeMap *typeMap, ReplacementMap *repl)
174 : refMap(refMap), typeMap(typeMap), repl(repl) {}
175 void postorder(const IR::AssignmentStatement *statement) override;
176 };
177
178 class Replace : public Transform {
179 DpdkProgramStructure *structure;
180 ReplacementMap *repl;
181
182 public:
184 : structure(structure), repl(repl) {}
185 const IR::Node *postorder(IR::AssignmentStatement *as) override;
186 const IR::Node *postorder(IR::Type_Struct *s) override;
187 const IR::Node *postorder(IR::P4Parser *parser) override;
188 };
189
191 passes.push_back(new P4::TypeChecking(refMap, typeMap));
192 passes.push_back(new Collect(refMap, typeMap, &repl));
193 passes.push_back(new Replace(s, &repl));
194 passes.push_back(new P4::ClearTypeMap(typeMap));
195 }
196};
197
198// This Pass collects infomation about the name of all metadata and header
199// And it collects every field of metadata and renames all fields with a prefix
200// according to the metadata struct name. Eventually, the reference of a fields
201// will become m.$(struct_name)_$(field_name).
203 DpdkProgramStructure *structure;
204
205 void pushMetadata(const IR::Parameter *p);
206 void pushMetadata(const IR::ParameterList *, std::list<int> indices);
207
208 public:
209 explicit CollectMetadataHeaderInfo(DpdkProgramStructure *structure) : structure(structure) {}
210 bool preorder(const IR::P4Program *p) override;
211 bool preorder(const IR::Type_Struct *s) override;
212};
213
214// Previously, we have collected the information about how the single metadata
215// struct looks like in CollectMetadataHeaderInfo. This pass finds a suitable
216// place to inject this struct.
218 DpdkProgramStructure *structure;
219
220 public:
221 explicit InjectJumboStruct(DpdkProgramStructure *structure) : structure(structure) {}
222 const IR::Node *preorder(IR::Type_Struct *s) override;
223};
224
225// This pass injects metadata field which is used as port for 'tx' instruction
226// into the single metadata struct.
227// This pass has to be applied after CollectMetadataHeaderInfo fills
228// local_metadata_type field in DpdkProgramStructure which is passed to the constructor.
230 DpdkProgramStructure *structure;
231
232 public:
233 explicit InjectFixedMetadataField(DpdkProgramStructure *structure) : structure(structure) {}
234 const IR::Node *preorder(IR::Type_Struct *s) override;
235};
236
241 DpdkProgramStructure *structure;
242
244
245 public:
246 explicit AlignHdrMetaField(DpdkProgramStructure *structure) : structure(structure) {
247 CHECK_NULL(structure);
248 }
249 const IR::Node *preorder(IR::Type_StructLike *st) override;
250 const IR::Node *preorder(IR::Member *m) override;
251};
252
253struct ByteAlignment : public PassManager {
254 P4::TypeMap *typeMap;
255 P4::ReferenceMap *refMap;
256 DpdkProgramStructure *structure;
257
258 public:
260 : typeMap(typeMap), refMap(refMap), structure(structure) {
261 CHECK_NULL(structure);
262 passes.push_back(new AlignHdrMetaField(structure));
263 passes.push_back(new P4::ClearTypeMap(typeMap));
264 passes.push_back(new P4::TypeChecking(refMap, typeMap, true));
265 /* DoRemoveLeftSlices pass converts the slice Member (LHS in assn stm)
266 resulting from above Pass into shift operation */
267 passes.push_back(new P4::DoRemoveLeftSlices(typeMap));
268 passes.push_back(new P4::ClearTypeMap(typeMap));
269 passes.push_back(new P4::TypeChecking(refMap, typeMap, true));
270 }
271};
272
274 public:
275 const IR::Node *postorder(IR::Type_Struct *st) override;
276};
277
278struct fieldInfo {
279 unsigned fieldWidth;
280 fieldInfo() { fieldWidth = 0; }
281};
282
283// This class is helpful for StatementUnroll and IfStatementUnroll. Since dpdk
284// asm is not able to process complex expression, e.g., a = b + c * d. We need
285// break it down. Therefore, we need some temporary variables to hold the
286// intermediate values. And this class is helpful to inject the declarations of
287// temporary value into P4Control and P4Parser.
289 std::map<const IR::Node *, IR::IndexedVector<IR::Declaration> *> decl_map;
290
291 public:
292 // push the declaration to the right code block.
293 void collect(const IR::P4Control *control, const IR::P4Parser *parser,
294 const IR::Declaration *decl) {
295 IR::IndexedVector<IR::Declaration> *decls = nullptr;
296 if (parser) {
297 auto res = decl_map.find(parser);
298 if (res != decl_map.end()) {
299 decls = res->second;
300 } else {
302 decl_map.emplace(parser, decls);
303 }
304 } else if (control) {
305 auto res = decl_map.find(control);
306 if (res != decl_map.end()) {
307 decls = res->second;
308 } else {
310 decl_map.emplace(control, decls);
311 }
312 }
313 BUG_CHECK(decls != nullptr, "decls cannot be null");
314 decls->push_back(decl);
315 }
316 IR::Node *inject_control(const IR::Node *orig, IR::P4Control *control) {
317 auto res = decl_map.find(orig);
318 if (res == decl_map.end()) {
319 return control;
320 }
321 control->controlLocals.prepend(*res->second);
322 return control;
323 }
324 IR::Node *inject_parser(const IR::Node *orig, IR::P4Parser *parser) {
325 auto res = decl_map.find(orig);
326 if (res == decl_map.end()) {
327 return parser;
328 }
329 parser->parserLocals.prepend(*res->second);
330 return parser;
331 }
332};
333
334/* This pass breaks complex expressions down, since dpdk asm cannot describe
335 * complex expression. This pass is not complete. MethodCallStatement should be
336 * unrolled as well. Note that IfStatement should not be unrolled here, as we
337 * have a separate pass for it, because IfStatement does not want to unroll
338 * logical expression(dpdk asm has conditional jmp for these cases)
339 */
341 private:
342 P4::ReferenceMap *refMap;
343 DpdkProgramStructure *structure;
344 DeclarationInjector injector;
345
346 public:
348 : refMap(refMap), structure(structure) {}
349 const IR::Node *preorder(IR::AssignmentStatement *a) override;
350 const IR::Node *postorder(IR::P4Control *a) override;
351 const IR::Node *postorder(IR::P4Parser *a) override;
352};
353
354/* This pass helps StatementUnroll to unroll expressions inside statements.
355 * For example, if an AssignmentStatement looks like this: a = b + c * d
356 * StatementUnroll's AssignmentStatement preorder will call ExpressionUnroll
357 * twice for BinaryExpression's left(b) and right(c * d). For left, since it is
358 * a simple expression, ExpressionUnroll will set root to PathExpression(b) and
359 * the decl and stmt is empty. For right, ExpressionUnroll will set root to
360 * PathExpression(tmp), decl contains tmp's declaration and stmt contains:
361 * tmp = c * d, which will be injected in front of the AssignmentStatement.
362 */
364 P4::ReferenceMap *refMap;
365
366 public:
369 IR::PathExpression *root;
370 ExpressionUnroll(P4::ReferenceMap *refMap, DpdkProgramStructure *) : refMap(refMap) {
371 setName("ExpressionUnroll");
372 }
373 bool preorder(const IR::Operation_Unary *a) override;
374 bool preorder(const IR::Operation_Binary *a) override;
375 bool preorder(const IR::MethodCallExpression *a) override;
376 bool preorder(const IR::Member *a) override;
377 bool preorder(const IR::PathExpression *a) override;
378 bool preorder(const IR::Constant *a) override;
379 bool preorder(const IR::BoolLiteral *a) override;
380};
381
382// This pass is similiar to StatementUnroll pass, the difference is that this
383// pass will call LogicalExpressionUnroll to unroll the expression, which treat
384// logical expression differently.
386 private:
387 P4::ReferenceMap *refMap;
388 DeclarationInjector injector;
389
390 public:
391 explicit IfStatementUnroll(P4::ReferenceMap *refMap) : refMap(refMap) {
392 setName("IfStatementUnroll");
393 }
394 const IR::Node *postorder(IR::SwitchStatement *a) override;
395 const IR::Node *postorder(IR::IfStatement *a) override;
396 const IR::Node *postorder(IR::P4Control *a) override;
397 const IR::Node *postorder(IR::P4Parser *a) override;
398};
399
400/* Assume one logical expression looks like this: a && (b + c > d), this pass
401 * will unroll the expression to {tmp = b + c; if(a && (tmp > d))}. Logical
402 * calculation will be unroll in a dedicated pass.
403 */
405 P4::ReferenceMap *refMap;
406
407 public:
410 IR::Expression *root;
411 static bool is_logical(const IR::Operation_Binary *bin) {
412 if (bin->is<IR::LAnd>() || bin->is<IR::LOr>() || bin->is<IR::Leq>() || bin->is<IR::Equ>() ||
413 bin->is<IR::Neq>() || bin->is<IR::Grt>() || bin->is<IR::Lss>() || bin->is<IR::Geq>() ||
414 bin->is<IR::Leq>())
415 return true;
416 else
417 return false;
418 }
419
420 explicit LogicalExpressionUnroll(P4::ReferenceMap *refMap) : refMap(refMap) {
421 visitDagOnce = false;
422 }
423 bool preorder(const IR::Operation_Unary *a) override;
424 bool preorder(const IR::Operation_Binary *a) override;
425 bool preorder(const IR::MethodCallExpression *a) override;
426 bool preorder(const IR::Member *a) override;
427 bool preorder(const IR::PathExpression *a) override;
428 bool preorder(const IR::Constant *a) override;
429 bool preorder(const IR::BoolLiteral *a) override;
430};
431
432// According to dpdk spec, Binary Operation will only have two parameters, which
433// looks like: a = a + b. Therefore, this pass transform all AssignStatement
434// that has Binary_Operation to become two-parameter form.
436 DeclarationInjector injector;
437 P4::ReferenceMap *refMap;
438
439 public:
440 explicit ConvertBinaryOperationTo2Params(P4::ReferenceMap *refMap) : refMap(refMap) {}
441 const IR::Node *postorder(IR::AssignmentStatement *a) override;
442 const IR::Node *postorder(IR::P4Control *a) override;
443 const IR::Node *postorder(IR::P4Parser *a) override;
444};
445
446// Since in dpdk asm, there is no local variable declaration, we need to collect
447// all local variables and inject them into the metadata struct.
448// Local variables which are of header types are injected into headers struct
449// instead of metadata struct, so that they can be instantiated as headers in the
450// resulting dpdk asm file.
453 P4::ReferenceMap *refMap;
454 P4::TypeMap *typeMap;
455 DpdkProgramStructure *structure;
456
457 void insert(const cstring prefix, const IR::IndexedVector<IR::Declaration> *locals) {
458 for (auto d : *locals) {
459 if (auto dv = d->to<IR::Declaration_Variable>()) {
460 const cstring name = refMap->newName(prefix + "_" + dv->name.name);
461 localsMap.emplace(dv, name);
462 } else if (!d->is<IR::P4Action>() && !d->is<IR::P4Table>() &&
463 !d->is<IR::Declaration_Instance>()) {
464 BUG("%1%: Unhandled declaration type", d);
465 }
466 }
467 }
468
469 public:
471 DpdkProgramStructure *structure)
472 : refMap(refMap), typeMap(typeMap), structure(structure) {}
473 const IR::Node *preorder(IR::P4Program *p) override;
474 const IR::Node *postorder(IR::Type_Struct *s) override;
475 const IR::Node *postorder(IR::Member *m) override;
476 const IR::Node *postorder(IR::PathExpression *path) override;
477 const IR::Node *postorder(IR::P4Control *c) override;
478 const IR::Node *postorder(IR::P4Parser *p) override;
479};
480
481// According to dpdk spec, action parameters should prepend a p. In order to
482// respect this, we need at first make all action parameter lists into separate
483// structs and declare that struct in the P4 program. Then we modify the action
484// parameter list. Eventually, it will only contain one parameter `t`, which is a
485// struct containing all parameters previously defined. Next, we prepend t. in
486// front of action parameters. Please note that it is possible that the user
487// defines a struct paremeter himself or define multiple struct parameters in
488// action parameterlist. Current implementation does not support this.
490 P4::TypeMap *typeMap;
491 P4::ReferenceMap *refMap;
492 DpdkProgramStructure *structure;
493
494 public:
496 DpdkProgramStructure *structure)
497 : typeMap(typeMap), refMap(refMap), structure(structure) {}
498 const IR::Node *postorder(IR::P4Action *a) override;
499 const IR::Node *postorder(IR::P4Program *s) override;
500 const IR::Node *preorder(IR::PathExpression *path) override;
501 const IR::Node *preorder(IR::MethodCallExpression *) override;
502};
503
504/* This class is used to process the default action
505 and store the parameter list for each table.
506 Later, this infomation is passed and saved in table
507 properties and then used for generating instruction
508 for default action in each table.
509*/
510class DefActionValue : public Inspector {
511 P4::TypeMap *typeMap;
512 P4::ReferenceMap *refMap;
513 DpdkProgramStructure *structure;
514
515 public:
517 : typeMap(typeMap), refMap(refMap), structure(structure) {}
518 void postorder(const IR::P4Table *t) override;
519};
520
521// dpdk does not support ternary operator so we need to translate ternary operator
522// to corresponding if else statement
523// Taken from frontend pass DoSimplifyExpressions in sideEffects.h
525 P4::TypeMap *typeMap;
526 P4::ReferenceMap *refMap;
527 IR::IndexedVector<IR::Declaration> toInsert; // temporaries
529
530 cstring createTemporary(const IR::Type *type);
531 const IR::Expression *addAssignment(Util::SourceInfo srcInfo, cstring varName,
532 const IR::Expression *expression);
533
534 public:
536 : typeMap(typeMap), refMap(refMap) {}
537 const IR::Node *preorder(IR::Mux *expression) override;
538 const IR::Node *postorder(IR::P4Parser *parser) override;
539 const IR::Node *postorder(IR::Function *function) override;
540 const IR::Node *postorder(IR::P4Control *control) override;
541 const IR::Node *postorder(IR::P4Action *action) override;
542 const IR::Node *postorder(IR::AssignmentStatement *statement) override;
543};
544
545// For dpdk asm, there is not object-oriented. Therefore, we cannot define a
546// checksum in dpdk asm. And dpdk asm only provides ckadd(checksum add) and
547// cksub(checksum sub). So we need to define a explicit state for each checksum
548// declaration. Essentially, this state will be declared in header struct and
549// initilized to 0. And for cksum.add(x), it will be translated to ckadd state
550// x. For dst = cksum.get(), it will be translated to mov dst state. This pass
551// collects checksum instances and index them.
553 P4::TypeMap *typeMap;
554 DpdkProgramStructure *structure;
555 std::vector<cstring> *csum_vec;
556 int index = 0;
557
558 public:
560 std::vector<cstring> *csum_vec)
561 : typeMap(typeMap), structure(structure), csum_vec(csum_vec) {}
562 bool preorder(const IR::Declaration_Instance *d) override {
563 auto type = typeMap->getType(d, true);
564 if (auto extn = type->to<IR::Type_Extern>()) {
565 if (extn->name == "InternetChecksum") {
566 std::ostringstream s;
567 s << "state_" << index++;
568 csum_vec->push_back(s.str());
569 structure->csum_map.emplace(d, s.str());
570 }
571 }
572 return false;
573 }
574};
575
576// This pass will inject checksum states into header. The reason why we inject
577// state into header instead of metadata is due to the implementation of dpdk
578// side(a question related to endianness)
580 DpdkProgramStructure *structure;
581 std::vector<cstring> *csum_vec;
582
583 public:
585 std::vector<cstring> *csum_vec)
586 : structure(structure), csum_vec(csum_vec) {}
587
588 const IR::Node *postorder(IR::P4Program *p) override {
589 auto new_objs = new IR::Vector<IR::Node>;
590 bool inserted = false;
591 for (auto obj : p->objects) {
592 if (obj->to<IR::Type_Header>() && !inserted) {
593 inserted = true;
594 if (csum_vec->size() > 0) {
595 auto fields = new IR::IndexedVector<IR::StructField>;
596 for (auto fld : *csum_vec) {
597 fields->push_back(
598 new IR::StructField(IR::ID(fld), IR::Type::Bits::get(16, false)));
599 }
600 new_objs->push_back(new IR::Type_Header(IR::ID("cksum_state_t"), *fields));
601 }
602 }
603 new_objs->push_back(obj);
604 }
605 p->objects = *new_objs;
606 return p;
607 }
608
609 const IR::Node *postorder(IR::Type_Struct *s) override {
610 if (s->name.name == structure->header_type) {
611 if (structure->csum_map.size() > 0)
612 s->fields.push_back(new IR::StructField(
613 IR::ID("cksum_state"), new IR::Type_Name(IR::ID("cksum_state_t"))));
614 }
615 return s;
616 }
617};
618
620 std::vector<cstring> csum_vec;
621
622 public:
624 passes.push_back(new CollectInternetChecksumInstance(typeMap, structure, &csum_vec));
625 passes.push_back(new InjectInternetChecksumIntermediateValue(structure, &csum_vec));
626 }
627};
628
629/* This pass collects PSA extern meter, counter and register declaration instances and
630 push them to a vector for emitting to the .spec file later */
632 DpdkProgramStructure *structure;
633
634 public:
635 explicit CollectExternDeclaration(DpdkProgramStructure *structure) : structure(structure) {}
636 bool preorder(const IR::Declaration_Instance *d) override {
637 if (auto type = d->type->to<IR::Type_Name>()) {
638 auto externTypeName = type->path->name.name;
639 if (externTypeName == "DirectMeter") {
640 if (d->arguments->size() != 1) {
641 ::P4::error(ErrorType::ERR_EXPECTED,
642 "%1%: expected type of meter as the only argument", d);
643 } else {
644 /* Check if the Direct meter is of PACKETS (0) type */
645 if (d->arguments->at(0)->expression->to<IR::Constant>()->asUnsigned() == 0)
646 warn(ErrorType::WARN_UNSUPPORTED,
647 "%1%: Packet metering is not supported."
648 " Falling back to byte metering.",
649 d);
650 }
651 } else {
652 // unsupported extern type
653 return false;
654 }
655 structure->externDecls.push_back(d);
656 } else if (auto type = d->type->to<IR::Type_Specialized>()) {
657 auto externTypeName = type->baseType->path->name.name;
658 if (externTypeName == "Meter") {
659 if (d->arguments->size() != 2) {
660 ::P4::error(ErrorType::ERR_EXPECTED,
661 "%1%: expected number of meters and type of meter as arguments", d);
662 } else {
663 /* Check if the meter is of PACKETS (0) type */
664 if (d->arguments->at(1)->expression->to<IR::Constant>()->asUnsigned() == 0)
665 warn(ErrorType::WARN_UNSUPPORTED,
666 "%1%: Packet metering is not supported."
667 " Falling back to byte metering.",
668 d);
669 }
670 } else if (externTypeName == "Counter") {
671 if (d->arguments->size() != 2) {
672 ::P4::error(ErrorType::ERR_EXPECTED,
673 "%1%: expected number of counters and type of counter as arguments",
674 d);
675 }
676 } else if (externTypeName == "DirectCounter") {
677 if (d->arguments->size() != 1) {
678 ::P4::error(ErrorType::ERR_EXPECTED,
679 "%1%: expected type of counter as the only argument", d);
680 }
681 } else if (externTypeName == "Register") {
682 if (d->arguments->size() != 1 && d->arguments->size() != 2) {
683 ::P4::error(ErrorType::ERR_EXPECTED,
684 "%1%: expected size and optionally init_val as arguments", d);
685 }
686 } else if (externTypeName == "Hash") {
687 if (d->arguments->size() != 1) {
688 ::P4::error(ErrorType::ERR_EXPECTED,
689 "%1%: expected hash algorithm as the only argument", d);
690 }
691 } else {
692 // unsupported extern type
693 return false;
694 }
695 structure->externDecls.push_back(d);
696 }
697 return false;
698 }
699};
700
701// This pass is preparing logical expression for following branching statement
702// optimization. This pass breaks parenthesis looks liks this: (a && b) && c.
703// After this pass, the expression looks like this: a && b && c. (The AST is
704// different).
706 public:
707 const IR::Node *postorder(IR::LAnd *land) {
708 if (auto land2 = land->left->to<IR::LAnd>()) {
709 auto sub = new IR::LAnd(land2->right, land->right);
710 return new IR::LAnd(land2->left, sub);
711 } else if (!land->left->is<IR::LOr>() && !land->left->is<IR::Equ>() &&
712 !land->left->is<IR::Neq>() && !land->left->is<IR::Leq>() &&
713 !land->left->is<IR::Geq>() && !land->left->is<IR::Lss>() &&
714 !land->left->is<IR::Grt>() && !land->left->is<IR::MethodCallExpression>() &&
715 !land->left->is<IR::PathExpression>() && !land->left->is<IR::Member>()) {
716 BUG("Logical Expression Unroll pass failed");
717 }
718 return land;
719 }
720 const IR::Node *postorder(IR::LOr *lor) {
721 if (auto lor2 = lor->left->to<IR::LOr>()) {
722 auto sub = new IR::LOr(lor2->right, lor->right);
723 return new IR::LOr(lor2->left, sub);
724 } else if (!lor->left->is<IR::LAnd>() && !lor->left->is<IR::Equ>() &&
725 !lor->left->is<IR::Neq>() && !lor->left->is<IR::Lss>() &&
726 !lor->left->is<IR::Grt>() && !lor->left->is<IR::MethodCallExpression>() &&
727 !lor->left->is<IR::PathExpression>() && !lor->left->is<IR::Member>()) {
728 BUG("Logical Expression Unroll pass failed");
729 }
730 return lor;
731 }
732};
733
734// This pass will swap the simple expression to the front of an logical
735// expression. Note that even for a subexpression of a logical expression, we
736// will swap it as well. For example, a && ((b && c) || d), will become
737// a && (d || (b && c))
739 bool is_simple(const IR::Node *n) {
740 if (n->is<IR::Equ>() || n->is<IR::Neq>() || n->is<IR::Lss>() || n->is<IR::Grt>() ||
741 n->is<IR::Geq>() || n->is<IR::Leq>() || n->is<IR::MethodCallExpression>() ||
742 n->is<IR::PathExpression>() || n->is<IR::Member>()) {
743 return true;
744 } else if (!n->is<IR::LAnd>() && !n->is<IR::LOr>()) {
745 BUG("Logical Expression Unroll pass failed");
746 } else {
747 return false;
748 }
749 }
750
751 public:
752 const IR::Node *postorder(IR::LAnd *land) {
753 if (!is_simple(land->left) && is_simple(land->right)) {
754 return new IR::LAnd(land->right, land->left);
755 } else if (!is_simple(land->left)) {
756 if (auto land2 = land->right->to<IR::LAnd>()) {
757 if (is_simple(land2->left)) {
758 auto sub = new IR::LAnd(land->left, land2->right);
759 return new IR::LAnd(land2->left, sub);
760 }
761 }
762 }
763 return land;
764 }
765 const IR::Node *postorder(IR::LOr *lor) {
766 if (!is_simple(lor->left) && is_simple(lor->right)) {
767 return new IR::LOr(lor->right, lor->left);
768 } else if (!is_simple(lor->left)) {
769 if (auto lor2 = lor->right->to<IR::LOr>()) {
770 if (is_simple(lor2->left)) {
771 auto sub = new IR::LOr(lor->left, lor2->right);
772 return new IR::LOr(lor2->left, sub);
773 }
774 }
775 }
776 return lor;
777 }
778};
779
780// This passmanager togethor transform logical expression into a form that
781// the simple expression will go to the front of the expression. And for
782// expression at the same level(the same level is that expressions that are
783// connected directly by && or ||) should be traversed from left to right
784// (a && b) && c is not a valid expression here.
786 public:
789 passes.push_back(r);
791 passes.push_back(r);
792 }
793};
794
795// This Pass collects infomation about the table keys for each table. This information
796// is later used for generating the context JSON output for use by the control plane
797// software.
799 DpdkProgramStructure *structure;
800
801 public:
802 explicit CollectTableInfo(DpdkProgramStructure *structure) : structure(structure) {
803 setName("CollectTableInfo");
804 }
805 bool preorder(const IR::Key *key) override;
806};
807
808// This pass transforms the tables such that all the Match keys are part of the same
809// header/metadata struct. If the match keys are from different headers, this pass creates
810// mirror copies of the struct field into the metadata struct and updates the table to use
811// the metadata copy.
812// This pass must be called right before CollectLocalVariables pass as the temporary
813// variables created for holding copy of the table keys are inserted to Metadata by
814// CollectLocalVariables pass.
816 int offsetInMetadata;
817 int size;
818};
819
820struct keyInfo {
821 int numElements;
822 int numExistingMetaFields;
823 bool isLearner;
824 bool isExact;
825 int size;
826 std::vector<struct keyElementInfo *> elements;
827};
828
831 DpdkProgramStructure *structure;
832 bool metaCopyNeeded = false;
833
834 public:
835 CopyMatchKeysToSingleStruct(P4::TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey,
836 DpdkProgramStructure *structure)
837 : P4::KeySideEffect(typeMap, invokedInKey), structure(structure) {
838 setName("CopyMatchKeysToSingleStruct");
839 }
840
841 const IR::Node *preorder(IR::Key *key) override;
842 const IR::Node *postorder(IR::KeyElement *element) override;
843 const IR::Node *doStatement(const IR::Statement *statement, const IR::Expression *expression,
844 const Visitor::Context *ctxt) override;
845 struct keyInfo *getKeyInfo(IR::Key *keys);
846 cstring getTableKeyName(const IR::Expression *e);
847 int getFieldSizeBits(const IR::Type *field_type);
848 bool isLearnerTable(const IR::P4Table *t);
849};
850
852 // Map which holds the switch expression variable and constant tuple per switch statement for
853 // each action.
854 // action_name: {<switch_var, constant_value>, <switch_var1, constant_value1>, ...}
855 std::map<cstring, std::vector<std::tuple<cstring, IR::Constant *>>> actionCaseMap;
856
857 public:
858 // Fill Switch Action Map
859 void addToSwitchMap(cstring actionName, cstring switchExprTmp, IR::Constant *caseLabelValue) {
860 actionCaseMap[actionName].push_back(std::make_tuple(switchExprTmp, caseLabelValue));
861 }
862
863 const IR::Node *setSwitchVarInAction(IR::P4Action *action) {
864 if (actionCaseMap.count(action->name.name)) {
865 // Insert assignment statements for each switch statement which uses this action name as
866 // switch case.
867 auto acm = actionCaseMap[action->name.name];
868 auto body = new IR::BlockStatement(action->body->srcInfo);
869 for (auto pair : acm) {
870 auto assn = new IR::AssignmentStatement(
871 new IR::PathExpression(IR::ID(get<0>(pair))), get<1>(pair));
872 body->push_back(assn);
873 }
874 for (auto s : action->body->components) body->push_back(s);
875 action->body = body;
876 actionCaseMap.erase(action->name.name);
877 }
878 return action;
879 }
880};
881
886 cstring switchExprTmp;
887 DeclarationInjector injector;
888
889 public:
890 enum class TableImplementation { DEFAULT, ACTION_PROFILE, ACTION_SELECTOR };
891 P4::ReferenceMap *refMap;
892 P4::TypeMap *typeMap;
893 DpdkProgramStructure *structure;
894 SwitchHandler &sw;
895 TableImplementation implementation;
896 std::set<cstring> match_tables;
897 std::map<cstring, cstring> group_tables;
898 std::map<cstring, cstring> member_tables;
899 std::map<cstring, cstring> member_ids;
900 std::map<cstring, cstring> group_ids;
901
903 DpdkProgramStructure *structure, SwitchHandler &sw)
904 : refMap(refMap), typeMap(typeMap), structure(structure), sw(sw) {
905 implementation = TableImplementation::DEFAULT;
906 }
907
908 const IR::Node *postorder(IR::MethodCallStatement *) override;
909 const IR::Node *postorder(IR::IfStatement *) override;
910 const IR::Node *postorder(IR::SwitchStatement *) override;
911 const IR::Node *postorder(IR::P4Control *) override;
912 std::tuple<const IR::P4Table *, cstring, cstring> create_match_table(
913 const IR::P4Table * /* tbl */);
914 const IR::P4Action *create_action(cstring /* actionName */, cstring /* id */, cstring);
915 const IR::P4Table *create_member_table(const IR::P4Table *, cstring, cstring);
916 const IR::P4Table *create_group_table(const IR::P4Table *, cstring, cstring, cstring, unsigned,
917 unsigned);
918 IR::Expression *initializeMemberAndGroupId(cstring tableName,
920};
921
929 public:
931 DpdkProgramStructure *structure, SwitchHandler &sw)
932 : SplitP4TableCommon(refMap, typeMap, structure, sw) {
933 implementation = TableImplementation::ACTION_SELECTOR;
934 }
935 const IR::Node *postorder(IR::P4Table *tbl) override;
936};
937
944 public:
946 DpdkProgramStructure *structure, SwitchHandler &sw)
947 : SplitP4TableCommon(refMap, typeMap, structure, sw) {
948 implementation = TableImplementation::ACTION_PROFILE;
949 }
950 const IR::Node *postorder(IR::P4Table *tbl) override;
951};
952
973 SwitchHandler &sw;
974
975 public:
976 explicit UpdateActionForSwitch(SwitchHandler &sw) : sw(sw) { setName("UpdateActionForSwitch"); }
977 const IR::Node *postorder(IR::P4Action *action) { return sw.setSwitchVarInAction(action); }
978};
982 SwitchHandler sw;
983
984 public:
986 DpdkProgramStructure *structure) {
987 passes.emplace_back(new P4::TypeChecking(refMap, typeMap));
988 passes.emplace_back(new SplitActionSelectorTable(refMap, typeMap, structure, sw));
989 passes.emplace_back(new UpdateActionForSwitch(sw));
990 passes.push_back(new P4::ClearTypeMap(typeMap));
991 passes.emplace_back(new P4::TypeChecking(refMap, typeMap, true));
992 passes.emplace_back(new SplitActionProfileTable(refMap, typeMap, structure, sw));
993 passes.emplace_back(new UpdateActionForSwitch(sw));
994 passes.push_back(new P4::ClearTypeMap(typeMap));
995 passes.emplace_back(new P4::TypeChecking(refMap, typeMap, true));
996 }
997};
998
999/* Collect size information from the owner table for direct counter and meter extern objects
1000 * and validate some of the constraints on usage of Direct Meter and Direct Counter extern
1001 * methods */
1003 P4::ReferenceMap *refMap;
1004 P4::TypeMap *typeMap;
1005 DpdkProgramStructure *structure;
1006 // To validate presence of specified method call for instancename within given action
1007 cstring method;
1008 cstring instancename;
1009 // To validate that same method call for different direct meter/counter instance does not exist
1010 // in any action
1011 cstring oneInstance;
1012 bool methodCallFound;
1013 int getTableSize(const IR::P4Table *tbl);
1014 bool ifMethodFound(const IR::P4Action *a, cstring method,
1015 cstring instancename = cstring::empty);
1016 void checkMethodCallInAction(const P4::ExternMethod *);
1017
1018 public:
1019 static ordered_map<cstring, int> directMeterCounterSizeMap;
1021 DpdkProgramStructure *structure)
1022 : refMap(refMap), typeMap(typeMap), structure(structure) {
1023 setName("CollectDirectCounterMeter");
1024 visitDagOnce = false;
1025 method = cstring::empty;
1026 instancename = cstring::empty;
1027 oneInstance = cstring::empty;
1028 methodCallFound = false;
1029 }
1030
1031 bool preorder(const IR::MethodCallStatement *mcs) override;
1032 bool preorder(const IR::AssignmentStatement *assn) override;
1033 bool preorder(const IR::P4Action *a) override;
1034 bool preorder(const IR::P4Table *t) override;
1035};
1036
1038 P4::ReferenceMap *refMap;
1039 P4::TypeMap *typeMap;
1040 DpdkProgramStructure *structure;
1041 void validateMethodInvocation(P4::ExternMethod *);
1042
1043 public:
1045 DpdkProgramStructure *structure)
1046 : refMap(refMap), typeMap(typeMap), structure(structure) {}
1047
1048 void postorder(const IR::AssignmentStatement *) override;
1049 void postorder(const IR::MethodCallStatement *) override;
1050};
1051
1053 P4::ReferenceMap *refMap;
1054 P4::TypeMap *typeMap;
1055 DpdkProgramStructure *structure;
1056
1057 public:
1059 DpdkProgramStructure *structure)
1060 : refMap(refMap), typeMap(typeMap), structure(structure) {}
1061
1062 void postorder(const IR::P4Table *t) override;
1063 void postorder(const IR::MethodCallStatement *) override;
1064};
1065
1067 P4::ReferenceMap *refMap;
1068 P4::TypeMap *typeMap;
1069 DpdkProgramStructure *structure;
1070
1071 public:
1073 DpdkProgramStructure *structure)
1074 : refMap(refMap), typeMap(typeMap), structure(structure) {}
1075
1076 void postorder(const IR::MethodCallStatement *) override;
1077 cstring getDefActionName(const IR::P4Table *t) {
1078 auto act = t->getDefaultAction();
1079 BUG_CHECK(act != nullptr, "%1%: default action does not exist", t);
1080 if (auto mc = act->to<IR::MethodCallExpression>()) {
1081 auto method = mc->method->to<IR::PathExpression>();
1082 return method->path->name;
1083 }
1084 return NULL;
1085 }
1086};
1087
1088// Dpdk does not allow operations (arithmetic, logical, bitwise, relational etc) on operands
1089// greater than 64-bit.
1091 public:
1092 ValidateOperandSize() { setName("ValidateOperandSize"); }
1093 void isValidOperandSize(const IR::Expression *e) {
1094 if (auto t = e->type->to<IR::Type_Bits>()) {
1095 if (t->width_bits() > dpdk_max_operand_size) {
1096 ::P4::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Unsupported bitwidth %1% in %2%",
1097 t->width_bits(), e);
1098 return;
1099 }
1100 }
1101 }
1102
1103 void postorder(const IR::Operation_Binary *binop) override {
1104 isValidOperandSize(binop->left);
1105 isValidOperandSize(binop->right);
1106 }
1107
1108 // Reject all operations except typecast if the operand size is beyond the supported limit
1109 void postorder(const IR::Operation_Unary *unop) override {
1110 if (unop->is<IR::Cast>()) return;
1111 isValidOperandSize(unop->expr);
1112 }
1113
1114 void postorder(const IR::Operation_Ternary *top) override {
1115 isValidOperandSize(top->e0);
1116 isValidOperandSize(top->e1);
1117 isValidOperandSize(top->e2);
1118 }
1119};
1120
1121class CollectErrors : public Inspector {
1122 DpdkProgramStructure *structure;
1123
1124 public:
1125 explicit CollectErrors(DpdkProgramStructure *structure) : structure(structure) {
1126 CHECK_NULL(structure);
1127 }
1128 void postorder(const IR::Type_Error *error) override {
1129 int id = 0;
1130 for (auto err : error->members) {
1131 if (structure->error_map.count(err->name.name) == 0) {
1132 structure->error_map.emplace(err->name.name, id++);
1133 }
1134 }
1135 }
1136};
1137
1163 P4::TypeMap *typeMap;
1173
1174 public:
1175 explicit ElimHeaderCopy(P4::TypeMap *typeMap) : typeMap{typeMap} {}
1176 bool isHeader(const IR::Expression *e);
1177 const IR::Node *preorder(IR::AssignmentStatement *as) override;
1178 const IR::Node *preorder(IR::MethodCallStatement *mcs) override;
1179 const IR::Node *postorder(IR::Member *m) override;
1180};
1181
1183 public:
1185 passes.push_back(new P4::ClearTypeMap(typeMap));
1186 passes.push_back(new P4::ResolveReferences(refMap));
1187 passes.push_back(new P4::TypeInference(typeMap, false));
1188 passes.push_back(new P4::TypeChecking(refMap, typeMap, true));
1189 passes.push_back(new ElimHeaderCopy(typeMap));
1190 }
1191};
1192
1194// If one operand is >64-bit and other is <= 64-bit, the smaller operand should be a header field
1195// to maintain the endianness for copy. This pass detects if these conditions are satisfied or not.
1197 bool &is_all_arg_header_fields;
1198
1199 public:
1200 explicit HaveNonHeaderLargeOperandAssignment(bool &is_all_arg_header_fields)
1201 : is_all_arg_header_fields(is_all_arg_header_fields) {}
1202 bool preorder(const IR::AssignmentStatement *assn) override {
1203 if (!is_all_arg_header_fields) return false;
1204 if ((isLargeFieldOperand(assn->left) && !isLargeFieldOperand(assn->right) &&
1205 !isInsideHeader(assn->right)) ||
1206 (isLargeFieldOperand(assn->left) && assn->right->is<IR::Constant>()) ||
1207 (!isLargeFieldOperand(assn->left) && isLargeFieldOperand(assn->right) &&
1208 !isInsideHeader(assn->left))) {
1209 is_all_arg_header_fields &= false;
1210 return false;
1211 }
1212 return false;
1213 }
1214};
1215
1219 P4::TypeMap *typeMap;
1220 bool &is_all_arg_header_fields;
1221
1222 public:
1223 HaveNonHeaderChecksumArgs(P4::TypeMap *typeMap, bool &is_all_arg_header_fields)
1224 : typeMap(typeMap), is_all_arg_header_fields(is_all_arg_header_fields) {}
1225 bool preorder(const IR::MethodCallExpression *mce) override {
1226 if (!is_all_arg_header_fields) return false;
1227 if (auto *m = mce->method->to<IR::Member>()) {
1228 if (auto *type = typeMap->getType(m->expr)->to<IR::Type_Extern>()) {
1229 if (type->name == "InternetChecksum") {
1230 if (m->member == "add" || m->member == "subtract") {
1231 for (auto arg : *mce->arguments) {
1232 if (auto se = arg->expression->to<IR::StructExpression>()) {
1233 for (auto c : se->components) {
1234 if (auto m0 = c->expression->to<IR::Member>()) {
1235 if (!typeMap->getType(m0->expr, true)
1236 ->is<IR::Type_Header>()) {
1237 is_all_arg_header_fields = false;
1238 return false;
1239 }
1240 } else {
1241 is_all_arg_header_fields = false;
1242 return false;
1243 }
1244 }
1245 } else if (arg->expression->to<IR::Constant>()) {
1246 is_all_arg_header_fields = false;
1247 return false;
1248 } else if (auto m = arg->expression->to<IR::Member>()) {
1249 if (!(typeMap->getType(m->expr, true)->is<IR::Type_Header>() ||
1250 typeMap->getType(m, true)->is<IR::Type_Header>())) {
1251 is_all_arg_header_fields = false;
1252 return false;
1253 }
1254 }
1255 }
1256 }
1257 }
1258 }
1259 }
1260 return false;
1261 }
1262};
1263
1271 P4::ReferenceMap *refMap;
1272 P4::TypeMap *typeMap;
1273 bool &is_all_args_header;
1274 IR::Vector<IR::Node> allTypeDecls;
1275
1276 public:
1277 static cstring pseudoHeaderInstanceName;
1278 static cstring pseudoHeaderTypeName;
1280 bool &is_all_args_header)
1281 : refMap(refMap), typeMap(typeMap), is_all_args_header(is_all_args_header) {
1282 pseudoHeaderInstanceName = refMap->newName("dpdk_pseudo_header");
1283 pseudoHeaderTypeName = refMap->newName("dpdk_pseudo_header_t");
1284 (void)this->typeMap;
1285 (void)this->refMap;
1286 }
1287
1288 const IR::Node *preorder(IR::P4Program *program) override;
1289 const IR::Node *preorder(IR::Type_Struct *st) override;
1290};
1291
1306
1308 P4::ReferenceMap *refMap;
1309 P4::TypeMap *typeMap;
1310 bool &is_all_args_header;
1311 IR::Vector<IR::Node> newStructTypes;
1312
1313 public:
1314 static std::vector<std::pair<cstring, const IR::Type *>> pseudoFieldNameType;
1316 bool &is_all_args_header)
1317 : refMap(refMap), typeMap(typeMap), is_all_args_header(is_all_args_header) {}
1318 std::pair<IR::AssignmentStatement *, IR::Member *> addAssignmentStmt(const IR::Expression *ne);
1319
1320 const IR::Node *postorder(IR::P4Program *p) override {
1321 if (newStructTypes.size() > 0) {
1322 IR::Vector<IR::Node> allTypeDecls;
1323 allTypeDecls.append(newStructTypes);
1324 allTypeDecls.append(p->objects);
1325 p->objects = allTypeDecls;
1326 }
1327 return p;
1328 }
1329 const IR::Node *postorder(IR::MethodCallStatement *statement) override;
1330 const IR::Node *postorder(IR::AssignmentStatement *statement) override;
1331};
1332
1336 P4::ReferenceMap *refMap;
1337 P4::TypeMap *typeMap;
1338 bool &is_all_args_header;
1339
1340 public:
1342 bool &is_all_args_header)
1343 : refMap(refMap), typeMap(typeMap), is_all_args_header(is_all_args_header) {
1344 (void)this->typeMap;
1345 (void)this->refMap;
1346 }
1347 const IR::Node *preorder(IR::Type_Header *h) override;
1348};
1349
1351 P4::ReferenceMap *refMap;
1352 P4::TypeMap *typeMap;
1353 bool &is_all_args_header;
1354
1355 public:
1357 bool &is_all_args_header_fields)
1358 : refMap(refMap), typeMap(typeMap), is_all_args_header(is_all_args_header_fields) {
1359 passes.push_back(new HaveNonHeaderChecksumArgs(typeMap, is_all_args_header));
1360 passes.push_back(new HaveNonHeaderLargeOperandAssignment(is_all_args_header));
1361 passes.push_back(new DpdkAddPseudoHeaderDecl(refMap, typeMap, is_all_args_header));
1362 passes.push_back(new P4::ClearTypeMap(typeMap));
1363 passes.push_back(new P4::TypeChecking(refMap, typeMap));
1364 passes.push_back(
1365 new MoveNonHeaderFieldsToPseudoHeader(refMap, typeMap, is_all_args_header));
1366 passes.push_back(new AddFieldsToPseudoHeader(refMap, typeMap, is_all_args_header));
1367 passes.push_back(new P4::ClearTypeMap(typeMap));
1368 passes.push_back(new P4::TypeChecking(refMap, typeMap));
1369 }
1370};
1371
1373 public:
1374 DpdkArchFirst() { setName("DpdkArchFirst"); }
1375};
1376
1378 public:
1379 DpdkArchLast() { setName("DpdkArchLast"); }
1380};
1381
1383 public:
1385 DpdkProgramStructure *structure) {
1386 auto *evaluator = new P4::EvaluatorPass(refMap, typeMap);
1387 auto *parseDpdk = new ParseDpdkArchitecture(structure);
1388 passes.push_back(evaluator);
1389 passes.push_back(new VisitFunctor([evaluator, parseDpdk]() {
1390 auto toplevel = evaluator->getToplevelBlock();
1391 auto main = toplevel->getMain();
1392 if (main == nullptr) {
1393 ::P4::error(ErrorType::ERR_NOT_FOUND,
1394 "Could not locate top-level block; is there a %1% module?",
1395 IR::P4Program::main);
1396 return;
1397 }
1398 main->apply(*parseDpdk);
1399 }));
1400 }
1401};
1402
1403// Add collected local struct variable decls as a field in metadata
1404// struct
1406 P4::TypeMap *typeMap;
1407
1408 public:
1409 explicit MoveCollectedStructLocalVariableToMetadata(P4::TypeMap *typeMap) : typeMap(typeMap) {}
1410 const IR::Node *preorder(IR::Type_Struct *s) override;
1411 const IR::Node *postorder(IR::P4Control *c) override;
1412 const IR::Node *postorder(IR::P4Program *p) override;
1413 const IR::Node *postorder(IR::P4Parser *c) override;
1414};
1415
1416// Collect all local struct variable and metadata struct type
1418 P4::ReferenceMap *refMap;
1419 P4::TypeMap *typeMap;
1420
1421 public:
1423 : refMap(refMap), typeMap(typeMap) {}
1424 const IR::Node *postorder(IR::P4Parser *c) override;
1425 const IR::Node *preorder(IR::PathExpression *path) override;
1426 static const IR::Type_Struct *metadataStrct;
1427 static std::map<cstring, const IR::Type *> fieldNameType;
1428 static IR::Vector<IR::Node> type_tobe_moved_at_top;
1429};
1430
1431// Collect all local struct decls and move it to metadata struct and finally
1432// flatten the metadata struct.
1434 public:
1436 passes.push_back(new P4::ClearTypeMap(typeMap));
1437 passes.push_back(new P4::ResolveReferences(refMap));
1438 passes.push_back(new P4::TypeInference(typeMap, false));
1439 passes.push_back(new P4::TypeChecking(refMap, typeMap, true));
1440 passes.push_back(new CollectStructLocalVariables(refMap, typeMap));
1441 passes.push_back(new MoveCollectedStructLocalVariableToMetadata(typeMap));
1442 passes.push_back(new P4::ClearTypeMap(typeMap));
1443 passes.push_back(new P4::ResolveReferences(refMap));
1444 passes.push_back(new P4::TypeInference(typeMap, false));
1445 passes.push_back(new P4::TypeChecking(refMap, typeMap, true));
1446 passes.push_back(new P4::FlattenInterfaceStructs(refMap, typeMap));
1447 }
1448};
1449
1450/* Helper class to detect use of IPSec accelerator */
1452 bool &is_ipsec_used;
1453 int &sa_id_width;
1454 P4::ReferenceMap *refMap;
1455 P4::TypeMap *typeMap;
1456 DpdkProgramStructure *structure;
1457
1458 public:
1459 CollectIPSecInfo(bool &is_ipsec_used, int &sa_id_width, P4::ReferenceMap *refMap,
1460 P4::TypeMap *typeMap, DpdkProgramStructure *structure)
1461 : is_ipsec_used(is_ipsec_used),
1462 sa_id_width(sa_id_width),
1463 refMap(refMap),
1464 typeMap(typeMap),
1465 structure(structure) {}
1466 bool preorder(const IR::MethodCallStatement *mcs) override {
1467 auto mi = P4::MethodInstance::resolve(mcs, refMap, typeMap);
1468 if (auto a = mi->to<P4::ExternMethod>()) {
1469 if (a->originalExternType->getName().name == "ipsec_accelerator") {
1470 if (structure->isPSA()) {
1471 ::P4::error(ErrorType::ERR_MODEL, "%1% is not available for PSA programs",
1472 a->originalExternType->getName().name);
1473 return false;
1474 }
1475 if (a->method->getName().name == "enable") {
1476 is_ipsec_used = true;
1477 } else if (a->method->getName().name == "set_sa_index") {
1478 auto typeArgs = a->expr->typeArguments;
1479 if (typeArgs->size() != 1) {
1480 ::P4::error(ErrorType::ERR_MODEL,
1481 "Unexpected number of type arguments for %1%", a->method->name);
1482 return false;
1483 }
1484 auto width = typeArgs->at(0);
1485 if (!width->is<IR::Type_Bits>()) {
1486 ::P4::error(ErrorType::ERR_MODEL, "Unexpected width type %1% for sa_index",
1487 width);
1488 return false;
1489 }
1490 sa_id_width = width->to<IR::Type_Bits>()->width_bits();
1491 }
1492 }
1493 }
1494 return false;
1495 }
1496};
1497
1498/* DPDK uses some fixed registers to hold the ipsec inbound/outbound input and output ports and a
1499 * pseudo compiler inserted header which shall be emitted in front of all headers. This class helps
1500 * insert required registers and a pseudo header for enabling IPSec encryption and decryption. It
1501 * also handles setting of output port in the deparser.
1502 */
1504 P4::ReferenceMap *refMap;
1505 DpdkProgramStructure *structure;
1506 bool &is_ipsec_used;
1507 int &sa_id_width;
1508 cstring newHeaderName = "platform_hdr_t"_cs;
1509 IR::Type_Header *ipsecHeader = nullptr;
1510 std::vector<cstring> registerInstanceNames = {
1511 "ipsec_port_out_inbound"_cs, "ipsec_port_out_outbound"_cs, "ipsec_port_in_inbound"_cs,
1512 "ipsec_port_in_outbound"_cs};
1513
1514 public:
1516 bool &is_ipsec_used, int &sa_id_width)
1517 : refMap(refMap),
1518 structure(structure),
1519 is_ipsec_used(is_ipsec_used),
1520 sa_id_width(sa_id_width) {
1521 setName("InsertReqDeclForIPSec");
1522 }
1523
1524 const IR::Node *preorder(IR::P4Program *program) override;
1525 const IR::Node *preorder(IR::Type_Struct *s) override;
1526 const IR::Node *preorder(IR::P4Control *c) override;
1527 IR::IndexedVector<IR::StatOrDecl> *addRegDeclInstance(std::vector<cstring> portRegs);
1528};
1529
1531 P4::ReferenceMap *refMap;
1532 P4::TypeMap *typeMap;
1533 DpdkProgramStructure *structure;
1534 bool is_ipsec_used = false;
1535 int sa_id_width = 32;
1536
1537 public:
1539 : refMap(refMap), typeMap(typeMap), structure(structure) {
1540 passes.push_back(
1541 new CollectIPSecInfo(is_ipsec_used, sa_id_width, refMap, typeMap, structure));
1542 passes.push_back(new InsertReqDeclForIPSec(refMap, structure, is_ipsec_used, sa_id_width));
1543 passes.push_back(new P4::ClearTypeMap(typeMap));
1544 passes.push_back(new P4::ResolveReferences(refMap));
1545 passes.push_back(new P4::TypeInference(typeMap, false));
1546 }
1547};
1548
1549} // namespace P4::DPDK
1550#endif /* BACKENDS_DPDK_DPDKARCH_H_ */
Definition typeChecker.h:32
This pass finally adds all the collected fields to pseudo header add collected pseudo header fields i...
Definition dpdkArch.h:1335
Definition dpdkArch.h:240
Definition dpdkArch.h:1052
Definition dpdkArch.h:1002
Definition dpdkArch.h:1121
Definition dpdkArch.h:631
Definition dpdkArch.h:1451
Definition dpdkArch.h:1433
Definition dpdkArch.h:451
Definition dpdkArch.h:202
Definition dpdkArch.h:1382
Definition dpdkArch.h:1417
Definition dpdkArch.h:798
bool preorder(const IR::Key *key) override
Definition dpdkArch.cpp:647
Definition dpdkArch.h:619
Definition dpdkArch.h:785
Definition dpdkArch.h:167
Definition dpdkArch.h:178
Definition dpdkArch.h:57
Definition dpdkArch.h:829
Definition dpdkArch.h:288
Definition dpdkArch.h:510
void postorder(const IR::P4Table *t) override
Definition dpdkArch.cpp:1228
Definition dpdkArch.h:524
This pass adds a pseudo header declaration, it will be used as container of operands where dpdk instr...
Definition dpdkArch.h:1270
Definition dpdkArch.h:1372
Definition dpdkArch.h:1377
Definition dpdkArch.h:1162
Definition dpdkArch.h:1182
Definition dpdkArch.h:363
Definition dpdkArch.h:1218
This pass checks whether an assignment statement has large operands (>64-bit).
Definition dpdkArch.h:1196
Definition dpdkArch.h:385
Definition dpdkArch.h:229
Definition dpdkArch.h:217
Definition dpdkArch.h:1503
IR::IndexedVector< IR::StatOrDecl > * addRegDeclInstance(std::vector< cstring > portRegs)
Create and add register declaration instance to program.
Definition dpdkArch.cpp:3225
Definition dpdkArch.h:404
bool preorder(const IR::Operation_Unary *a) override
Definition dpdkArch.cpp:910
This pass identifies and collects statement which requires it's operand to be in a header and also in...
Definition dpdkArch.h:1307
Definition dpdkArch.h:489
Definition dpdkArch.h:273
const IR::Node * postorder(IR::Type_Struct *st) override
Definition dpdkArch.cpp:623
Definition dpdkArch.h:943
Definition dpdkArch.h:928
Definition dpdkArch.h:885
IR::Expression * initializeMemberAndGroupId(cstring tableName, IR::IndexedVector< IR::StatOrDecl > *decls)
Definition dpdkArch.cpp:2135
std::tuple< const IR::P4Table *, cstring, cstring > create_match_table(const IR::P4Table *)
Definition dpdkArch.cpp:1785
Definition dpdkArch.h:340
Definition dpdkArch.h:851
Definition dpdkArch.h:972
Definition dpdkArch.h:1066
Definition dpdkArch.h:1037
Definition dpdkArch.h:1090
Definition removeLeftSlices.h:35
Definition evaluator.h:114
Definition methodInstance.h:168
Definition flattenInterfaceStructs.h:253
Definition node.h:52
Definition node.h:95
Definition vector.h:58
Definition visitor.h:400
Definition sideEffects.h:295
static MethodInstance * resolve(const IR::MethodCallExpression *mce, const DeclarationLookup *refMap, TypeMap *typeMap, bool useExpressionType=false, const Visitor::Context *ctxt=nullptr, bool incomplete=false)
Definition methodInstance.cpp:27
Definition dpdkProgramStructure.h:119
Definition pass_manager.h:40
Definition pass_manager.h:145
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
cstring newName(std::string_view base) override
Generate a name from base that fresh for the program.
Definition referenceMap.cpp:96
Definition resolveReferences.h:121
Definition visitor.h:424
Definition typeChecker.h:55
Definition typeChecker.h:481
Definition typeMap.h:41
Definition source_file.h:124
Definition pass_manager.h:184
Definition cstring.h:85
Definition ordered_map.h:32
Definition dpdk/backend.cpp:36
void expressionUnrollSanityCheck(const IR::Expression *e)
Definition dpdkArch.cpp:47
Definition dpdkArch.h:815
Definition dpdkArch.h:820
Definition cstring.h:80
const int dpdk_max_operand_size
Maximum operand size for unary, binary and ternary operations.
Definition dpdk/constants.h:65
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition error.h:51
Definition dpdkArch.h:253
Definition dpdkArch.h:108
Definition dpdkArch.h:1350
Definition dpdkArch.h:1530
Definition dpdkArch.h:278
Collect information related to P4 programs targeting dpdk.
Definition dpdkProgramStructure.h:16
bool isPSA(void)
Predicate that states whether architecture is PSA or not.
Definition dpdkProgramStructure.h:89
Definition id.h:28
bool is() const noexcept
Definition rtti.h:216
Definition visitor.h:47