530    using Counter = p4configv1::Counter;
 
  531    using Meter = p4configv1::Meter;
 
  532    using CounterSpec = p4configv1::CounterSpec;
 
  533    using MeterSpec = p4configv1::MeterSpec;
 
  536                               const IR::ToplevelBlock *evaluatedProgram)
 
  537        : refMap(refMap), typeMap(typeMap), evaluatedProgram(evaluatedProgram) {
 
  538        jsonPrintOptions.add_whitespace = 
true;
 
  542                                const IR::TableBlock *tableBlock)
 override {
 
  543        CHECK_NULL(tableBlock);
 
  544        auto table = tableBlock->container;
 
  545        bool isConstructedInPlace = 
false;
 
  550                                              refMap, typeMap, &isConstructedInPlace);
 
  554                    ::error(ErrorType::ERR_EXPECTED,
 
  555                            "Expected an action profile or action selector: %1%",
 
  556                            instance->expression);
 
  557                } 
else if (isConstructedInPlace) {
 
  558                    symbols->
add(SymbolType::P4RT_ACTION_PROFILE(), *instance->name);
 
  563            auto instance = getExternInstanceFromProperty(
 
  564                table, CounterTraits::directPropertyName(), refMap, typeMap, &isConstructedInPlace);
 
  566                if (instance->type->name != CounterTraits::directTypeName()) {
 
  567                    ::error(ErrorType::ERR_EXPECTED, 
"Expected a direct counter: %1%",
 
  568                            instance->expression);
 
  569                } 
else if (isConstructedInPlace) {
 
  570                    symbols->
add(SymbolType::P4RT_DIRECT_COUNTER(), *instance->name);
 
  575            auto instance = getExternInstanceFromProperty(table, MeterTraits::directPropertyName(),
 
  576                                                          refMap, typeMap, &isConstructedInPlace);
 
  578                if (instance->type->name != MeterTraits::directTypeName()) {
 
  579                    ::error(ErrorType::ERR_EXPECTED, 
"Expected a direct meter: %1%",
 
  580                            instance->expression);
 
  581                } 
else if (isConstructedInPlace) {
 
  582                    symbols->
add(SymbolType::P4RT_DIRECT_METER(), *instance->name);
 
 
  589                                    const IR::AssignmentStatement *)
 override {}
 
 
  594                               const IR::ExternBlock *externBlock)
 override {
 
  595        CHECK_NULL(externBlock);
 
  601        if (decl == 
nullptr) 
return;
 
  603        if (externBlock->type->name == CounterTraits::typeName()) {
 
  604            symbols->
add(SymbolType::P4RT_COUNTER(), decl);
 
  605        } 
else if (externBlock->type->name == CounterTraits::directTypeName()) {
 
  606            symbols->
add(SymbolType::P4RT_DIRECT_COUNTER(), decl);
 
  607        } 
else if (externBlock->type->name == MeterTraits::typeName()) {
 
  608            symbols->
add(SymbolType::P4RT_METER(), decl);
 
  609        } 
else if (externBlock->type->name == MeterTraits::directTypeName()) {
 
  610            symbols->
add(SymbolType::P4RT_DIRECT_METER(), decl);
 
  613            symbols->
add(SymbolType::P4RT_ACTION_PROFILE(), decl);
 
  615            symbols->
add(SymbolType::P4RT_REGISTER(), decl);
 
 
  623        (void)externFunction;
 
 
  636            if (!block->is<IR::TableBlock>()) 
return;
 
  637            auto table = block->to<IR::TableBlock>()->container;
 
  638            auto implementation = getTableImplementationName(table, refMap);
 
  640                actionProfilesRefs[*implementation].insert(table->controlPlaneName());
 
 
  645                            p4configv1::Table *table, 
const IR::TableBlock *tableBlock)
 override {
 
  646        CHECK_NULL(tableBlock);
 
  647        auto tableDeclaration = tableBlock->container;
 
  651        auto implementation = getActionProfile(tableDeclaration, refMap, typeMap);
 
  657        if (implementation) {
 
  658            auto id = symbols.
getId(SymbolType::P4RT_ACTION_PROFILE(), implementation->name);
 
  659            table->set_implementation_id(
id);
 
  661            if (isExternPropertyConstructedInPlace(tableDeclaration, propertyName))
 
  662                addActionProfile(symbols, p4info, *implementation);
 
  666            auto id = symbols.
getId(SymbolType::P4RT_DIRECT_COUNTER(), directCounter->name);
 
  667            table->add_direct_resource_ids(
id);
 
  669            addCounter(symbols, p4info, *directCounter);
 
  673            auto id = symbols.
getId(SymbolType::P4RT_DIRECT_METER(), directMeter->name);
 
  674            table->add_direct_resource_ids(
id);
 
  676            addMeter(symbols, p4info, *directMeter);
 
  680    void addExternInstance(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
 
  681                           const IR::ExternBlock *externBlock)
 override {
 
  682        auto decl = externBlock->node->to<IR::Declaration_Instance>();
 
  683        if (decl == 
nullptr) 
return;
 
  685        auto p4RtTypeInfo = p4info->mutable_type_info();
 
  686        if (externBlock->type->name == CounterTraits::typeName()) {
 
  688                                                                         typeMap, p4RtTypeInfo);
 
  689            if (counter) addCounter(symbols, p4info, *counter);
 
  690        } 
else if (externBlock->type->name == MeterTraits::typeName()) {
 
  693            if (meter) addMeter(symbols, p4info, *meter);
 
  694        } 
else if (externBlock->type->name == RegisterTraits<arch>::typeName()) {
 
  696            if (register_) addRegister(symbols, p4info, *register_);
 
  697        } 
else if (externBlock->type->name == ActionProfileTraits<arch>::typeName() ||
 
  698                   externBlock->type->name == ActionSelectorTraits<arch>::typeName()) {
 
  699            auto actionProfile = getActionProfile(externBlock);
 
  700            if (actionProfile) addActionProfile(symbols, p4info, *actionProfile);
 
  704    void addExternFunction(
const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
 
  710                          const IR::ExternBlock *)
 override {}
 
 
  714        return jsonPrintOptions;
 
 
  717    static std::optional<ActionProfile> getActionProfile(
cstring name, 
const IR::Type_Extern *type,
 
  719                                                         const IR::IAnnotated *annotations) {
 
  722            actionProfileType = ActionProfileType::INDIRECT_WITH_SELECTOR;
 
  723        } 
else if (type->name == ActionProfileTraits<arch>::typeName()) {
 
  724            actionProfileType = ActionProfileType::INDIRECT;
 
  729        return ActionProfile{name, actionProfileType, size, annotations};
 
  737        auto instance = getExternInstanceFromProperty(table, propertyName, refMap, typeMap);
 
  738        if (!instance) 
return std::nullopt;
 
  741        if (!size->template is<IR::Constant>()) {
 
  742            ::error(ErrorType::ERR_INVALID, 
"Action profile '%1%' has non-constant size '%2%'",
 
  743                    *instance->name, size);
 
  746        return getActionProfile(*instance->name, instance->type,
 
  747                                size->template to<IR::Constant>()->asInt(),
 
  748                                getTableImplementationAnnotations(table, refMap));
 
 
  755        if (!size->template is<IR::Constant>()) {
 
  756            ::error(ErrorType::ERR_INVALID, 
"Action profile '%1%' has non-constant size '%2%'",
 
  757                    decl->controlPlaneName(), size);
 
  760        return getActionProfile(decl->controlPlaneName(), instance->type,
 
  761                                size->template to<IR::Constant>()->asInt(),
 
  762                                decl->
to<IR::IAnnotated>());
 
 
  767        auto profile = p4Info->add_action_profiles();
 
  768        auto id = symbols.
getId(SymbolType::P4RT_ACTION_PROFILE(), actionProfile.name);
 
  769        setPreamble(profile->mutable_preamble(), 
id, actionProfile.name,
 
  770                    symbols.
getAlias(actionProfile.name), actionProfile.annotations,
 
  774                        return name == 
"max_group_size" || name == 
"selector_size_semantics" ||
 
  775                               name == 
"max_member_weight";
 
  777        profile->set_with_selector(actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR);
 
  778        profile->set_size(actionProfile.size);
 
  779        auto maxGroupSizeAnnotation = actionProfile.annotations->getAnnotation(
"max_group_size"_cs);
 
  780        if (maxGroupSizeAnnotation) {
 
  781            if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR) {
 
  782                auto maxGroupSizeConstant =
 
  783                    maxGroupSizeAnnotation->expr[0]->checkedTo<IR::Constant>();
 
  784                CHECK_NULL(maxGroupSizeConstant);
 
  785                profile->set_max_group_size(maxGroupSizeConstant->asInt());
 
  787                ::warning(ErrorType::WARN_IGNORE,
 
  788                          "Ignoring annotation @max_group_size on action profile '%1%', " 
  789                          "which does not have a selector",
 
  790                          actionProfile.annotations);
 
  795        auto selectorSizeSemanticsAnnotation =
 
  796            actionProfile.annotations->getAnnotation(
"selector_size_semantics"_cs);
 
  797        if (selectorSizeSemanticsAnnotation) {
 
  798            if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR) {
 
  799                auto selectorSizeSemantics =
 
  800                    selectorSizeSemanticsAnnotation->expr[0]->checkedTo<IR::StringLiteral>();
 
  801                CHECK_NULL(selectorSizeSemantics);
 
  804                if (selectorSizeSemantics->value.toUpper() == 
"SUM_OF_WEIGHTS") {
 
  805                    profile->mutable_sum_of_weights();
 
  806                } 
else if (selectorSizeSemantics->value.toUpper() == 
"SUM_OF_MEMBERS") {
 
  807                    profile->mutable_sum_of_members();
 
  809                    ::error(ErrorType::ERR_INVALID,
 
  810                            "Expected selector_size_semantics value \"sum_of_weights\" or " 
  811                            "\"sum_of_members\", but got '%1%'",
 
  812                            selectorSizeSemantics);
 
  815                ::warning(ErrorType::WARN_IGNORE,
 
  816                          "Ignoring annotation @selector_size_semantics on action " 
  817                          "profile '%1%', which does not have a selector ",
 
  818                          actionProfile.annotations);
 
  823        auto maxMemberWeightAnnotation =
 
  824            actionProfile.annotations->getAnnotation(
"max_member_weight"_cs);
 
  825        if (maxMemberWeightAnnotation) {
 
  826            if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR &&
 
  827                profile->has_sum_of_members()) {
 
  828                auto maxMemberWeightConstant =
 
  829                    maxMemberWeightAnnotation->expr[0]->checkedTo<IR::Constant>();
 
  830                CHECK_NULL(maxMemberWeightConstant);
 
  831                profile->mutable_sum_of_members()->set_max_member_weight(
 
  832                    maxMemberWeightConstant->asInt());
 
  833            } 
else if (actionProfile.type != ActionProfileType::INDIRECT_WITH_SELECTOR) {
 
  834                ::warning(ErrorType::WARN_IGNORE,
 
  835                          "Ignoring annotation @max_member_weight on action profile " 
  836                          "'%1%', which does not have a selector",
 
  837                          actionProfile.annotations);
 
  839                ::warning(ErrorType::WARN_IGNORE,
 
  840                          "Ignoring annotation @max_member_weight on action profile '%1%', " 
  841                          "which does not use 'sum_of_members' as its SelectorSizeSemantics",
 
  842                          actionProfile.annotations);
 
  846        auto tablesIt = actionProfilesRefs.find(actionProfile.name);
 
  847        if (tablesIt != actionProfilesRefs.end()) {
 
  848            for (
const auto &table : tablesIt->second)
 
  849                profile->add_table_ids(symbols.getId(P4RuntimeSymbolType::P4RT_TABLE(), table));
 
  854    template <
typename Kind>
 
  857        setPreamble(counter->mutable_preamble(), 
id, counterInstance.
name,
 
  859        auto counter_spec = counter->mutable_spec();
 
  860        counter_spec->set_unit(CounterTraits::mapUnitName(counterInstance.
unit));
 
 
  865        if (counterInstance.
table) {
 
  866            auto counter = p4Info->add_direct_counters();
 
  867            auto id = symbols.
getId(SymbolType::P4RT_DIRECT_COUNTER(), counterInstance.
name);
 
  869            auto tableId = symbols.
getId(P4RuntimeSymbolType::P4RT_TABLE(), *counterInstance.
table);
 
  870            counter->set_direct_table_id(tableId);
 
  872            auto counter = p4Info->add_counters();
 
  873            auto id = symbols.
getId(SymbolType::P4RT_COUNTER(), counterInstance.
name);
 
  875            counter->set_size(counterInstance.
size);
 
  877                counter->mutable_index_type_name()->set_name(counterInstance.
index_type_name);
 
  883    template <
typename Kind>
 
  886        setPreamble(meter->mutable_preamble(), 
id, meterInstance.
name,
 
  888        auto meter_spec = meter->mutable_spec();
 
  889        meter_spec->set_unit(MeterTraits::mapUnitName(meterInstance.
unit));
 
 
  894        if (meterInstance.
table) {
 
  895            auto meter = p4Info->add_direct_meters();
 
  896            auto id = symbols.
getId(SymbolType::P4RT_DIRECT_METER(), meterInstance.
name);
 
  898            auto tableId = symbols.
getId(P4RuntimeSymbolType::P4RT_TABLE(), *meterInstance.
table);
 
  899            meter->set_direct_table_id(tableId);
 
  901            auto meter = p4Info->add_meters();
 
  902            auto id = symbols.
getId(SymbolType::P4RT_METER(), meterInstance.
name);
 
  904            meter->set_size(meterInstance.
size);
 
  906                meter->mutable_index_type_name()->set_name(meterInstance.
index_type_name);
 
  911    void addRegister(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
 
  912                     const Register ®isterInstance) {
 
  913        auto register_ = p4Info->add_registers();
 
  914        auto id = symbols.getId(SymbolType::P4RT_REGISTER(), registerInstance.name);
 
  915        setPreamble(register_->mutable_preamble(), 
id, registerInstance.name,
 
  916                    symbols.getAlias(registerInstance.name), registerInstance.annotations);
 
  917        register_->set_size(registerInstance.size);
 
  918        register_->mutable_type_spec()->CopyFrom(*registerInstance.typeSpec);
 
  919        if (registerInstance.index_type_name) {
 
  920            register_->mutable_index_type_name()->set_name(registerInstance.index_type_name);
 
  924    void addDigest(
const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
 
  925                   const Digest &digest) {
 
  930        auto id = symbols.getId(SymbolType::P4RT_DIGEST(), digest.name);
 
  934        auto *digestInstance = p4Info->add_digests();
 
  935        setPreamble(digestInstance->mutable_preamble(), 
id, digest.name,
 
  936                    symbols.getAlias(digest.name), digest.annotations);
 
  937        digestInstance->mutable_type_spec()->CopyFrom(*digest.typeSpec);
 
  946    static const IR::IAnnotated *getTableImplementationAnnotations(
const IR::P4Table *table,
 
  952        if (impl == 
nullptr) 
return nullptr;
 
  953        if (!impl->value->is<IR::ExpressionValue>()) 
return nullptr;
 
  954        auto expr = impl->value->to<IR::ExpressionValue>()->expression;
 
  955        if (expr->is<IR::ConstructorCallExpression>()) 
return impl->to<IR::IAnnotated>();
 
  956        if (expr->is<IR::PathExpression>()) {
 
  957            auto decl = refMap->
getDeclaration(expr->to<IR::PathExpression>()->path, 
true);
 
  958            return decl->
to<IR::IAnnotated>();
 
  963    static std::optional<cstring> getTableImplementationName(
const IR::P4Table *table,
 
  966        if (impl == 
nullptr) 
return std::nullopt;
 
  967        if (!impl->value->is<IR::ExpressionValue>()) {
 
  968            ::error(ErrorType::ERR_EXPECTED,
 
  969                    "Expected implementation property value for table %1% to be an expression: %2%",
 
  970                    table->controlPlaneName(), impl);
 
  973        auto expr = impl->value->to<IR::ExpressionValue>()->expression;
 
  974        if (expr->is<IR::ConstructorCallExpression>()) 
return impl->controlPlaneName();
 
  975        if (expr->is<IR::PathExpression>()) {
 
  976            auto decl = refMap->
getDeclaration(expr->to<IR::PathExpression>()->path, 
true);
 
  977            return decl->controlPlaneName();
 
  982    ReferenceMap *refMap;
 
  984    const IR::ToplevelBlock *evaluatedProgram;
 
  986    std::unordered_map<cstring, std::set<cstring>> actionProfilesRefs;
 
  992    google::protobuf::util::JsonPrintOptions jsonPrintOptions;