675 const IR::ToplevelBlock *evaluatedProgram)
676 : refMap(refMap), typeMap(typeMap), evaluatedProgram(evaluatedProgram) {}
688 auto declName = decl ? decl->controlPlaneName() : cstring::empty;
689 return getFullyQualifiedName(block, declName);
707 cstring getFullyQualifiedName(
const IR::Block *block,
const cstring name,
708 bool skip_control_plane_name =
false) {
709 cstring block_name = cstring::empty;
710 cstring control_plane_name = cstring::empty;
711 cstring full_name = getBlockNamePrefix(block);
712 if (!skip_control_plane_name) {
713 if (
auto cont = block->getContainer()) {
714 block_name = cont->getName();
715 control_plane_name = cont->controlPlaneName();
716 full_name = prefix(full_name, control_plane_name);
720 if (!name.isNullOrEmpty()) full_name = prefix(full_name, name);
721 LOG5(
"Block : " << block <<
", block_name: " << block_name
722 <<
", block_name_prefix: " << getBlockNamePrefix(block)
723 <<
", control_plane_name: " << control_plane_name <<
", name: " << name
724 <<
", fqname: " << full_name);
728 virtual cstring getBlockNamePrefix(
const IR::Block *) {
return defaultPipeName; }
731 const IR::TableBlock *tableBlock)
override {
732 CHECK_NULL(tableBlock);
733 bool isConstructedInPlace =
false;
741 auto table = tableBlock->container;
742 LOG2(
"Collecting Table Properties on block " << table->name);
744 table, implementationString,
"ActionProfile"_cs, refMap, typeMap,
745 &isConstructedInPlace);
746 if (action_profile) {
747 cstring tableName = *action_profile->name;
748 tableName = prefix(getBlockNamePrefix(tableBlock), tableName);
749 if (isConstructedInPlace)
750 symbols->
add(SymbolType::P4RT_ACTION_PROFILE(), tableName);
753 table, implementationString,
"ActionSelector"_cs, refMap, typeMap,
754 &isConstructedInPlace);
755 if (action_selector) {
756 cstring tableName = *action_selector->name;
757 tableName = prefix(getBlockNamePrefix(tableBlock), tableName);
758 if (action_selector->substitution.lookupByName(
"size"_cs)) {
759 std::string selectorName(tableName +
"_sel");
760 symbols->
add(SymbolType::P4RT_ACTION_SELECTOR(), selectorName);
761 symbols->
add(SymbolType::P4RT_ACTION_PROFILE(), tableName);
763 symbols->
add(SymbolType::P4RT_ACTION_SELECTOR(), tableName);
773 const IR::ExternBlock *externBlock) {
774 CHECK_NULL(externBlock);
780 if (decl ==
nullptr)
return;
783 if (externBlock->type->name ==
"Counter") {
784 symbols->
add(SymbolType::P4RT_COUNTER(), symName);
785 }
else if (externBlock->type->name ==
"DirectCounter") {
786 symbols->
add(SymbolType::P4RT_DIRECT_COUNTER(), symName);
787 }
else if (externBlock->type->name ==
"Meter") {
788 symbols->
add(SymbolType::P4RT_METER(), symName);
789 }
else if (externBlock->type->name ==
"DirectMeter") {
790 symbols->
add(SymbolType::P4RT_DIRECT_METER(), symName);
791 }
else if (externBlock->type->name ==
"ActionProfile") {
792 symbols->
add(SymbolType::P4RT_ACTION_PROFILE(), symName);
793 }
else if (externBlock->type->name ==
"ActionSelector") {
794 if (externBlock->findParameterValue(
"size"_cs)) {
795 std::string selectorName(symName +
"_sel");
796 symbols->
add(SymbolType::P4RT_ACTION_SELECTOR(), selectorName);
797 symbols->
add(SymbolType::P4RT_ACTION_PROFILE(), symName);
799 symbols->
add(SymbolType::P4RT_ACTION_SELECTOR(), symName);
801 }
else if (externBlock->type->name ==
"Digest") {
802 symbols->
add(SymbolType::P4RT_DIGEST(), symName);
803 }
else if (externBlock->type->name ==
"Register") {
804 symbols->
add(SymbolType::P4RT_REGISTER(), symName);
805 }
else if (externBlock->type->name ==
"DirectRegister") {
806 symbols->
add(SymbolType::P4RT_DIRECT_REGISTER(), symName);
807 }
else if (externBlock->type->name ==
"Hash") {
808 symbols->
add(SymbolType::P4RT_HASH(), symName);
813 const IR::AssignmentStatement *)
override {}
820 const IR::ParserBlock *parserBlock) {
821 CHECK_NULL(parserBlock);
822 auto parser = parserBlock->container;
827 for (
auto s : parser->parserLocals) {
828 if (
auto inst = s->to<IR::P4ValueSet>()) {
829 symbols->
add(SymbolType::P4RT_VALUE_SET(), inst->controlPlaneName());
840 if (!block->is<IR::ParserBlock>())
return;
841 collectParserSymbols(symbols, block->to<IR::ParserBlock>());
846 p4configv1::P4Info *p4info, p4configv1::Table *table,
847 const IR::TableBlock *tableBlock,
848 cstring blockPrefix = cstring::empty) {
849 CHECK_NULL(tableBlock);
850 auto tableDeclaration = tableBlock->container;
854 auto p4RtTypeInfo = p4info->mutable_type_info();
862 auto directRegister =
getDirectRegister(tableDeclaration, refMap, typeMap, p4RtTypeInfo);
866 auto id = actionProfile->getId(symbols, blockPrefix);
867 table->set_implementation_id(
id);
868 if (isExternPropertyConstructedInPlace(tableDeclaration, implementationString)) {
869 addActionProfile(symbols, p4info, *actionProfile, blockPrefix);
873 if (actionSelector) {
874 auto id = actionSelector->getId(symbols, blockPrefix);
875 table->set_implementation_id(
id);
877 addActionSelector(symbols, p4info, *actionSelector, blockPrefix);
887 auto id = symbols.
getId(SymbolType::P4RT_DIRECT_COUNTER(),
888 prefix(blockPrefix, directCounter->name));
889 table->add_direct_resource_ids(
id);
890 addCounter(symbols, p4info, *directCounter, blockPrefix);
894 auto id = symbols.
getId(SymbolType::P4RT_DIRECT_METER(),
895 prefix(blockPrefix, directMeter->name));
896 table->add_direct_resource_ids(
id);
897 addMeter(symbols, p4info, *directMeter, blockPrefix);
900 if (directRegister) {
901 auto id = symbols.
getId(SymbolType::P4RT_DIRECT_REGISTER(),
902 prefix(blockPrefix, directRegister->name));
903 table->add_direct_resource_ids(
id);
904 addRegister(symbols, p4info, *directRegister, blockPrefix);
909 if (supportsTimeout) {
910 table->set_idle_timeout_behavior(p4configv1::Table::NOTIFY_CONTROL);
912 table->set_idle_timeout_behavior(p4configv1::Table::NO_TIMEOUT);
919 auto timeout = table->properties->getProperty(
"idle_timeout"_cs);
920 if (timeout ==
nullptr)
return false;
921 if (!timeout->value->is<IR::ExpressionValue>()) {
922 error(
"Unexpected value %1% for idle_timeout on table %2%", timeout, table);
926 auto expr = timeout->value->to<IR::ExpressionValue>()->expression;
927 if (!expr->is<IR::BoolLiteral>()) {
929 "Unexpected non-boolean value %1% for idle_timeout "
930 "property on table %2%",
935 return expr->to<IR::BoolLiteral>()->value;
942 p4configv1::P4TypeInfo *p4RtTypeInfo) {
943 auto directRegisterInstance =
945 if (!directRegisterInstance)
return std::nullopt;
950 const IR::ExternBlock *)
override {}
953 p4configv1::P4Info *p4info,
const IR::ExternBlock *externBlock,
954 cstring pipeName = cstring::empty) {
956 LOG1(
"Adding Extern Instances for pipe " << pipeName << indent);
957 auto decl = externBlock->node->
to<IR::Declaration_Instance>();
960 if (decl ==
nullptr)
return;
964 auto p4RtTypeInfo = p4info->mutable_type_info();
966 if (externBlock->type->name ==
"ActionProfile") {
968 if (actionProfile) addActionProfile(symbols, p4info, *actionProfile, pipeName);
969 }
else if (externBlock->type->name ==
"ActionSelector") {
971 if (actionSelector) addActionSelector(symbols, p4info, *actionSelector, pipeName);
972 }
else if (externBlock->type->name ==
"Counter") {
974 Counterlike<ArchCounterExtern>::from(externBlock, refMap, typeMap, p4RtTypeInfo);
975 if (counter) addCounter(symbols, p4info, *counter, pipeName);
976 }
else if (externBlock->type->name ==
"Meter") {
978 Counterlike<ArchMeterExtern>::from(externBlock, refMap, typeMap, p4RtTypeInfo);
979 if (meter) addMeter(symbols, p4info, *meter, pipeName);
980 }
else if (externBlock->type->name ==
"Digest") {
981 auto digest = getDigest(decl, p4RtTypeInfo);
982 if (digest) addDigest(symbols, p4info, *digest, pipeName);
983 }
else if (externBlock->type->name ==
"Register") {
984 auto register_ =
Register::from(externBlock, refMap, typeMap, p4RtTypeInfo);
985 if (register_) addRegister(symbols, p4info, *register_, pipeName);
986 }
else if (externBlock->type->name ==
"Hash") {
987 auto dynHash = getDynHash(decl, p4RtTypeInfo);
988 if (dynHash) addDynHash(symbols, p4info, *dynHash, pipeName);
992 void addExternFunction(
const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
993 const P4::ExternFunction *)
override {}
995 void addValueSet(
const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
996 const ValueSet &valueSetInstance) {
997 ::barefoot::ValueSet valueSet;
998 valueSet.set_size(valueSetInstance.size);
999 valueSet.mutable_type_spec()->CopyFrom(*valueSetInstance.typeSpec);
1000 addP4InfoExternInstance(symbols, SymbolType::P4RT_VALUE_SET(),
"ValueSet"_cs,
1001 valueSetInstance.name, valueSetInstance.annotations, valueSet,
1003 LOG2(
"Added Instance - Value Set " << valueSetInstance.name);
1006 void analyzeParser(
const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
1007 const IR::ParserBlock *parserBlock) {
1008 CHECK_NULL(parserBlock);
1009 auto parser = parserBlock->container;
1012 for (
auto s : parser->parserLocals) {
1013 if (
auto inst = s->to<IR::P4ValueSet>()) {
1014 auto valueSet = ValueSet::from(inst->controlPlaneName(), inst, refMap, typeMap,
1015 p4info->mutable_type_info());
1016 if (valueSet) addValueSet(symbols, p4info, *valueSet);
1022 ::p4::config::v1::P4Info *p4info)
override {
1028 if (!block->is<IR::ParserBlock>())
return;
1029 analyzeParser(symbols, p4info, block->to<IR::ParserBlock>());
1034 const IR::ExternBlock *)
override {}
1038 std::optional<Digest> getDigest(
const IR::Declaration_Instance *decl,
1039 p4configv1::P4TypeInfo *p4RtTypeInfo) {
1040 std::vector<const P4::ExternMethod *> packCalls;
1048 decl, [&](
const P4::ExternMethod *method) { packCalls.push_back(method); });
1049 if (packCalls.size() == 0)
return std::nullopt;
1050 if (packCalls.size() > 1) {
1051 error(
"Expected single call to pack for digest instance '%1%'", decl);
1052 return std::nullopt;
1054 LOG4(
"Found 'pack' method call for digest instance " << decl->controlPlaneName());
1056 BUG_CHECK(decl->type->is<IR::Type_Specialized>(),
"%1%: expected Type_Specialized",
1058 auto type = decl->type->to<IR::Type_Specialized>();
1059 BUG_CHECK(type->arguments->size() == 1,
"%1%: expected one type argument", decl);
1060 auto typeArg = type->arguments->at(0);
1063 BUG_CHECK(typeSpec !=
nullptr,
1064 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
1065 return Digest{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>()};
1068 std::optional<DynHash> getDynHash(
const IR::Declaration_Instance *decl,
1069 p4configv1::P4TypeInfo *p4RtTypeInfo) {
1070 std::vector<const P4::ExternMethod *> hashCalls;
1073 decl, [&](
const P4::ExternMethod *method) { hashCalls.push_back(method); });
1074 if (hashCalls.size() == 0)
return std::nullopt;
1075 if (hashCalls.size() > 1) {
1077 "Expected single call to get for hash instance '%1%'."
1078 "Control plane API is not generated for this hash call",
1080 return std::nullopt;
1082 LOG4(
"Found 'get' method call for hash instance " << decl->controlPlaneName());
1086 if (
auto *call = hashCalls[0]->expr->to<IR::MethodCallExpression>()) {
1088 if (
auto t = call->type->to<IR::Type_Bits>()) {
1089 hashWidth = t->width_bits();
1092 auto fieldListArg = call->arguments->at(0);
1093 LOG4(
"FieldList for Hash: " << fieldListArg);
1094 auto *typeArgs =
new IR::Vector<IR::Type>();
1095 std::vector<DynHash::hashField> hashFieldInfo;
1096 if (fieldListArg->expression->is<IR::ListExpression>() ||
1097 fieldListArg->expression->is<IR::StructExpression>()) {
1098 for (
auto f : *getListExprComponents(*fieldListArg->expression)) {
1099 if (
auto c = f->to<IR::Concat>()) {
1100 for (
auto e : convertConcatToList(c)) {
1101 hashFieldInfo.push_back({e->toString(), e->is<IR::Constant>()});
1102 typeArgs->push_back(e->type);
1106 hashFieldInfo.push_back({f->toString(), f->is<IR::Constant>()});
1107 auto t = f->type->is<IR::Type_SerEnum>() ? f->type->to<IR::Type_SerEnum>()->type
1109 typeArgs->push_back(t);
1112 auto *typeList =
new IR::Type_List(*typeArgs);
1114 typeList, p4RtTypeInfo);
1115 BUG_CHECK(typeSpec !=
nullptr,
1116 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
1117 return DynHash{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>(),
1118 hashFieldInfo, hashWidth};
1120 return std::nullopt;
1129 if (!instance)
return std::nullopt;
1130 if (instance->type->name !=
"ActionProfile")
return std::nullopt;
1131 auto size = instance->substitution.lookupByName(
"size"_cs)->expression;
1133 BUG_CHECK(size->template is<IR::Constant>(),
"Non-constant size");
1134 return ActionProfile{*instance->name, size->template to<IR::Constant>()->asInt(),
1135 getTableImplementationAnnotations(table, refMap)};
1141 auto size = instance->getParameterValue(
"size"_cs);
1142 BUG_CHECK(size->
is<IR::Constant>(),
"Non-constant size");
1143 return ActionProfile{decl->controlPlaneName(), size->
to<IR::Constant>()->asInt(),
1144 decl->to<IR::IAnnotated>()};
1153 table, implementationString,
"ActionSelector"_cs, refMap, typeMap);
1154 if (!action_selector)
return std::nullopt;
1157 if (action_selector->substitution.lookupByName(
"size"_cs)) {
1158 auto size = action_selector->substitution.lookupByName(
"size"_cs)->expression;
1159 BUG_CHECK(size->template is<IR::Constant>(),
"Non-constant size");
1162 size->template to<IR::Constant>()->asInt(),
1163 defaultMaxGroupSize,
1164 size->template to<IR::Constant>()->asInt(),
1165 getTableImplementationAnnotations(table, refMap),
1169 action_selector->substitution.lookupByName(
"max_group_size"_cs)->expression;
1170 auto numGroups = action_selector->substitution.lookupByName(
"num_groups"_cs)->expression;
1172 BUG_CHECK(maxGroupSize->template is<IR::Constant>(),
"Non-constant max group size");
1173 BUG_CHECK(numGroups->template is<IR::Constant>(),
"Non-constant num groups");
1175 *action_selector->name,
1177 maxGroupSize->template to<IR::Constant>()->asInt(),
1178 numGroups->template to<IR::Constant>()->asInt(),
1179 getTableImplementationAnnotations(table, refMap),
1183 std::optional<ActionSelector>
getActionSelector(
const IR::ExternBlock *instance) {
1186 if (instance->findParameterValue(
"size"_cs)) {
1187 auto size = instance->getParameterValue(
"size"_cs);
1188 BUG_CHECK(size->is<IR::Constant>(),
"Non-constant size");
1191 size->to<IR::Constant>()->asInt(),
1192 defaultMaxGroupSize,
1193 size->to<IR::Constant>()->asInt(),
1194 actionSelDecl->to<IR::IAnnotated>(),
1197 auto maxGroupSize = instance->getParameterValue(
"max_group_size"_cs);
1198 auto numGroups = instance->getParameterValue(
"num_groups"_cs);
1199 BUG_CHECK(maxGroupSize->is<IR::Constant>(),
"Non-constant max group size");
1200 BUG_CHECK(numGroups->is<IR::Constant>(),
"Non-constant num groups");
1201 auto action_profile = instance->getParameterValue(
"action_profile"_cs);
1202 auto action_profile_decl =
1203 action_profile->to<IR::ExternBlock>()->node->to<IR::IDeclaration>();
1204 return ActionSelector{actionSelDecl->controlPlaneName(),
1205 cstring::to_cstring(action_profile_decl->controlPlaneName()),
1207 maxGroupSize->to<IR::Constant>()->asInt(),
1208 numGroups->to<IR::Constant>()->asInt(),
1209 actionSelDecl->to<IR::IAnnotated>(),
1213 static p4configv1::Extern *getP4InfoExtern(P4::ControlPlaneAPI::P4RuntimeSymbolType typeId,
1214 cstring typeName, p4configv1::P4Info *p4info) {
1215 for (
auto &externType : *p4info->mutable_externs()) {
1216 if (externType.extern_type_id() ==
static_cast<p4rt_id_t
>(typeId))
return &externType;
1218 auto *externType = p4info->add_externs();
1219 externType->set_extern_type_id(
static_cast<p4rt_id_t
>(typeId));
1220 externType->set_extern_type_name(typeName);
1224 static void addP4InfoExternInstance(
const P4RuntimeSymbolTableIface &symbols,
1225 P4::ControlPlaneAPI::P4RuntimeSymbolType typeId,
1226 cstring typeName, cstring name,
1227 const IR::IAnnotated *annotations,
1228 const ::google::protobuf::Message &message,
1229 p4configv1::P4Info *p4info) {
1230 auto *externType = getP4InfoExtern(typeId, typeName, p4info);
1231 auto *externInstance = externType->add_instances();
1232 auto *pre = externInstance->mutable_preamble();
1233 pre->set_id(symbols.
getId(typeId, name));
1234 pre->set_name(name);
1235 pre->set_alias(symbols.
getAlias(name));
1236 Helpers::addAnnotations(pre, annotations);
1238 externInstance->mutable_info()->PackFrom(message);
1241 void addDigest(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1242 const Digest &digestInstance, cstring pipeName = cstring::empty) {
1243 ::barefoot::Digest digest;
1244 digest.mutable_type_spec()->CopyFrom(*digestInstance.typeSpec);
1245 auto digestName = prefix(pipeName, digestInstance.name);
1246 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIGEST(),
"Digest"_cs, digestName,
1247 digestInstance.annotations, digest, p4Info);
1248 LOG2(
"Added Instance - Digest " << digestName);
1251 void addDynHash(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1252 const DynHash &dynHashInstance, cstring pipeName = cstring::empty) {
1253 ::barefoot::DynHash dynHash;
1254 dynHash.set_hash_width(dynHashInstance.hashWidth);
1255 dynHash.mutable_type_spec()->CopyFrom(*dynHashInstance.typeSpec);
1256 auto dynHashName = prefix(pipeName, dynHashInstance.name);
1257 for (
const auto &f : dynHashInstance.hashFieldInfo) {
1258 auto newF = dynHash.add_field_infos();
1259 newF->set_field_name(f.hashFieldName);
1260 newF->set_is_constant(f.isConstant);
1262 addP4InfoExternInstance(symbols, SymbolType::P4RT_HASH(),
"DynHash"_cs, dynHashName,
1263 dynHashInstance.annotations, dynHash, p4Info);
1264 LOG2(
"Added Instance - DynHash " << dynHashName);
1269 void addRegister(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1270 const Register ®isterInstance, cstring pipeName = cstring::empty) {
1271 auto registerName = prefix(pipeName, registerInstance.name);
1272 if (registerInstance.size == 0) {
1273 ::barefoot::DirectRegister register_;
1274 register_.mutable_type_spec()->CopyFrom(*registerInstance.typeSpec);
1275 register_.set_data_field_name(registerInstance.name);
1276 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_REGISTER(),
1277 "DirectRegister"_cs, registerName, registerInstance.annotations,
1279 LOG2(
"Added Instance - DirectRegister " << registerName);
1281 ::barefoot::Register register_;
1282 register_.set_size(registerInstance.size);
1283 register_.mutable_type_spec()->CopyFrom(*registerInstance.typeSpec);
1284 register_.set_data_field_name(registerInstance.name);
1285 addP4InfoExternInstance(symbols, SymbolType::P4RT_REGISTER(),
"Register"_cs,
1286 registerName, registerInstance.annotations, register_, p4Info);
1287 LOG2(
"Added Instance - Register " << registerName);
1292 template <
typename Kind>
1295 auto counter_spec = counter->mutable_spec();
1296 counter_spec->set_unit(CounterTraits::mapUnitName(counterInstance.
unit));
1301 const cstring blockPrefix = cstring::empty) {
1302 if (counterInstance.
table) {
1303 ::barefoot::DirectCounter counter;
1305 auto tableName = prefix(blockPrefix, *counterInstance.
table);
1306 auto counterName = prefix(blockPrefix, counterInstance.
name);
1308 symbols.
getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
1309 counter.set_direct_table_id(tableId);
1310 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_COUNTER(),
1312 counterName, counterInstance.
annotations, counter, p4Info);
1313 LOG2(
"Added Instance - DirectCounter " << counterName);
1315 ::barefoot::Counter counter;
1317 counter.set_size(counterInstance.
size);
1318 auto counterName = prefix(blockPrefix, counterInstance.
name);
1319 addP4InfoExternInstance(symbols, SymbolType::P4RT_COUNTER(),
1321 counterName, counterInstance.
annotations, counter, p4Info);
1322 LOG2(
"Added Instance - Counter " << counterName);
1327 template <
typename Kind>
1329 using ::barefoot::MeterSpec;
1331 auto meter_spec = meter->mutable_spec();
1333 meter_spec->set_type(MeterSpec::COLOR_AWARE);
1335 meter_spec->set_type(MeterSpec::COLOR_UNAWARE);
1337 meter_spec->set_unit(CounterlikeTraits<ArchMeterExtern>::mapUnitName(meterInstance.
unit));
1342 const cstring blockPrefix = cstring::empty) {
1343 auto meterName = prefix(blockPrefix, meterInstance.
name);
1344 if (meterInstance.
table) {
1345 ::barefoot::DirectMeter meter;
1347 auto tableName = prefix(blockPrefix, *meterInstance.
table);
1349 symbols.
getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
1350 meter.set_direct_table_id(tableId);
1351 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_METER(),
1353 meterName, meterInstance.
annotations, meter, p4Info);
1354 LOG2(
"Added Instance - DirectMeter " << meterName);
1356 ::barefoot::Meter meter;
1358 meter.set_size(meterInstance.
size);
1359 addP4InfoExternInstance(symbols, SymbolType::P4RT_METER(),
1361 meterName, meterInstance.
annotations, meter, p4Info);
1362 LOG2(
"Added Instance - Meter " << meterName);
1366 void addActionProfile(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1367 const ActionProfile &actionProfile, cstring pipeName = cstring::empty) {
1368 ::barefoot::ActionProfile profile;
1369 profile.set_size(actionProfile.size);
1370 auto actionProfileName = prefix(pipeName, actionProfile.name);
1373 for (
const auto &table : tablesIt->second) {
1374 cstring tableName = table;
1375 if (!pipeName.isNullOrEmpty()) tableName = prefix(pipeName, tableName);
1376 profile.add_table_ids(symbols.
getId(
1377 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1380 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_PROFILE(),
"ActionProfile"_cs,
1381 actionProfileName, actionProfile.annotations, profile, p4Info);
1382 LOG2(
"Added Extern Instance - Action Profile " << actionProfileName);
1385 virtual void addActionSelector(
const P4RuntimeSymbolTableIface &symbols,
1386 p4configv1::P4Info *p4Info,
const ActionSelector &actionSelector,
1387 cstring blockPrefix = cstring::empty) {
1388 ::barefoot::ActionSelector selector;
1389 selector.set_max_group_size(actionSelector.maxGroupSize);
1390 selector.set_num_groups(actionSelector.numGroups);
1391 cstring actionSelectorName = prefix(blockPrefix, actionSelector.name);
1392 if (actionSelector.actionProfileName) {
1393 selector.set_action_profile_id(
1394 symbols.
getId(SymbolType::P4RT_ACTION_PROFILE(),
1395 prefix(blockPrefix, *actionSelector.actionProfileName)));
1398 for (
const auto &table : tablesIt->second) {
1399 cstring tableName = prefix(blockPrefix, table);
1400 selector.add_table_ids(symbols.
getId(
1401 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1404 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_SELECTOR(),
1405 "ActionSelector"_cs, actionSelectorName,
1406 actionSelector.annotations, selector, p4Info);
1407 LOG2(
"Added Extern Instance - Action Selector " << actionSelectorName);
1409 ::barefoot::ActionProfile profile;
1410 profile.set_size(actionSelector.size);
1413 for (
const auto &table : tablesIt->second) {
1414 cstring tableName = prefix(blockPrefix, table);
1415 profile.add_table_ids(symbols.
getId(
1416 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1417 selector.add_table_ids(symbols.
getId(
1418 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1424 cstring profileName = actionSelectorName;
1425 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_PROFILE(),
"ActionProfile"_cs,
1426 profileName, actionSelector.annotations, profile, p4Info);
1427 selector.set_action_profile_id(
1428 symbols.
getId(SymbolType::P4RT_ACTION_PROFILE(), profileName));
1429 cstring selectorName = profileName +
"_sel";
1430 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_SELECTOR(),
1431 "ActionSelector"_cs, selectorName, actionSelector.annotations,
1433 LOG2(
"Added Extern Instance - Action Selector " << selectorName);
1441 template <
typename Func>
1444 evaluatedProgram->getProgram(), [&](
const IR::MethodCallExpression *call) {
1445 auto instance = P4::MethodInstance::resolve(call, refMap, typeMap);
1446 if (instance->template is<P4::ExternMethod>() && instance->object == object) {
1447 function(instance->template to<P4::ExternMethod>());
1455 return table->properties->getProperty(implementationString);
1458 const IR::IAnnotated *getTableImplementationAnnotations(
const IR::P4Table *table,
1460 auto impl = getTableImplementationProperty(table);
1461 if (impl ==
nullptr)
return nullptr;
1462 if (!impl->value->template is<IR::ExpressionValue>())
return nullptr;
1463 auto expr = impl->value->template to<IR::ExpressionValue>()->expression;
1464 if (expr->template is<IR::ConstructorCallExpression>())
1465 return impl->template to<IR::IAnnotated>();
1466 if (expr->template is<IR::PathExpression>()) {
1467 auto decl = refMap->
getDeclaration(expr->template to<IR::PathExpression>()->path,
true);
1468 return decl->template to<IR::IAnnotated>();
1473 std::optional<cstring> getTableImplementationName(
const IR::P4Table *table,
1475 auto impl = getTableImplementationProperty(table);
1476 if (impl ==
nullptr)
return std::nullopt;
1477 if (!impl->value->template is<IR::ExpressionValue>()) {
1478 error(
"Expected %1% property value for table %2% to be an expression: %2%",
1479 implementationString, table->controlPlaneName(), impl);
1480 return std::nullopt;
1482 auto expr = impl->value->template to<IR::ExpressionValue>()->expression;
1483 if (expr->template is<IR::ConstructorCallExpression>())
return impl->controlPlaneName();
1484 if (expr->template is<IR::PathExpression>()) {
1485 auto decl = refMap->
getDeclaration(expr->template to<IR::PathExpression>()->path,
true);
1486 return decl->controlPlaneName();
1488 return std::nullopt;
1493 const IR::ToplevelBlock *evaluatedProgram;
1501 cstring defaultPipeName =
"pipe"_cs;
1503 static constexpr int64_t defaultMaxGroupSize = 120;
1506 google::protobuf::util::JsonPrintOptions jsonPrintOptions;
1510 return jsonPrintOptions;
1519 template <
typename Func>
1520 void forAllPipeBlocks(
const IR::ToplevelBlock *evaluatedProgram, Func function) {
1521 auto main = evaluatedProgram->getMain();
1522 if (!main) ::fatal_error(
"Program does not contain a `main` module");
1523 auto cparams = main->getConstructorParameters();
1525 for (
auto param : main->constantValue) {
1527 if (!param.second)
continue;
1528 auto pipe = param.second;
1529 if (!pipe->is<IR::PackageBlock>()) {
1530 error(ErrorType::ERR_INVALID,
1531 "%1% package block. You are compiling for the %2% "
1532 "P4 architecture.\n"
1533 "Please verify that you included the correct architecture file.",
1534 pipe, BackendOptions().arch);
1537 auto idxParam = cparams->getParameter(index);
1538 auto pipeName = idxParam->name;
1539 function(pipeName, pipe->to<IR::PackageBlock>());
1543 template <
typename Func>
1544 void forAllPortMetadataBlocks(
const IR::ToplevelBlock *evaluatedProgram, Func function) {
1545 auto main = evaluatedProgram->getMain();
1546 if (!main) ::fatal_error(
"Program does not contain a `main` module");
1547 if (main->type->name ==
"MultiParserSwitch") {
1548 int numParsersPerPipe = Device::numParsersPerPipe();
1549 auto parsersName =
"ig_prsr"_cs;
1550 forAllPipeBlocks(evaluatedProgram, [&](
cstring,
const IR::PackageBlock *pkg) {
1551 auto parsers = pkg->findParameterValue(parsersName);
1552 BUG_CHECK(parsers,
"Expected Block");
1553 if (!parsers->is<IR::PackageBlock>()) {
1554 error(ErrorType::ERR_INVALID,
1555 "%1% package block. "
1556 "You are compiling for the %2% P4 architecture.\n"
1557 "Please verify that you included the correct architecture file.",
1558 parsers, BackendOptions().arch);
1561 auto parsersBlock = parsers->to<IR::PackageBlock>();
1562 for (
int idx = 0; idx < numParsersPerPipe; idx++) {
1563 auto mpParserName =
"prsr" + std::to_string(idx);
1564 auto parser = parsersBlock->findParameterValue(mpParserName);
1566 auto parserBlock = parser->to<IR::ParserBlock>();
1567 if (hasUserPortMetadata.count(parserBlock) == 0) {
1568 auto portMetadataFullName =
1569 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
1570 function(portMetadataFullName, parserBlock);
1575 auto parserName =
"ingress_parser"_cs;
1576 forAllPipeBlocks(evaluatedProgram, [&](
cstring,
const IR::PackageBlock *pkg) {
1577 auto *block = pkg->findParameterValue(parserName);
1579 if (!block->is<IR::ParserBlock>())
return;
1580 auto parserBlock = block->to<IR::ParserBlock>();
1581 if (hasUserPortMetadata.count(parserBlock) == 0) {
1582 auto portMetadataFullName =
1583 getFullyQualifiedName(parserBlock, PortMetadata::name());
1584 function(portMetadataFullName, parserBlock);
1591 const IR::ToplevelBlock *evaluatedProgram)
1592 : BFRuntimeArchHandlerCommon<Arch::TNA>(refMap, typeMap, evaluatedProgram) {
1594 LOG1(
"BFRuntimeArchHandlerTofino" << indent);
1595 implementationString =
"implementation"_cs;
1597 std::set<cstring> pipes;
1598 LOG2(
"Populating blockNamePrefixMap" << Log::indent);
1604 forAllPipeBlocks(evaluatedProgram, [&](
cstring pipeName,
const IR::PackageBlock *pkg) {
1606 auto decl = pkg->node->to<IR::Declaration_Instance>();
1607 cstring blockNamePrefix = pipeName;
1608 if (decl) blockNamePrefix = decl->controlPlaneName();
1609 blockNamePrefixMap[block] = blockNamePrefix;
1610 LOG4(
"Updating blockNamePrefixMap with " << &*block << block->toString() <<
" : "
1611 << blockNamePrefixMap[block]);
1612 pipes.insert(pipeName);
1618 static std::vector<cstring> gressNames = {
"ig"_cs,
"eg"_cs};
1619 int numParsersPerPipe = Device::numParsersPerPipe();
1621 auto main = evaluatedProgram->getMain();
1622 if (!main) ::fatal_error(
"Program does not contain a `main` module");
1624 isMultiParser =
false;
1625 if (main->type->name ==
"MultiParserSwitch") {
1626 forAllPipeBlocks(evaluatedProgram, [&](
cstring pipeName,
const IR::PackageBlock *pkg) {
1628 pkg->type->name ==
"MultiParserPipeline",
1629 "Only MultiParserPipeline pipes can be used with a MultiParserSwitch switch");
1630 for (
auto gressName : gressNames) {
1631 auto parsersName = gressName +
"_prsr";
1632 auto parsers = pkg->findParameterValue(parsersName);
1633 BUG_CHECK(parsers && parsers->is<IR::PackageBlock>(),
"Expected PackageBlock");
1634 auto parsersBlock = parsers->to<IR::PackageBlock>();
1635 auto decl = parsersBlock->node->to<IR::Declaration_Instance>();
1636 if (decl) parsersName = decl->controlPlaneName();
1637 for (
int idx = 0; idx < numParsersPerPipe; idx++) {
1638 auto parserName =
"prsr" + std::to_string(idx);
1639 auto parser = parsersBlock->findParameterValue(parserName);
1641 BUG_CHECK(parser->is<IR::ParserBlock>(),
"Expected ParserBlock");
1642 auto parserBlock = parser->to<IR::ParserBlock>();
1645 auto parserFullName = pipeName +
"." + parsersName +
"." + parserName;
1646 blockNamePrefixMap[parserBlock] = parserFullName;
1648 isMultiParser =
true;
1654 cstring getBlockNamePrefix(
const IR::Block *blk)
override {
1655 if (blockNamePrefixMap.count(blk) > 0)
return blockNamePrefixMap[blk];
1656 return cstring::empty;
1660 const IR::ExternBlock *externBlock)
override {
1661 collectExternInstanceCommon(symbols, externBlock);
1663 CHECK_NULL(externBlock);
1669 if (decl ==
nullptr)
return;
1672 if (externBlock->type->name ==
"Lpf") {
1673 symbols->
add(SymbolType::P4RT_LPF(), symName);
1674 }
else if (externBlock->type->name ==
"DirectLpf") {
1675 symbols->
add(SymbolType::P4RT_DIRECT_LPF(), symName);
1676 }
else if (externBlock->type->name ==
"Wred") {
1677 symbols->
add(SymbolType::P4RT_WRED(), symName);
1678 }
else if (externBlock->type->name ==
"DirectWred") {
1679 symbols->
add(SymbolType::P4RT_DIRECT_WRED(), symName);
1680 }
else if (externBlock->type->name ==
"RegisterParam") {
1681 symbols->
add(SymbolType::P4RT_REGISTER_PARAM(), symName);
1689 const IR::ParserBlock *parserBlock) {
1690 auto portMetadata = getPortMetadataExtract(externFunction, refMap, typeMap,
nullptr);
1692 if (hasUserPortMetadata.count(parserBlock)) {
1693 error(
"Cannot have multiple extern calls for %1%",
1694 BFN::ExternPortMetadataUnpackString);
1697 hasUserPortMetadata.insert(parserBlock);
1698 auto portMetadataFullName =
1699 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
1700 symbols->
add(SymbolType::P4RT_PORT_METADATA(), portMetadataFullName);
1704 void collectParserSymbols(P4RuntimeSymbolTableIface *symbols,
1705 const IR::ParserBlock *parserBlock) {
1706 CHECK_NULL(parserBlock);
1707 auto parser = parserBlock->container;
1711 for (
auto state : parser->states) {
1713 state, [&](
const IR::MethodCallExpression *call) {
1715 if (instance->is<P4::ExternFunction>())
1716 collectPortMetadataExternFunction(
1717 symbols, instance->to<P4::ExternFunction>(), parserBlock);
1721 for (
auto s : parser->parserLocals) {
1722 if (
auto inst = s->to<IR::P4ValueSet>()) {
1723 auto name = getFullyQualifiedName(parserBlock, inst->controlPlaneName(),
true);
1724 symbols->
add(SymbolType::P4RT_VALUE_SET(), name);
1733 auto *params = parser->getApplyParameters();
1734 for (
auto p : *params) {
1735 if (p->type->toString() ==
"ingress_intrinsic_metadata_t") {
1736 BUG_CHECK(ingressIntrinsicMdParamName.count(parserBlock) == 0 ||
1737 ingressIntrinsicMdParamName[parserBlock] == p->name.toString(),
1738 "%1%: Multiple names of intrinsic metadata found in this parser block",
1740 ingressIntrinsicMdParamName[parserBlock] = p->name;
1764 static std::vector<cstring> gressNames = {
"ingress"_cs,
"egress"_cs};
1765 forAllPipeBlocks(evaluatedProgram, [&](
cstring pipeName,
const IR::PackageBlock *pkg) {
1766 for (
auto gressName : gressNames) {
1767 auto gress = pkg->findParameterValue(gressName);
1768 BUG_CHECK(gress->is<IR::ControlBlock>(),
"Expected control");
1769 auto control = gress->to<IR::ControlBlock>();
1770 if (blockNamePrefixMap.count(control) > 0) pipeName = blockNamePrefixMap[control];
1771 snapshotInfo.emplace(control,
1772 SnapshotInfo{pipeName, gressName, 0u, cstring::empty, {}});
1773 LOG3(
"Adding SnapshotInfo for " << control->getName() <<
" " << gressName
1774 <<
" on pipe " << pipeName);
1787 CHECK_NULL(controlBlock);
1788 auto control = controlBlock->container;
1789 CHECK_NULL(control);
1791 auto sinfoIt = snapshotInfo.find(controlBlock);
1794 if (sinfoIt == snapshotInfo.end())
return;
1795 auto snapshot_name = getFullyQualifiedName(controlBlock, control->externalName());
1796 LOG1(
"Collecting Snapshot for control " << snapshot_name << indent);
1801 if (snapshots.count(snapshot_name)) {
1802 snapshotInfo.erase(sinfoIt);
1805 snapshots.insert(snapshot_name);
1806 sinfoIt->second.name = snapshot_name;
1807 auto snapshotFields = &sinfoIt->second.fields;
1808 auto params = control->getApplyParameters();
1809 for (
size_t idx = 0; idx < params->size(); idx++) {
1810 auto p = params->getParameter(idx);
1813 auto includeValid = (idx == sinfoIt->second.userHdrParamIdx);
1817 LOG3(
"Adding snaphot to bfrt info for control: " << snapshot_name);
1818 symbols->
add(SymbolType::P4RT_SNAPSHOT(), snapshot_name);
1827 static std::vector<cstring> gressNames = {
"ig"_cs,
"eg"_cs};
1828 int numParsersPerPipe = Device::numParsersPerPipe();
1830 auto main = evaluatedProgram->getMain();
1831 if (!main) ::fatal_error(
"Program does not contain a `main` module");
1832 if (main->type->name !=
"MultiParserSwitch")
return;
1834 forAllPipeBlocks(evaluatedProgram, [&](
cstring pipeName,
const IR::PackageBlock *pkg) {
1835 BUG_CHECK(pkg->type->name ==
"MultiParserPipeline",
1836 "Only MultiParserPipeline pipes can be used with a MultiParserSwitch switch");
1837 for (
auto gressName : gressNames) {
1838 ::barefoot::ParserChoices parserChoices;
1840 if (
auto decl = pkg->node->to<IR::Declaration_Instance>()) pipeName = decl->Name();
1842 parserChoices.set_pipe(pipeName);
1843 if (gressName ==
"ig")
1844 parserChoices.set_direction(::barefoot::DIRECTION_INGRESS);
1846 parserChoices.set_direction(::barefoot::DIRECTION_EGRESS);
1848 auto parsersName = gressName +
"_prsr";
1849 auto parsers = pkg->findParameterValue(parsersName);
1850 BUG_CHECK(parsers && parsers->is<IR::PackageBlock>(),
"Expected PackageBlock");
1851 auto parsersBlock = parsers->to<IR::PackageBlock>();
1852 auto decl = parsersBlock->node->to<IR::Declaration_Instance>();
1853 if (decl) parsersName = decl->controlPlaneName();
1854 for (
int idx = 0; idx < numParsersPerPipe; idx++) {
1855 auto parserName =
"prsr" + std::to_string(idx);
1856 auto parser = parsersBlock->findParameterValue(parserName);
1858 BUG_CHECK(parser->is<IR::ParserBlock>(),
"Expected ParserBlock");
1859 auto parserBlock = parser->to<IR::ParserBlock>();
1860 auto decl = parserBlock->node->to<IR::Declaration_Instance>();
1861 auto userName = (decl ==
nullptr) ? cstring::empty : decl->controlPlaneName();
1863 auto choice = parserChoices.add_choices();
1864 auto parserFullName = prefix(parsersName, parserName);
1865 parserFullName = prefix(pipeName, parserFullName);
1866 choice->set_arch_name(parserFullName);
1867 choice->set_type_name(parserBlock->getName().name);
1868 choice->set_user_name(userName);
1870 auto parsersFullName = prefix(pipeName, parsersName);
1871 symbols->
add(SymbolType::P4RT_PARSER_CHOICES(), parsersFullName);
1872 parserConfiguration.emplace(parsersFullName, parserChoices);
1879 LOG1(
"BFRuntimeArchHandlerTofino::collectExtra" << indent);
1880 LOG2(
"Collecting Parser Symbols" << Log::indent);
1886 if (!block->is<IR::ParserBlock>())
return;
1887 collectParserSymbols(symbols, block->to<IR::ParserBlock>());
1891 LOG2(
"Collecting Snapshot Fields" << Log::indent);
1897 if (!block->is<IR::ControlBlock>())
return;
1898 collectSnapshot(symbols, block->to<IR::ControlBlock>(), &snapshotFieldIds);
1902 LOG2(
"Collecting Parser Choices" << Log::indent);
1906 LOG2(
"Collecting PortMetadata" << Log::indent);
1909 forAllPortMetadataBlocks(
1910 evaluatedProgram, [&](
cstring portMetadataFullName,
const IR::ParserBlock *) {
1911 symbols->
add(SymbolType::P4RT_PORT_METADATA(), portMetadataFullName);
1912 LOG3(
"Adding PortMetadata symbol: " << portMetadataFullName);
1919 LOG1(
"BFRuntimeArchHandlerTofino::postCollect" << indent);
1924 if (!block->is<IR::TableBlock>())
return;
1925 auto table = block->to<IR::TableBlock>()->container;
1926 auto implementation = getTableImplementationName(table, refMap);
1927 if (implementation) {
1928 auto pipeName = blockNamePrefixMap[block];
1929 auto implName = prefix(pipeName, *implementation);
1931 LOG5(
"Adding action profile : " << implName <<
" for table "
1932 << table->controlPlaneName());
1939 if (!block->is<IR::ExternBlock>())
return;
1940 auto selectorExternBlock = block->to<IR::ExternBlock>();
1941 if (selectorExternBlock->type->name !=
"ActionSelector")
return;
1942 auto selectorDecl = selectorExternBlock->node->to<IR::Declaration_Instance>();
1943 CHECK_NULL(selectorDecl);
1944 auto profile = selectorExternBlock->getParameterValue(
"action_profile"_cs);
1946 auto profileExternBlock = profile->to<IR::ExternBlock>();
1947 auto profileDecl = profileExternBlock->node->to<IR::Declaration_Instance>();
1948 CHECK_NULL(profileDecl);
1949 auto pipeName = blockNamePrefixMap[selectorExternBlock];
1950 auto profileDeclName = prefix(pipeName, profileDecl->controlPlaneName());
1951 auto selectorDeclName = prefix(pipeName, selectorDecl->controlPlaneName());
1955 LOG5(
"Adding action profile : " << profileDeclName <<
" for tables "
1965 if (!block->is<IR::ExternBlock>())
return;
1966 auto externBlock = block->to<IR::ExternBlock>();
1967 if (externBlock->type->name !=
"Meter" && externBlock->type->name !=
"DirectMeter")
1969 auto decl = externBlock->node->to<IR::Declaration_Instance>();
1974 auto call = method->expr;
1975 if (call->arguments->size() == 2) {
1976 LOG3(
"Meter " << decl->controlPlaneName() <<
" is color-aware "
1977 <<
"because of 2-argument call to execute()");
1983 class RegisterParamFinder :
public Inspector {
1984 BFRuntimeArchHandlerTofino &self;
1986 bool checkExtern(
const IR::Declaration_Instance *decl,
cstring name) {
1987 if (
auto *specialized = decl->type->to<IR::Type_Specialized>())
1988 if (
auto *name_type = specialized->baseType->to<IR::Type_Name>())
1989 return name_type->path->name == name;
1994 RegisterParamFinder(BFRuntimeArchHandlerTofino &self) : self(self) {}
1995 bool preorder(
const IR::MethodCallExpression *mce)
override {
1998 if (method->
object ==
nullptr)
2000 auto *reg_param = method->
object->
to<IR::Declaration_Instance>();
2001 if (reg_param ==
nullptr)
2003 if (!checkExtern(reg_param,
"RegisterParam"_cs))
return true;
2006 if (reg_action ==
nullptr)
return true;
2007 if (!checkExtern(reg_action,
"DirectRegisterAction"_cs) &&
2008 !checkExtern(reg_action,
"RegisterAction"_cs))
2010 BUG_CHECK(reg_action->arguments->size() > 0,
"%1%: Missing argument", reg_action);
2011 auto *rap = reg_action->arguments->at(0)->expression->to<IR::PathExpression>();
2012 if (rap ==
nullptr)
return true;
2015 if (rap_decl ==
nullptr)
return true;
2016 if (checkExtern(rap_decl,
"Register"_cs))
2017 self.registerParam2register[reg_param->controlPlaneName()] =
2018 rap_decl->controlPlaneName();
2019 if (checkExtern(rap_decl,
"DirectRegister"_cs))
2020 self.registerParam2table[reg_param->controlPlaneName()] =
2021 rap_decl->controlPlaneName();
2024 void postorder(
const IR::P4Table *table)
override {
2026 auto *registers = table->properties->getProperty(
"registers"_cs);
2027 if (registers ==
nullptr)
return;
2028 auto *registers_value = registers->value->to<IR::ExpressionValue>();
2029 CHECK_NULL(registers_value);
2030 auto *registers_path = registers_value->expression->to<IR::PathExpression>();
2031 CHECK_NULL(registers_path);
2032 auto *registers_decl =
getDeclInst(self.refMap, registers_path);
2033 CHECK_NULL(registers_decl);
2035 for (
auto r : self.registerParam2table)
2036 if (r.second == registers_decl->controlPlaneName())
2037 self.registerParam2table[r.first] = table->controlPlaneName();
2041 evaluatedProgram->getProgram()->apply(RegisterParamFinder(*
this));
2045 p4configv1::Table *table,
const IR::TableBlock *tableBlock)
override {
2046 CHECK_NULL(tableBlock);
2047 auto tableDeclaration = tableBlock->container;
2048 auto blockPrefix = blockNamePrefixMap[tableBlock];
2050 addTablePropertiesCommon(symbols, p4info, table, tableBlock, blockPrefix);
2052 auto directLpf = getDirectLpf(tableDeclaration, refMap, typeMap);
2055 symbols.
getId(SymbolType::P4RT_DIRECT_LPF(), prefix(blockPrefix, directLpf->name));
2056 table->add_direct_resource_ids(
id);
2057 addLpf(symbols, p4info, *directLpf, blockPrefix);
2060 auto directWred = getDirectWred(tableDeclaration, refMap, typeMap);
2062 auto id = symbols.
getId(SymbolType::P4RT_DIRECT_WRED(),
2063 prefix(blockPrefix, directWred->name));
2064 table->add_direct_resource_ids(
id);
2065 addWred(symbols, p4info, *directWred, blockPrefix);
2072 template <
typename T>
2075 auto directFilterInstance =
2077 if (!directFilterInstance)
return std::nullopt;
2078 CHECK_NULL(directFilterInstance->type);
2079 if (directFilterInstance->type->name != filterType)
return std::nullopt;
2080 return T::fromDirect(*directFilterInstance, table);
2098 const IR::ExternBlock *externBlock)
override {
2099 auto decl = externBlock->node->to<IR::Declaration_Instance>();
2102 if (decl ==
nullptr)
return;
2107 auto pipeName = blockNamePrefixMap[externBlock];
2109 addExternInstanceCommon(symbols, p4info, externBlock, pipeName);
2111 auto p4RtTypeInfo = p4info->mutable_type_info();
2113 if (externBlock->type->name ==
"Lpf") {
2115 if (lpf) addLpf(symbols, p4info, *lpf, pipeName);
2116 }
else if (externBlock->type->name ==
"Wred") {
2117 auto wred = Wred::from(externBlock);
2118 if (wred) addWred(symbols, p4info, *wred, pipeName);
2119 }
else if (externBlock->type->name ==
"RegisterParam") {
2120 auto register_param_ = RegisterParam::from(externBlock, refMap, typeMap, p4RtTypeInfo);
2121 if (register_param_) addRegisterParam(symbols, p4info, *register_param_, pipeName);
2125 void addExternFunction(
const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
2126 const P4::ExternFunction *)
override {}
2128 void addPortMetadataExternFunction(
const P4RuntimeSymbolTableIface &symbols,
2129 p4configv1::P4Info *p4info,
2130 const P4::ExternFunction *externFunction,
2131 const IR::ParserBlock *parserBlock) {
2132 auto p4RtTypeInfo = p4info->mutable_type_info();
2133 auto portMetadata = getPortMetadataExtract(externFunction, refMap, typeMap, p4RtTypeInfo);
2135 if (blockNamePrefixMap.count(parserBlock)) {
2136 auto portMetadataFullName =
2137 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
2138 addPortMetadata(symbols, p4info, *portMetadata, portMetadataFullName, parserBlock);
2143 void analyzeParser(
const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
2144 const IR::ParserBlock *parserBlock) {
2145 CHECK_NULL(parserBlock);
2146 auto parser = parserBlock->container;
2149 for (
auto s : parser->parserLocals) {
2150 if (
auto inst = s->to<IR::P4ValueSet>()) {
2152 getFullyQualifiedName(parserBlock, inst->controlPlaneName(),
true);
2154 ValueSet::from(namePrefix, inst, refMap, typeMap, p4info->mutable_type_info());
2155 if (valueSet) addValueSet(symbols, p4info, *valueSet);
2160 for (
auto state : parser->states) {
2162 state, [&](
const IR::MethodCallExpression *call) {
2164 if (instance->is<P4::ExternFunction>())
2165 addPortMetadataExternFunction(
2166 symbols, p4info, instance->to<P4::ExternFunction>(), parserBlock);
2172 ::p4::config::v1::P4Info *p4info)
override {
2180 p4info->clear_value_sets();
2183 if (!block->is<IR::ParserBlock>())
return;
2184 analyzeParser(symbols, p4info, block->to<IR::ParserBlock>());
2189 forAllPortMetadataBlocks(evaluatedProgram, [&](
cstring portMetadataFullName,
2190 const IR::ParserBlock *parserBlock) {
2191 addPortMetadataDefault(symbols, p4info, portMetadataFullName, parserBlock);
2194 for (
const auto &snapshot : snapshotInfo) addSnapshot(symbols, p4info, snapshot.second);
2196 for (
const auto &parser : parserConfiguration)
2197 addParserChoices(symbols, p4info, parser.first, parser.second);
2204 p4configv1::P4TypeInfo *p4RtTypeInfo) {
2205 if (function->method->name != BFN::ExternPortMetadataUnpackString)
return std::nullopt;
2207 if (
auto *call = function->expr->to<IR::MethodCallExpression>()) {
2208 auto *typeArg = call->typeArguments->at(0);
2210 typeArg, p4RtTypeInfo);
2213 return std::nullopt;
2218 const IR::ParserBlock *parserBlock) {
2219 ::barefoot::PortMetadata portMetadata;
2220 portMetadata.mutable_type_spec()->CopyFrom(*portMetadataExtract.typeSpec);
2221 CHECK_NULL(parserBlock);
2222 auto parser = parserBlock->container;
2224 BUG_CHECK(ingressIntrinsicMdParamName.count(parserBlock),
2225 "%1%: Name of the intrinsic metadata not found for this parser block",
2227 portMetadata.set_key_name(ingressIntrinsicMdParamName[parserBlock]);
2228 addP4InfoExternInstance(symbols, SymbolType::P4RT_PORT_METADATA(),
"PortMetadata"_cs, name,
2229 nullptr, portMetadata, p4Info);
2233 p4configv1::P4Info *p4Info,
const cstring &name,
2234 const IR::ParserBlock *parserBlock) {
2235 ::barefoot::PortMetadata portMetadata;
2236 CHECK_NULL(parserBlock);
2237 auto parser = parserBlock->container;
2240 if (ingressIntrinsicMdParamName.count(parserBlock)) {
2241 portMetadata.set_key_name(ingressIntrinsicMdParamName[parserBlock]);
2244 auto const DP0TKN = BFN::getDefaultPhase0TableKeyName();
2245 portMetadata.set_key_name(DP0TKN);
2248 addP4InfoExternInstance(symbols, SymbolType::P4RT_PORT_METADATA(),
"PortMetadata"_cs, name,
2249 nullptr, portMetadata, p4Info);
2252 void addSnapshot(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2253 const SnapshotInfo &snapshotInstance) {
2254 ::barefoot::Snapshot snapshot;
2255 snapshot.set_pipe(snapshotInstance.pipe);
2256 if (snapshotInstance.gress ==
"ingress")
2257 snapshot.set_direction(::barefoot::DIRECTION_INGRESS);
2258 else if (snapshotInstance.gress ==
"egress")
2259 snapshot.set_direction(::barefoot::DIRECTION_EGRESS);
2261 BUG(
"Invalid gress '%1%'", snapshotInstance.gress);
2262 for (
const auto &f : snapshotInstance.fields) {
2263 auto newF = snapshot.add_fields();
2265 newF->set_name(f.name);
2266 newF->set_bitwidth(f.bitwidth);
2268 addP4InfoExternInstance(symbols, SymbolType::P4RT_SNAPSHOT(),
"Snapshot"_cs,
2269 snapshotInstance.name,
nullptr, snapshot, p4Info);
2272 void addParserChoices(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2273 cstring name, const ::barefoot::ParserChoices &parserChoices) {
2274 addP4InfoExternInstance(symbols, SymbolType::P4RT_PARSER_CHOICES(),
"ParserChoices"_cs,
2275 name,
nullptr, parserChoices, p4Info);
2278 void addLpf(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2279 const Lpf &lpfInstance,
const cstring pipeName) {
2280 auto lpfName = prefix(pipeName, lpfInstance.name);
2281 if (lpfInstance.table) {
2282 ::barefoot::DirectLpf lpf;
2283 auto tableName = prefix(pipeName, *lpfInstance.table);
2285 symbols.
getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
2286 lpf.set_direct_table_id(tableId);
2287 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_LPF(),
"DirectLpf"_cs, lpfName,
2288 lpfInstance.annotations, lpf, p4Info);
2289 LOG2(
"Added Instance - Direct LPF " << lpfName);
2291 ::barefoot::Lpf lpf;
2292 lpf.set_size(lpfInstance.size);
2293 addP4InfoExternInstance(symbols, SymbolType::P4RT_LPF(),
"Lpf"_cs, lpfName,
2294 lpfInstance.annotations, lpf, p4Info);
2295 LOG2(
"Added Instance - LPF " << lpfName);
2300 template <
typename Kind>
2302 using ::barefoot::WredSpec;
2303 auto wred_spec = wred->mutable_spec();
2304 wred_spec->set_drop_value(wredInstance.dropValue);
2305 wred_spec->set_no_drop_value(wredInstance.noDropValue);
2309 const Wred &wredInstance,
const cstring pipeName) {
2310 auto wredName = prefix(pipeName, wredInstance.name);
2311 if (wredInstance.
table) {
2312 ::barefoot::DirectWred wred;
2313 setWredCommon(&wred, wredInstance);
2314 auto tableName = prefix(pipeName, *wredInstance.
table);
2316 symbols.
getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
2317 wred.set_direct_table_id(tableId);
2318 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_WRED(),
"DirectWred"_cs,
2319 wredName, wredInstance.annotations, wred, p4Info);
2320 LOG2(
"Added Instance - Direct WRED " << wredName);
2322 ::barefoot::Wred wred;
2323 setWredCommon(&wred, wredInstance);
2324 wred.set_size(wredInstance.size);
2325 addP4InfoExternInstance(symbols, SymbolType::P4RT_WRED(),
"Wred"_cs, wredName,
2326 wredInstance.annotations, wred, p4Info);
2327 LOG2(
"Added Instance - WRED " << wredName);
2333 void addRegisterParam(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2334 const RegisterParam ®isterParamInstance,
2335 cstring pipeName = cstring::empty) {
2336 p4rt_id_t tableId = 0;
2337 if (registerParam2register.count(registerParamInstance.name) > 0)
2339 symbols.
getId(SymbolType::P4RT_REGISTER(),
2340 prefix(pipeName, registerParam2register[registerParamInstance.name]));
2341 else if (registerParam2table.count(registerParamInstance.name) > 0)
2343 symbols.
getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(),
2344 prefix(pipeName, registerParam2table[registerParamInstance.name]));
2346 ::barefoot::RegisterParam register_param_;
2347 register_param_.mutable_type_spec()->CopyFrom(*registerParamInstance.typeSpec);
2348 register_param_.set_table_id(tableId);
2349 register_param_.set_initial_value(registerParamInstance.initial_value);
2350 register_param_.set_data_field_name(registerParamInstance.name);
2351 auto registerParamName = prefix(pipeName, registerParamInstance.name);
2352 addP4InfoExternInstance(symbols, SymbolType::P4RT_REGISTER_PARAM(),
"RegisterParam"_cs,
2353 registerParamName, registerParamInstance.annotations,
2354 register_param_, p4Info);
2355 LOG2(
"Added Instance - RegisterParam " << registerParamName);
2360 std::unordered_set<cstring> snapshots;
2362 std::unordered_set<const IR::Block *> hasUserPortMetadata;
2366 std::unordered_map<const IR::ParserBlock *, cstring> ingressIntrinsicMdParamName;
2368 using SnapshotInfoMap = std::map<const IR::ControlBlock *, SnapshotInfo>;
2369 SnapshotInfoMap snapshotInfo;
2371 std::unordered_map<const IR::Block *, cstring> blockNamePrefixMap;
2373 std::map<cstring, ::barefoot::ParserChoices> parserConfiguration;
2378 std::unordered_map<cstring, cstring> registerParam2register;
2380 std::unordered_map<cstring, cstring> registerParam2table;