From f901822d3ccc520a54ffe9c5b1919ee94ef72cd9 Mon Sep 17 00:00:00 2001 From: fruffy Date: Thu, 25 Jan 2024 20:47:31 +0000 Subject: [PATCH] Basic support for `@p4runtime_translation` and `@p4runtime_translation_mappings`. --- backends/bmv2/common/annotations.h | 10 +- .../testgen/targets/bmv2/CMakeLists.txt | 48 +++--- .../modules/testgen/targets/bmv2/bmv2.cpp | 11 ++ .../targets/bmv2/p4runtime_translation.cpp | 69 +++++++++ .../targets/bmv2/p4runtime_translation.h | 31 ++++ .../targets/bmv2/test_backend/protobuf_ir.cpp | 144 ++++++++++++++---- .../targets/bmv2/test_backend/protobuf_ir.h | 32 +++- frontends/p4/parseAnnotations.h | 4 + 8 files changed, 287 insertions(+), 62 deletions(-) create mode 100644 backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp create mode 100644 backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h diff --git a/backends/bmv2/common/annotations.h b/backends/bmv2/common/annotations.h index b4bbc090fe3..a8015e4aa79 100644 --- a/backends/bmv2/common/annotations.h +++ b/backends/bmv2/common/annotations.h @@ -29,8 +29,14 @@ class ParseAnnotations : public P4::ParseAnnotations { public: ParseAnnotations() : P4::ParseAnnotations("BMV2", false, - {PARSE_EMPTY("metadata"), PARSE_EXPRESSION_LIST("field_list"), - PARSE("alias", StringLiteral), PARSE("priority", Constant)}) {} + { + PARSE_EMPTY("metadata"), + PARSE_EXPRESSION_LIST("field_list"), + PARSE("alias", StringLiteral), + PARSE("priority", Constant), + PARSE_EXPRESSION_LIST("p4runtime_translation_mappings"), + PARSE_P4RUNTIME_TRANSLATION("p4runtime_translation"), + }) {} }; } // namespace BMV2 diff --git a/backends/p4tools/modules/testgen/targets/bmv2/CMakeLists.txt b/backends/p4tools/modules/testgen/targets/bmv2/CMakeLists.txt index e3a0d98565c..d1c548cc407 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/CMakeLists.txt +++ b/backends/p4tools/modules/testgen/targets/bmv2/CMakeLists.txt @@ -5,29 +5,31 @@ if(ENABLE_TESTING) endif() # Source files for p4testgen. -set(TESTGEN_SOURCES - ${TESTGEN_SOURCES} - ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/common.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/protobuf.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/protobuf_ir.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/metadata.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/ptf.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/stf.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/bmv2.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/cmd_stepper.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/concolic.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/constants.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/contrib/bmv2_hash/calculations.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/expr_stepper.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/map_direct_externs.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/p4_asserts_parser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/p4_refers_to_parser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/program_info.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/table_stepper.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/target.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test_backend.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test_spec.cpp - PARENT_SCOPE +set( + TESTGEN_SOURCES + ${TESTGEN_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/common.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/protobuf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/protobuf_ir.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/metadata.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/ptf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_backend/stf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bmv2.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/cmd_stepper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/concolic.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/constants.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/contrib/bmv2_hash/calculations.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/expr_stepper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/map_direct_externs.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/p4_asserts_parser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/p4_refers_to_parser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/p4runtime_translation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/program_info.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/table_stepper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/target.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_backend.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_spec.cpp + PARENT_SCOPE ) set(TESTGEN_GTEST_SOURCES diff --git a/backends/p4tools/modules/testgen/targets/bmv2/bmv2.cpp b/backends/p4tools/modules/testgen/targets/bmv2/bmv2.cpp index 0af444d7856..6a4e7ee95aa 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/bmv2.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/bmv2.cpp @@ -1,5 +1,6 @@ #include "backends/p4tools/modules/testgen/targets/bmv2/bmv2.h" +#include #include #include @@ -7,13 +8,19 @@ #include "backends/p4tools/common/compiler/compiler_target.h" #include "backends/p4tools/common/compiler/midend.h" #include "frontends/common/options.h" +#include "frontends/common/resolveReferences/referenceMap.h" +#include "frontends/p4/typeChecking/typeChecker.h" +#include "frontends/p4/typeMap.h" #include "lib/cstring.h" +#include "lib/error.h" +#include "midend/coverage.h" #include "backends/p4tools/modules/testgen/core/compiler_target.h" #include "backends/p4tools/modules/testgen/options.h" #include "backends/p4tools/modules/testgen/targets/bmv2/map_direct_externs.h" #include "backends/p4tools/modules/testgen/targets/bmv2/p4_asserts_parser.h" #include "backends/p4tools/modules/testgen/targets/bmv2/p4_refers_to_parser.h" +#include "backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h" namespace P4Tools::P4Testgen::Bmv2 { @@ -106,9 +113,13 @@ CompilerResultOrError Bmv2V1ModelCompilerTarget::runCompilerImpl( MidEnd Bmv2V1ModelCompilerTarget::mkMidEnd(const CompilerOptions &options) const { MidEnd midEnd(options); + auto *refMap = midEnd.getRefMap(); + auto *typeMap = midEnd.getTypeMap(); midEnd.addPasses({ // Parse BMv2-specific annotations. new BMV2::ParseAnnotations(), + new P4::TypeChecking(refMap, typeMap, true), + new PropagateP4RuntimeTranslation(*typeMap), }); midEnd.addDefaultPasses(); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp new file mode 100644 index 00000000000..16745675936 --- /dev/null +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp @@ -0,0 +1,69 @@ +#include "backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h" + +std::vector +P4Tools::P4Testgen::Bmv2::PropagateP4RuntimeTranslation::lookupP4RuntimeAnnotations( + const P4::TypeMap &typeMap, const IR::Type *type) { + std::vector p4RuntimeAnnotations; + const auto *typeName = type->to(); + if (typeName != nullptr) { + type = typeMap.getType(typeName); + if (type == nullptr) { + ::error("Type %1% not found in the type map.", typeName); + return p4RuntimeAnnotations; + } + type = type->getP4Type(); + } + const auto *annotatedType = type->to(); + if (annotatedType == nullptr) { + return p4RuntimeAnnotations; + } + const auto *p4runtimeAnnotation = annotatedType->getAnnotation("p4runtime_translation"); + if (p4runtimeAnnotation != nullptr) { + BUG_CHECK(!p4runtimeAnnotation->needsParsing, + "The @p4runtime_translation annotation should have been parsed already."); + p4RuntimeAnnotations.push_back(p4runtimeAnnotation); + } + const auto *p4runtimeTranslationMappings = + annotatedType->getAnnotation("p4runtime_translation_mappings"); + if (p4runtimeTranslationMappings != nullptr) { + BUG_CHECK( + !p4runtimeTranslationMappings->needsParsing, + "The @p4runtime_translation_mappings annotation should have been parsed already."); + p4RuntimeAnnotations.push_back(p4runtimeTranslationMappings); + } + return p4RuntimeAnnotations; +} + +const IR::Parameter *P4Tools::P4Testgen::Bmv2::PropagateP4RuntimeTranslation::preorder( + IR::Parameter *parameter) { + auto p4RuntimeAnnotations = lookupP4RuntimeAnnotations(_typeMap, parameter->type); + if (p4RuntimeAnnotations.empty()) { + return parameter; + } + auto *annotationsVector = parameter->annotations->clone(); + for (const auto *p4runtimeAnnotation : p4RuntimeAnnotations) { + annotationsVector->annotations.push_back(p4runtimeAnnotation); + } + parameter->annotations = annotationsVector; + return parameter; +} + +const IR::KeyElement *P4Tools::P4Testgen::Bmv2::PropagateP4RuntimeTranslation::preorder( + IR::KeyElement *keyElement) { + auto p4RuntimeAnnotations = lookupP4RuntimeAnnotations(_typeMap, keyElement->expression->type); + if (p4RuntimeAnnotations.empty()) { + return keyElement; + } + auto *annotationsVector = keyElement->annotations->clone(); + for (const auto *p4runtimeAnnotation : p4RuntimeAnnotations) { + annotationsVector->annotations.push_back(p4runtimeAnnotation); + } + keyElement->annotations = annotationsVector; + return keyElement; +} + +P4Tools::P4Testgen::Bmv2::PropagateP4RuntimeTranslation::PropagateP4RuntimeTranslation( + const P4::TypeMap &typeMap) + : _typeMap(typeMap) { + setName("PropagateP4RuntimeTranslation"); +} diff --git a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h new file mode 100644 index 00000000000..d13ea270f1b --- /dev/null +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h @@ -0,0 +1,31 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_TESTGEN_TARGETS_BMV2_P4RUNTIME_TRANSLATION_H_ +#define BACKENDS_P4TOOLS_MODULES_TESTGEN_TARGETS_BMV2_P4RUNTIME_TRANSLATION_H_ +#include + +#include "frontends/p4/typeMap.h" +#include "ir/ir.h" +#include "ir/visitor.h" + +namespace P4Tools::P4Testgen::Bmv2 { + +/// Propagates P4Runtime annotations attached to type definitions to the nodes which use these type +/// definitions. For now, this is restricted to key elements and action parameters. +class PropagateP4RuntimeTranslation : public Transform { + /// We use the typemap to look up the original declaration for type reference. + /// These declarations may have an annotation. + std::reference_wrapper _typeMap; + + /// Look up annotations relevant to P4Runtime. They may influence the control plane interfaces. + static std::vector lookupP4RuntimeAnnotations( + const P4::TypeMap &typeMap, const IR::Type *type); + + const IR::Parameter *preorder(IR::Parameter *parameter) override; + const IR::KeyElement *preorder(IR::KeyElement *keyElement) override; + + public: + explicit PropagateP4RuntimeTranslation(const P4::TypeMap &typeMap); +}; + +} // namespace P4Tools::P4Testgen::Bmv2 + +#endif /* BACKENDS_P4TOOLS_MODULES_TESTGEN_TARGETS_BMV2_P4RUNTIME_TRANSLATION_H_ */ diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp index 41d9f39f211..5f2bdb3e66f 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp @@ -8,7 +8,9 @@ #include +#include "backends/p4tools/common/lib/format_int.h" #include "backends/p4tools/common/lib/util.h" +#include "frontends/parsers/parserDriver.h" #include "lib/exceptions.h" #include "lib/log.h" #include "nlohmann/json.hpp" @@ -21,26 +23,76 @@ namespace P4Tools::P4Testgen::Bmv2 { ProtobufIr::ProtobufIr(const TestBackendConfiguration &testBackendConfiguration) : Bmv2TestFramework(testBackendConfiguration) {} +std::optional ProtobufIr::checkForP4RuntimeTranslationAnnotation( + const IR::IAnnotated *node) { + const auto *p4RuntimeTranslationAnnotation = node->getAnnotation("p4runtime_translation"); + if (p4RuntimeTranslationAnnotation == nullptr) { + return std::nullopt; + } + auto annotationVector = p4RuntimeTranslationAnnotation->expr; + BUG_CHECK(annotationVector.size() == 2, "Expected size of %1% to be 2. ", annotationVector); + const auto *targetValue = annotationVector.at(1); + if (targetValue->is()) { + return "str"; + } + // An integer technically specifies a width but that is not (yet) of any concern to us. + if (targetValue->is()) { + return "hex_str"; + } + TESTGEN_UNIMPLEMENTED("Unsupported @p4runtime_translation token %1%", targetValue); +} + +std::map ProtobufIr::getP4RuntimeTranslationMappings(const IR::IAnnotated *node) { + std::map p4RuntimeTranslationMappings; + const auto *p4RuntimeTranslationMappingAnnotation = + node->getAnnotation("p4runtime_translation_mappings"); + if (p4RuntimeTranslationMappingAnnotation == nullptr) { + return p4RuntimeTranslationMappings; + } + BUG_CHECK(!p4RuntimeTranslationMappingAnnotation->needsParsing, + "The @p4runtime_translation_mappings annotation should have been parsed already."); + auto annotationExpr = p4RuntimeTranslationMappingAnnotation->expr; + BUG_CHECK(annotationExpr.size() == 1, "Expected size of %1% to be 1. ", annotationExpr); + const auto *exprList = annotationExpr.at(0)->checkedTo(); + for (const auto *expr : exprList->components) { + const auto *exprTuple = expr->checkedTo(); + const auto &components = exprTuple->components; + auto left = components.at(0)->checkedTo()->value; + auto right = components.at(1)->checkedTo()->value; + p4RuntimeTranslationMappings.emplace(right.str().c_str(), left); + } + + return p4RuntimeTranslationMappings; +} + std::string ProtobufIr::getFormatOfNode(const IR::IAnnotated *node) { + auto p4RuntimeTranslationFormat = checkForP4RuntimeTranslationAnnotation(node); + if (p4RuntimeTranslationFormat.has_value()) { + return p4RuntimeTranslationFormat.value(); + } + const auto *formatAnnotation = node->getAnnotation("format"); - std::string formatString = "hex_str"; - if (formatAnnotation != nullptr) { - BUG_CHECK(formatAnnotation->body.size() == 1, - "@format annotation can only have one member."); - auto formatString = formatAnnotation->body.at(0)->text; - if (formatString == "IPV4_ADDRESS") { - formatString = "ipv4"; - } else if (formatString == "IPV6_ADDRESS") { - formatString = "ipv6"; - } else if (formatString == "MAC_ADDRESS") { - formatString = "mac"; - } else if (formatString == "HEX_STR") { - formatString = "hex_str"; - } else { - TESTGEN_UNIMPLEMENTED("Unsupported @format string %1%", formatString); - } + if (formatAnnotation == nullptr) { + return "hex_str"; + } + BUG_CHECK(formatAnnotation->body.size() == 1, "@format annotation can only have one member."); + auto annotationFormatString = formatAnnotation->body.at(0)->text; + if (annotationFormatString == "IPV4_ADDRESS") { + return "ipv4"; + } + if (annotationFormatString == "IPV6_ADDRESS") { + return "ipv6"; } - return formatString; + if (annotationFormatString == "MAC_ADDRESS") { + return "mac"; + } + if (annotationFormatString == "HEX_STR") { + return "hex_str"; + } + if (annotationFormatString == "STRING") { + return "str"; + } + TESTGEN_UNIMPLEMENTED("Unsupported @format string %1%", annotationFormatString); } std::string ProtobufIr::getTestCaseTemplate() { @@ -168,7 +220,21 @@ entities { std::string ProtobufIr::formatNetworkValue(const std::string &type, const IR::Expression *value) { if (type == "hex_str") { - return formatHexExpr(value, {false, true, false, false}); + return formatHexExpr(value, {false, true, true, false}); + } + // Assume that any string format can be converted from a string literal, bool + // literal, or constant. + if (type == "str") { + if (const auto *constant = value->to()) { + return constant->value.str(); + } + if (const auto *literal = value->to()) { + return literal->value.c_str(); + } + if (const auto *boolValue = value->to()) { + return boolValue->value ? "true" : "false"; + } + TESTGEN_UNIMPLEMENTED("Unsupported string format value \"%1%\".", value); } // At this point, any value must be a constant. const auto *constant = value->checkedTo(); @@ -196,31 +262,49 @@ std::string ProtobufIr::formatNetworkValue(const std::string &type, const IR::Ex TESTGEN_UNIMPLEMENTED("Unsupported network value type %1%", type); } +std::string ProtobufIr::formatNetworkValue(const IR::IAnnotated *node, const std::string &type, + const IR::Expression *value) { + auto p4RuntimeTranslationMappings = getP4RuntimeTranslationMappings(node); + auto formattedNetworkValue = formatNetworkValue(type, value); + + auto it = p4RuntimeTranslationMappings.find(formattedNetworkValue); + if (it != p4RuntimeTranslationMappings.end()) { + return (*it).second.c_str(); + } + + return formattedNetworkValue; +} + void ProtobufIr::createKeyMatch(cstring fieldName, const TableMatch &fieldMatch, inja::json &rulesJson) { inja::json j; j["field_name"] = fieldName; - j["format"] = getFormatOfNode(fieldMatch.getKey()); + const auto *keyElement = fieldMatch.getKey(); + j["format"] = getFormatOfNode(keyElement); if (const auto *elem = fieldMatch.to()) { - j["value"] = formatNetworkValue(j["format"], elem->getEvaluatedValue()).c_str(); + j["value"] = formatNetworkValue(keyElement, j["format"], elem->getEvaluatedValue()).c_str(); rulesJson["single_exact_matches"].push_back(j); } else if (const auto *elem = fieldMatch.to()) { - j["lo"] = formatNetworkValue(j["format"], elem->getEvaluatedLow()).c_str(); - j["hi"] = formatNetworkValue(j["format"], elem->getEvaluatedHigh()).c_str(); + j["lo"] = formatNetworkValue(keyElement, j["format"], elem->getEvaluatedLow()).c_str(); + j["hi"] = formatNetworkValue(keyElement, j["format"], elem->getEvaluatedHigh()).c_str(); rulesJson["range_matches"].push_back(j); } else if (const auto *elem = fieldMatch.to()) { - j["value"] = formatNetworkValue(j["format"], elem->getEvaluatedValue()).c_str(); - j["mask"] = formatNetworkValue(j["format"], elem->getEvaluatedMask()).c_str(); - rulesJson["ternary_matches"].push_back(j); // If the rule has a ternary match we need to add the priority. rulesJson["needs_priority"] = true; + // Skip any ternary match where the mask is all zeroes. + if (elem->getEvaluatedMask()->value == 0) { + return; + } + j["value"] = formatNetworkValue(keyElement, j["format"], elem->getEvaluatedValue()).c_str(); + j["mask"] = formatNetworkValue(keyElement, j["format"], elem->getEvaluatedMask()).c_str(); + rulesJson["ternary_matches"].push_back(j); } else if (const auto *elem = fieldMatch.to()) { - j["value"] = formatNetworkValue(j["format"], elem->getEvaluatedValue()).c_str(); + j["value"] = formatNetworkValue(keyElement, j["format"], elem->getEvaluatedValue()).c_str(); j["prefix_len"] = elem->getEvaluatedPrefixLength()->value.str(); rulesJson["lpm_matches"].push_back(j); } else if (const auto *elem = fieldMatch.to()) { - j["value"] = formatNetworkValue(j["format"], elem->getEvaluatedValue()).c_str(); + j["value"] = formatNetworkValue(keyElement, j["format"], elem->getEvaluatedValue()).c_str(); if (elem->addAsExactMatch()) { j["use_exact"] = "True"; } else { @@ -255,10 +339,12 @@ inja::json ProtobufIr::getControlPlaneForTable(const TableMatchMap &matches, for (const auto &actArg : args) { inja::json j; - j["format"] = getFormatOfNode(actArg.getActionParam()); + const auto *actionParameter = actArg.getActionParam(); + j["format"] = getFormatOfNode(actionParameter); j["param"] = actArg.getActionParamName().c_str(); - j["value"] = formatNetworkValue(j["format"], actArg.getEvaluatedValue()).c_str(); + j["value"] = + formatNetworkValue(actionParameter, j["format"], actArg.getEvaluatedValue()).c_str(); rulesJson["act_args"].push_back(j); } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.h b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.h index 07ab6a3845b..527bdde4da1 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.h +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.h @@ -35,24 +35,40 @@ class ProtobufIr : public Bmv2TestFramework { private: /// Emits a test case. /// @param testId specifies the test name. - /// @param selectedBranches enumerates the choices the interpreter made for this path. - /// @param currentCoverage contains statistics about the current coverage of this test and its - /// preceding tests. + /// @param selectedBranches enumerates the choices the interpreter made for + /// this path. + /// @param currentCoverage contains statistics about the current coverage of + /// this test and its preceding tests. void emitTestcase(const TestSpec *testSpec, cstring selectedBranches, size_t testId, const std::string &testCase, float currentCoverage); /// @returns the inja test case template as a string. static std::string getTestCaseTemplate(); - /// Tries to find the @format annotation of a node and, if present, returns the format specified - /// in this annotation. Returns "hex" by default. + /// Checks whether the node has a `@p4runtime_translation` attached to it. If + /// that is the case, returns the translated type contained within the + /// annotation. + static std::optional checkForP4RuntimeTranslationAnnotation( + const IR::IAnnotated *node); + + /// Looks up annotations for the given node and returns the P4RuntimeTranslationMappings, + /// if they exist. Currently, this map is a pure cstring map. + static std::map getP4RuntimeTranslationMappings(const IR::IAnnotated *node); + + /// Tries to find the @format annotation of a node and, if present, returns + /// the format specified in this annotation. Returns "hex" by default. static std::string getFormatOfNode(const IR::IAnnotated *node); - /// Converts an IR::Expression into a formatted string value. The format depends on @param type. + /// Converts an IR::Expression into a formatted string value. The format + /// depends on @param type. static std::string formatNetworkValue(const std::string &type, const IR::Expression *value); - /// Fill in @param rulesJson by iterating over @param fieldMatch and creating the appropriate - /// match key. + /// see @formatNetworkValue. The node may have annotations which influence the format. + static std::string formatNetworkValue(const IR::IAnnotated *node, const std::string &type, + const IR::Expression *value); + + /// Fill in @param rulesJson by iterating over @param fieldMatch and creating + /// the appropriate match key. static void createKeyMatch(cstring fieldName, const TableMatch &fieldMatch, inja::json &rulesJson); }; diff --git a/frontends/p4/parseAnnotations.h b/frontends/p4/parseAnnotations.h index c8f286336f5..947c49e0321 100644 --- a/frontends/p4/parseAnnotations.h +++ b/frontends/p4/parseAnnotations.h @@ -107,6 +107,10 @@ namespace P4 { #define PARSE_STRING_LITERAL_LIST(aname) \ { aname, &P4::ParseAnnotations::parseStringLiteralList } +// Parses a P4Runtime translation which contains both types or expressions. +#define PARSE_P4RUNTIME_TRANSLATION(aname) \ + { aname, &P4::ParseAnnotations::parseP4rtTranslationAnnotation } + class ParseAnnotations : public Modifier { public: using Modifier::postorder;