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