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 DPDK {
39// This pass removes label that no jmps jump to
40class RemoveRedundantLabel : public Transform {
41 public:
42 const IR::IndexedVector<IR::DpdkAsmStatement> *removeRedundantLabel(
43 const IR::IndexedVector<IR::DpdkAsmStatement> &s);
44
45 const IR::Node *postorder(IR::DpdkListStatement *l) override {
46 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
47 newStmts = removeRedundantLabel(l->statements);
48 l->statements = *newStmts;
49 return l;
50 }
51
52 const IR::Node *postorder(IR::DpdkAction *l) override {
53 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
54 newStmts = removeRedundantLabel(l->statements);
55 l->statements = *newStmts;
56 return l;
57 }
58};
59
60// This pass removes jmps that jump to a label that is immediately after it.
61// For example,
62// (jmp label1)
63// (label1)
64//
65// jmp label1 will be removed.
66
67class RemoveConsecutiveJmpAndLabel : public Transform {
68 public:
69 const IR::IndexedVector<IR::DpdkAsmStatement> *removeJmpAndLabel(
70 const IR::IndexedVector<IR::DpdkAsmStatement> &s);
71 const IR::Node *postorder(IR::DpdkListStatement *l) override {
72 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
73 newStmts = removeJmpAndLabel(l->statements);
74 l->statements = *newStmts;
75 return l;
76 }
77
78 const IR::Node *postorder(IR::DpdkAction *l) override {
79 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
80 newStmts = removeJmpAndLabel(l->statements);
81 l->statements = *newStmts;
82 return l;
83 }
84};
85
86// This pass removes labels whose next instruction is a jmp statement. This pass
87// will update any kinds of jmp(conditional + unconditional) that jump to this
88// label to the label that jmp statement jump to. For example:
89// jeq label1
90// ...
91// ...
92// label1
93// jmp label2
94//
95// will become:
96// jeq label2
97// ...
98// ...
99// jmp label2
100
101class ThreadJumps : public Transform {
102 public:
103 const IR::IndexedVector<IR::DpdkAsmStatement> *threadJumps(
104 const IR::IndexedVector<IR::DpdkAsmStatement> &s);
105
106 const IR::Node *postorder(IR::DpdkListStatement *l) override {
107 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
108 newStmts = threadJumps(l->statements);
109 l->statements = *newStmts;
110 return l;
111 }
112
113 const IR::Node *postorder(IR::DpdkAction *l) override {
114 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
115 newStmts = threadJumps(l->statements);
116 l->statements = *newStmts;
117 return l;
118 }
119};
120
121// This pass removes labels whose next instruction is a label. In addition, it
122// will update any jmp that jump to this label to the label next to it.
123
124class RemoveLabelAfterLabel : public Transform {
125 public:
126 const IR::IndexedVector<IR::DpdkAsmStatement> *removeLabelAfterLabel(
127 const IR::IndexedVector<IR::DpdkAsmStatement> &s);
128
129 const IR::Node *postorder(IR::DpdkListStatement *l) override {
130 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
131 newStmts = removeLabelAfterLabel(l->statements);
132 l->statements = *newStmts;
133 return l;
134 }
135
136 const IR::Node *postorder(IR::DpdkAction *l) override {
137 const IR::IndexedVector<IR::DpdkAsmStatement> *newStmts;
138 newStmts = removeLabelAfterLabel(l->statements);
139 l->statements = *newStmts;
140 return l;
141 }
142};
143
144// This pass Collects all metadata struct member used in program
145class CollectUsedMetadataField : public Inspector {
146 ordered_set<cstring> &used_fields;
147
148 public:
150 : used_fields(used_fields) {}
151 bool preorder(const IR::Member *m) override {
152 // metadata struct field used like m.<field_name> in expressions
153 if (m->expr->toString() == "m") used_fields.insert(m->member.toString());
154 return true;
155 }
156};
157
158// This pass removes all unused fields from metadata struct
159class RemoveUnusedMetadataFields : public Transform {
160 ordered_set<cstring> &used_fields;
161
162 public:
164 : used_fields(used_fields) {}
165 const IR::Node *preorder(IR::DpdkAsmProgram *p) override;
166 bool isByteSizeField(const IR::Type *field_type);
167};
168
169// This pass shorten the Identifier length
170class ShortenTokenLength : public Transform {
172 static size_t count;
173 // Currently Dpdk allows Identifier of 63 char long or less
174 // including dots(.) for member exp.
175 // worst case member expression will look like below(for headers)
176 // 1.30.30 => 63(including dot(.))
177 // if id name less than allowedLength keep it same
178 cstring shortenString(cstring str, size_t allowedLength = 60) {
179 if (str.size() <= allowedLength) return str;
180 auto itr = newNameMap.find(str);
181 if (itr != newNameMap.end()) return itr->second;
182 // make sure new string length less or equal allowedLength
183 cstring newStr = str.substr(0, allowedLength - std::to_string(count).size());
184 newStr += std::to_string(count);
185 count++;
186 newNameMap.insert(std::pair<cstring, cstring>(str, newStr));
187 origNameMap.insert(std::pair<cstring, cstring>(newStr, str));
188 return newStr;
189 }
190
191 cstring dropSuffixIfNoAction(IR::ID name) {
192 if (name.originalName == "NoAction") return name.originalName;
193 return name.name;
194 }
195
196 public:
198 : newNameMap(newNameMap) {}
199 static ordered_map<cstring, cstring> origNameMap;
200
201 const IR::Node *preorder(IR::Member *m) override {
202 if (m->toString().startsWith("m.") || m->toString().startsWith("t."))
203 m->member = shortenString(m->member);
204 else
205 m->member = shortenString(m->member, 30);
206 return m;
207 }
208
209 const IR::Node *preorder(IR::DpdkStructType *s) override {
210 if (s->getAnnotations()->getSingle("__packet_data__")) {
211 s->name = shortenString(s->name);
212 IR::IndexedVector<IR::StructField> changedFields;
213 for (auto field : s->fields) {
214 IR::StructField *f = new IR::StructField(field->name, field->type);
215 f->name = shortenString(f->name, 30);
216 changedFields.push_back(f);
217 }
218 return new IR::DpdkStructType(s->srcInfo, s->name, s->annotations, changedFields);
219 } else {
220 s->name = shortenString(s->name);
221 IR::IndexedVector<IR::StructField> changedFields;
222 for (auto field : s->fields) {
223 IR::StructField *f = new IR::StructField(field->name, field->type);
224 f->name = shortenString(f->name);
225 changedFields.push_back(f);
226 }
227 return new IR::DpdkStructType(s->srcInfo, s->name, s->annotations, changedFields);
228 }
229 return s;
230 }
231
232 const IR::Node *preorder(IR::DpdkHeaderType *h) override {
233 h->name = shortenString(h->name);
234 IR::IndexedVector<IR::StructField> changedFields;
235 for (auto field : h->fields) {
236 IR::StructField *f = new IR::StructField(field->name, field->type);
237 f->name = shortenString(f->name, 30);
238 changedFields.push_back(f);
239 }
240 return new IR::DpdkHeaderType(h->srcInfo, h->name, h->annotations, changedFields);
241 }
242
243 const IR::Node *preorder(IR::DpdkExternDeclaration *e) override {
244 e->name = shortenString(e->name);
245 return e;
246 }
247
248 const IR::Node *preorder(IR::Declaration *g) override {
249 g->name = shortenString(g->name);
250 return g;
251 }
252
253 void shortenParamTypeName(IR::ParameterList &pl) {
254 IR::IndexedVector<IR::Parameter> new_pl;
255 for (auto p : pl.parameters) {
256 auto newType0 = p->type->to<IR::Type_Name>();
257 auto path0 = newType0->path->clone();
258 path0->name = shortenString(path0->name);
259 new_pl.push_back(new IR::Parameter(p->srcInfo, p->name, p->annotations, p->direction,
260 new IR::Type_Name(newType0->srcInfo, path0),
261 p->defaultValue));
262 }
263 pl = IR::ParameterList{new_pl};
264 }
265
266 const IR::Node *preorder(IR::DpdkAction *a) override {
267 a->name = shortenString(dropSuffixIfNoAction(a->name));
268 shortenParamTypeName(a->para);
269 return a;
270 }
271
272 const IR::Node *preorder(IR::ActionList *al) override {
273 IR::IndexedVector<IR::ActionListElement> new_al;
274 for (auto ale : al->actionList) {
275 auto methodCallExpr = ale->expression->to<IR::MethodCallExpression>();
276 auto pathExpr = methodCallExpr->method->to<IR::PathExpression>();
277 auto path0 = pathExpr->path->clone();
278 path0->name = shortenString(dropSuffixIfNoAction(path0->name));
279 new_al.push_back(new IR::ActionListElement(
280 ale->srcInfo, ale->annotations,
281 new IR::MethodCallExpression(
282 methodCallExpr->srcInfo, methodCallExpr->type,
283 new IR::PathExpression(pathExpr->srcInfo, pathExpr->type, path0),
284 methodCallExpr->typeArguments, methodCallExpr->arguments)));
285 }
286 return new IR::ActionList(al->srcInfo, new_al);
287 }
288
289 const IR::Node *preorder(IR::DpdkTable *t) override {
290 t->name = shortenString(t->name);
291 auto methodCallExpr = t->default_action->to<IR::MethodCallExpression>();
292 auto pathExpr = methodCallExpr->method->to<IR::PathExpression>();
293 auto path0 = pathExpr->path->clone();
294 path0->name = shortenString(dropSuffixIfNoAction(path0->name));
295 t->default_action = new IR::MethodCallExpression(
296 methodCallExpr->srcInfo, methodCallExpr->type,
297 new IR::PathExpression(pathExpr->srcInfo, pathExpr->type, path0),
298 methodCallExpr->typeArguments, methodCallExpr->arguments);
299 return t;
300 }
301
302 const IR::Node *preorder(IR::DpdkLearner *l) override {
303 l->name = shortenString(l->name);
304 return l;
305 }
306
307 const IR::Node *preorder(IR::DpdkSelector *s) override {
308 s->name = shortenString(s->name);
309 return s;
310 }
311
312 const IR::Node *preorder(IR::DpdkLearnStatement *ls) override {
313 ls->action = shortenString(dropSuffixIfNoAction(ls->action));
314 return ls;
315 }
316
317 const IR::Node *preorder(IR::DpdkApplyStatement *as) override {
318 as->table = shortenString(as->table);
319 return as;
320 }
321
322 const IR::Node *preorder(IR::DpdkJmpStatement *j) override {
323 j->label = shortenString(j->label);
324 return j;
325 }
326
327 const IR::Node *preorder(IR::DpdkLabelStatement *ls) override {
328 ls->label = shortenString(ls->label);
329 return ls;
330 }
331
332 const IR::Node *preorder(IR::DpdkJmpActionStatement *jas) override {
333 jas->action = shortenString(dropSuffixIfNoAction(jas->action));
334 return jas;
335 }
336};
337
340class CollectUseDefInfo : public Inspector {
341 P4::TypeMap *typeMap;
342
343 public:
344 // Member expression as string considered key for all below maps, and value contains
345 // number of occurences either at use or def point.
346 // And this point it's assumed all keys are unique.
347 std::unordered_map<cstring /*member expresion as string */, int> usesInfo;
348 std::unordered_map<cstring, int> defInfo;
349 std::unordered_map<cstring /*def*/, const IR::Expression * /*use*/> replacementMap;
350 std::unordered_map<cstring, bool> dontEliminate;
351
352 explicit CollectUseDefInfo(P4::TypeMap *typeMap) : typeMap(typeMap) {
353 dontEliminate["m.pna_main_output_metadata_output_port"] = true;
354 dontEliminate["m.psa_ingress_output_metadata_drop"] = true;
355 dontEliminate["m.psa_ingress_output_metadata_egress_port"] = true;
356 }
357
358 bool preorder(const IR::DpdkJmpCondStatement *b) override {
359 usesInfo[b->src1->toString()]++;
360 usesInfo[b->src2->toString()]++;
361 return false;
362 }
363
364 bool preorder(const IR::DpdkLearnStatement *b) override {
365 usesInfo[b->timeout->toString()]++;
366 dontEliminate[b->timeout->toString()] = true;
367 if (b->argument) {
368 usesInfo[b->argument->toString()]++;
369 // dpdk expect all action argument to be contiguous starting from first argument
370 // passed to learner action
371 dontEliminate[b->argument->toString()] = true;
372 }
373 return false;
374 }
375
376 bool preorder(const IR::DpdkUnaryStatement *u) override {
377 usesInfo[u->src->toString()]++;
378 defInfo[u->dst->toString()]++;
379 // do not eliminate the destination
380 dontEliminate[u->dst->toString()] = true;
381 return false;
382 }
383
384 bool preorder(const IR::DpdkBinaryStatement *b) override {
385 usesInfo[b->src1->toString()]++;
386 usesInfo[b->src2->toString()]++;
387 defInfo[b->dst->toString()]++;
388 // dst and src1 can not be eliminated, because both are same
389 // and dpdk does not allow src1 to be constant
390 dontEliminate[b->dst->toString()] = true;
391 dontEliminate[b->src1->toString()] = true;
392 return false;
393 }
394
395 bool preorder(const IR::DpdkMovStatement *mv) override {
396 defInfo[mv->dst->toString()]++;
397 usesInfo[mv->src->toString()]++;
398 replacementMap[mv->dst->toString()] = mv->src;
399 return false;
400 }
401
402 bool preorder(const IR::DpdkCastStatement *c) override {
403 usesInfo[c->src->toString()]++;
404 defInfo[c->dst->toString()]++;
405 replacementMap[c->dst->toString()] = c->src;
406 return false;
407 }
408
409 bool preorder(const IR::DpdkMirrorStatement *m) override {
410 usesInfo[m->slotId->toString()]++;
411 usesInfo[m->sessionId->toString()]++;
412 // dpdk expect it as metadata struct member
413 dontEliminate[m->slotId->toString()] = true;
414 dontEliminate[m->sessionId->toString()] = true;
415 return false;
416 }
417
418 bool preorder(const IR::DpdkEmitStatement *e) override {
419 auto type = typeMap->getType(e->header)->to<IR::Type_Header>();
420 if (type)
421 for (auto f : type->fields) {
422 cstring name = e->header->toString() + "." + f->name.toString();
423 usesInfo[name]++;
424 }
425 return false;
426 }
427
428 bool preorder(const IR::DpdkExtractStatement *e) override {
429 auto type = typeMap->getType(e->header)->to<IR::Type_Header>();
430 if (type)
431 for (auto f : type->fields) {
432 cstring name = e->header->toString() + "." + f->name.toString();
433 defInfo[name]++;
434 }
435 if (e->length) {
436 usesInfo[e->length->toString()]++;
437 // dpdk expect length to be metadata struct member
438 dontEliminate[e->length->toString()] = true;
439 }
440 return false;
441 }
442
443 bool preorder(const IR::DpdkLookaheadStatement *l) override {
444 auto type = typeMap->getType(l->header)->to<IR::Type_Header>();
445 if (type)
446 for (auto f : type->fields) {
447 cstring name = l->header->toString() + "." + f->name.toString();
448 defInfo[name]++;
449 }
450 return false;
451 }
452
453 bool preorder(const IR::DpdkRxStatement *r) override {
454 usesInfo[r->port->toString()]++;
455 // always required
456 dontEliminate[r->port->toString()] = true;
457 return false;
458 }
459
460 bool preorder(const IR::DpdkTxStatement *t) override {
461 usesInfo[t->port->toString()]++;
462 // always required
463 dontEliminate[t->port->toString()] = true;
464 return false;
465 }
466
467 bool preorder(const IR::DpdkRecircidStatement *t) override {
468 usesInfo[t->pass->toString()]++;
469 // uses standard metadata fields
470 dontEliminate[t->pass->toString()] = true;
471 return false;
472 }
473
474 bool preorder(const IR::DpdkRearmStatement *r) override {
475 if (r->timeout) {
476 usesInfo[r->timeout->toString()]++;
477 // dpdk requires it in metadata struct
478 dontEliminate[r->timeout->toString()] = true;
479 }
480 return false;
481 }
482
483 bool preorder(const IR::DpdkChecksumAddStatement *c) override {
484 usesInfo[c->field->toString()]++;
485 // dpdk requires it in header
486 if (auto m = c->field->to<IR::Member>())
487 if (m->expr->is<IR::Type_Header>()) dontEliminate[c->field->toString()] = true;
488 return false;
489 }
490
491 bool preorder(const IR::DpdkChecksumSubStatement *c) override {
492 usesInfo[c->field->toString()]++;
493 // dpdk requires it in header
494 if (auto m = c->field->to<IR::Member>())
495 if (m->expr->is<IR::Type_Header>()) dontEliminate[c->field->toString()] = true;
496 return false;
497 }
498
499 bool preorder(const IR::DpdkGetHashStatement *c) override {
500 usesInfo[c->dst->toString()]++;
501 // dpdk requires it in metadata struct
502 dontEliminate[c->dst->toString()] = true;
503 return false;
504 }
505
506 bool preorder(const IR::DpdkVerifyStatement *v) override {
507 usesInfo[v->condition->toString()]++;
508 usesInfo[v->error->toString()]++;
509 // dpdk requires it in metadata struct
510 dontEliminate[v->condition->toString()] = true;
511 dontEliminate[v->error->toString()] = true;
512 return false;
513 }
514
515 bool preorder(const IR::DpdkMeterDeclStatement *c) override {
516 usesInfo[c->size->toString()]++;
517 return false;
518 }
519
520 bool preorder(const IR::DpdkMeterExecuteStatement *e) override {
521 usesInfo[e->index->toString()]++;
522 if (e->length) usesInfo[e->length->toString()]++;
523 usesInfo[e->color_in->toString()]++;
524 usesInfo[e->color_out->toString()]++;
525 return false;
526 }
527
528 bool preorder(const IR::DpdkCounterCountStatement *c) override {
529 usesInfo[c->index->toString()]++;
530 if (c->incr) usesInfo[c->incr->toString()]++;
531 return false;
532 }
533
534 bool preorder(const IR::DpdkRegisterDeclStatement *r) override {
535 usesInfo[r->size->toString()]++;
536 return false;
537 }
538
539 bool preorder(const IR::DpdkRegisterReadStatement *r) override {
540 usesInfo[r->index->toString()]++;
541 defInfo[r->dst->toString()]++;
542 return false;
543 }
544
545 bool preorder(const IR::DpdkRegisterWriteStatement *r) override {
546 usesInfo[r->index->toString()]++;
547 return false;
548 }
549
550 bool preorder(const IR::DpdkTable *t) override {
551 auto keys = t->match_keys;
552 if (keys)
553 for (auto ke : keys->keyElements) {
554 dontEliminate[ke->expression->toString()] = true;
555 }
556 return false;
557 }
558
559 bool haveSingleUseDef(cstring str) { return defInfo[str] == 1 && usesInfo[str] == 1; }
560};
561
562// This pass identifies redundant copies/moves and eliminates them.
563class CopyPropagationAndElimination : public Transform {
564 std::unordered_map<cstring, int> newUsesInfo;
565 P4::TypeMap *typeMap;
566 CollectUseDefInfo *collectUseDef;
567
568 public:
569 explicit CopyPropagationAndElimination(P4::TypeMap *typeMap) : typeMap(typeMap) {}
570
571 const IR::Expression *getIrreplaceableExpr(cstring str, bool allowConst);
572 const IR::Expression *replaceIfCopy(const IR::Expression *expr, bool allowConst = true);
573 const IR::DpdkAsmStatement *elimCastOrMov(const IR::DpdkAsmStatement *stmt);
574 IR::IndexedVector<IR::DpdkAsmStatement> copyPropAndDeadCodeElim(
575 IR::IndexedVector<IR::DpdkAsmStatement> stmts);
576
577 CollectUseDefInfo *calculateUseDef() {
578 collectUseDef = new CollectUseDefInfo(typeMap);
579 collectUseDef->setCalledBy(this);
580 return collectUseDef;
581 }
582 const IR::Node *preorder(IR::DpdkAction *a) override {
583 a->apply(*calculateUseDef());
584 return a;
585 }
586
587 const IR::Node *preorder(IR::DpdkListStatement *l) override {
588 l->apply(*calculateUseDef());
589 return l;
590 }
591
592 const IR::Node *postorder(IR::DpdkAction *a) override {
593 a->statements = copyPropAndDeadCodeElim(a->statements);
594 return a;
595 }
596
597 const IR::Node *postorder(IR::DpdkListStatement *l) override {
598 return new IR::DpdkListStatement(copyPropAndDeadCodeElim(l->statements));
599 }
600};
601
602// This Pass emits Table config consumed by dpdk target in a text file if
603// const entries are present in p4 program.
604// Most of the code taken from control-plane/p4RuntimeSerializer.h/.cpp
605class EmitDpdkTableConfig : public Inspector {
606 P4::ReferenceMap *refMap;
607 P4::TypeMap *typeMap;
609 std::ofstream dpdkTableConfigFile;
610
611 void addExact(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
612 void addLpm(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
613 void addTernary(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
614 void addRange(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
615 void addOptional(const IR::Expression *k, int keyWidth, P4::TypeMap *typeMap);
616 void addMatchKey(const IR::DpdkTable *table, const IR::ListExpression *keyset,
617 P4::TypeMap *typeMap);
618 void addAction(const IR::Expression *actionRef, P4::ReferenceMap *refMap, P4::TypeMap *typeMap);
619 int getTypeWidth(const IR::Type *type, P4::TypeMap *typeMap);
620 cstring getKeyMatchType(const IR::KeyElement *ke, P4::ReferenceMap *refMap);
621 const IR::EntriesList *getEntries(const IR::DpdkTable *dt);
622 const IR::Key *getKey(const IR::DpdkTable *dt);
623 big_int convertSimpleKeyExpressionToBigInt(const IR::Expression *k, int keyWidth,
624 P4::TypeMap *typeMap);
625 bool tableNeedsPriority(const IR::DpdkTable *table, P4::ReferenceMap *refMap);
626 bool isAllKeysDefaultExpression(const IR::ListExpression *keyset);
627 void print(cstring str, cstring sep = "");
628 void print(big_int, cstring sep = "");
629
630 public:
633 : refMap(refMap), typeMap(typeMap), newNameMap(newNameMap) {}
634 void postorder(const IR::DpdkTable *table) override;
635};
636
637// Instructions can only appear in actions and apply block of .spec file.
638// All these individual passes work on the actions and apply block of .spec file.
639class DpdkAsmOptimization : public PassRepeated {
640 private:
641 public:
643 passes.push_back(new RemoveRedundantLabel);
644 auto r = new PassRepeated{new RemoveLabelAfterLabel};
645 passes.push_back(r);
646 passes.push_back(new RemoveConsecutiveJmpAndLabel);
647 passes.push_back(new RemoveRedundantLabel);
648 passes.push_back(r);
649 passes.push_back(new ThreadJumps);
650 }
651};
652
653} // namespace DPDK
654#endif /* BACKENDS_DPDK_DPDKASMOPT_H_ */
Definition dpdkAsmOpt.h:340
Definition dpdkAsmOpt.h:145
Definition dpdkAsmOpt.h:563
Definition dpdkAsmOpt.h:639
Definition dpdkAsmOpt.h:605
Definition dpdkAsmOpt.h:67
Definition dpdkAsmOpt.h:124
Definition dpdkAsmOpt.h:40
Definition dpdkAsmOpt.h:159
Definition dpdkAsmOpt.h:170
Definition dpdkAsmOpt.h:101
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition typeMap.h:42
Definition cstring.h:72
Definition ordered_map.h:30
Definition ordered_set.h:30
Definition backend.cpp:35