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_egress_port"_cs, portWidth,
334 mkMember(
"ig_intr_md_for_dprsr"_cs,
"mirror_egress_port"_cs, portWidth));
335 cvt(INGRESS,
"standard_metadata.ingress_port"_cs, 9,
336 mkMember(
"ig_intr_md"_cs,
"ingress_port"_cs, portWidth));
339 cvt(EGRESS,
"eg_intr_md_from_parser_aux.egress_parser_err"_cs, 16,
340 mkMember(
"eg_intr_md_from_parser_aux"_cs,
"parser_err"_cs, 16));
341 cvt(EGRESS,
"eg_intr_md_from_parser_aux.clone_src"_cs, 4,
342 mkMember(
"meta"_cs, COMPILER_META,
"clone_src"_cs, 4));
343 cvt(EGRESS,
"eg_intr_md_from_parser_aux.egress_global_tstamp"_cs, 48,
344 mkMember(
"eg_intr_md_from_parser_aux"_cs,
"global_tstamp"_cs, 48));
345 cvt(EGRESS,
"eg_intr_md_for_oport.drop_ctl"_cs, 3,
346 mkMember(
"eg_intr_md_for_dprsr"_cs,
"drop_ctl"_cs, 3));
347 cvt(EGRESS,
"eg_intr_md_from_parser_aux.egress_global_ver"_cs, 32,
348 mkMember(
"eg_intr_md_from_parser_aux"_cs,
"global_ver"_cs, 32));
349 cvt(EGRESS,
"eg_intr_md.deq_timedelta"_cs, 32,
350 mkMember(
"eg_intr_md"_cs,
"deq_timedelta"_cs, 18));
351 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_hash"_cs, 13,
352 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_hash"_cs, 13));
353 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_io_select"_cs, 1,
354 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_io_select"_cs, 1));
355 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_multicast_ctrl"_cs, 1,
356 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_multicast_ctrl"_cs, 1));
357 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_ingress_cos"_cs, 3,
358 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_ingress_cos"_cs, 3));
359 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_deflect_on_drop"_cs, 1,
360 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_deflect_on_drop"_cs, 1));
361 cvt(EGRESS,
"eg_intr_md_for_mb.mirror_egress_port"_cs, portWidth,
362 mkMember(
"eg_intr_md_for_dprsr"_cs,
"mirror_egress_port"_cs, portWidth));
363 cvt(EGRESS,
"meta.standard_metadata.ingress_port"_cs, 9,
364 mkMember(
"meta"_cs,
"ig_intr_md"_cs,
"ingress_port"_cs, portWidth));
365 cvt(EGRESS,
"standard_metadata.ingress_port"_cs, 9,
366 mkMember(
"meta"_cs,
"ig_intr_md"_cs,
"ingress_port"_cs, portWidth));
370 const IR::Node *preorder(IR::Member *member)
override {
372 if (!member->type->is<IR::Type_Bits>())
return member;
375 if (
auto *parser = findOrigCtxt<IR::P4Parser>()) {
376 thread = (parser->name ==
"IngressParserImpl") ? INGRESS : EGRESS;
377 }
else if (
auto *control = findOrigCtxt<IR::P4Control>()) {
378 if (structure->mapControlToGress.count(control->name)) {
379 thread = structure->mapControlToGress.at(control->name);
380 }
else if (control->name ==
"EgressDeparserImpl") {
382 }
else if (control->name ==
"IngressDeparserImpl") {
392 auto &nameMap = (thread == INGRESS) ? ingressMetadataNameMap : egressMetadataNameMap;
395 member->apply(*linearizer);
396 if (!linearizer->linearPath)
return member;
397 auto path = *linearizer->linearPath;
398 auto fn = path.to_cstring(
"."_cs,
false);
399 if (nameMap.count(fn)) {
400 LOG3(
"Translating " << member <<
" to " << nameMap.at(fn));
401 return nameMap.at(fn);
540class ParserCounterSelectCaseConverter :
public Transform {
542 bool isNegative =
false;
543 bool needsCast =
false;
547 ParserCounterSelectCaseConverter() {}
549 void cannotFit(
const IR::AssignmentStatement *stmt,
const char *what) {
550 error(
"Parser counter %1% amount cannot fit into 8-bit. %2%", what, stmt);
553 bool isParserCounter(
const IR::Member *member) {
555 member->apply(*linearizer);
556 if (!linearizer->linearPath)
return false;
557 auto path = linearizer->linearPath->to_cstring();
558 return (path ==
"ig_prsr_ctrl.parser_counter");
561 std::pair<unsigned, unsigned> getAlignLoHi(
const IR::Member *member) {
562 auto header = member->expr->type->to<IR::Type_Header>();
568 for (
auto field : boost::adaptors::reverse(header->fields)) {
569 auto size = field->type->width_bits();
571 if (field->name == member->member) {
574 "Parser counter load field is of width %1% bits"
575 " which is greater than what HW supports (8 bits): %2%",
579 return {bits % 8, (bits + size - 1) % 8};
585 BUG(
"%1% not found in header?", member->member);
594 bool isZero(
const IR::Expression *expr)
const {
595 auto cst = expr->to<IR::Constant>();
596 if (cst ==
nullptr)
return false;
597 return cst->value == 0;
600 bool isOne(
const IR::Expression *expr)
const {
601 auto cst = expr->to<IR::Constant>();
602 if (cst ==
nullptr)
return false;
603 return cst->value == 1;
606 int isPowerOf2(
const IR::Expression *expr)
const {
607 auto cst = expr->to<IR::Constant>();
608 if (cst ==
nullptr)
return -1;
609 big_int value = cst->value;
610 if (value <= 0)
return -1;
611 auto bitcnt = bitcount(value);
612 if (bitcnt != 1)
return -1;
613 auto log = Util::scan1(value, 0);
618 const IR::Node *postorder(IR::Sub *expr) {
619 if (isZero(expr->right))
return expr->left;
620 if (isZero(expr->left))
return new IR::Neg(expr->srcInfo, expr->right);
622 if (expr->right->is<IR::Constant>()) {
623 auto cst = expr->right->to<IR::Constant>();
624 auto neg =
new IR::Constant(cst->srcInfo, cst->type, -cst->value, cst->base,
true);
625 auto result =
new IR::Add(expr->srcInfo, expr->left, neg);
631 const IR::Node *postorder(IR::Mul *expr) {
632 if (isZero(expr->left))
return expr->left;
633 if (isZero(expr->right))
return expr->right;
634 if (isOne(expr->left))
return expr->right;
635 if (isOne(expr->right))
return expr->left;
636 auto exp = isPowerOf2(expr->left);
638 auto amt =
new IR::Constant(exp);
639 auto sh =
new IR::Shl(expr->srcInfo, expr->right, amt);
642 exp = isPowerOf2(expr->right);
644 auto amt =
new IR::Constant(exp);
645 auto sh =
new IR::Shl(expr->srcInfo, expr->left, amt);
652 const IR::Node *preorder(IR::AssignmentStatement *assign) {
654 auto stmt = getOriginal<IR::AssignmentStatement>();
655 auto parserCounter =
new IR::PathExpression(
"ig_prsr_ctrl_parser_counter"_cs);
656 auto right = stmt->right;
657 auto left = stmt->left;
660 while (
auto slice = left->to<IR::Slice>()) left = slice->e0;
661 while (
auto cast = left->to<IR::Cast>()) left = cast->expr;
663 left->apply(*linearizer);
664 auto path = *linearizer->linearPath;
665 if (path.to_cstring() !=
"ig_prsr_ctrl.parser_counter")
return assign;
668 if (
auto cast = right->to<IR::Cast>()) {
669 if (cast->destType->is<IR::Type_Bits>()) {
677 IR::MethodCallStatement *methodCall =
nullptr;
679 if (right->to<IR::Constant>() || right->to<IR::Member>()) {
681 methodCall =
new IR::MethodCallStatement(
682 stmt->srcInfo,
new IR::MethodCallExpression(
683 stmt->srcInfo,
new IR::Member(parserCounter,
"set"),
686 }
else if (
auto add = right->to<IR::Add>()) {
687 auto member = add->left->to<IR::Member>();
689 auto counterWidth = IR::Type::Bits::get(8);
690 auto maskWidth = IR::Type::Bits::get(Device::currentDevice() == Device::TOFINO ? 3 : 8);
692 auto max =
new IR::Constant(counterWidth, 255);
695 if (member && isParserCounter(member)) {
696 methodCall =
new IR::MethodCallStatement(stmt->srcInfo,
697 new IR::Member(parserCounter,
"increment"),
698 {new IR::Argument(add->right)});
700 if (
auto *amt = add->right->to<IR::Constant>()) {
703 auto shr =
new IR::Constant(counterWidth, 0);
704 auto mask =
new IR::Constant(
705 maskWidth, Device::currentDevice() == Device::TOFINO ? 7 : 255);
706 auto add =
new IR::Constant(counterWidth, amt->asUnsigned());
708 methodCall =
new IR::MethodCallStatement(
709 stmt->srcInfo,
new IR::MethodCallExpression(
710 stmt->srcInfo,
new IR::Member(parserCounter,
"set"),
711 new IR::Vector<IR::Type>({member->type}),
712 new IR::Vector<IR::Argument>(
713 {new IR::Argument(member), new IR::Argument(max),
714 new IR::Argument(shr), new IR::Argument(mask),
715 new IR::Argument(add)})));
716 }
else if (
auto *shl = add->left->to<IR::Shl>()) {
717 if (
auto *rot = shl->right->to<IR::Constant>()) {
718 auto left = shl->left;
720 if (
auto cast = left->to<IR::Cast>()) {
721 if (cast->destType->is<IR::Type_Bits>()) {
726 if (
auto *field = left->to<IR::Member>()) {
727 if (!rot->fitsUint() || rot->asUnsigned() >> 8)
728 cannotFit(stmt,
"multiply");
730 if (!amt->fitsUint() || amt->asUnsigned() >> 8)
731 cannotFit(stmt,
"immediate");
733 unsigned lo = 0, hi = 7;
734 std::tie(lo, hi) = getAlignLoHi(field);
737 new IR::Constant(counterWidth, 8 - rot->asUnsigned() - lo);
739 unsigned rot_hi = std::min(hi + rot->asUnsigned(), 7u);
740 auto mask =
new IR::Constant(
741 maskWidth, Device::currentDevice() == Device::TOFINO
743 : (1 << (rot_hi + 1)) - 1);
744 auto add =
new IR::Constant(counterWidth, amt->asUnsigned());
746 methodCall =
new IR::MethodCallStatement(
748 new IR::MethodCallExpression(
749 stmt->srcInfo,
new IR::Member(parserCounter,
"set"),
750 new IR::Vector<IR::Type>({field->type}),
751 new IR::Vector<IR::Argument>(
752 {new IR::Argument(field), new IR::Argument(max),
753 new IR::Argument(shr), new IR::Argument(mask),
754 new IR::Argument(add)})));
761 if (!methodCall)
error(
"Unsupported syntax for parser counter: %1%", stmt);
765 const IR::Node *preorder(IR::SelectExpression *node) {
766 bool isPrsrCtr =
false;
767 for (
unsigned i = 0; i < node->select->components.size(); i++) {
768 auto select = node->select->components[i];
769 if (
auto member = select->to<IR::Member>()) {
770 if (isParserCounter(member)) {
771 if (counterIdx >= 0)
error(
"Multiple selects on parser counter in %1%", node);
777 if (!isPrsrCtr) prune();
781 const IR::Node *postorder(IR::SelectExpression *node) {
787 bool isNegative =
false;
788 bool needsCast =
false;
790 const IR::Expression *convert(
const IR::Constant *c,
bool toBool =
true,
792 auto val = c->asUnsigned();
798 "Parser counter only supports test "
799 "of value being zero or negative.");
803 return new IR::BoolLiteral(~val);
805 return new IR::Constant(IR::Type::Bits::get(1), ~val & 1);
808 const IR::Node *preorder(IR::Mask *mask)
override {
810 mask->left = convert(mask->left->to<IR::Constant>(),
false);
811 mask->right = convert(mask->right->to<IR::Constant>(),
false,
false);
816 const IR::Node *preorder(IR::Constant *c)
override {
return convert(c); }
819 const IR::Node *preorder(IR::SelectCase *node) {
822 if (
auto list = node->keyset->to<IR::ListExpression>()) {
823 auto newList = list->clone();
824 for (
unsigned i = 0; i < newList->components.size(); i++) {
825 if (
int(i) == counterIdx) {
826 newList->components[i] = newList->components[i]->apply(rewrite);
830 node->keyset = newList;
832 node->keyset = node->keyset->apply(rewrite);
834 isNegative |= rewrite.isNegative;
835 needsCast |= rewrite.needsCast;
842 std::set<cstring> need_parser_counter;
845 : caseConverter(cc) {}
847 bool isParserCounter(
const IR::Member *member) {
849 member->apply(*linearizer);
850 if (!linearizer->linearPath)
return false;
851 auto path = linearizer->linearPath->to_cstring();
852 return (path ==
"ig_prsr_ctrl.parser_counter");
855 const IR::Node *postorder(IR::Member *node) {
856 if (isParserCounter(node)) {
857 auto prsr = findContext<IR::P4Parser>();
858 need_parser_counter.insert(prsr->name);
859 auto parserCounter =
new IR::PathExpression(
"ig_prsr_ctrl_parser_counter");
861 new IR::Member(parserCounter, caseConverter.isNegative ?
"is_negative" :
"is_zero");
862 const IR::Expression *methodCall =
new IR::MethodCallExpression(
864 if (caseConverter.needsCast)
865 methodCall =
new IR::Cast(IR::Type::Bits::get(1), methodCall);
871 const IR::Node *postorder(IR::P4Parser *parser) {
872 if (need_parser_counter.count(parser->name) != 0) {
873 auto type =
new IR::Type_Name(
"ParserCounter");
874 auto decl =
new IR::Declaration_Instance(
"ig_prsr_ctrl_parser_counter", type,
876 auto locals = parser->parserLocals.clone();
877 locals->push_back(decl);
878 return new IR::P4Parser(parser->srcInfo, parser->name, parser->type,
879 parser->constructorParams, *locals, parser->states);
932 std::map<cstring, std::set<cstring>> need_checksum;
933 std::map<cstring, ordered_set<const IR::Member *>> residualChecksumPayloadFields;
936 template <
typename Func>
937 void forAllExtracts(
const IR::ParserState *state, Func function) {
939 for (
auto expr : state->components) {
940 if (!expr->is<IR::MethodCallStatement>())
continue;
941 auto mce = expr->to<IR::MethodCallStatement>()->methodCall;
944 if (inst ==
nullptr)
continue;
946 if (em->actualExternType->name ==
"packet_in" && em->method->name ==
"extract") {
947 auto extracted = inst->substitution.lookupByName(
"hdr"_cs)->apply(cloner);
948 if (extracted ==
nullptr ||
949 !extracted->to<IR::Argument>()->expression->is<IR::Member>())
951 function(extracted->to<IR::Argument>()->expression->to<IR::Member>());
957 static bool equiv(
const IR::Expression *a,
const IR::Expression *b) {
958 if (a == b)
return true;
959 if (
typeid(*a) !=
typeid(*b))
return false;
960 if (
auto ma = a->to<IR::Member>()) {
961 auto mb = b->to<IR::Member>();
962 return ma->member == mb->member && equiv(ma->expr, mb->expr);
964 if (
auto pa = a->to<IR::PathExpression>()) {
965 auto pb = b->to<IR::PathExpression>();
966 return pa->path->name == pb->path->name;
971 static bool belongsTo(
const IR::Member *a,
const IR::Member *b) {
972 if (!a || !b)
return false;
975 if (equiv(a, b))
return true;
978 if (a->type->is<IR::Type::Bits>()) {
979 if (equiv(a->expr, b))
return true;
987 : refMap(refMap), typeMap(typeMap), structure(structure), graph(graph) {}
991 auto orig = getOriginal<IR::ParserState>();
992 BUG_CHECK(orig !=
nullptr,
"function must be invoked within ParserState visitor");
994 auto descendants = graph->get_all_descendants(orig);
995 for (
auto d : descendants) {
996 forAllExtracts(d, [&](
const IR::Member *member) { rv.insert(member); });
1004 std::vector<ChecksumInfo> &checksum_fields,
1005 const IR::Member *member,
1008 if (checksum_fields.empty())
return;
1010 const IR::Expression *constant =
nullptr;
1011 for (
auto csum : checksum_fields) {
1012 if (!csum.parserUpdateLocations.count(gress))
continue;
1013 std::vector<const IR::Expression *> exprList;
1014 auto path = BFN::PathLinearizer::convert(csum.destField);
1015 if (!checksum.count(path))
1016 checksum.emplace(path, structure->makeUniqueName(
"checksum"_cs));
1017 auto fieldList = csum.fieldList;
1018 if (!fieldList->is<IR::ListExpression>())
continue;
1019 for (
auto f : fieldList->to<IR::ListExpression>()->components) {
1020 if (f->is<IR::Constant>()) {
1022 }
else if (belongsTo(f->to<IR::Member>(), member)) {
1024 exprList.emplace_back(constant);
1029 exprList.emplace_back(f->apply(cloner));
1035 for (
auto e : exprList) {
1036 auto mce =
new IR::MethodCallExpression(
1037 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"subtract"),
1040 auto subtractCall =
new IR::MethodCallStatement(mce);
1041 statements->push_back(subtractCall);
1044 if (belongsTo(csum.destField->to<IR::Member>(), member)) {
1045 auto destField = csum.destField->apply(cloner);
1046 auto mce =
new IR::MethodCallExpression(
1047 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"subtract"),
1050 auto subtractCall =
new IR::MethodCallStatement(mce);
1051 statements->push_back(subtractCall);
1053 if (csum.with_payload) {
1054 BUG_CHECK(csum.residulChecksumName != std::nullopt,
1055 "residual checksum field name cannot be empty");
1056 auto *rmember =
new IR::Member(
1057 IR::Type::Bits::get(16),
1058 new IR::Member(
new IR::PathExpression(
"meta"),
IR::ID(
"bridged_header")),
1059 IR::ID(*csum.residulChecksumName));
1060 auto *mce =
new IR::MethodCallExpression(
1061 new IR::Member(
new IR::PathExpression(checksum.at(path)),
1062 "subtract_all_and_deposit"),
1065 auto *deposit =
new IR::MethodCallStatement(mce);
1066 std::cout << member->member << std::endl;
1067 structure->checksumDepositToHeader[gress][member->member] = deposit;
1076 std::vector<ChecksumInfo> &checksum_fields,
1077 const IR::Member *member,
1081 for (
auto csum : checksum_fields) {
1082 if (!csum.parserUpdateLocations.count(gress))
continue;
1083 auto path = BFN::PathLinearizer::convert(csum.destField);
1084 if (!checksum.count(path))
1085 checksum.emplace(path, structure->makeUniqueName(
"checksum"_cs));
1086 auto csumInst = checksum.at(path);
1087 auto fieldList = csum.fieldList;
1088 if (!fieldList->is<IR::ListExpression>())
continue;
1089 for (
auto f : fieldList->to<IR::ListExpression>()->components) {
1090 if (belongsTo(f->to<IR::Member>(), member)) {
1091 auto mce =
new IR::MethodCallExpression(
1092 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"add"),
1096 auto addCall =
new IR::MethodCallStatement(mce);
1097 statements->push_back(addCall);
1098 structure->ingressVerifyChecksumToStates[csumInst].insert(state);
1102 auto destField = csum.destField->apply(cloner);
1103 if (belongsTo(destField->to<IR::Member>(), member)) {
1104 auto mce =
new IR::MethodCallExpression(
1105 new IR::Member(
new IR::PathExpression(checksum.at(path)),
"add"),
1108 auto addCall =
new IR::MethodCallStatement(mce);
1109 statements->push_back(addCall);
1110 structure->ingressVerifyChecksumToStates[csumInst].insert(state);
1115 void postorder(IR::ParserState *state)
override {
1120 auto parser = findContext<IR::P4Parser>();
1121 auto gress = parser->name ==
"IngressParserImpl" ? INGRESS : EGRESS;
1122 forAllExtracts(state, [&](
const IR::Member *member) {
1123 createAddCallsForVerifyChecksum(addCalls, structure->verifyChecksums, member, checksum,
1124 gress, state->name);
1126 forAllExtracts(state, [&](
const IR::Member *member) {
1127 auto rc = structure->residualChecksums;
1128 createSubtractCallsForResidualChecksum(subtractCalls, rc, member, checksum, gress);
1130 if (subtractCalls->size() != 0) {
1131 state->components.append(*subtractCalls);
1133 if (addCalls->size() != 0) state->components.append(*addCalls);
1135 if (subtractCalls->size() != 0 || addCalls->size() != 0) {
1136 auto parser = findContext<IR::P4Parser>();
1137 for (
auto it = checksum.begin(); it != checksum.end(); it++)
1138 need_checksum[parser->name].insert(it->second);
1142 bool preorder(IR::P4Parser *)
override {
1147 void postorder(IR::P4Parser *parser)
override {
1148 if (need_checksum.count(parser->name)) {
1149 auto csums = need_checksum.at(parser->name);
1150 for (
auto csum : csums) {
1151 auto inst =
new IR::Type_Name(
"Checksum");
1153 auto decl =
new IR::Declaration_Instance(csum, inst, args);
1154 parser->parserLocals.push_back(decl);
1159 void postorder(IR::MethodCallExpression *mce)
override {
1164 if (em->actualExternType->name !=
"Checksum" || em->method->name !=
"update")
return;
1165 auto assign = findOrigCtxt<IR::BaseAssignmentStatement>();
1166 if (assign ==
nullptr)
return;
1167 auto destField = assign->left;
1171 if (structure->residualChecksums.empty())
return;
1172 auto path = BFN::PathLinearizer::convert(destField);
1173 if (!residualChecksumPayloadFields.count(path))
return;
1174 auto data = inst->substitution.lookupByName(
"data"_cs);
1176 if (
auto expr = data->expression->to<IR::ListExpression>()) {
1178 IR::ListExpression *fl = expr->clone();
1180 auto payload = residualChecksumPayloadFields.at(path);
1181 for (
auto p : payload) fl->push_back(p->apply(cloner));
1183 args->push_back(
new IR::Argument(fl));
1184 mce->arguments = args;