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