P4C
The P4 Compiler
Loading...
Searching...
No Matches
checksum.h
1
19#ifndef BACKENDS_TOFINO_BF_P4C_ARCH_FROMV1_0_CHECKSUM_H_
20#define BACKENDS_TOFINO_BF_P4C_ARCH_FROMV1_0_CHECKSUM_H_
21
22#include "backends/tofino/bf-p4c/arch/intrinsic_metadata.h"
23#include "backends/tofino/bf-p4c/lib/assoc.h"
24#include "backends/tofino/bf-p4c/midend/parser_graph.h"
25#include "frontends/p4/methodInstance.h"
26#include "v1_program_structure.h"
27
29
31 bool with_payload;
32 const IR::Expression *cond;
33 const IR::Expression *fieldList;
34 const IR::Expression *destField;
35 std::set<gress_t> parserUpdateLocations;
36 std::set<gress_t> deparserUpdateLocations;
37 std::optional<cstring> residulChecksumName;
38};
39
40namespace BFN::V1 {
41
43 public:
47 residualChecksumPayloadFields;
49 destToGressToState;
50 std::map<gress_t, std::map<cstring, IR::Statement *>> checksumDepositToHeader;
51 DeclToStates ingressVerifyDeclToStates;
52 P4ParserGraphs parserGraphs;
53
55 P4::TypeMap *typeMap);
56};
57
58static bool analyzeChecksumCall(const IR::MethodCallStatement *statement, cstring which) {
59 auto methodCall = statement->methodCall->to<IR::MethodCallExpression>();
60 if (!methodCall) {
61 ::warning("Expected a non-empty method call expression: %1%", statement);
62 return false;
63 }
64 auto method = methodCall->method->to<IR::PathExpression>();
65 if (!method || (method->path->name != which)) {
66 ::warning("Expected an %1% statement in %2%", statement, which);
67 return false;
68 }
69 if (methodCall->arguments->size() != 4) {
70 ::warning("Expected 4 arguments for %1% statement: %2%", statement, which);
71 return false;
72 }
73
74 auto destField = (*methodCall->arguments)[2]->expression->to<IR::Member>();
75 CHECK_NULL(destField);
76
77 auto condition = (*methodCall->arguments)[0]->expression;
78 CHECK_NULL(condition);
79
80 bool nominalCondition = false;
81 if (auto mc = condition->to<IR::MethodCallExpression>()) {
82 if (auto m = mc->method->to<IR::Member>()) {
83 if (m->member == "isValid") {
84 if (m->expr->equiv(*(destField->expr))) {
85 nominalCondition = true;
86 }
87 }
88 }
89 }
90
91 auto bl = condition->to<IR::BoolLiteral>();
92 if (which == "verify_checksum" && !nominalCondition && (!bl || bl->value != true))
93 error("Tofino does not support conditional checksum verification: %1%", destField);
94
95 auto algorithm = (*methodCall->arguments)[3]->expression->to<IR::Member>();
96 if (!algorithm || (algorithm->member != "csum16"))
97 error("Tofino only supports \"csum16\" for checksum calculation: %1%", destField);
98
99 return true;
100}
101
102static IR::Declaration_Instance *createChecksumDeclaration(ProgramStructure *structure,
103 const IR::MethodCallStatement *) {
104 // auto mc = csum->methodCall->to<IR::MethodCallExpression>();
105
106 // auto typeArgs = new IR::Vector<IR::Type>();
107 auto inst = new IR::Type_Name("Checksum");
108
109 auto csum_name = cstring::make_unique(structure->unique_names, "checksum"_cs, '_');
110 structure->unique_names.insert(csum_name);
111 auto args = new IR::Vector<IR::Argument>();
112 auto decl = new IR::Declaration_Instance(csum_name, inst, args);
113
114 return decl;
115}
116
117static IR::AssignmentStatement *createChecksumError(const IR::Declaration *decl, gress_t gress) {
118 auto methodCall = new IR::Member(new IR::PathExpression(decl->name), "verify");
119 auto verifyCall = new IR::MethodCallExpression(methodCall, {});
120 auto rhs_val = new IR::Cast(IR::Type::Bits::get(1), verifyCall);
121
122 cstring intr_md;
123
124 if (gress == INGRESS)
125 intr_md = "ig_intr_md_from_prsr"_cs;
126 else if (gress == EGRESS)
127 intr_md = "eg_intr_md_from_prsr"_cs;
128 else
129 BUG("Unhandled gress: %1%.", gress);
130
131 auto parser_err = new IR::Member(new IR::PathExpression(intr_md), "parser_err");
132
133 auto lhs = new IR::Slice(parser_err, 12, 12);
134 auto rhs = new IR::BOr(lhs, rhs_val);
135 return new IR::AssignmentStatement(lhs, rhs);
136}
137
138static std::vector<gress_t> getChecksumUpdateLocations(const IR::MethodCallExpression *call,
139 const IR::BlockStatement *block,
140 cstring pragma) {
141 std::vector<gress_t> updateLocations;
142 if (pragma == "calculated_field_update_location")
143 updateLocations = {EGRESS};
144 else if (pragma == "residual_checksum_parser_update_location")
145 updateLocations = {INGRESS};
146 else
147 BUG("Invalid use of function getChecksumUpdateLocation");
148
149 for (auto annot : block->annotations) {
150 if (annot->name.name == pragma) {
151 auto &exprs = annot->getExpr();
152 auto gress = exprs[0]->to<IR::StringLiteral>();
153 auto pCall = exprs[1]->to<IR::MethodCallExpression>();
154 if (pCall && !pCall->equiv(*call)) continue;
155 if (gress->value == "ingress")
156 updateLocations = {INGRESS};
157 else if (gress->value == "egress")
158 updateLocations = {EGRESS};
159 else if (gress->value == "ingress_and_egress")
160 updateLocations = {INGRESS, EGRESS};
161 else
162 error(
163 "Invalid use of @pragma %1%, valid value "
164 " is ingress/egress/ingress_and_egress",
165 pragma);
166 }
167 }
168
169 return updateLocations;
170}
171
173 P4::ReferenceMap *refMap;
174 P4::TypeMap *typeMap;
175
176 public:
177 std::vector<const IR::MethodCallStatement *> verifyChecksums;
178 std::vector<const IR::MethodCallStatement *> residualChecksums;
181
183 : refMap(refMap), typeMap(typeMap) {
184 setName("CollectParserChecksums");
185 }
186
187 void postorder(const IR::MethodCallStatement *node) override {
188 auto mce = node->methodCall->to<IR::MethodCallExpression>();
189 CHECK_NULL(mce);
190 auto mi = P4::MethodInstance::resolve(node, refMap, typeMap);
191 if (auto ef = mi->to<P4::ExternFunction>()) {
192 if (ef->method->name == "verify_checksum" &&
193 analyzeChecksumCall(node, "verify_checksum"_cs)) {
194 verifyChecksums.push_back(node);
195 } else if (ef->method->name == "update_checksum_with_payload" &&
196 analyzeChecksumCall(node, "update_checksum_with_payload"_cs)) {
197 residualChecksums.push_back(node);
198
199 auto block = findContext<IR::BlockStatement>();
200 CHECK_NULL(block);
201 parserUpdateLocations[node] = getChecksumUpdateLocations(
202 mce, block, "residual_checksum_parser_update_location"_cs);
203 deparserUpdateLocations[node] =
204 getChecksumUpdateLocations(mce, block, "calculated_field_update_location"_cs);
205 }
206 }
207 }
208};
209
211 public:
213 const CollectParserChecksums *collect, const P4ParserGraphs *graph,
214 ProgramStructure *structure)
215 : translate(translate), collect(collect), graph(graph), structure(structure) {}
216
217 private:
218 TranslateParserChecksums *translate;
219 const CollectParserChecksums *collect;
220 const P4ParserGraphs *graph;
221 ProgramStructure *structure;
222
224
226 ingressParserResidualChecksumDecls, egressParserResidualChecksumDecls;
227
228 unsigned residualChecksumCnt = 0;
229
233
234 StateToExtracts stateToExtracts;
235 ExtractToState extractToState;
236
237 struct CollectExtractMembers : public Inspector {
238 CollectExtractMembers(StateToExtracts &stateToExtracts, ExtractToState &extractToState)
239 : stateToExtracts(stateToExtracts), extractToState(extractToState) {}
240
241 StateToExtracts &stateToExtracts;
242 ExtractToState &extractToState;
243
244 void postorder(const IR::MethodCallStatement *statement) override {
245 auto *call = statement->methodCall;
246 CHECK_NULL(call);
247 auto *method = call->method->to<IR::Member>();
248 auto *state = findContext<IR::ParserState>();
249
250 if (method && method->member == "extract") {
251 for (auto m : *(call->arguments)) {
252 stateToExtracts[state].push_back(m->expression);
253 extractToState[m->expression] = state;
254 }
255 }
256 }
257 };
258
259 profile_t init_apply(const IR::Node *root) override {
260 CollectExtractMembers cem(stateToExtracts, extractToState);
261 root->apply(cem);
262 return Inspector::init_apply(root);
263 }
264
265 // FIXME -- yet another 'deep' comparison for expressions
266 static bool equiv(const IR::Expression *a, const IR::Expression *b) {
267 if (a == b) return true;
268 if (typeid(*a) != typeid(*b)) return false;
269 if (auto ma = a->to<IR::Member>()) {
270 auto mb = b->to<IR::Member>();
271 return ma->member == mb->member && equiv(ma->expr, mb->expr);
272 }
273 if (auto pa = a->to<IR::PathExpression>()) {
274 auto pb = b->to<IR::PathExpression>();
275 return pa->path->name == pb->path->name;
276 }
277 return false;
278 }
279
280 static bool belongsTo(const IR::Member *a, const IR::Member *b) {
281 if (!a || !b) return false;
282
283 // case 1: a is field, b is field
284 if (equiv(a, b)) return true;
285
286 // case 2: a is field, b is header
287 if (a->type->is<IR::Type::Bits>()) {
288 if (equiv(a->expr, b)) return true;
289 }
290
291 return false;
292 }
293
294 // FIXME: Replacing the source info should not be necessary, but it currently required
295 // to work around an issue with ResolutionContext. ResolutionContext looks at the location
296 // of a name and a potential declaration to see if the declaration applies. The issue
297 // is that the source address of the substituted checksum add calls will use the source
298 // location of the checksum parser declaration.
299 const IR::Path *replaceSrcInfo(const IR::Path *path, const Util::SourceInfo &srcInfo) {
300 if (!srcInfo.isValid()) return path;
301
302 auto *newPath = path->clone();
303 newPath->srcInfo = srcInfo;
304 newPath->name = IR::ID(srcInfo, newPath->name.name, newPath->name.originalName);
305
306 return newPath;
307 }
308
309 const IR::PathExpression *replaceSrcInfo(const IR::PathExpression *pe,
310 const Util::SourceInfo &srcInfo) {
311 if (!srcInfo.isValid()) return pe;
312
313 auto *newPE = pe->clone();
314 newPE->srcInfo = srcInfo;
315 newPE->path = replaceSrcInfo(newPE->path, srcInfo);
316
317 return newPE;
318 }
319
320 const IR::Member *replaceSrcInfo(const IR::Member *member, const Util::SourceInfo &srcInfo) {
321 if (!srcInfo.isValid()) return member;
322
323 auto *newMember = member->clone();
324 newMember->srcInfo = srcInfo;
325
326 if (const auto *exprMember = newMember->expr->to<IR::Member>()) {
327 newMember->expr = replaceSrcInfo(exprMember, srcInfo);
328 } else if (const auto *exprPathExpression = newMember->expr->to<IR::PathExpression>()) {
329 newMember->expr = replaceSrcInfo(exprPathExpression, srcInfo);
330 }
331
332 return newMember;
333 }
334
335 void implementVerifyChecksum(const IR::MethodCallStatement *vc, const IR::ParserState *state) {
336 cstring stateName = state->name;
337 auto &extracts = stateToExtracts[state];
338
339 auto mc = vc->methodCall->to<IR::MethodCallExpression>();
340
341 auto fieldlist = mc->arguments->at(1)->expression;
342 auto destfield = mc->arguments->at(2)->expression;
343
344 // check if any of the fields or dest belong to extracts
345 // TODO verify on ingress only?
346
347 const IR::Declaration *decl = nullptr;
348
349 if (verifyDeclarationMap.count(vc)) {
350 decl = verifyDeclarationMap.at(vc);
351 } else {
352 decl = createChecksumDeclaration(structure, vc);
353 verifyDeclarationMap[vc] = decl;
354 structure->ingressParserDeclarations.push_back(decl);
355 }
356
357 if (fieldlist->is<IR::ListExpression>()) {
358 for (auto f : fieldlist->to<IR::ListExpression>()->components) {
359 for (auto extract : extracts) {
360 if (belongsTo(f->to<IR::Member>(), extract->to<IR::Member>())) {
361 if (const auto *member = f->to<IR::Member>()) {
362 f = replaceSrcInfo(member, state->srcInfo);
363 }
364 auto addCall = new IR::MethodCallStatement(
365 mc->srcInfo,
366 new IR::MethodCallExpression(
367 mc->srcInfo,
368 new IR::Member(new IR::PathExpression(decl->name), "add"),
369 new IR::Vector<IR::Type>({f->type}),
370 new IR::Vector<IR::Argument>({new IR::Argument(f)})));
371
372 structure->ingressParserStatements[stateName].push_back(addCall);
373 translate->ingressVerifyDeclToStates[decl].insert(state->name);
374 }
375 }
376 }
377 } else if (fieldlist->is<IR::StructExpression>()) {
378 for (auto fld : fieldlist->to<IR::StructExpression>()->components) {
379 auto f = fld->expression;
380 for (auto extract : extracts) {
381 if (belongsTo(f->to<IR::Member>(), extract->to<IR::Member>())) {
382 if (const auto *member = f->to<IR::Member>()) {
383 f = replaceSrcInfo(member, state->srcInfo);
384 }
385 auto addCall = new IR::MethodCallStatement(
386 mc->srcInfo,
387 new IR::MethodCallExpression(
388 mc->srcInfo,
389 new IR::Member(new IR::PathExpression(decl->name), "add"),
390 new IR::Vector<IR::Type>({f->type}),
391 new IR::Vector<IR::Argument>({new IR::Argument(f)})));
392
393 structure->ingressParserStatements[stateName].push_back(addCall);
394 translate->ingressVerifyDeclToStates[decl].insert(state->name);
395 LOG1("B: Adding add call: " << addCall);
396 }
397 }
398 }
399 }
400
401 auto *destfieldAdj = destfield;
402 if (const auto *member = destfield->to<IR::Member>()) {
403 destfieldAdj = replaceSrcInfo(member, state->srcInfo);
404 }
405 for (auto extract : extracts) {
406 if (belongsTo(destfieldAdj->to<IR::Member>(), extract->to<IR::Member>())) {
407 BUG_CHECK(decl, "No fields have been added before verify?");
408
409 auto addCall = new IR::MethodCallStatement(
410 mc->srcInfo,
411 new IR::MethodCallExpression(
412 mc->srcInfo, new IR::Member(new IR::PathExpression(decl->name), "add"),
413 new IR::Vector<IR::Type>({destfieldAdj->type}),
414 new IR::Vector<IR::Argument>({new IR::Argument(destfieldAdj)})));
415
416 structure->ingressParserStatements[stateName].push_back(addCall);
417 translate->ingressVerifyDeclToStates[decl].insert(state->name);
418 }
419 }
420 }
421
422 ordered_set<const IR::Expression *> collectResidualChecksumPayloadFields(
423 const IR::ParserState *state) {
425
426 auto descendants = graph->get_all_descendants(state);
427
428 for (auto d : descendants) {
429 auto &extracts = stateToExtracts[d];
430 for (auto m : extracts) rv.insert(m);
431 }
432
433 return rv;
434 }
435
436 void implementParserResidualChecksum(const IR::MethodCallStatement *rc,
437 const IR::ParserState *state,
438 const std::vector<gress_t> &parserUpdateLocations,
439 const std::vector<gress_t> &deparserUpdateLocations) {
440 cstring stateName = state->name;
441 auto &extracts = stateToExtracts[state];
442
443 auto mc = rc->methodCall->to<IR::MethodCallExpression>();
444
445 auto condition = mc->arguments->at(0)->expression;
446 auto fieldlist = mc->arguments->at(1)->expression;
447 auto destfield = mc->arguments->at(2)->expression;
448 if (parserUpdateLocations.size() == 1 && parserUpdateLocations[0] == INGRESS &&
449 deparserUpdateLocations.size() == 1 && deparserUpdateLocations[0] == EGRESS) {
450 translate->needBridging.insert(destfield);
451 }
452
453 if (!translate->residualChecksums.count(destfield)) {
454 auto *compilerMetadataPath = new IR::PathExpression(COMPILER_META);
455 auto *compilerMetadataDecl = const_cast<IR::Type_Struct *>(
456 structure->type_declarations.at("compiler_generated_metadata_t"_cs)
457 ->to<IR::Type_Struct>());
458 compilerMetadataDecl->annotations = {
459 new IR::Annotation(IR::ID("__compiler_generated"), {})};
460
461 std::stringstream residualFieldName;
462 residualFieldName << "residual_checksum_";
463 residualFieldName << residualChecksumCnt++;
464
465 auto *residualChecksum = new IR::Member(IR::Type::Bits::get(16), compilerMetadataPath,
466 residualFieldName.str().c_str());
467
468 compilerMetadataDecl->fields.push_back(
469 new IR::StructField(residualFieldName.str().c_str(), IR::Type::Bits::get(16)));
470
471 translate->residualChecksums[destfield] = residualChecksum;
472 translate->destToGressToState[destfield][deparserUpdateLocations[0]] = state;
473 }
474
475 for (auto location : parserUpdateLocations) {
476 std::vector<const IR::Declaration *> *parserDeclarations = nullptr;
477 std::vector<const IR::StatOrDecl *> *parserStatements = nullptr;
478
480 *parserResidualChecksumDecls = nullptr;
481
482 if (location == INGRESS) {
483 parserDeclarations = &structure->ingressParserDeclarations;
484 parserStatements = &structure->ingressParserStatements[stateName];
485 parserResidualChecksumDecls = &ingressParserResidualChecksumDecls;
486 } else if (location == EGRESS) {
487 parserDeclarations = &structure->egressParserDeclarations;
488 parserStatements = &structure->egressParserStatements[stateName];
489 parserResidualChecksumDecls = &egressParserResidualChecksumDecls;
490 }
491
492 IR::Declaration_Instance *decl = nullptr;
493 auto it = parserResidualChecksumDecls->find(rc);
494 if (it == parserResidualChecksumDecls->end()) {
495 decl = createChecksumDeclaration(structure, rc);
496 parserDeclarations->push_back(decl);
497 (*parserResidualChecksumDecls)[rc] = decl;
498 } else {
499 decl = parserResidualChecksumDecls->at(rc);
500 }
501 const IR::Expression *constant = nullptr;
502 for (auto extract : extracts) {
503 std::vector<const IR::Expression *> exprList;
504 if (fieldlist->is<IR::ListExpression>()) {
505 for (auto f : fieldlist->to<IR::ListExpression>()->components) {
506 if (f->is<IR::Constant>()) {
507 constant = f;
508 } else if (belongsTo(f->to<IR::Member>(), extract->to<IR::Member>())) {
509 if (constant) {
510 exprList.emplace_back(constant);
511 constant = nullptr;
512 // If immediate next field after the constant is extracted in this
513 // field then the constant belongs to subtract field list of this
514 // state
515 }
516 exprList.emplace_back(f);
517
518 } else {
519 constant = nullptr;
520 }
521 }
522 } else if (fieldlist->is<IR::StructExpression>()) {
523 for (auto fld : fieldlist->to<IR::StructExpression>()->components) {
524 auto f = fld->expression;
525 if (f->is<IR::Constant>()) {
526 constant = f;
527 } else if (belongsTo(f->to<IR::Member>(), extract->to<IR::Member>())) {
528 if (constant) {
529 exprList.emplace_back(constant);
530 constant = nullptr;
531 // If immediate next field after the constant is extracted in this
532 // field then the constant belongs to subtract field list of this
533 // state
534 }
535 exprList.emplace_back(f);
536
537 } else {
538 constant = nullptr;
539 }
540 }
541 }
542 for (auto e : exprList) {
543 auto subtractCall = new IR::MethodCallStatement(
544 mc->srcInfo,
545 new IR::MethodCallExpression(
546 mc->srcInfo,
547 new IR::Member(new IR::PathExpression(decl->name), "subtract"),
548 new IR::Vector<IR::Type>({e->type}),
549 new IR::Vector<IR::Argument>({new IR::Argument(e)})));
550
551 parserStatements->push_back(subtractCall);
552 }
553
554 if (belongsTo(destfield->to<IR::Member>(), extract->to<IR::Member>())) {
555 auto subtractCall = new IR::MethodCallStatement(
556 mc->srcInfo,
557 new IR::MethodCallExpression(
558 mc->srcInfo,
559 new IR::Member(new IR::PathExpression(decl->name), "subtract"),
560 new IR::Vector<IR::Type>({destfield->type}),
561 new IR::Vector<IR::Argument>({new IR::Argument(destfield)})));
562
563 parserStatements->push_back(subtractCall);
564 auto *residualChecksum = translate->residualChecksums.at(destfield);
565
566 auto *deposit = new IR::MethodCallStatement(
567 mc->srcInfo,
568 new IR::MethodCallExpression(
569 mc->srcInfo,
570 new IR::Member(new IR::PathExpression(decl->name),
571 "subtract_all_and_deposit"),
572 new IR::Vector<IR::Type>({residualChecksum->type}),
573 new IR::Vector<IR::Argument>({new IR::Argument(residualChecksum)})));
574
575 translate
576 ->checksumDepositToHeader[location][extract->to<IR::Member>()->member] =
577 deposit;
578 if (auto boolLiteral = condition->to<IR::BoolLiteral>()) {
579 if (!boolLiteral->value) {
580 // Do not add the if-statement if the condition is always true.
581 deposit = nullptr;
582 }
583 }
584
585 if (deposit) {
586 auto payloadFields = collectResidualChecksumPayloadFields(state);
587 translate->residualChecksumPayloadFields[destfield] = payloadFields;
588 }
589 }
590 }
591 }
592 }
593
594 void postorder(const IR::ParserState *state) override {
595 // see if any of the "verify_checksum" or "update_checksum_with_payload" statement
596 // is relavent to this state. If so, convert to TNA function calls.
597 for (auto *vc : collect->verifyChecksums) {
598 implementVerifyChecksum(vc, state);
599 }
600
601 for (auto *rc : collect->residualChecksums) {
602 implementParserResidualChecksum(rc, state, collect->parserUpdateLocations.at(rc),
603 collect->deparserUpdateLocations.at(rc));
604 }
605 }
606};
607
609 public:
610 const V1::TranslateParserChecksums *translate;
611 explicit InsertChecksumDeposit(const V1::TranslateParserChecksums *translate)
612 : translate(translate) {}
613 const IR::Node *preorder(IR::ParserState *state) override {
614 auto parser = findContext<IR::BFN::TnaParser>();
615 if (!translate->checksumDepositToHeader.count(parser->thread)) return state;
616 auto components = new IR::IndexedVector<IR::StatOrDecl>();
617 auto &checksumDeposit = translate->checksumDepositToHeader.at(parser->thread);
618 for (auto component : state->components) {
619 components->push_back(component);
620 auto methodCall = component->to<IR::MethodCallStatement>();
621 if (!methodCall) continue;
622 auto call = methodCall->methodCall->to<IR::MethodCallExpression>();
623 if (!call) continue;
624 if (auto method = call->method->to<IR::Member>()) {
625 if (method->member == "extract") {
626 for (auto arg : *call->arguments) {
627 const IR::Member *member = nullptr;
628 if (auto index = arg->expression->to<IR::ArrayIndex>()) {
629 member = index->left->to<IR::Member>();
630 } else if (arg->expression->is<IR::Member>()) {
631 member = arg->expression->to<IR::Member>();
632 }
633 if (member && checksumDeposit.count(member->member)) {
634 components->push_back(checksumDeposit.at(member->member));
635 }
636 }
637 }
638 }
639 }
640 state->components = *components;
641 return state;
642 }
643};
644
646 public:
647 std::map<cstring, ordered_map<const IR::Declaration *, ordered_set<cstring>>> endStates;
648
649 struct ComputeEndStates : public Inspector {
651
652 explicit ComputeEndStates(InsertChecksumError *self) : self(self) {}
653
654 void printStates(const ordered_set<cstring> &states) {
655 for (auto s : states) std::cout << " " << s << std::endl;
656 }
657
658 ordered_set<cstring> computeChecksumEndStates(const ordered_set<cstring> &calcStates) {
659 auto &parserGraphs = self->translate->parserGraphs;
660
661 if (LOGGING(3)) {
662 std::cout << "calc states are:" << std::endl;
663 printStates(calcStates);
664 }
665
666 ordered_set<cstring> endStates;
667
668 // A calculation state is a verification end state if no other state of the
669 // same calculation is its descendant. Otherwise, include all of the state's
670 // children states that are not a calculation state.
671
672 for (auto a : calcStates) {
673 bool isEndState = true;
674 for (auto b : calcStates) {
675 if (parserGraphs.is_ancestor(a, b)) {
676 isEndState = false;
677 break;
678 }
679 }
680 if (isEndState) {
681 endStates.insert(a);
682 } else {
683 if (parserGraphs.succs.count(a)) {
684 for (auto succ : parserGraphs.succs.at(a)) {
685 if (calcStates.count(succ)) continue;
686
687 for (auto s : calcStates) {
688 if (!parserGraphs.is_ancestor(succ, s)) {
689 endStates.insert(succ);
690 }
691 }
692 }
693 }
694 }
695 }
696
697 BUG_CHECK(!endStates.empty(), "Unable to find verification end state?");
698
699 if (LOGGING(3)) {
700 std::cout << "end states are:" << std::endl;
701 printStates(endStates);
702 }
703
704 return endStates;
705 }
706
707 bool preorder(const IR::BFN::TnaParser *parser) override {
708 // TODO verify on ingress only
709 if (parser->thread != INGRESS) return false;
710
711 // compute checksum end states
712 for (auto kv : self->translate->ingressVerifyDeclToStates)
713 self->endStates[parser->name][kv.first] = computeChecksumEndStates(kv.second);
714
715 return false;
716 }
717 };
718
719 // TODO we probably don't want to insert statement into the "accept" state
720 // since this is a special state. Add a dummy state before "accept" if it is
721 // a checksum verification end state.
723 const IR::Node *preorder(IR::BFN::TnaParser *parser) override {
724 for (auto &kv : self->endStates[parser->name]) {
725 if (kv.second.count("accept"_cs)) {
726 if (!dummy) {
727 dummy = createGeneratedParserState("before_accept"_cs, {}, "accept"_cs);
728 parser->states.push_back(dummy);
729 }
730 kv.second.erase("accept"_cs);
731 kv.second.insert("__before_accept"_cs);
732 LOG3("add dummy state before \"accept\"");
733 }
734 }
735
736 return parser;
737 }
738
739 const IR::Node *postorder(IR::PathExpression *path) override {
740 auto parser = findContext<IR::BFN::TnaParser>();
741 auto state = findContext<IR::ParserState>();
742 auto select = findContext<IR::SelectCase>();
743
744 if (parser && state && select) {
745 bool isCalcState = false;
746
747 for (auto kv : self->translate->ingressVerifyDeclToStates) {
748 for (auto s : kv.second) {
749 if (s == state->name) {
750 isCalcState = true;
751 break;
752 }
753 }
754 }
755
756 if (!isCalcState) return path;
757
758 for (auto &kv : self->endStates[parser->name]) {
759 if (path->path->name == "accept" && kv.second.count("__before_accept"_cs)) {
760 path = new IR::PathExpression("__before_accept");
761 LOG3("modify transition to \"before_accept\"");
762 }
763 }
764 }
765
766 return path;
767 }
768
769 const IR::ParserState *dummy = nullptr;
771
772 explicit InsertBeforeAccept(InsertChecksumError *self) : self(self) {}
773 };
774
775 struct InsertEndStates : public Transform {
776 const IR::Node *preorder(IR::ParserState *state) override {
777 auto parser = findContext<IR::BFN::TnaParser>();
778
779 if (state->name == "reject") return state;
780
781 for (auto &kv : self->endStates[parser->name]) {
782 auto *decl = kv.first;
783 for (auto endState : kv.second) {
784 if (endState == state->name) {
785 auto *checksumError = createChecksumError(decl, parser->thread);
786 state->components.push_back(checksumError);
787
788 LOG3("verify " << toString(parser->thread) << " " << decl->name.name
789 << " in state " << endState);
790 }
791 }
792 }
793
794 return state;
795 }
796
798
799 explicit InsertEndStates(InsertChecksumError *self) : self(self) {}
800 };
801
802 explicit InsertChecksumError(const V1::TranslateParserChecksums *translate)
803 : translate(translate) {
804 addPasses({
805 new ComputeEndStates(this),
806 new InsertBeforeAccept(this),
807 new InsertEndStates(this),
808 });
809 }
810
811 const V1::TranslateParserChecksums *translate;
812};
813
814} // namespace BFN::V1
815
816#endif /* BACKENDS_TOFINO_BF_P4C_ARCH_FROMV1_0_CHECKSUM_H_ */
Definition checksum.h:172
Definition checksum.h:608
Definition checksum.h:645
Definition checksum.h:210
Definition checksum.h:42
Definition methodInstance.h:194
Definition node.h:52
Definition node.h:94
Definition vector.h:59
Definition visitor.h:400
static MethodInstance * resolve(const IR::MethodCallExpression *mce, const DeclarationLookup *refMap, TypeMap *typeMap, bool useExpressionType=false, const Visitor::Context *ctxt=nullptr, bool incomplete=false)
Definition methodInstance.cpp:27
Definition ir/pass_manager.h:40
Definition backends/common/programStructure.h:32
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition visitor.h:424
Definition typeMap.h:41
Definition source_file.h:131
Definition visitor.h:78
Definition cstring.h:85
Definition ordered_set.h:32
Definition assoc.h:300
Definition assoc.h:355
Extends p4c's parser graph with various algorithms.
Definition parser_graph.h:32
const IR::ParserState * createGeneratedParserState(cstring name, IR::IndexedVector< IR::StatOrDecl > &&statements, const IR::Expression *selectExpression)
Definition intrinsic_metadata.cpp:82
void warning(const char *format, Args &&...args)
Report a warning with the given message.
Definition lib/error.h:115
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:51
Definition v1_program_structure.h:36
Definition checksum.h:30
Definition id.h:28