113 IR::ConstructorCallExpression *createHashExtern(
const IR::Expression *,
const IR::Type *);
116 const IR::P4Table *convertTable(
const IR::V1Table *table,
cstring newName,
118 std::map<cstring, cstring> &)
override;
121 const IR::Declaration_Instance *convertActionProfile(
const IR::ActionProfile *action_profile,
125 const IR::Declaration_Instance *convertDirectCounter(
const IR::Counter *c,
127 const IR::Declaration_Instance *convertDirectMeter(
const IR::Meter *c,
129 const IR::Statement *convertMeterCall(
const IR::Meter *m)
override;
130 const IR::Statement *convertCounterCall(
cstring c)
override;
131 const IR::Expression *counterType(
const IR::CounterOrMeter *cm)
override;
132 const IR::Declaration_Instance *convert(
const IR::Register *reg,
cstring newName,
133 const IR::Type *regElementType)
override;
137 const IR::P4Control *convertControl(
const IR::V1Control *control,
cstring newName)
override;
138 const IR::ParserState *convertParser(
const IR::V1Parser *control,
140 const IR::Declaration_Instance *
convert(
const IR::CounterOrMeter *cm,
cstring newName)
override;
141 const IR::Type_Control *controlType(
IR::ID name)
override;
143 void addIngressParams(IR::ParameterList *param);
144 void addEgressParams(IR::ParameterList *param);
145 void setupControlArguments();
148 const IR::Expression *stdMetaReference(
const IR::Parameter *param);
149 void checkHeaderType(
const IR::Type_StructLike *hdr,
bool toStruct)
override;
152 std::vector<cstring> findActionInTables(
const IR::V1Control *control);
157 const IR::ParserState *createEmptyMirrorState(
cstring nextState);
158 const IR::ParserState *createMirrorState(gress_t,
unsigned,
const IR::Expression *,
cstring,
160 const IR::ParserState *createResubmitState(gress_t,
unsigned,
const IR::Expression *,
cstring,
162 const IR::SelectCase *createSelectCase(gress_t gress,
unsigned digestId,
163 const IR::ParserState *newState);
169 void removeP14IntrinsicMetadataTypes();
171 void createIntrinsicMetadataTypes();
172 void loadModel()
override;
175 void collectControlGressMapping();
176 void collectBridgedFieldsInControls();
177 void collectBridgedFieldsInParsers();
178 void collectBridgedFields();
179 void collectDigestFields();
181 void createCompilerGeneratedTypes();
183 void checkForReservedTnaTypes();
184 void collectHeaderReference(
const IR::V1Control *control);
185 void parseUpdateLocationAnnotation(std::set<gress_t> &,
const IR::Annotation *,
cstring);
186 bool useResidualChecksum();
187 bool useBridgeMetadata();
191 const IR::ListExpression *);
192 void createDigestHeaderTypeAndInstance(
unsigned index,
const IR::Expression *expr,
cstring name,
194 const IR::StatOrDecl *createDigestEmit(
195 cstring,
unsigned, std::pair<std::optional<cstring>,
const IR::Expression *>,
cstring,
197 const IR::StatOrDecl *createBridgeEmit();
198 using ChecksumUpdateInfo = std::pair<IR::StatOrDecl *, ChecksumInfo>;
200 std::vector<ChecksumUpdateInfo> &);
201 void createChecksumVerifyStatements(gress_t gress);
202 void createIngressParser();
203 void createEgressParser();
204 void createParser()
override;
205 void createIngressDeparser();
206 void createEgressDeparser();
207 void createDeparser()
override;
208 void createPipeline();
209 void createMain()
override;
215 gress_t currentGress;
216 std::map<cstring, bitvec> controlParamUse;
217 std::map<cstring, gress_t> mapControlToGress;
218 gress_t getGress(
cstring name);
219 std::map<unsigned long, unsigned> cloneIndexHashes[2];
220 std::map<unsigned long, unsigned> resubmitIndexHashes;
221 std::map<unsigned long, unsigned> digestIndexHashes;
222 std::map<unsigned long, unsigned> recirculateIndexHashes;
223 std::map<cstring, std::vector<const IR::Parameter *>> controlParams;
227 std::map<cstring, std::map<unsigned, std::pair<std::optional<cstring>,
const IR::Expression *>>>
230 std::map<cstring, BFN::LinearPath> bridgedFieldInfo;
231 std::map<cstring, const IR::Type_StructLike *> tna_intr_md_types;
235 std::vector<ChecksumInfo> residualChecksums;
236 std::vector<ChecksumInfo> verifyChecksums;
242 std::map<gress_t, std::map<cstring, IR::Statement *>> checksumDepositToHeader;
246 template <
typename Func>
247 void forAllResidualChecksums(std::vector<const IR::CalculatedField *> calculated_fields,
249 for (
auto cf : calculated_fields) {
250 for (
auto uov : cf->specs) {
251 if (!uov.update)
continue;
252 auto flc = field_list_calculations.get(uov.name.name);
253 auto fl = getFieldLists(flc);
254 if (fl ==
nullptr)
continue;
262 template <
typename Func>
263 void forAllChecksums(std::vector<const IR::CalculatedField *> calculated_fields,
265 for (
auto cf : calculated_fields) {
266 for (
auto uov : cf->specs) {
267 if (!uov.update)
continue;
268 auto flc = field_list_calculations.get(uov.name.name);
269 auto fl = getFieldLists(flc);
270 if (fl ==
nullptr)
continue;
271 function(cf, flc, uov, fl);
280 std::map<cstring, const IR::Expression *> ingressMetadataNameMap;
281 std::map<cstring, const IR::Expression *> egressMetadataNameMap;
282 std::map<cstring, int> widthMap;
284 void cvt(gress_t gress,
cstring src,
int src_width,
const IR::Member *dst) {
286 (gress == gress_t::INGRESS) ? ingressMetadataNameMap : egressMetadataNameMap;
287 if (src_width > dst->type->width_bits()) {
288 auto casted =
new IR::Cast(IR::Type_Bits::get(src_width), dst);
289 nameMap.emplace(src, casted);
291 nameMap.emplace(src, dst);
293 widthMap.emplace(src, src_width);
298 new IR::Member(
new IR::Member(
new IR::PathExpression(
IR::ID(meta)), strct), field);
299 mem->type = IR::Type::Bits::get(width);
303 const IR::Member *mkMember(
cstring strct,
cstring field,
int width) {
304 auto mem =
new IR::Member(
new IR::PathExpression(
IR::ID(strct)), field);
305 mem->type = IR::Type::Bits::get(width);
311 int portWidth = Device::portBitWidth();
313 cvt(INGRESS,
"ig_intr_md_from_parser_aux.ingress_parser_err"_cs, 16,
314 mkMember(
"ig_intr_md_from_parser_aux"_cs,
"parser_err"_cs, 16));
315 cvt(INGRESS,
"meta.standard_metadata.egress_spec"_cs, 9,
316 mkMember(
"ig_intr_md_for_tm"_cs,
"ucast_egress_port"_cs, portWidth));
317 cvt(INGRESS,
"meta.standard_metadata.ingress_port"_cs, 9,
318 mkMember(
"ig_intr_md"_cs,
"ingress_port"_cs, portWidth));
319 cvt(INGRESS,
"ig_intr_md_for_tm.drop_ctl"_cs, 1,
320 mkMember(
"ig_intr_md_for_dprsr"_cs,
"drop_ctl"_cs, 1));
321 cvt(INGRESS,
"ig_intr_md_from_parser_aux.ingress_global_tstamp"_cs, 48,
322 mkMember(
"ig_intr_md_from_parser_aux"_cs,
"global_tstamp"_cs, 48));
323 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_hash"_cs, 13,
324 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_hash"_cs, 13));
325 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_io_select"_cs, 1,
326 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_io_select"_cs, 1));
327 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_multicast_ctrl"_cs, 1,
328 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_multicast_ctrl"_cs, 1));
329 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_ingress_cos"_cs, 3,
330 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_ingress_cos"_cs, 3));
331 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_deflect_on_drop"_cs, 1,
332 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_deflect_on_drop"_cs, 1));
333 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_copy_to_cpu_ctrl"_cs, 1,
334 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_copy_to_cpu_ctrl"_cs, 1));
335 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_copy_to_cpu_ctrl"_cs, 1,
336 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_copy_to_cpu_ctrl"_cs, 1));
337 cvt(INGRESS,
"ig_intr_md_for_mb.mirror_egress_port"_cs, portWidth,
338 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_egress_port"_cs, portWidth));
339 cvt(INGRESS,
"standard_metadata.ingress_port"_cs, 9,
340 mkMember(
"ig_intr_md"_cs,
"ingress_port"_cs, portWidth));
343 cvt(EGRESS,
"eg_intr_md_from_parser_aux.egress_parser_err"_cs, 16,
344 mkMember(
"eg_intr_md_from_parser_aux"_cs,
"parser_err"_cs, 16));
345 cvt(EGRESS,
"eg_intr_md_from_parser_aux.clone_src"_cs, 4,
346 mkMember(
"meta"_cs, COMPILER_META,
"clone_src"_cs, 4));
347 cvt(EGRESS,
"eg_intr_md_from_parser_aux.egress_global_tstamp"_cs, 48,
348 mkMember(
"eg_intr_md_from_parser_aux"_cs,
"global_tstamp"_cs, 48));
349 cvt(EGRESS,
"eg_intr_md_for_oport.drop_ctl"_cs, 3,
350 mkMember(
"eg_intr_md_for_dprsr"_cs,
"drop_ctl"_cs, 3));
351 cvt(EGRESS,
"eg_intr_md_from_parser_aux.egress_global_ver"_cs, 32,
352 mkMember(
"eg_intr_md_from_parser_aux"_cs,
"global_ver"_cs, 32));
353 cvt(EGRESS,
"eg_intr_md.deq_timedelta"_cs, 32,
354 mkMember(
"eg_intr_md"_cs,
"deq_timedelta"_cs, 18));
355 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_hash"_cs, 13,
356 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_hash"_cs, 13));
357 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_io_select"_cs, 1,
358 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_io_select"_cs, 1));
359 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_multicast_ctrl"_cs, 1,
360 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_multicast_ctrl"_cs, 1));
361 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_ingress_cos"_cs, 3,
362 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_ingress_cos"_cs, 3));
363 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_deflect_on_drop"_cs, 1,
364 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_deflect_on_drop"_cs, 1));
365 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_copy_to_cpu_ctrl"_cs, 1,
366 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_copy_to_cpu_ctrl"_cs, 1));
367 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_copy_to_cpu_ctrl"_cs, 1,
368 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_copy_to_cpu_ctrl"_cs, 1));
369 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_egress_port"_cs, portWidth,
370 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_egress_port"_cs, portWidth));
371 cvt(EGRESS,
"meta.standard_metadata.ingress_port"_cs, 9,
372 mkMember(
"meta"_cs,
"ig_intr_md"_cs,
"ingress_port"_cs, portWidth));
373 cvt(EGRESS,
"standard_metadata.ingress_port"_cs, 9,
374 mkMember(
"meta"_cs,
"ig_intr_md"_cs,
"ingress_port"_cs, portWidth));
378 const IR::Node *preorder(IR::Member *member)
override {
380 if (!member->type->is<IR::Type_Bits>())
return member;
383 if (
auto *parser = findOrigCtxt<IR::P4Parser>()) {
384 thread = (parser->name ==
"IngressParserImpl") ? INGRESS : EGRESS;
385 }
else if (
auto *control = findOrigCtxt<IR::P4Control>()) {
386 if (structure->mapControlToGress.count(control->name)) {
387 thread = structure->mapControlToGress.at(control->name);
388 }
else if (control->name ==
"EgressDeparserImpl") {
390 }
else if (control->name ==
"IngressDeparserImpl") {
400 auto &nameMap = (thread == INGRESS) ? ingressMetadataNameMap : egressMetadataNameMap;
403 member->apply(*linearizer);
404 if (!linearizer->linearPath)
return member;
405 auto path = *linearizer->linearPath;
406 auto fn = path.to_cstring(
"."_cs,
false);
407 if (nameMap.count(fn)) {
408 LOG3(
"Translating " << member <<
" to " << nameMap.at(fn));
409 return nameMap.at(fn);
550 bool isNegative =
false;
551 bool needsCast =
false;
557 void cannotFit(
const IR::AssignmentStatement *stmt,
const char *what) {
558 error(
"Parser counter %1% amount cannot fit into 8-bit. %2%", what, stmt);
561 bool isParserCounter(
const IR::Member *member) {
563 member->apply(*linearizer);
564 if (!linearizer->linearPath)
return false;
565 auto path = linearizer->linearPath->to_cstring();
566 return (path ==
"ig_prsr_ctrl.parser_counter");
569 std::pair<unsigned, unsigned> getAlignLoHi(
const IR::Member *member) {
570 auto header = member->expr->type->to<IR::Type_Header>();
576 for (
auto field : boost::adaptors::reverse(header->fields)) {
577 auto size = field->type->width_bits();
579 if (field->name == member->member) {
582 "Parser counter load field is of width %1% bits"
583 " which is greater than what HW supports (8 bits): %2%",
587 return {bits % 8, (bits + size - 1) % 8};
593 BUG(
"%1% not found in header?", member->member);
602 bool isZero(
const IR::Expression *expr)
const {
603 auto cst = expr->to<IR::Constant>();
604 if (cst ==
nullptr)
return false;
605 return cst->value == 0;
608 bool isOne(
const IR::Expression *expr)
const {
609 auto cst = expr->to<IR::Constant>();
610 if (cst ==
nullptr)
return false;
611 return cst->value == 1;
614 int isPowerOf2(
const IR::Expression *expr)
const {
615 auto cst = expr->to<IR::Constant>();
616 if (cst ==
nullptr)
return -1;
617 big_int value = cst->value;
618 if (value <= 0)
return -1;
619 auto bitcnt = bitcount(value);
620 if (bitcnt != 1)
return -1;
621 auto log = Util::scan1(value, 0);
626 const IR::Node *postorder(IR::Sub *expr) {
627 if (isZero(expr->right))
return expr->left;
628 if (isZero(expr->left))
return new IR::Neg(expr->srcInfo, expr->right);
630 if (expr->right->is<IR::Constant>()) {
631 auto cst = expr->right->to<IR::Constant>();
632 auto neg =
new IR::Constant(cst->srcInfo, cst->type, -cst->value, cst->base,
true);
633 auto result =
new IR::Add(expr->srcInfo, expr->left, neg);
639 const IR::Node *postorder(IR::Mul *expr) {
640 if (isZero(expr->left))
return expr->left;
641 if (isZero(expr->right))
return expr->right;
642 if (isOne(expr->left))
return expr->right;
643 if (isOne(expr->right))
return expr->left;
644 auto exp = isPowerOf2(expr->left);
646 auto amt =
new IR::Constant(exp);
647 auto sh =
new IR::Shl(expr->srcInfo, expr->right, amt);
650 exp = isPowerOf2(expr->right);
652 auto amt =
new IR::Constant(exp);
653 auto sh =
new IR::Shl(expr->srcInfo, expr->left, amt);
660 const IR::Node *preorder(IR::AssignmentStatement *assign) {
662 auto stmt = getOriginal<IR::AssignmentStatement>();
663 auto parserCounter =
new IR::PathExpression(
"ig_prsr_ctrl_parser_counter"_cs);
664 auto right = stmt->right;
665 auto left = stmt->left;
668 while (
auto slice = left->to<IR::Slice>()) left = slice->e0;
669 while (
auto cast = left->to<IR::Cast>()) left = cast->expr;
671 left->apply(*linearizer);
672 auto path = *linearizer->linearPath;
673 if (path.to_cstring() !=
"ig_prsr_ctrl.parser_counter")
return assign;
676 if (
auto cast = right->to<IR::Cast>()) {
677 if (cast->destType->is<IR::Type_Bits>()) {
685 IR::MethodCallStatement *methodCall =
nullptr;
687 if (right->to<IR::Constant>() || right->to<IR::Member>()) {
689 methodCall =
new IR::MethodCallStatement(
690 stmt->srcInfo,
new IR::MethodCallExpression(
691 stmt->srcInfo,
new IR::Member(parserCounter,
"set"),
694 }
else if (
auto add = right->to<IR::Add>()) {
695 auto member = add->left->to<IR::Member>();
697 auto counterWidth = IR::Type::Bits::get(8);
698 auto maskWidth = IR::Type::Bits::get(Device::currentDevice() == Device::TOFINO ? 3 : 8);
700 auto max =
new IR::Constant(counterWidth, 255);
703 if (member && isParserCounter(member)) {
704 methodCall =
new IR::MethodCallStatement(stmt->srcInfo,
705 new IR::Member(parserCounter,
"increment"),
706 {new IR::Argument(add->right)});
708 if (
auto *amt = add->right->to<IR::Constant>()) {
711 auto shr =
new IR::Constant(counterWidth, 0);
712 auto mask =
new IR::Constant(
713 maskWidth, Device::currentDevice() == Device::TOFINO ? 7 : 255);
714 auto add =
new IR::Constant(counterWidth, amt->asUnsigned());
716 methodCall =
new IR::MethodCallStatement(
717 stmt->srcInfo,
new IR::MethodCallExpression(
718 stmt->srcInfo,
new IR::Member(parserCounter,
"set"),
721 {new IR::Argument(member), new IR::Argument(max),
722 new IR::Argument(shr), new IR::Argument(mask),
723 new IR::Argument(add)})));
724 }
else if (
auto *shl = add->left->to<IR::Shl>()) {
725 if (
auto *rot = shl->right->to<IR::Constant>()) {
726 auto left = shl->left;
728 if (
auto cast = left->to<IR::Cast>()) {
729 if (cast->destType->is<IR::Type_Bits>()) {
734 if (
auto *field = left->to<IR::Member>()) {
735 if (!rot->fitsUint() || rot->asUnsigned() >> 8)
736 cannotFit(stmt,
"multiply");
738 if (!amt->fitsUint() || amt->asUnsigned() >> 8)
739 cannotFit(stmt,
"immediate");
741 unsigned lo = 0, hi = 7;
742 std::tie(lo, hi) = getAlignLoHi(field);
745 new IR::Constant(counterWidth, 8 - rot->asUnsigned() - lo);
747 unsigned rot_hi = std::min(hi + rot->asUnsigned(), 7u);
748 auto mask =
new IR::Constant(
749 maskWidth, Device::currentDevice() == Device::TOFINO
751 : (1 << (rot_hi + 1)) - 1);
752 auto add =
new IR::Constant(counterWidth, amt->asUnsigned());
754 methodCall =
new IR::MethodCallStatement(
756 new IR::MethodCallExpression(
757 stmt->srcInfo,
new IR::Member(parserCounter,
"set"),
760 {new IR::Argument(field), new IR::Argument(max),
761 new IR::Argument(shr), new IR::Argument(mask),
762 new IR::Argument(add)})));
769 if (!methodCall)
error(
"Unsupported syntax for parser counter: %1%", stmt);
773 const IR::Node *preorder(IR::SelectExpression *node) {
774 bool isPrsrCtr =
false;
775 for (
unsigned i = 0; i < node->select->components.size(); i++) {
776 auto select = node->select->components[i];
777 if (
auto member = select->to<IR::Member>()) {
778 if (isParserCounter(member)) {
779 if (counterIdx >= 0)
error(
"Multiple selects on parser counter in %1%", node);
785 if (!isPrsrCtr) prune();
789 const IR::Node *postorder(IR::SelectExpression *node) {
795 bool isNegative =
false;
796 bool needsCast =
false;
798 const IR::Expression *convert(
const IR::Constant *c,
bool toBool =
true,
800 auto val = c->asUnsigned();
806 "Parser counter only supports test "
807 "of value being zero or negative.");
811 return new IR::BoolLiteral(~val);
813 return new IR::Constant(IR::Type::Bits::get(1), ~val & 1);
816 const IR::Node *preorder(IR::Mask *mask)
override {
818 mask->left = convert(mask->left->to<IR::Constant>(),
false);
819 mask->right = convert(mask->right->to<IR::Constant>(),
false,
false);
824 const IR::Node *preorder(IR::Constant *c)
override {
return convert(c); }
827 const IR::Node *preorder(IR::SelectCase *node) {
830 if (
auto list = node->keyset->to<IR::ListExpression>()) {
831 auto newList = list->clone();
832 for (
unsigned i = 0; i < newList->components.size(); i++) {
833 if (
int(i) == counterIdx) {
834 newList->components[i] = newList->components[i]->apply(rewrite);
838 node->keyset = newList;
840 node->keyset = node->keyset->apply(rewrite);
842 isNegative |= rewrite.isNegative;
843 needsCast |= rewrite.needsCast;
940 std::map<cstring, std::set<cstring>> need_checksum;
941 std::map<cstring, ordered_set<const IR::Member *>> residualChecksumPayloadFields;
944 template <
typename Func>
945 void forAllExtracts(
const IR::ParserState *state, Func function) {
947 for (
auto expr : state->components) {
948 if (!expr->is<IR::MethodCallStatement>())
continue;
949 auto mce = expr->to<IR::MethodCallStatement>()->methodCall;
952 if (inst ==
nullptr)
continue;
954 if (em->actualExternType->name ==
"packet_in" && em->method->name ==
"extract") {
955 auto extracted = inst->substitution.lookupByName(
"hdr"_cs)->apply(cloner);
956 if (extracted ==
nullptr ||
957 !extracted->to<IR::Argument>()->expression->is<IR::Member>())
959 function(extracted->to<IR::Argument>()->expression->to<IR::Member>());
965 static bool equiv(
const IR::Expression *a,
const IR::Expression *b) {
966 if (a == b)
return true;
967 if (
typeid(*a) !=
typeid(*b))
return false;
968 if (
auto ma = a->to<IR::Member>()) {
969 auto mb = b->to<IR::Member>();
970 return ma->member == mb->member && equiv(ma->expr, mb->expr);
972 if (
auto pa = a->to<IR::PathExpression>()) {
973 auto pb = b->to<IR::PathExpression>();
974 return pa->path->name == pb->path->name;
979 static bool belongsTo(
const IR::Member *a,
const IR::Member *b) {
980 if (!a || !b)
return false;
983 if (equiv(a, b))
return true;
986 if (a->type->is<IR::Type::Bits>()) {
987 if (equiv(a->expr, b))
return true;
995 : refMap(refMap), typeMap(typeMap), structure(structure), graph(graph) {}
999 auto orig = getOriginal<IR::ParserState>();
1000 BUG_CHECK(orig !=
nullptr,
"function must be invoked within ParserState visitor");
1002 auto descendants = graph->get_all_descendants(orig);
1003 for (
auto d : descendants) {
1004 forAllExtracts(d, [&](
const IR::Member *member) { rv.insert(member); });
1012 std::vector<ChecksumInfo> &checksum_fields,
1013 const IR::Member *member,
1016 if (checksum_fields.empty())
return;
1018 const IR::Expression *constant =
nullptr;
1019 for (
auto csum : checksum_fields) {
1020 if (!csum.parserUpdateLocations.count(gress))
continue;
1021 std::vector<const IR::Expression *> exprList;
1022 auto path = BFN::PathLinearizer::convert(csum.destField);
1023 if (!checksum.count(path))
1024 checksum.emplace(path, structure->makeUniqueName(
"checksum"_cs));
1025 auto fieldList = csum.fieldList;
1026 if (!fieldList->is<IR::ListExpression>())
continue;
1027 for (
auto f : fieldList->to<IR::ListExpression>()->components) {
1028 if (f->is<IR::Constant>()) {
1030 }
else if (belongsTo(f->to<IR::Member>(), member)) {
1032 exprList.emplace_back(constant);
1037 exprList.emplace_back(f->apply(cloner));
1043 for (
auto e : exprList) {
1044 auto mce =
new IR::MethodCallExpression(
1045 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"subtract"),
1048 auto subtractCall =
new IR::MethodCallStatement(mce);
1049 statements->push_back(subtractCall);
1052 if (belongsTo(csum.destField->to<IR::Member>(), member)) {
1053 auto destField = csum.destField->apply(cloner);
1054 auto mce =
new IR::MethodCallExpression(
1055 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"subtract"),
1058 auto subtractCall =
new IR::MethodCallStatement(mce);
1059 statements->push_back(subtractCall);
1061 if (csum.with_payload) {
1062 BUG_CHECK(csum.residulChecksumName != std::nullopt,
1063 "residual checksum field name cannot be empty");
1064 auto *rmember =
new IR::Member(
1065 IR::Type::Bits::get(16),
1066 new IR::Member(
new IR::PathExpression(
"meta"),
IR::ID(
"bridged_header")),
1067 IR::ID(*csum.residulChecksumName));
1068 auto *mce =
new IR::MethodCallExpression(
1069 new IR::Member(
new IR::PathExpression(checksum.at(path)),
1070 "subtract_all_and_deposit"),
1073 auto *deposit =
new IR::MethodCallStatement(mce);
1074 std::cout << member->member << std::endl;
1075 structure->checksumDepositToHeader[gress][member->member] = deposit;
1084 std::vector<ChecksumInfo> &checksum_fields,
1085 const IR::Member *member,
1089 for (
auto csum : checksum_fields) {
1090 if (!csum.parserUpdateLocations.count(gress))
continue;
1091 auto path = BFN::PathLinearizer::convert(csum.destField);
1092 if (!checksum.count(path))
1093 checksum.emplace(path, structure->makeUniqueName(
"checksum"_cs));
1094 auto csumInst = checksum.at(path);
1095 auto fieldList = csum.fieldList;
1096 if (!fieldList->is<IR::ListExpression>())
continue;
1097 for (
auto f : fieldList->to<IR::ListExpression>()->components) {
1098 if (belongsTo(f->to<IR::Member>(), member)) {
1099 auto mce =
new IR::MethodCallExpression(
1100 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"add"),
1104 auto addCall =
new IR::MethodCallStatement(mce);
1105 statements->push_back(addCall);
1106 structure->ingressVerifyChecksumToStates[csumInst].insert(state);
1110 auto destField = csum.destField->apply(cloner);
1111 if (belongsTo(destField->to<IR::Member>(), member)) {
1112 auto mce =
new IR::MethodCallExpression(
1113 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"add"),
1116 auto addCall =
new IR::MethodCallStatement(mce);
1117 statements->push_back(addCall);
1118 structure->ingressVerifyChecksumToStates[csumInst].insert(state);
1123 void postorder(IR::ParserState *state)
override {
1128 auto parser = findContext<IR::P4Parser>();
1129 auto gress = parser->name ==
"IngressParserImpl" ? INGRESS : EGRESS;
1130 forAllExtracts(state, [&](
const IR::Member *member) {
1131 createAddCallsForVerifyChecksum(addCalls, structure->verifyChecksums, member, checksum,
1132 gress, state->name);
1134 forAllExtracts(state, [&](
const IR::Member *member) {
1135 auto rc = structure->residualChecksums;
1136 createSubtractCallsForResidualChecksum(subtractCalls, rc, member, checksum, gress);
1138 if (subtractCalls->size() != 0) {
1139 state->components.append(*subtractCalls);
1141 if (addCalls->size() != 0) state->components.append(*addCalls);
1143 if (subtractCalls->size() != 0 || addCalls->size() != 0) {
1144 auto parser = findContext<IR::P4Parser>();
1145 for (
auto it = checksum.begin(); it != checksum.end(); it++)
1146 need_checksum[parser->name].insert(it->second);
1150 bool preorder(IR::P4Parser *)
override {
1155 void postorder(IR::P4Parser *parser)
override {
1156 if (need_checksum.count(parser->name)) {
1157 auto csums = need_checksum.at(parser->name);
1158 for (
auto csum : csums) {
1159 auto inst =
new IR::Type_Name(
"Checksum");
1161 auto decl =
new IR::Declaration_Instance(csum, inst, args);
1162 parser->parserLocals.push_back(decl);
1167 void postorder(IR::MethodCallExpression *mce)
override {
1172 if (em->actualExternType->name !=
"Checksum" || em->method->name !=
"update")
return;
1173 auto assign = findOrigCtxt<IR::AssignmentStatement>();
1174 if (assign ==
nullptr)
return;
1175 auto destField = assign->left;
1179 if (structure->residualChecksums.empty())
return;
1180 auto path = BFN::PathLinearizer::convert(destField);
1181 if (!residualChecksumPayloadFields.count(path))
return;
1182 auto data = inst->substitution.lookupByName(
"data"_cs);
1184 if (
auto expr = data->expression->to<IR::ListExpression>()) {
1186 IR::ListExpression *fl = expr->clone();
1188 auto payload = residualChecksumPayloadFields.at(path);
1189 for (
auto p : payload) fl->push_back(p->apply(cloner));
1191 args->push_back(
new IR::Argument(fl));
1192 mce->arguments = args;