P4C
The P4 Compiler
 
Loading...
Searching...
No Matches
converters.h
1/*
2Copyright 2013-present Barefoot Networks, Inc.
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 FRONTENDS_P4_FROMV1_0_CONVERTERS_H_
18#define FRONTENDS_P4_FROMV1_0_CONVERTERS_H_
19
20#include <typeindex>
21#include <typeinfo>
22
23#include "frontends/p4/coreLibrary.h"
24#include "ir/dump.h"
25#include "ir/ir.h"
26#include "ir/pass_manager.h"
27#include "lib/safe_vector.h"
28#include "programStructure.h"
29
30namespace P4V1 {
31
32// Converts expressions from P4-14 to P4-16
33// However, the type in each expression is still a P4-14 type.
34class ExpressionConverter : public Transform {
35 protected:
36 ProgramStructure *structure;
37 P4::P4CoreLibrary &p4lib;
38 using funcType = std::function<const IR::Node *(const IR::Node *)>;
39 static std::map<cstring, funcType> *cvtForType;
40
41 public:
42 bool replaceNextWithLast; // if true p[next] becomes p.last
43 explicit ExpressionConverter(ProgramStructure *structure)
44 : structure(structure), p4lib(P4::P4CoreLibrary::instance()), replaceNextWithLast(false) {
45 setName("ExpressionConverter");
46 }
47 const IR::Type *getFieldType(const IR::Type_StructLike *ht, cstring fieldName);
48 const IR::Node *postorder(IR::Constant *expression) override;
49 const IR::Node *postorder(IR::Member *field) override;
50 const IR::Node *postorder(IR::FieldList *fl) override;
51 const IR::Node *postorder(IR::Mask *expression) override;
52 const IR::Node *postorder(IR::ActionArg *arg) override;
53 const IR::Node *postorder(IR::Primitive *primitive) override;
54 const IR::Node *postorder(IR::PathExpression *ref) override;
55 const IR::Node *postorder(IR::ConcreteHeaderRef *nhr) override;
56 const IR::Node *postorder(IR::HeaderStackItemRef *ref) override;
57 const IR::Node *postorder(IR::GlobalRef *gr) override;
58 const IR::Node *postorder(IR::Equ *equ) override;
59 const IR::Node *postorder(IR::Neq *neq) override;
60 const IR::Expression *convert(const IR::Node *node) {
61 auto result = node->apply(*this);
62 return result->to<IR::Expression>();
63 }
64 static void addConverter(cstring type, funcType);
65 static funcType get(cstring type);
66};
67
69 std::map<cstring, cstring> *renameMap;
70
71 public:
72 StatementConverter(ProgramStructure *structure, std::map<cstring, cstring> *renameMap)
73 : ExpressionConverter(structure), renameMap(renameMap) {}
74
75 const IR::Node *preorder(IR::Apply *apply) override;
76 const IR::Node *preorder(IR::Primitive *primitive) override;
77 const IR::Node *preorder(IR::If *cond) override;
78 const IR::Statement *convert(const IR::Vector<IR::Expression> *toConvert);
79
80 const IR::Statement *convert(const IR::Node *node) {
81 auto conv = node->apply(*this);
82 auto result = conv->to<IR::Statement>();
83 BUG_CHECK(result != nullptr, "Conversion of %1% did not produce a statement", node);
84 return result;
85 }
86};
87
89 const IR::Type_Varbits *postorder(IR::Type_Varbits *) override;
90 const IR::Type_StructLike *postorder(IR::Type_StructLike *) override;
91 const IR::StructField *postorder(IR::StructField *) override;
92
93 public:
94 explicit TypeConverter(ProgramStructure *structure) : ExpressionConverter(structure) {}
95};
96
98 static std::map<cstring, ExternConverter *> *cvtForType;
99
100 public:
101 virtual const IR::Type_Extern *convertExternType(ProgramStructure *, const IR::Type_Extern *,
102 cstring);
103 virtual const IR::Declaration_Instance *convertExternInstance(
104 ProgramStructure *, const IR::Declaration_Instance *, cstring,
105 IR::IndexedVector<IR::Declaration> *);
106 virtual const IR::Statement *convertExternCall(ProgramStructure *,
107 const IR::Declaration_Instance *,
108 const IR::Primitive *);
109 virtual bool convertAsGlobal(ProgramStructure *, const IR::Declaration_Instance *) {
110 return false;
111 }
112 ExternConverter() {}
115 static void addConverter(cstring type, ExternConverter *);
116 static ExternConverter *get(cstring type);
117 static ExternConverter *get(const IR::Type_Extern *type) { return get(type->name); }
118 static ExternConverter *get(const IR::Declaration_Instance *ext) {
119 return get(ext->type->to<IR::Type_Extern>());
120 }
121 static const IR::Type_Extern *cvtExternType(ProgramStructure *s, const IR::Type_Extern *e,
122 cstring name) {
123 return get(e)->convertExternType(s, e, name);
124 }
125 static const IR::Declaration_Instance *cvtExternInstance(
126 ProgramStructure *s, const IR::Declaration_Instance *di, cstring name,
127 IR::IndexedVector<IR::Declaration> *scope) {
128 return get(di)->convertExternInstance(s, di, name, scope);
129 }
130 static const IR::Statement *cvtExternCall(ProgramStructure *s,
131 const IR::Declaration_Instance *di,
132 const IR::Primitive *p) {
133 return get(di)->convertExternCall(s, di, p);
134 }
135 static bool cvtAsGlobal(ProgramStructure *s, const IR::Declaration_Instance *di) {
136 return get(di)->convertAsGlobal(s, di);
137 }
138};
139
141 static std::map<cstring, std::vector<PrimitiveConverter *>> *all_converters;
142 cstring prim_name;
143 int priority;
144
145 protected:
146 PrimitiveConverter(cstring name, int prio);
147 virtual ~PrimitiveConverter();
148
149 // helper functions
150 safe_vector<const IR::Expression *> convertArgs(ProgramStructure *, const IR::Primitive *);
151
152 public:
153 virtual const IR::Statement *convert(ProgramStructure *, const IR::Primitive *) = 0;
154 static const IR::Statement *cvtPrimitive(ProgramStructure *, const IR::Primitive *);
155};
156
165#define CONVERT_PRIMITIVE(NAME, ...) \
166 class PrimitiveConverter_##NAME##_##__VA_ARGS__ : public PrimitiveConverter { \
167 const IR::Statement *convert(ProgramStructure *, const IR::Primitive *) override; \
168 PrimitiveConverter_##NAME##_##__VA_ARGS__() \
169 : PrimitiveConverter(#NAME, __VA_ARGS__ + 0) {} \
170 static PrimitiveConverter_##NAME##_##__VA_ARGS__ singleton; \
171 } PrimitiveConverter_##NAME##_##__VA_ARGS__::singleton; \
172 const IR::Statement *PrimitiveConverter_##NAME##_##__VA_ARGS__::convert( \
173 ProgramStructure *structure, const IR::Primitive *primitive)
174
176
177class DiscoverStructure : public Inspector {
178 ProgramStructure *structure;
179
180 // These names can only be used for very specific purposes
181 std::map<cstring, cstring> reserved_names = {
182 {"standard_metadata_t", "type"}, {"standard_metadata", "metadata"}, {"egress", "control"}};
183
184 void checkReserved(const IR::Node *node, cstring nodeName, cstring kind) const {
185 auto it = reserved_names.find(nodeName);
186 if (it == reserved_names.end()) return;
187 if (it->second != kind)
188 ::error(ErrorType::ERR_INVALID, "%1%: invalid name; it can only be used for %2%", node,
189 it->second);
190 }
191 void checkReserved(const IR::Node *node, cstring nodeName) const {
192 checkReserved(node, nodeName, nullptr);
193 }
194
195 public:
196 explicit DiscoverStructure(ProgramStructure *structure) : structure(structure) {
197 CHECK_NULL(structure);
198 setName("DiscoverStructure");
199 }
200
201 void postorder(const IR::ParserException *ex) override {
202 warn(ErrorType::WARN_UNSUPPORTED, "%1%: parser exception is not translated to P4-16", ex);
203 }
204 void postorder(const IR::Metadata *md) override {
205 structure->metadata.emplace(md);
206 checkReserved(md, md->name, "metadata");
207 }
208 void postorder(const IR::Header *hd) override {
209 structure->headers.emplace(hd);
210 checkReserved(hd, hd->name);
211 }
212 void postorder(const IR::Type_StructLike *t) override {
213 structure->types.emplace(t);
214 checkReserved(t, t->name, "type");
215 }
216 void postorder(const IR::V1Control *control) override {
217 structure->controls.emplace(control);
218 checkReserved(control, control->name, "control");
219 }
220 void postorder(const IR::V1Parser *parser) override {
221 structure->parserStates.emplace(parser);
222 checkReserved(parser, parser->name);
223 }
224 void postorder(const IR::V1Table *table) override {
225 structure->tables.emplace(table);
226 checkReserved(table, table->name);
227 }
228 void postorder(const IR::ActionFunction *action) override {
229 structure->actions.emplace(action);
230 checkReserved(action, action->name);
231 }
232 void postorder(const IR::HeaderStack *stack) override {
233 structure->stacks.emplace(stack);
234 checkReserved(stack, stack->name);
235 }
236 void postorder(const IR::Counter *count) override {
237 structure->counters.emplace(count);
238 checkReserved(count, count->name);
239 }
240 void postorder(const IR::Register *reg) override {
241 structure->registers.emplace(reg);
242 checkReserved(reg, reg->name);
243 }
244 void postorder(const IR::ActionProfile *ap) override {
245 structure->action_profiles.emplace(ap);
246 checkReserved(ap, ap->name);
247 }
248 void postorder(const IR::FieldList *fl) override {
249 structure->field_lists.emplace(fl);
250 checkReserved(fl, fl->name);
251 }
252 void postorder(const IR::FieldListCalculation *flc) override {
253 structure->field_list_calculations.emplace(flc);
254 checkReserved(flc, flc->name);
255 }
256 void postorder(const IR::CalculatedField *cf) override {
257 structure->calculated_fields.push_back(cf);
258 }
259 void postorder(const IR::Meter *m) override {
260 structure->meters.emplace(m);
261 checkReserved(m, m->name);
262 }
263 void postorder(const IR::ActionSelector *as) override {
264 structure->action_selectors.emplace(as);
265 checkReserved(as, as->name);
266 }
267 void postorder(const IR::Type_Extern *ext) override {
268 structure->extern_types.emplace(ext);
269 checkReserved(ext, ext->name);
270 }
271 void postorder(const IR::Declaration_Instance *ext) override {
272 structure->externs.emplace(ext);
273 checkReserved(ext, ext->name);
274 }
275 void postorder(const IR::ParserValueSet *pvs) override {
276 structure->value_sets.emplace(pvs);
277 checkReserved(pvs, pvs->name);
278 }
279};
280
281class ComputeCallGraph : public Inspector {
282 ProgramStructure *structure;
283
284 public:
285 explicit ComputeCallGraph(ProgramStructure *structure) : structure(structure) {
286 CHECK_NULL(structure);
287 setName("ComputeCallGraph");
288 }
289
290 void postorder(const IR::V1Parser *parser) override {
291 LOG3("Scanning parser " << parser->name);
292 structure->parsers.add(parser->name);
293 if (!parser->default_return.name.isNullOrEmpty())
294 structure->parsers.calls(parser->name, parser->default_return);
295 if (parser->cases != nullptr)
296 for (auto ce : *parser->cases) structure->parsers.calls(parser->name, ce->action.name);
297 for (auto expr : parser->stmts) {
298 if (expr->is<IR::Primitive>()) {
299 auto primitive = expr->to<IR::Primitive>();
300 if (primitive->name == "extract") {
301 BUG_CHECK(primitive->operands.size() == 1, "Expected 1 operand for %1%",
302 primitive);
303 auto dest = primitive->operands.at(0);
304 LOG3("Parser " << parser->name << " extracts into " << dest);
305 structure->extracts[parser->name].push_back(dest);
306 }
307 }
308 }
309 }
310 void postorder(const IR::Primitive *primitive) override {
311 auto name = primitive->name;
312 const IR::GlobalRef *glob = nullptr;
313 const IR::Declaration_Instance *extrn = nullptr;
314 if (!primitive->operands.empty()) glob = primitive->operands[0]->to<IR::GlobalRef>();
315 if (glob) extrn = glob->obj->to<IR::Declaration_Instance>();
316
317 if (extrn) {
318 auto parent = findContext<IR::ActionFunction>();
319 BUG_CHECK(parent != nullptr, "%1%: Extern call not within action", primitive);
320 structure->calledExterns.calls(parent->name, extrn->name.name);
321 return;
322 } else if (primitive->name == "count") {
323 // counter invocation
324 auto ctrref = primitive->operands.at(0);
325 const IR::Counter *ctr = nullptr;
326 if (auto gr = ctrref->to<IR::GlobalRef>())
327 ctr = gr->obj->to<IR::Counter>();
328 else if (auto nr = ctrref->to<IR::PathExpression>())
329 ctr = structure->counters.get(nr->path->name);
330 if (ctr == nullptr) {
331 ::error(ErrorType::ERR_NOT_FOUND, "%1%: Cannot find counter", ctrref);
332 return;
333 }
334 auto parent = findContext<IR::ActionFunction>();
335 BUG_CHECK(parent != nullptr, "%1%: Counter call not within action", primitive);
336 structure->calledCounters.calls(parent->name, ctr->name.name);
337 return;
338 } else if (primitive->name == "execute_meter") {
339 auto mtrref = primitive->operands.at(0);
340 const IR::Meter *mtr = nullptr;
341 if (auto gr = mtrref->to<IR::GlobalRef>())
342 mtr = gr->obj->to<IR::Meter>();
343 else if (auto nr = mtrref->to<IR::PathExpression>())
344 mtr = structure->meters.get(nr->path->name);
345 if (mtr == nullptr) {
346 ::error(ErrorType::ERR_NOT_FOUND, "%1%: Cannot find meter", mtrref);
347 return;
348 }
349 auto parent = findContext<IR::ActionFunction>();
350 BUG_CHECK(parent != nullptr, "%1%: not within action", primitive);
351 structure->calledMeters.calls(parent->name, mtr->name.name);
352 return;
353 } else if (primitive->name == "register_read" || primitive->name == "register_write") {
354 const IR::Expression *regref;
355 if (primitive->name == "register_read")
356 regref = primitive->operands.at(1);
357 else
358 regref = primitive->operands.at(0);
359 const IR::Register *reg = nullptr;
360 if (auto gr = regref->to<IR::GlobalRef>())
361 reg = gr->obj->to<IR::Register>();
362 else if (auto nr = regref->to<IR::PathExpression>())
363 reg = structure->registers.get(nr->path->name);
364 if (reg == nullptr) {
365 ::error(ErrorType::ERR_NOT_FOUND, "%1%: Cannot find register", regref);
366 return;
367 }
368 auto parent = findContext<IR::ActionFunction>();
369 BUG_CHECK(parent != nullptr, "%1%: not within action", primitive);
370 structure->calledRegisters.calls(parent->name, reg->name.name);
371 return;
372 } else if (structure->actions.contains(name)) {
373 auto parent = findContext<IR::ActionFunction>();
374 BUG_CHECK(parent != nullptr, "%1%: Action call not within action", primitive);
375 structure->calledActions.calls(parent->name, name);
376 } else if (structure->controls.contains(name)) {
377 auto parent = findContext<IR::V1Control>();
378 BUG_CHECK(parent != nullptr, "%1%: Control call not within control", primitive);
379 structure->calledControls.calls(parent->name, name);
380 }
381 }
382 void postorder(const IR::GlobalRef *gref) override {
383 cstring caller;
384 if (auto af = findContext<IR::ActionFunction>()) {
385 caller = af->name;
386 } else if (auto di = findContext<IR::Declaration_Instance>()) {
387 caller = di->name;
388 } else {
389 BUG("%1%: GlobalRef not within action or extern", gref);
390 }
391 if (auto ctr = gref->obj->to<IR::Counter>())
392 structure->calledCounters.calls(caller, ctr->name.name);
393 else if (auto mtr = gref->obj->to<IR::Meter>())
394 structure->calledMeters.calls(caller, mtr->name.name);
395 else if (auto reg = gref->obj->to<IR::Register>())
396 structure->calledRegisters.calls(caller, reg->name.name);
397 else if (auto ext = gref->obj->to<IR::Declaration_Instance>())
398 structure->calledExterns.calls(caller, ext->name.name);
399 }
400};
401
405class ComputeTableCallGraph : public Inspector {
406 ProgramStructure *structure;
407
408 public:
409 explicit ComputeTableCallGraph(ProgramStructure *structure) : structure(structure) {
410 CHECK_NULL(structure);
411 setName("ComputeTableCallGraph");
412 }
413
414 void postorder(const IR::Apply *apply) override {
415 LOG3("Scanning " << apply->name);
416 auto tbl = structure->tables.get(apply->name.name);
417 if (tbl == nullptr) {
418 ::error(ErrorType::ERR_NOT_FOUND, "%1%: Could not find table", apply->name);
419 return;
420 }
421 auto parent = findContext<IR::V1Control>();
422 if (!parent) {
423 ::error(ErrorType::ERR_UNEXPECTED, "%1%: Apply not within a control block?", apply);
424 return;
425 }
426
427 auto ctrl = get(structure->tableMapping, tbl);
428
429 // skip control block that is unused.
430 if (!structure->calledControls.isCallee(parent->name) &&
431 parent->name != P4V1::V1Model::instance.ingress.name &&
432 parent->name != P4V1::V1Model::instance.egress.name)
433 return;
434
435 if (ctrl != nullptr && ctrl != parent) {
436 auto previous = get(structure->tableInvocation, tbl);
437 ::error(ErrorType::ERR_INVALID,
438 "%1%: Table invoked from two different controls: %2% and %3%", tbl, apply,
439 previous);
440 }
441 LOG3("Invoking " << tbl << " in " << parent->name);
442 structure->tableMapping.emplace(tbl, parent);
443 structure->tableInvocation.emplace(tbl, apply);
444 }
445};
446
447class Rewriter : public Transform {
448 ProgramStructure *structure;
449
450 public:
451 explicit Rewriter(ProgramStructure *structure) : structure(structure) {
452 CHECK_NULL(structure);
453 setName("Rewriter");
454 }
455
456 const IR::Node *preorder(IR::V1Program *global) override {
457 if (LOGGING(4)) {
458 LOG4("#### Initial P4_14 program");
459 dump(global);
460 }
461 prune();
462 auto *rv = structure->create(global->srcInfo);
463 if (LOGGING(4)) {
464 LOG4("#### Generated P4_16 program");
465 dump(rv);
466 }
467 return rv;
468 }
469};
470
506class FixExtracts final : public Transform {
507 ProgramStructure *structure;
508
509 struct HeaderSplit {
511 const IR::Type_Header *fixedHeaderType;
513 const IR::Expression *headerLength;
514 };
515
517 // The following vector contains only IR::Type_Header, but it is easier
518 // to append if the elements are Node.
519 IR::Vector<IR::Node> allTypeDecls;
521 IR::IndexedVector<IR::Declaration> varDecls;
523 std::map<cstring, HeaderSplit *> fixedPart;
524
528 HeaderSplit *splitHeaderType(const IR::Type_Header *type) {
529 // Maybe we have seen this type already
530 auto fixed = ::get(fixedPart, type->name.name);
531 if (fixed != nullptr) return fixed;
532
533 const IR::Expression *headerLength = nullptr;
534 // We allocate the following when we find the first varbit field.
535 const IR::Type_Header *fixedHeaderType = nullptr;
536 IR::IndexedVector<IR::StructField> fields;
537
538 for (auto f : type->fields) {
539 if (f->type->is<IR::Type_Varbits>()) {
540 cstring hname = structure->makeUniqueName(type->name);
541 if (fixedHeaderType != nullptr) {
542 ::error(ErrorType::ERR_INVALID,
543 "%1%: header types with multiple varbit fields are not supported",
544 type);
545 return nullptr;
546 }
547 fixedHeaderType = new IR::Type_Header(IR::ID(hname), fields);
548 // extract length from annotation
549 auto anno = f->getAnnotation(IR::Annotation::lengthAnnotation);
550 BUG_CHECK(anno != nullptr, "No length annotation on varbit field", f);
551 BUG_CHECK(anno->expr.size() == 1, "Expected exactly 1 argument", anno->expr);
552 headerLength = anno->expr.at(0);
553 // We keep going through the loop just to check whether there is another
554 // varbit field in the header.
555 } else if (fixedHeaderType == nullptr) {
556 // We only keep the fields prior to the varbit field
557 fields.push_back(f);
558 }
559 }
560 if (fixedHeaderType != nullptr) {
561 LOG3("Extracted fixed-size header type from " << type << " into " << fixedHeaderType);
562 fixed = new HeaderSplit;
563 fixed->fixedHeaderType = fixedHeaderType;
564 fixed->headerLength = headerLength;
565 fixedPart.emplace(type->name.name, fixed);
566 allTypeDecls.push_back(fixedHeaderType);
567 return fixed;
568 }
569 return nullptr;
570 }
571
579 class RewriteLength final : public Transform {
580 const IR::Type_Header *header;
581 const IR::Declaration *var;
582
583 public:
584 explicit RewriteLength(const IR::Type_Header *header, const IR::Declaration *var)
585 : header(header), var(var) {
586 setName("RewriteLength");
587 }
588
589 const IR::Node *postorder(IR::PathExpression *expression) override {
590 if (expression->path->absolute) return expression;
591 for (auto f : header->fields) {
592 if (f->name == expression->path->name)
593 return new IR::Member(expression->srcInfo, new IR::PathExpression(var->name),
594 f->name);
595 }
596 return expression;
597 }
598 };
599
600 public:
601 explicit FixExtracts(ProgramStructure *structure) : structure(structure) {
602 CHECK_NULL(structure);
603 setName("FixExtracts");
604 }
605
606 const IR::Node *postorder(IR::P4Program *program) override {
607 // P4-14 headers cannot refer to other types, so it is safe
608 // to prepend them to the list of declarations.
609 allTypeDecls.append(program->objects);
610 program->objects = allTypeDecls;
611 return program;
612 }
613
614 const IR::Node *postorder(IR::P4Parser *parser) override {
615 if (!varDecls.empty()) {
616 parser->parserLocals.append(varDecls);
617 varDecls.clear();
618 }
619 return parser;
620 }
621
622 const IR::Node *postorder(IR::MethodCallStatement *statement) override {
623 auto mce = getOriginal<IR::MethodCallStatement>()->methodCall;
624 LOG3("Looking up in extracts " << dbp(mce));
625 auto ht = ::get(structure->extractsSynthesized, mce);
626 if (ht == nullptr)
627 // not an extract
628 return statement;
629
630 // This is an extract method invocation
631 BUG_CHECK(mce->arguments->size() == 1, "%1%: expected 1 argument", mce);
632 auto arg = mce->arguments->at(0);
633
634 auto fixed = splitHeaderType(ht);
635 if (fixed == nullptr) return statement;
636 CHECK_NULL(fixed->headerLength);
637 CHECK_NULL(fixed->fixedHeaderType);
638
639 auto result = new IR::IndexedVector<IR::StatOrDecl>();
640 cstring varName = structure->makeUniqueName("tmp_hdr");
641 auto var =
642 new IR::Declaration_Variable(IR::ID(varName), fixed->fixedHeaderType->to<IR::Type>());
643 varDecls.push_back(var);
644
645 // Create lookahead
646 auto member = mce->method->to<IR::Member>(); // should be packet_in.extract
647 CHECK_NULL(member);
648 auto typeArgs = new IR::Vector<IR::Type>();
649 typeArgs->push_back(fixed->fixedHeaderType->getP4Type());
650 auto lookaheadMethod =
651 new IR::Member(member->expr, P4::P4CoreLibrary::instance().packetIn.lookahead.name);
652 auto lookahead = new IR::MethodCallExpression(mce->srcInfo, lookaheadMethod, typeArgs,
654 auto assign =
655 new IR::AssignmentStatement(mce->srcInfo, new IR::PathExpression(varName), lookahead);
656 result->push_back(assign);
657 LOG3("Created lookahead " << assign);
658
659 // Create actual extract
660 RewriteLength rewrite(fixed->fixedHeaderType, var);
661 rewrite.setCalledBy(this);
662 auto length = fixed->headerLength->apply(rewrite);
663 auto args = new IR::Vector<IR::Argument>();
664 args->push_back(arg->clone());
665 auto type = IR::Type_Bits::get(P4::P4CoreLibrary::instance().packetIn.extractSecondArgSize);
666 auto cast = new IR::Cast(Util::SourceInfo(), type, length);
667 args->push_back(new IR::Argument(cast));
668 auto expression = new IR::MethodCallExpression(mce->srcInfo, mce->method->clone(), args);
669 result->push_back(new IR::MethodCallStatement(expression));
670 return result;
671 }
672};
673
674/*
675 This class is used to adjust the expressions in a @length
676 annotation on a varbit field. The P4-14 to P4-16 converter inserts
677 these annotations on the unique varbit field in a header; the
678 annotations are created from the header max_length and length
679 fields. The length annotation contains an expression which is used
680 to compute the length of the varbit field. The problem that we are
681 solving here is that expression semantics is different in P4-14 and
682 P4-16. Consider the canonical case of an IPv4 header:
683
684 header_type ipv4_t {
685 fields {
686 version : 4;
687 ihl : 4;
688 // lots of other fields...
689 options: *;
690 }
691 length : ihl*4;
692 max_length : 64;
693 }
694
695 This generates the following P4-16 structure:
696 struct ipv4_t {
697 bit<4> version;
698 bit<4> ihl;
699 @length((ihl*4) * 8 - 20) // 20 is the size of the fixed part of the header
700 varbit<(64 - 20) * 8> options;
701 }
702
703 When such a header is used in an extract statement, the @length
704 annotation is used to compute the second argument of the extract
705 method. The problem we are solving here is the fact that ihl is
706 only represented on 4 bits, so the evaluation ihl*4 will actually
707 overflow. This is not a problem in P4-14, but it is a problem in
708 P4-16. Unfortunately there is no easy way to guess how many bits
709 are required to evaluate this computation. So what we do is to cast
710 all PathExpressions to 32-bits. This is really just a heuristic,
711 but since the semantics of P4-14 expressions is unclear, we cannot
712 do much better than this.
713*/
714class AdjustLengths : public Transform {
715 public:
716 AdjustLengths() { setName("AdjustLengths"); }
717 const IR::Node *postorder(IR::PathExpression *expression) override {
718 auto anno = findContext<IR::Annotation>();
719 if (anno == nullptr) return expression;
720 if (anno->name != "length") return expression;
721
722 LOG3("Inserting cast in length annotation");
723 auto type = IR::Type_Bits::get(32);
724 auto cast = new IR::Cast(expression->srcInfo, type, expression);
725 return cast;
726 }
727};
728
731class DetectDuplicates : public Inspector {
732 public:
733 DetectDuplicates() { setName("DetectDuplicates"); }
734
735 bool preorder(const IR::V1Program *program) override {
736 auto &map = program->scope;
737 auto firstWithKey = map.begin();
738 while (firstWithKey != map.end()) {
739 auto key = firstWithKey->first;
740 auto range = map.equal_range(key);
741 for (auto s = range.first; s != range.second; s++) {
742 auto n = s;
743 for (n++; n != range.second; n++) {
744 auto e1 = s->second;
745 auto e2 = n->second;
746 if (e1->node_type_name() == e2->node_type_name()) {
747 if (e1->srcInfo.getStart().isValid())
748 ::error(ErrorType::ERR_DUPLICATE, "%1%: same name as %2%", e1, e2);
749 else
750 // This name is probably standard_metadata_t, a built-in declaration
751 ::error(ErrorType::ERR_INVALID, "%1% is invalid; name %2% is reserved",
752 e2, key);
753 }
754 }
755 }
756 firstWithKey = range.second;
757 }
758 // prune; we're done; everything is top-level
759 return false;
760 }
761};
762
763// If a parser state has a pragma @packet_entry, it is treated as a new entry
764// point to the parser.
765class CheckIfMultiEntryPoint : public Inspector {
766 ProgramStructure *structure;
767
768 public:
769 explicit CheckIfMultiEntryPoint(ProgramStructure *structure) : structure(structure) {
770 setName("CheckIfMultiEntryPoint");
771 }
772 bool preorder(const IR::ParserState *state) {
773 for (const auto *anno : state->getAnnotations()->annotations) {
774 if (anno->name.name == "packet_entry") {
775 structure->parserEntryPoints.emplace(state->name, state);
776 }
777 }
778 return false;
779 }
780};
781
782// Generate a new start state that selects on the meta variable,
783// standard_metadata.instance_type and branches into one of the entry points.
784// The backend is responsible for removing the use of the meta variable and
785// eliminate the new start state. The new start state is not added if the user
786// does not use the @packet_entry pragma.
787class InsertCompilerGeneratedStartState : public Transform {
788 ProgramStructure *structure;
789 IR::Vector<IR::Node> allTypeDecls;
790 IR::IndexedVector<IR::ParserState> parserStates;
792 cstring newStartState;
793 cstring newInstanceType;
794
795 public:
796 explicit InsertCompilerGeneratedStartState(ProgramStructure *structure) : structure(structure) {
797 setName("InsertCompilerGeneratedStartState");
798 structure->allNames.insert({IR::ParserState::start, 0});
799 structure->allNames.insert({"InstanceType", 0});
800 newStartState = structure->makeUniqueName(IR::ParserState::start);
801 newInstanceType = structure->makeUniqueName("InstanceType");
802 }
803
804 const IR::Node *postorder(IR::P4Program *program) override {
805 allTypeDecls.append(program->objects);
806 program->objects = allTypeDecls;
807 return program;
808 }
809
810 // rename original start state
811 const IR::Node *postorder(IR::ParserState *state) override {
812 if (structure->parserEntryPoints.empty()) return state;
813 if (state->name == IR::ParserState::start) {
814 state->name = newStartState;
815 }
816 return state;
817 }
818
819 // Rename any path refering to original start state
820 const IR::Node *postorder(IR::Path *path) override {
821 if (structure->parserEntryPoints.empty()) return path;
822 // At this point any identifier called start should have been renamed
823 // to unique name (e.g. start_1) => we can safely assume that any
824 // "start" refers to the parser state
825 if (path->name.name != IR::ParserState::start) return path;
826 // Just to make sure we can also check it explicitly
827 auto pe = getContext()->node->to<IR::PathExpression>();
828 auto sc = findContext<IR::SelectCase>();
829 auto ps = findContext<IR::ParserState>();
830 // Either the path is within SelectCase->state<PathExpression>->path
831 if (pe && ((sc && pe->equiv(*sc->state->to<IR::PathExpression>())) ||
832 // Or just within ParserState->selectExpression<PathExpression>->path
833 (ps && pe->equiv(*ps->selectExpression->to<IR::PathExpression>()))))
834 path->name = newStartState;
835 return path;
836 }
837
838 const IR::Node *postorder(IR::P4Parser *parser) override {
839 if (structure->parserEntryPoints.empty()) return parser;
840 IR::IndexedVector<IR::SerEnumMember> members;
841 // transition to original start state
842 members.push_back(new IR::SerEnumMember("START", new IR::Constant(0)));
843 selCases.push_back(new IR::SelectCase(
844 new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)), "START"),
845 new IR::PathExpression(new IR::Path(newStartState))));
846
847 // transition to addtional entry points
848 unsigned idx = 1;
849 for (auto p : structure->parserEntryPoints) {
850 members.push_back(new IR::SerEnumMember(p.first, new IR::Constant(idx++)));
851 selCases.push_back(new IR::SelectCase(
852 new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)),
853 p.first),
854 new IR::PathExpression(new IR::Path(p.second->name))));
855 }
856 auto instAnnos = new IR::Annotations();
857 instAnnos->add(new IR::Annotation(IR::Annotation::nameAnnotation, ".$InstanceType"));
858 auto instEnum =
859 new IR::Type_SerEnum(newInstanceType, instAnnos, IR::Type_Bits::get(32), members);
860 allTypeDecls.push_back(instEnum);
861
863 selExpr.push_back(
864 new IR::Cast(new IR::Type_Name(newInstanceType),
865 new IR::Member(new IR::PathExpression(new IR::Path("standard_metadata")),
866 "instance_type")));
867 auto selects = new IR::SelectExpression(new IR::ListExpression(selExpr), selCases);
868 auto annos = new IR::Annotations();
869 annos->add(new IR::Annotation(IR::Annotation::nameAnnotation, ".$start"));
870 auto startState = new IR::ParserState(IR::ParserState::start, annos, selects);
871 parserStates.push_back(startState);
872
873 if (!parserStates.empty()) {
874 parser->states.append(parserStates);
875 parserStates.clear();
876 }
877 return parser;
878 }
879};
880
884class FixMultiEntryPoint : public PassManager {
885 public:
886 explicit FixMultiEntryPoint(ProgramStructure *structure) {
887 setName("FixMultiEntryPoint");
888 passes.emplace_back(new CheckIfMultiEntryPoint(structure));
889 passes.emplace_back(new InsertCompilerGeneratedStartState(structure));
890 }
891};
892
901class MoveIntrinsicMetadata : public Transform {
902 ProgramStructure *structure;
903 const IR::Type_Struct *stdType = nullptr;
904 const IR::Type_Struct *userType = nullptr;
905 const IR::Type_Struct *intrType = nullptr;
906 const IR::Type_Struct *queueType = nullptr;
907 const IR::StructField *intrField = nullptr;
908 const IR::StructField *queueField = nullptr;
909
910 public:
911 explicit MoveIntrinsicMetadata(ProgramStructure *structure) : structure(structure) {
912 CHECK_NULL(structure);
913 setName("MoveIntrinsicMetadata");
914 }
915 const IR::Node *preorder(IR::P4Program *program) override {
916 stdType = program->getDeclsByName(structure->v1model.standardMetadataType.name)
917 ->single()
918 ->to<IR::Type_Struct>();
919 userType = program->getDeclsByName(structure->v1model.metadataType.name)
920 ->single()
921 ->to<IR::Type_Struct>();
922 CHECK_NULL(stdType);
923 CHECK_NULL(userType);
924 intrField = userType->getField(structure->v1model.intrinsicMetadata.name);
925 if (intrField != nullptr) {
926 auto intrTypeName = intrField->type;
927 auto tn = intrTypeName->to<IR::Type_Name>();
928 BUG_CHECK(tn, "%1%: expected a Type_Name", intrTypeName);
929 auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault();
930 if (nt == nullptr || !nt->is<IR::Type_Struct>()) {
931 ::error(ErrorType::ERR_INVALID, "%1%: expected a structure", tn);
932 return program;
933 }
934 intrType = nt->to<IR::Type_Struct>();
935 LOG2("Intrinsic metadata type " << intrType);
936 }
937
938 queueField = userType->getField(structure->v1model.queueingMetadata.name);
939 if (queueField != nullptr) {
940 auto queueTypeName = queueField->type;
941 auto tn = queueTypeName->to<IR::Type_Name>();
942 BUG_CHECK(tn, "%1%: expected a Type_Name", queueTypeName);
943 auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault();
944 if (nt == nullptr || !nt->is<IR::Type_Struct>()) {
945 ::error(ErrorType::ERR_INVALID, "%1%: expected a structure", tn);
946 return program;
947 }
948 queueType = nt->to<IR::Type_Struct>();
949 LOG2("Queueing metadata type " << queueType);
950 }
951 return program;
952 }
953
954 const IR::Node *postorder(IR::Type_Struct *type) override {
955 if (getOriginal() == stdType) {
956 if (intrType != nullptr) {
957 for (auto f : intrType->fields) {
958 if (type->fields.getDeclaration(f->name) == nullptr) {
959 ::error(ErrorType::ERR_NOT_FOUND, "%1%: no such field in standard_metadata",
960 f->name);
961 LOG2("standard_metadata: " << type);
962 }
963 }
964 }
965 if (queueType != nullptr) {
966 for (auto f : queueType->fields) {
967 if (type->fields.getDeclaration(f->name) == nullptr) {
968 ::error(ErrorType::ERR_NOT_FOUND, "%1%: no such field in standard_metadata",
969 f->name);
970 LOG2("standard_metadata: " << type);
971 }
972 }
973 }
974 }
975 return type;
976 }
977
978 const IR::Node *postorder(IR::StructField *field) override {
979 if (getOriginal() == intrField || getOriginal() == queueField)
980 // delete it from its parent
981 return nullptr;
982 return field;
983 }
984
985 const IR::Node *postorder(IR::Member *member) override {
986 // We rewrite expressions like meta.intrinsic_metadata.x as
987 // standard_metadata.x. We know that these parameter names
988 // are always the same.
989 if (member->member != structure->v1model.intrinsicMetadata.name &&
990 member->member != structure->v1model.queueingMetadata.name)
991 return member;
992 auto pe = member->expr->to<IR::PathExpression>();
993 if (pe == nullptr || pe->path->absolute) return member;
994 if (pe->path->name == structure->v1model.parser.metadataParam.name) {
995 LOG2("Renaming reference " << member);
996 return new IR::PathExpression(new IR::Path(
997 member->expr->srcInfo,
998 IR::ID(pe->path->name.srcInfo, structure->v1model.standardMetadata.name)));
999 }
1000 return member;
1001 }
1002};
1003
1006class FindRecirculated : public Inspector {
1007 ProgramStructure *structure;
1008
1009 void add(const IR::Primitive *primitive, unsigned operand) {
1010 if (primitive->operands.size() <= operand) {
1011 // not enough arguments, do nothing.
1012 // resubmit and recirculate have optional arguments
1013 return;
1014 }
1015 auto expression = primitive->operands.at(operand);
1016 if (!expression->is<IR::PathExpression>()) {
1017 ::error(ErrorType::ERR_EXPECTED, "%1%: expected a field list", expression);
1018 return;
1019 }
1020 auto nr = expression->to<IR::PathExpression>();
1021 auto fl = structure->field_lists.get(nr->path->name);
1022 if (fl == nullptr) {
1023 ::error(ErrorType::ERR_EXPECTED, "%1%: Expected a field list", expression);
1024 return;
1025 }
1026 LOG3("Recirculated " << nr->path->name);
1027 structure->allFieldLists.emplace(fl);
1028 }
1029
1030 public:
1031 explicit FindRecirculated(ProgramStructure *structure) : structure(structure) {
1032 CHECK_NULL(structure);
1033 setName("FindRecirculated");
1034 }
1035
1036 void postorder(const IR::Primitive *primitive) override {
1037 if (primitive->name == "recirculate" || primitive->name == "resubmit") {
1038 add(primitive, 0);
1039 } else if (primitive->name.startsWith("clone") && primitive->operands.size() == 2) {
1040 add(primitive, 1);
1041 }
1042 }
1043};
1044
1046
1047// Is fed a P4-14 program and outputs an equivalent P4-16 program in v1model
1048class Converter : public PassManager {
1049 public:
1050 ProgramStructure *structure;
1051 static ProgramStructure *(*createProgramStructure)();
1052 static ConversionContext *(*createConversionContext)();
1053 Converter();
1054 void loadModel() { structure->loadModel(); }
1055 Visitor::profile_t init_apply(const IR::Node *node) override;
1056};
1057
1058} // namespace P4V1
1059
1060#endif /* FRONTENDS_P4_FROMV1_0_CONVERTERS_H_ */
Definition externInstance.h:33
Definition coreLibrary.h:100
Definition converters.h:714
Definition converters.h:765
Definition converters.h:281
Definition converters.h:405
Definition programStructure.h:32
Definition converters.h:1048
Definition converters.h:731
Definition converters.h:177
Definition converters.h:34
Definition converters.h:97
static void addConverter(cstring type, ExternConverter *)
Definition converters.cpp:579
Definition converters.h:1006
Definition converters.h:506
Definition converters.h:884
Definition converters.h:787
Definition converters.h:901
Definition converters.h:140
Information about the structure of a P4-14 program, used to convert it to a P4-16 program.
Definition programStructure.h:45
ordered_set< const IR::FieldList * > allFieldLists
Field lists that appear in the program.
Definition programStructure.h:163
Definition converters.h:447
Definition converters.h:68
Definition converters.h:88
Definition source_file.h:126
Definition cstring.h:72
Definition safe_vector.h:25