P4C
The P4 Compiler
Loading...
Searching...
No Matches
dpdkAsmOpt.h
1/*
2 * Copyright 2020 Intel Corp.
3 * SPDX-FileCopyrightText: 2020 Intel Corp.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef BACKENDS_DPDK_DPDKASMOPT_H_
9#define BACKENDS_DPDK_DPDKASMOPT_H_
10
11#include <fstream>
12
13#include "dpdkUtils.h"
14#include "frontends/common/constantFolding.h"
15#include "frontends/common/resolveReferences/referenceMap.h"
16#include "frontends/p4/coreLibrary.h"
17#include "frontends/p4/enumInstance.h"
18#include "frontends/p4/evaluator/evaluator.h"
19#include "frontends/p4/methodInstance.h"
20#include "frontends/p4/simplify.h"
21#include "frontends/p4/typeMap.h"
22#include "frontends/p4/unusedDeclarations.h"
23#include "ir/ir.h"
24#include "lib/big_int_util.h"
25#include "lib/json.h"
26
27#define DPDK_TABLE_MAX_KEY_SIZE 64 * 8
28
29namespace P4::DPDK {
30
31using namespace P4::literals;
32
34class RemoveRedundantLabel : public Transform {
35 public:
38
39 const IR::Node *postorder(IR::DpdkListStatement *l) override {
41 newStmts = removeRedundantLabel(l->statements);
42 l->statements = *newStmts;
43 return l;
44 }
45
46 const IR::Node *postorder(IR::DpdkAction *l) override {
48 newStmts = removeRedundantLabel(l->statements);
49 l->statements = *newStmts;
50 return l;
51 }
52};
53
60
61class RemoveConsecutiveJmpAndLabel : public Transform {
62 public:
63 const IR::IndexedVector<IR::DpdkAsmStatement> *removeJmpAndLabel(
65 const IR::Node *postorder(IR::DpdkListStatement *l) override {
67 newStmts = removeJmpAndLabel(l->statements);
68 l->statements = *newStmts;
69 return l;
70 }
71
72 const IR::Node *postorder(IR::DpdkAction *l) override {
74 newStmts = removeJmpAndLabel(l->statements);
75 l->statements = *newStmts;
76 return l;
77 }
78};
79
94
95class ThreadJumps : public Transform {
96 public:
99
100 const IR::Node *postorder(IR::DpdkListStatement *l) override {
102 newStmts = threadJumps(l->statements);
103 l->statements = *newStmts;
104 return l;
105 }
106
107 const IR::Node *postorder(IR::DpdkAction *l) override {
109 newStmts = threadJumps(l->statements);
110 l->statements = *newStmts;
111 return l;
112 }
113};
114
117
118class RemoveLabelAfterLabel : public Transform {
119 public:
120 const IR::IndexedVector<IR::DpdkAsmStatement> *removeLabelAfterLabel(
122
123 const IR::Node *postorder(IR::DpdkListStatement *l) override {
125 newStmts = removeLabelAfterLabel(l->statements);
126 l->statements = *newStmts;
127 return l;
128 }
129
130 const IR::Node *postorder(IR::DpdkAction *l) override {
132 newStmts = removeLabelAfterLabel(l->statements);
133 l->statements = *newStmts;
134 return l;
135 }
136};
137
139class CollectUsedMetadataField : public Inspector {
140 ordered_set<cstring> &used_fields;
141
142 public:
143 explicit CollectUsedMetadataField(ordered_set<cstring> &used_fields)
144 : used_fields(used_fields) {}
145 bool preorder(const IR::Member *m) override {
146 // metadata struct field used like m.<field_name> in expressions
147 if (m->expr->toString() == "m") used_fields.insert(m->member.toString());
148 return true;
149 }
150};
151
153class RemoveUnusedMetadataFields : public Transform {
154 ordered_set<cstring> &used_fields;
155
156 public:
157 explicit RemoveUnusedMetadataFields(ordered_set<cstring> &used_fields)
158 : used_fields(used_fields) {}
159 const IR::Node *preorder(IR::DpdkAsmProgram *p) override;
160 bool isByteSizeField(const IR::Type *field_type);
161};
162
164class ShortenTokenLength : public Transform {
166 static size_t count;
172 cstring shortenString(cstring str, size_t allowedLength = 60) {
173 if (str.size() <= allowedLength) return str;
174 auto itr = newNameMap.find(str);
175 if (itr != newNameMap.end()) return itr->second;
176 // make sure new string length less or equal allowedLength
177 cstring newStr = str.substr(0, allowedLength - std::to_string(count).size());
178 newStr += std::to_string(count);
179 count++;
180 newNameMap.insert(std::pair<cstring, cstring>(str, newStr));
181 origNameMap.insert(std::pair<cstring, cstring>(newStr, str));
182 return newStr;
183 }
184
185 cstring dropSuffixIfNoAction(IR::ID name) {
186 if (name.originalName == "NoAction") return name.originalName;
187 return name.name;
188 }
189
190 public:
191 explicit ShortenTokenLength(ordered_map<cstring, cstring> &newNameMap)
192 : newNameMap(newNameMap) {}
193 static ordered_map<cstring, cstring> origNameMap;
194
195 const IR::Node *preorder(IR::Member *m) override {
196 if (m->toString().startsWith("m.") || m->toString().startsWith("t."))
197 m->member = shortenString(m->member);
198 else
199 m->member = shortenString(m->member, 30);
200 return m;
201 }
202
203 const IR::Node *preorder(IR::DpdkStructType *s) override {
204 if (s->getAnnotation("__packet_data__"_cs)) {
205 s->name = shortenString(s->name);
207 for (auto field : s->fields) {
208 IR::StructField *f = new IR::StructField(field->name, field->type);
209 f->name = shortenString(f->name, 30);
210 changedFields.push_back(f);
211 }
212 return new IR::DpdkStructType(s->srcInfo, s->name, s->annotations, changedFields);
213 } else {
214 s->name = shortenString(s->name);
216 for (auto field : s->fields) {
217 IR::StructField *f = new IR::StructField(field->name, field->type);
218 f->name = shortenString(f->name);
219 changedFields.push_back(f);
220 }
221 return new IR::DpdkStructType(s->srcInfo, s->name, s->annotations, changedFields);
222 }
223 return s;
224 }
225
226 const IR::Node *preorder(IR::DpdkHeaderType *h) override {
227 h->name = shortenString(h->name);
229 for (auto field : h->fields) {
230 IR::StructField *f = new IR::StructField(field->name, field->type);
231 f->name = shortenString(f->name, 30);
232 changedFields.push_back(f);
233 }
234 return new IR::DpdkHeaderType(h->srcInfo, h->name, h->annotations, changedFields);
235 }
236
237 const IR::Node *preorder(IR::DpdkExternDeclaration *e) override {
238 e->name = shortenString(e->name);
239 return e;
240 }
241
242 const IR::Node *preorder(IR::Declaration *g) override {
243 g->name = shortenString(g->name);
244 return g;
245 }
246
247 void shortenParamTypeName(IR::ParameterList &pl) {
249 for (auto p : pl.parameters) {
250 auto newType0 = p->type->to<IR::Type_Name>();
251 auto path0 = newType0->path->clone();
252 path0->name = shortenString(path0->name);
253 new_pl.push_back(new IR::Parameter(p->srcInfo, p->name, p->annotations, p->direction,
254 new IR::Type_Name(newType0->srcInfo, path0),
255 p->defaultValue));
256 }
257 pl = IR::ParameterList{new_pl};
258 }
259
260 const IR::Node *preorder(IR::DpdkAction *a) override {
261 a->name = shortenString(dropSuffixIfNoAction(a->name));
262 shortenParamTypeName(a->para);
263 return a;
264 }
265
266 const IR::Node *preorder(IR::ActionList *al) override {
268 for (auto ale : al->actionList) {
269 auto methodCallExpr = ale->expression->to<IR::MethodCallExpression>();
270 auto pathExpr = methodCallExpr->method->to<IR::PathExpression>();
271 auto path0 = pathExpr->path->clone();
272 path0->name = shortenString(dropSuffixIfNoAction(path0->name));
273 new_al.push_back(new IR::ActionListElement(
274 ale->srcInfo, ale->annotations,
275 new IR::MethodCallExpression(
276 methodCallExpr->srcInfo, methodCallExpr->type,
277 new IR::PathExpression(pathExpr->srcInfo, pathExpr->type, path0),
278 methodCallExpr->typeArguments, methodCallExpr->arguments)));
279 }
280 return new IR::ActionList(al->srcInfo, new_al);
281 }
282
283 const IR::Node *preorder(IR::DpdkTable *t) override {
284 t->name = shortenString(t->name);
285 auto methodCallExpr = t->default_action->to<IR::MethodCallExpression>();
286 auto pathExpr = methodCallExpr->method->to<IR::PathExpression>();
287 auto path0 = pathExpr->path->clone();
288 path0->name = shortenString(dropSuffixIfNoAction(path0->name));
289 t->default_action = new IR::MethodCallExpression(
290 methodCallExpr->srcInfo, methodCallExpr->type,
291 new IR::PathExpression(pathExpr->srcInfo, pathExpr->type, path0),
292 methodCallExpr->typeArguments, methodCallExpr->arguments);
293 return t;
294 }
295
296 const IR::Node *preorder(IR::DpdkLearner *l) override {
297 l->name = shortenString(l->name);
298 return l;
299 }
300
301 const IR::Node *preorder(IR::DpdkSelector *s) override {
302 s->name = shortenString(s->name);
303 return s;
304 }
305
306 const IR::Node *preorder(IR::DpdkLearnStatement *ls) override {
307 ls->action = shortenString(dropSuffixIfNoAction(ls->action));
308 return ls;
309 }
310
311 const IR::Node *preorder(IR::DpdkApplyStatement *as) override {
312 as->table = shortenString(as->table);
313 return as;
314 }
315
316 const IR::Node *preorder(IR::DpdkJmpStatement *j) override {
317 j->label = shortenString(j->label);
318 return j;
319 }
320
321 const IR::Node *preorder(IR::DpdkLabelStatement *ls) override {
322 ls->label = shortenString(ls->label);
323 return ls;
324 }
325
326 const IR::Node *preorder(IR::DpdkJmpActionStatement *jas) override {
327 jas->action = shortenString(dropSuffixIfNoAction(jas->action));
328 return jas;
329 }
330};
331
334class CollectUseDefInfo : public Inspector {
335 P4::TypeMap *typeMap;
336
337 public:
341 std::unordered_map<cstring /*member expresion as string */, int> usesInfo;
342 std::unordered_map<cstring, int> defInfo;
343 std::unordered_map<cstring /*def*/, const IR::Expression * /*use*/> replacementMap;
344 std::unordered_map<cstring, bool> dontEliminate;
345
346 explicit CollectUseDefInfo(P4::TypeMap *typeMap) : typeMap(typeMap) {
347 dontEliminate["m.pna_main_output_metadata_output_port"_cs] = true;
348 dontEliminate["m.psa_ingress_output_metadata_drop"_cs] = true;
349 dontEliminate["m.psa_ingress_output_metadata_egress_port"_cs] = true;
350 }
351
352 bool preorder(const IR::DpdkJmpCondStatement *b) override {
353 usesInfo[b->src1->toString()]++;
354 usesInfo[b->src2->toString()]++;
355 return false;
356 }
357
358 bool preorder(const IR::DpdkLearnStatement *b) override {
359 usesInfo[b->timeout->toString()]++;
360 dontEliminate[b->timeout->toString()] = true;
361 if (b->argument) {
362 usesInfo[b->argument->toString()]++;
363 // dpdk expect all action argument to be contiguous starting from first argument
364 // passed to learner action
365 dontEliminate[b->argument->toString()] = true;
366 }
367 return false;
368 }
369
370 bool preorder(const IR::DpdkUnaryStatement *u) override {
371 usesInfo[u->src->toString()]++;
372 defInfo[u->dst->toString()]++;
373 // do not eliminate the destination
374 dontEliminate[u->dst->toString()] = true;
375 return false;
376 }
377
378 bool preorder(const IR::DpdkBinaryStatement *b) override {
379 usesInfo[b->src1->toString()]++;
380 usesInfo[b->src2->toString()]++;
381 defInfo[b->dst->toString()]++;
382 // dst and src1 can not be eliminated, because both are same
383 // and dpdk does not allow src1 to be constant
384 dontEliminate[b->dst->toString()] = true;
385 dontEliminate[b->src1->toString()] = true;
386 return false;
387 }
388
389 bool preorder(const IR::DpdkMovStatement *mv) override {
390 defInfo[mv->dst->toString()]++;
391 usesInfo[mv->src->toString()]++;
392 replacementMap[mv->dst->toString()] = mv->src;
393 return false;
394 }
395
396 bool preorder(const IR::DpdkCastStatement *c) override {
397 usesInfo[c->src->toString()]++;
398 defInfo[c->dst->toString()]++;
399 replacementMap[c->dst->toString()] = c->src;
400 return false;
401 }
402
403 bool preorder(const IR::DpdkMirrorStatement *m) override {
404 usesInfo[m->slotId->toString()]++;
405 usesInfo[m->sessionId->toString()]++;
406 // dpdk expect it as metadata struct member
407 dontEliminate[m->slotId->toString()] = true;
408 dontEliminate[m->sessionId->toString()] = true;
409 return false;
410 }
411
412 bool preorder(const IR::DpdkEmitStatement *e) override {
413 auto type = typeMap->getType(e->header)->to<IR::Type_Header>();
414 if (type)
415 for (auto f : type->fields) {
416 cstring name = e->header->toString() + "." + f->name.toString();
417 usesInfo[name]++;
418 }
419 return false;
420 }
421
422 bool preorder(const IR::DpdkExtractStatement *e) override {
423 auto type = typeMap->getType(e->header)->to<IR::Type_Header>();
424 if (type)
425 for (auto f : type->fields) {
426 cstring name = e->header->toString() + "." + f->name.toString();
427 defInfo[name]++;
428 }
429 if (e->length) {
430 usesInfo[e->length->toString()]++;
431 // dpdk expect length to be metadata struct member
432 dontEliminate[e->length->toString()] = true;
433 }
434 return false;
435 }
436
437 bool preorder(const IR::DpdkLookaheadStatement *l) override {
438 auto type = typeMap->getType(l->header)->to<IR::Type_Header>();
439 if (type)
440 for (auto f : type->fields) {
441 cstring name = l->header->toString() + "." + f->name.toString();
442 defInfo[name]++;
443 }
444 return false;
445 }
446
447 bool preorder(const IR::DpdkRxStatement *r) override {
448 usesInfo[r->port->toString()]++;
449 // always required
450 dontEliminate[r->port->toString()] = true;
451 return false;
452 }
453
454 bool preorder(const IR::DpdkTxStatement *t) override {
455 usesInfo[t->port->toString()]++;
456 // always required
457 dontEliminate[t->port->toString()] = true;
458 return false;
459 }
460
461 bool preorder(const IR::DpdkRecircidStatement *t) override {
462 usesInfo[t->pass->toString()]++;
463 // uses standard metadata fields
464 dontEliminate[t->pass->toString()] = true;
465 return false;
466 }
467
468 bool preorder(const IR::DpdkRearmStatement *r) override {
469 if (r->timeout) {
470 usesInfo[r->timeout->toString()]++;
471 // dpdk requires it in metadata struct
472 dontEliminate[r->timeout->toString()] = true;
473 }
474 return false;
475 }
476
477 bool preorder(const IR::DpdkChecksumAddStatement *c) override {
478 usesInfo[c->field->toString()]++;
479 // dpdk requires it in header
480 if (auto m = c->field->to<IR::Member>())
481 if (m->expr->is<IR::Type_Header>()) dontEliminate[c->field->toString()] = true;
482 return false;
483 }
484
485 bool preorder(const IR::DpdkChecksumSubStatement *c) override {
486 usesInfo[c->field->toString()]++;
487 // dpdk requires it in header
488 if (auto m = c->field->to<IR::Member>())
489 if (m->expr->is<IR::Type_Header>()) dontEliminate[c->field->toString()] = true;
490 return false;
491 }
492
493 bool preorder(const IR::DpdkGetHashStatement *c) override {
494 usesInfo[c->dst->toString()]++;
495 // dpdk requires it in metadata struct
496 dontEliminate[c->dst->toString()] = true;
497 return false;
498 }
499
500 bool preorder(const IR::DpdkVerifyStatement *v) override {
501 usesInfo[v->condition->toString()]++;
502 usesInfo[v->error->toString()]++;
503 // dpdk requires it in metadata struct
504 dontEliminate[v->condition->toString()] = true;
505 dontEliminate[v->error->toString()] = true;
506 return false;
507 }
508
509 bool preorder(const IR::DpdkMeterDeclStatement *c) override {
510 usesInfo[c->size->toString()]++;
511 return false;
512 }
513
514 bool preorder(const IR::DpdkMeterExecuteStatement *e) override {
515 usesInfo[e->index->toString()]++;
516 if (e->length) usesInfo[e->length->toString()]++;
517 usesInfo[e->color_in->toString()]++;
518 usesInfo[e->color_out->toString()]++;
519 return false;
520 }
521
522 bool preorder(const IR::DpdkCounterCountStatement *c) override {
523 usesInfo[c->index->toString()]++;
524 if (c->incr) usesInfo[c->incr->toString()]++;
525 return false;
526 }
527
528 bool preorder(const IR::DpdkRegisterDeclStatement *r) override {
529 usesInfo[r->size->toString()]++;
530 return false;
531 }
532
533 bool preorder(const IR::DpdkRegisterReadStatement *r) override {
534 usesInfo[r->index->toString()]++;
535 defInfo[r->dst->toString()]++;
536 return false;
537 }
538
539 bool preorder(const IR::DpdkRegisterWriteStatement *r) override {
540 usesInfo[r->index->toString()]++;
541 return false;
542 }
543
544 bool preorder(const IR::DpdkTable *t) override {
545 auto keys = t->match_keys;
546 if (keys)
547 for (auto ke : keys->keyElements) {
548 dontEliminate[ke->expression->toString()] = true;
549 }
550 return false;
551 }
552
553 bool haveSingleUseDef(cstring str) { return defInfo[str] == 1 && usesInfo[str] == 1; }
554};
555
557class CopyPropagationAndElimination : public Transform {
558 std::unordered_map<cstring, int> newUsesInfo;
559 P4::TypeMap *typeMap;
560 CollectUseDefInfo *collectUseDef;
561
562 public:
563 explicit CopyPropagationAndElimination(P4::TypeMap *typeMap) : typeMap(typeMap) {}
564
565 const IR::Expression *getIrreplaceableExpr(cstring str, bool allowConst);
566 const IR::Expression *replaceIfCopy(const IR::Expression *expr, bool allowConst = true);
567 const IR::DpdkAsmStatement *elimCastOrMov(const IR::DpdkAsmStatement *stmt);
568 IR::IndexedVector<IR::DpdkAsmStatement> copyPropAndDeadCodeElim(
570
571 CollectUseDefInfo *calculateUseDef() {
572 collectUseDef = new CollectUseDefInfo(typeMap);
573 collectUseDef->setCalledBy(this);
574 return collectUseDef;
575 }
576 const IR::Node *preorder(IR::DpdkAction *a) override {
577 a->apply(*calculateUseDef());
578 return a;
579 }
580
581 const IR::Node *preorder(IR::DpdkListStatement *l) override {
582 l->apply(*calculateUseDef());
583 return l;
584 }
585
586 const IR::Node *postorder(IR::DpdkAction *a) override {
587 a->statements = copyPropAndDeadCodeElim(a->statements);
588 return a;
589 }
590
591 const IR::Node *postorder(IR::DpdkListStatement *l) override {
592 return new IR::DpdkListStatement(copyPropAndDeadCodeElim(l->statements));
593 }
594};
595
599class EmitDpdkTableConfig : public Inspector {
600 P4::ReferenceMap *refMap;
601 P4::TypeMap *typeMap;
603 std::ofstream dpdkTableConfigFile;
604
605 void addExact(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
606 void addLpm(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
607 void addTernary(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
608 void addRange(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
609 void addOptional(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
610 void addMatchKey(const IR::DpdkTable *table, const IR::ListExpression *keyset,
611 P4::TypeMap *typeMap);
612 void addAction(const IR::Expression *actionRef, P4::ReferenceMap *refMap, P4::TypeMap *typeMap);
613 int getTypeWidth(const IR::Type *type, P4::TypeMap *typeMap);
614 cstring getKeyMatchType(const IR::KeyElement *ke, P4::ReferenceMap *refMap);
615 const IR::EntriesList *getEntries(const IR::DpdkTable *dt);
616 const IR::Key *getKey(const IR::DpdkTable *dt);
617 big_int convertSimpleKeyExpressionToBigInt(const IR::Expression *k, int keyWidth,
618 P4::TypeMap *typeMap);
619 bool tableNeedsPriority(const IR::DpdkTable *table, P4::ReferenceMap *refMap);
620 bool isAllKeysDefaultExpression(const IR::ListExpression *keyset);
621 void print(std::string_view str, std::string_view sep = "");
622 void print(big_int, std::string_view sep = "");
623
624 public:
625 EmitDpdkTableConfig(P4::ReferenceMap *refMap, P4::TypeMap *typeMap,
627 : refMap(refMap), typeMap(typeMap), newNameMap(newNameMap) {}
628 void postorder(const IR::DpdkTable *table) override;
629};
630
633class DpdkAsmOptimization : public PassRepeated {
634 private:
635 public:
636 DpdkAsmOptimization() {
637 passes.push_back(new RemoveRedundantLabel);
638 auto r = new PassRepeated{new RemoveLabelAfterLabel};
639 passes.push_back(r);
640 passes.push_back(new RemoveConsecutiveJmpAndLabel);
641 passes.push_back(new RemoveRedundantLabel);
642 passes.push_back(r);
643 passes.push_back(new ThreadJumps);
644 }
645};
646
647} // namespace P4::DPDK
648#endif /* BACKENDS_DPDK_DPDKASMOPT_H_ */
Definition dpdkAsmOpt.h:334
std::unordered_map< cstring, int > usesInfo
Definition dpdkAsmOpt.h:341
Definition dpdkAsmOpt.h:61
Definition dpdkAsmOpt.h:118
This pass removes label that no jmps jump to.
Definition dpdkAsmOpt.h:34
const IR::IndexedVector< IR::DpdkAsmStatement > * removeRedundantLabel(const IR::IndexedVector< IR::DpdkAsmStatement > &s)
The assumption is compiler can only produce forward jumps.
Definition dpdkAsmOpt.cpp:12
Definition dpdkAsmOpt.h:95
Definition indexed_vector.h:31
Definition node.h:53
Class used to encode maps from paths to declarations.
Definition referenceMap.h:67
Definition typeMap.h:32
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition dpdk/backend.cpp:26
Definition id.h:28