From 269d0d3eeb44bb9f8df29bec549c570c611cc464 Mon Sep 17 00:00:00 2001 From: fruffy Date: Thu, 4 Jul 2024 11:27:48 -0400 Subject: [PATCH] Options refactor. Signed-off-by: fruffy --- backends/p4tools/BUILD.bazel | 4 +- .../common/compiler/compiler_target.cpp | 20 --- .../p4tools/common/compiler/compiler_target.h | 18 -- backends/p4tools/common/compiler/context.h | 8 +- backends/p4tools/common/core/target.cpp | 97 +++++++++-- backends/p4tools/common/core/target.h | 21 ++- backends/p4tools/common/options.cpp | 155 +----------------- backends/p4tools/common/options.h | 9 +- backends/p4tools/common/p4ctool.h | 15 +- .../p4tools/modules/smith/core/target.cpp | 6 + backends/p4tools/modules/smith/core/target.h | 2 + backends/p4tools/modules/smith/options.cpp | 5 - backends/p4tools/modules/smith/options.h | 7 +- backends/p4tools/modules/smith/smith.cpp | 16 +- .../p4tools/modules/testgen/core/target.cpp | 5 + .../p4tools/modules/testgen/core/target.h | 2 + backends/p4tools/modules/testgen/options.cpp | 10 +- backends/p4tools/modules/testgen/options.h | 6 +- .../testgen/targets/bmv2/test/gtest_utils.h | 29 +++- .../bmv2/test/testgen_api/api_test.cpp | 17 +- .../bmv2/test/testgen_api/benchmark.cpp | 18 +- .../testgen_api/control_plane_filter_test.cpp | 29 +--- .../test/testgen_api/output_option_test.cpp | 17 +- .../modules/testgen/test/gtest_utils.cpp | 15 +- .../modules/testgen/test/gtest_utils.h | 24 ++- backends/p4tools/modules/testgen/testgen.cpp | 33 ++-- backends/p4tools/modules/testgen/testgen.h | 10 +- 27 files changed, 265 insertions(+), 333 deletions(-) diff --git a/backends/p4tools/BUILD.bazel b/backends/p4tools/BUILD.bazel index a14608e84f..b4e2c9af88 100644 --- a/backends/p4tools/BUILD.bazel +++ b/backends/p4tools/BUILD.bazel @@ -117,11 +117,11 @@ filegroup( srcs = glob( ["modules/testgen/targets/%s/**/*.h" % target for target in TESTGEN_TARGETS], - exclude = ["modules/testgen/targets/%s/test/**" % target for target in TESTGEN_TARGETS], + exclude = ["modules/testgen/targets/%s/test/**/*.h" % target for target in TESTGEN_TARGETS], ) + glob( ["modules/testgen/targets/%s/**/*.cpp" % target for target in TESTGEN_TARGETS], - exclude = ["modules/testgen/targets/%s/test/**" % target for target in TESTGEN_TARGETS], + exclude = ["modules/testgen/targets/%s/test/**/*.cpp" % target for target in TESTGEN_TARGETS], ), ) diff --git a/backends/p4tools/common/compiler/compiler_target.cpp b/backends/p4tools/common/compiler/compiler_target.cpp index bfdc368e65..f140b0e25d 100644 --- a/backends/p4tools/common/compiler/compiler_target.cpp +++ b/backends/p4tools/common/compiler/compiler_target.cpp @@ -1,9 +1,7 @@ #include "backends/p4tools/common/compiler/compiler_target.h" #include -#include -#include "backends/p4tools/common/compiler/context.h" #include "backends/p4tools/common/compiler/midend.h" #include "backends/p4tools/common/core/target.h" #include "frontends/common/applyOptionsPragmas.h" @@ -16,15 +14,6 @@ namespace P4::P4Tools { -ICompileContext *CompilerTarget::makeContext(std::string_view toolName) { - return get(toolName).makeContextImpl(); -} - -std::vector *CompilerTarget::initCompiler(std::string_view toolName, int argc, - char **argv) { - return get(toolName).initCompilerImpl(argc, argv); -} - CompilerResultOrError CompilerTarget::runCompiler(const CompilerOptions &options, std::string_view toolName) { const auto *program = P4Tools::CompilerTarget::runParser(options); @@ -67,15 +56,6 @@ CompilerResultOrError CompilerTarget::runCompilerImpl(const CompilerOptions &opt return *new CompilerResult(*program); } -ICompileContext *CompilerTarget::makeContextImpl() const { - return new CompileContext(); -} - -std::vector *CompilerTarget::initCompilerImpl(int argc, char **argv) const { - auto *result = CompileContext::get().options().process(argc, argv); - return ::P4::errorCount() > 0 ? nullptr : result; -} - const IR::P4Program *CompilerTarget::runParser(const ParserOptions &options) { const auto *program = P4::parseP4File(options); if (::P4::errorCount() > 0) { diff --git a/backends/p4tools/common/compiler/compiler_target.h b/backends/p4tools/common/compiler/compiler_target.h index 4c09c4f3c6..33c673fbde 100644 --- a/backends/p4tools/common/compiler/compiler_target.h +++ b/backends/p4tools/common/compiler/compiler_target.h @@ -2,7 +2,6 @@ #define BACKENDS_P4TOOLS_COMMON_COMPILER_COMPILER_TARGET_H_ #include -#include #include "backends/p4tools/common/compiler/compiler_result.h" #include "backends/p4tools/common/compiler/context.h" @@ -19,15 +18,6 @@ namespace P4::P4Tools { /// Encapsulates the details of invoking the P4 compiler for a target device and architecture. class CompilerTarget : public Target { public: - /// @returns a new compilation context for the compiler. - static ICompileContext *makeContext(std::string_view toolName); - - /// Initializes the P4 compiler with the given compiler-specific command-line arguments. - /// - /// @returns any unprocessed arguments, or nullptr if there was an error. - static std::vector *initCompiler(std::string_view toolName, int argc, - char **argv); - /// Runs the P4 compiler to produce an IR and various other kinds of information on the input /// program. /// @@ -49,18 +39,10 @@ class CompilerTarget : public Target { std::string_view toolName, const IR::P4Program *); protected: - /// @see @makeContext. - [[nodiscard]] virtual ICompileContext *makeContextImpl() const; - /// @see runCompiler. virtual CompilerResultOrError runCompilerImpl(const CompilerOptions &options, const IR::P4Program *) const; - /// This implementation just forwards the given arguments to the compiler. - /// - /// @see @initCompiler. - virtual std::vector *initCompilerImpl(int argc, char **argv) const; - /// Parses the P4 program specified on the command line. /// /// @returns nullptr if an error occurs during parsing. diff --git a/backends/p4tools/common/compiler/context.h b/backends/p4tools/common/compiler/context.h index 13e69f3fc2..f486c6e21c 100644 --- a/backends/p4tools/common/compiler/context.h +++ b/backends/p4tools/common/compiler/context.h @@ -2,7 +2,7 @@ #define BACKENDS_P4TOOLS_COMMON_COMPILER_CONTEXT_H_ #include "backends/p4tools/common/compiler/configuration.h" -#include "frontends/common/options.h" +#include "frontends/common/parser_options.h" namespace P4::P4Tools { @@ -18,17 +18,17 @@ class CompileContext : public virtual P4CContext { template explicit CompileContext(CompileContext &context) - : optionsInstance(context.options()) {} + : _optionsInstance(context.options()) {} /// @return the compiler options for this compilation context. - OptionsType &options() override { return optionsInstance; } + OptionsType &options() override { return _optionsInstance; } protected: const CompilerConfiguration &getConfigImpl() override { return CompilerConfiguration::get(); } private: /// The compiler options for this compilation context. - OptionsType optionsInstance; + OptionsType _optionsInstance; }; } // namespace P4::P4Tools diff --git a/backends/p4tools/common/core/target.cpp b/backends/p4tools/common/core/target.cpp index 7b5bd977ca..521215cafa 100644 --- a/backends/p4tools/common/core/target.cpp +++ b/backends/p4tools/common/core/target.cpp @@ -6,15 +6,14 @@ #include #include #include -#include #include "backends/p4tools/common/lib/variables.h" #include "ir/irutils.h" namespace P4::P4Tools { -Target::Spec::Spec(std::string deviceName, std::string archName) - : deviceName(std::move(deviceName)), archName(std::move(archName)) { +Target::Spec::Spec(std::string_view deviceName, std::string_view archName) + : deviceName(deviceName), archName(archName) { // Convert names to lower case. std::transform(this->archName.begin(), this->archName.end(), this->archName.begin(), ::tolower); std::transform(this->deviceName.begin(), this->deviceName.end(), this->deviceName.begin(), @@ -37,8 +36,8 @@ std::map>> Targe std::map> Target::defaultArchByDevice = {}; std::map> Target::defaultDeviceByArch = {}; -bool Target::init(std::string deviceName, std::string archName) { - Spec spec(std::move(deviceName), std::move(archName)); +bool Target::init(std::string_view deviceName, std::string_view archName) { + Spec spec(deviceName, archName); if (registry.count(spec) != 0U) { curTarget = spec; @@ -48,23 +47,95 @@ bool Target::init(std::string deviceName, std::string archName) { return false; } -bool Target::setDevice(std::string deviceName) { - std::transform(deviceName.begin(), deviceName.end(), deviceName.begin(), ::tolower); - if (defaultArchByDevice.count(deviceName) == 0U) { +std::optional Target::initializeTarget(std::string_view toolName, + std::string_view target, + std::string_view arch) { + // Establish a dummy compilation context so that we can use ::error to report errors while + // processing target and arch. + class DummyCompileContext : public BaseCompileContext { + } dummyContext; + AutoCompileContext autoDummyContext(&dummyContext); + if (!P4Tools::Target::setDevice(target)) { + ::P4::error("Unsupported device: %s", target); + return std::nullopt; + } + if (!P4Tools::Target::setArch(arch)) { + ::P4::error("Unsupported architecture: %s", arch); + return std::nullopt; + } + const auto &instances = registry.at(*curTarget); + auto instance = instances.find(toolName); + BUG_CHECK(instance != instances.end(), "Architecture %1% on device %2% not supported for %3%", + curTarget->archName, curTarget->deviceName, toolName); + + return instance->second->makeContext(); +} + +std::optional Target::initializeTarget(std::string_view toolName, + const std::vector &args) { + // Establish a dummy compilation context so that we can use ::error to report errors while + // processing target and arch. + class DummyCompileContext : public BaseCompileContext { + } dummyContext; + AutoCompileContext autoDummyContext(&dummyContext); + if (args.size() < 3) { + ::P4::error("Missing --target and --arch arguments"); + return std::nullopt; + } + std::optional target; + std::optional arch; + // Loop through arguments (skip the program name) + for (size_t i = 1; i < args.size(); ++i) { + const std::string &arg = args[i]; + if (arg == "--arch") { + if (i + 1 < args.size()) { + arch = args[i + 1]; + } else { + ::P4::error("Missing architecture name after --arch"); + return std::nullopt; + } + } + if (arg == "--target") { + if (i + 1 < args.size()) { + target = args[i + 1]; + } else { + ::P4::error("Missing device name after --target"); + return std::nullopt; + } + } + } + if (!target) { + ::P4::error("Missing --target argument"); + return std::nullopt; + } + if (!arch) { + ::P4::error("Missing --arch argument"); + return std::nullopt; + } + return initializeTarget(toolName, target.value(), arch.value()); +} + +bool Target::setDevice(std::string_view deviceName) { + std::string lowerCaseDeviceName(deviceName); + std::transform(lowerCaseDeviceName.begin(), lowerCaseDeviceName.end(), + lowerCaseDeviceName.begin(), ::tolower); + if (defaultArchByDevice.count(lowerCaseDeviceName) == 0U) { return false; } - auto archName = curTarget ? curTarget->archName : defaultArchByDevice.at(deviceName); + auto archName = curTarget ? curTarget->archName : defaultArchByDevice.at(deviceName.data()); return init(deviceName, archName); } -bool Target::setArch(std::string archName) { - std::transform(archName.begin(), archName.end(), archName.begin(), ::tolower); - if (defaultDeviceByArch.count(archName) == 0U) { +bool Target::setArch(std::string_view archName) { + std::string lowerCaseArchName(archName); + std::transform(lowerCaseArchName.begin(), lowerCaseArchName.end(), lowerCaseArchName.begin(), + ::tolower); + if (defaultDeviceByArch.count(lowerCaseArchName) == 0U) { return false; } - auto deviceName = curTarget ? curTarget->deviceName : defaultDeviceByArch.at(archName); + auto deviceName = curTarget ? curTarget->deviceName : defaultDeviceByArch.at(archName.data()); return init(deviceName, archName); } diff --git a/backends/p4tools/common/core/target.h b/backends/p4tools/common/core/target.h index 0dd7e505e1..d4182cf30d 100644 --- a/backends/p4tools/common/core/target.h +++ b/backends/p4tools/common/core/target.h @@ -1,11 +1,13 @@ #ifndef BACKENDS_P4TOOLS_COMMON_CORE_TARGET_H_ #define BACKENDS_P4TOOLS_COMMON_CORE_TARGET_H_ +#include #include #include #include #include "ir/ir.h" +#include "lib/compile_context.h" #include "lib/exceptions.h" namespace P4::P4Tools { @@ -22,7 +24,7 @@ class Target { std::string archName; /// Names provided to this constructor are converted to lower case. - Spec(std::string deviceName, std::string archName); + Spec(std::string_view deviceName, std::string_view archName); /// Lexicographic ordering on (deviceName, archName). bool operator<(const Spec &) const; @@ -32,7 +34,7 @@ class Target { /// /// @returns true on success. If initialization fails, false is returned, and nothing is /// changed. - static bool init(std::string deviceName, std::string archName); + static bool init(std::string_view deviceName, std::string_view archName); /// Initializes the global target device to @deviceName without changing the architecture. If /// no architecture was previously selected, then the first architecture registered for the @@ -40,7 +42,7 @@ class Target { /// /// @returns true on success. If initialization fails, false is returned, and nothing is /// changed. - static bool setDevice(std::string deviceName); + static bool setDevice(std::string_view deviceName); /// Initializes the global target architecture to @archName without changing the device. If no /// device was previously selected, then the first device registered for the architecture is @@ -48,7 +50,7 @@ class Target { /// /// @returns true on success. If initialization fails, false is returned, and nothing is /// changed. - static bool setArch(std::string archName); + static bool setArch(std::string_view archName); /// The name of the tool supported by this instance. std::string toolName; @@ -67,11 +69,22 @@ class Target { virtual const IR::Expression *createTargetUninitialized(const IR::Type *type, bool forceTaint) const; + /// Initializes the global target device and architecture to @deviceName and @archName. + /// Returns 0 on success. If initialization fails, returns -1. + static std::optional initializeTarget(std::string_view toolName, + const std::vector &args); + static std::optional initializeTarget(std::string_view toolName, + std::string_view target, + std::string_view arch); + protected: /// Creates and registers a new Target instance for the given @toolName, @deviceName, and /// @archName. Target(std::string_view toolName, const std::string &deviceName, const std::string &archName); + /// @returns a new compilation context for the compiler. + [[nodiscard]] virtual ICompileContext *makeContext() const = 0; + /// @returns the target instance for the given tool and active target, as selected by @init. // // Implemented here because of limitations of templates. diff --git a/backends/p4tools/common/options.cpp b/backends/p4tools/common/options.cpp index 90e0d9af84..4afea5a07b 100644 --- a/backends/p4tools/common/options.cpp +++ b/backends/p4tools/common/options.cpp @@ -2,18 +2,16 @@ #include #include -#include #include #include #include #include "backends/p4tools/common/compiler/compiler_target.h" -#include "backends/p4tools/common/core/target.h" +#include "backends/p4tools/common/lib/logging.h" #include "backends/p4tools/common/lib/util.h" -#include "backends/p4tools/common/version.h" +#include "frontends/common/options.h" #include "frontends/common/parser_options.h" #include "lib/error.h" -#include "lib/exceptions.h" namespace P4::P4Tools { @@ -27,8 +25,7 @@ std::tuple AbstractP4cToolOptions::convertArgs( return {argc, argv}; } -std::optional AbstractP4cToolOptions::process( - const std::vector &args) { +int AbstractP4cToolOptions::process(const std::vector &args) { // Compiler expects path to executable as first element in argument list. compilerArgs.push_back(args.at(0)); @@ -37,141 +34,26 @@ std::optional AbstractP4cToolOptions::process( char **argv = nullptr; std::tie(argc, argv) = convertArgs(args); - // Establish a dummy compilation context so that we can use ::P4::error to report errors while - // processing command-line options. - class DummyCompileContext : public BaseCompileContext { - } dummyContext; - AutoCompileContext autoDummyContext(&dummyContext); - // Delegate to the hook. auto *remainingArgs = process(argc, argv); if ((remainingArgs == nullptr) || ::P4::errorCount() > 0) { - return std::nullopt; - } - - // Establish the real compilation context. - auto *compilerContext = P4Tools::CompilerTarget::makeContext(_toolName); - AutoCompileContext autoContext(compilerContext); - - // Initialize the compiler, forwarding any compiler-specific options. - std::tie(argc, argv) = convertArgs(compilerArgs); - auto *unprocessedCompilerArgs = P4Tools::CompilerTarget::initCompiler(_toolName, argc, argv); - - if ((unprocessedCompilerArgs == nullptr) || ::P4::errorCount() > 0) { - return std::nullopt; + return EXIT_FAILURE; } - BUG_CHECK(unprocessedCompilerArgs->empty(), "Compiler did not process all of its arguments: %s", - cstring::join(unprocessedCompilerArgs->begin(), unprocessedCompilerArgs->end(), " ")); - - // Remaining arguments should be source files. Ensure we have exactly one and send it to the - // compiler. - if (remainingArgs->size() > 1) { - ::P4::error("Only one input file can be specified. Duplicate args:\n%1%", - cstring::join(remainingArgs->begin(), remainingArgs->end(), "\n ")); - usage(); - return std::nullopt; - } - if (remainingArgs->empty()) { - ::P4::error("No input files specified"); - usage(); - return std::nullopt; - } - P4CContext::get().options().file = remainingArgs->at(0); - + setInputFile(); if (!validateOptions()) { - return std::nullopt; + return EXIT_FAILURE; } - return compilerContext; + return EXIT_SUCCESS; } std::vector *AbstractP4cToolOptions::process(int argc, char *const argv[]) { - return Util::Options::process(argc, argv); + return ParserOptions::process(argc, argv); } -/// Specifies a command-line option to inherit from the compiler, and any special handling for the -/// option. -struct InheritedCompilerOptionSpec { - /// The name of the command-line option. For example, "--target". - const char *option; - - /// A descriptive name for the parameter to the option, or nullptr if the option has no - /// parameters. - const char *argName; - - /// A description of the option. - const char *description; - - /// An optional handler for the option. If provided, this is executed before the option is - /// forwarded to the compiler. Any argument to the option is provided to the handler. The - /// handler should return true on successful processing, and false otherwise. - std::optional> handler; -}; - AbstractP4cToolOptions::AbstractP4cToolOptions(std::string_view toolName, std::string_view message) - : Options(message), _toolName(toolName) { + : CompilerOptions(message), _toolName(toolName) { // Register some common options. - registerOption( - "--help", nullptr, - [this](const char *) { - usage(); - exit(0); - return false; - }, - "Shows this help message and exits"); - - registerOption( - "--version", nullptr, - [this](const char *) { - printVersion(binaryName); - exit(0); - return false; - }, - "Prints version information and exits"); - - // Inherit some compiler options, setting them up to be forwarded to the compiler. - std::vector inheritedCompilerOptions = { - {"-I", "path", "Adds the given path to the preprocessor include path", {}}, - {"--Wwarn", - "diagnostic", - "Report a warning for a compiler diagnostic, or treat all warnings " - "as warnings (the default) if no diagnostic is specified.", - {}}, - {"-D", "arg=value", "Defines a preprocessor symbol", {}}, - {"-U", "arg", "Undefines a preprocessor symbol", {}}, - {"-E", nullptr, "Preprocess only. Prints preprocessed program on stdout.", {}}, - {"--nocpp", - nullptr, - "Skips the preprocessor; assumes the input file is already preprocessed.", - {}}, - {"--std", "{p4-14|p4-16}", "Specifies source language version.", {}}, - {"-T", "loglevel", "Adjusts logging level per file.", {}}, - {"--target", "target", "Specifies the device targeted by the program.", - std::optional>{[](const char *arg) { - if (!P4Tools::Target::setDevice(arg)) { - ::P4::error("Unsupported target device: %s", arg); - return false; - } - return true; - }}}, - {"--arch", "arch", "Specifies the architecture targeted by the program.", - std::optional>{[](const char *arg) { - if (!P4Tools::Target::setArch(arg)) { - ::P4::error("Unsupported architecture: %s", arg); - return false; - } - return true; - }}}, - {"--top4", - "pass1[,pass2]", - "Dump the P4 representation after\n" - "passes whose name contains one of `passX' substrings.\n" - "When '-v' is used this will include the compiler IR.\n", - {}}, - {"--dump", "folder", "Folder where P4 programs are dumped.", {}}, - {"-v", nullptr, "Increase verbosity level (can be repeated)", {}}, - }; - registerOption( "--seed", "seed", [this](const char *arg) { @@ -189,25 +71,6 @@ AbstractP4cToolOptions::AbstractP4cToolOptions(std::string_view toolName, std::s return true; }, "Disable printing of information messages to standard output."); - - for (const auto &optionSpec : inheritedCompilerOptions) { - registerOption( - optionSpec.option, optionSpec.argName, - [this, optionSpec](const char *arg) { - // Add to the list of arguments being forwarded to the compiler. - compilerArgs.push_back(optionSpec.option); - if (optionSpec.argName != nullptr) { - compilerArgs.push_back(arg); - } - - // Invoke the handler, if provided. - if (optionSpec.handler) { - return (*optionSpec.handler)(arg); - } - return true; - }, - optionSpec.description); - } } bool AbstractP4cToolOptions::validateOptions() const { return true; } diff --git a/backends/p4tools/common/options.h b/backends/p4tools/common/options.h index 96a7fe33bc..9d6ad49e88 100644 --- a/backends/p4tools/common/options.h +++ b/backends/p4tools/common/options.h @@ -6,16 +6,15 @@ #include #include +#include "frontends/common/options.h" #include "lib/compile_context.h" -#include "lib/cstring.h" -#include "lib/options.h" namespace P4::P4Tools { /// Encapsulates and processes command-line options for a compiler-based tool. Implementations /// should use the singleton pattern and define a static get() for obtaining the singleton /// instance. -class AbstractP4cToolOptions : protected Util::Options { +class AbstractP4cToolOptions : public CompilerOptions { private: /// The name of the tool associated with these options. std::string _toolName; @@ -30,8 +29,8 @@ class AbstractP4cToolOptions : protected Util::Options { /// Processes options. /// - /// @returns a compilation context on success, std::nullopt on error. - std::optional process(const std::vector &args); + /// @returns an EXIT_SUCCESS context on success, EXIT_FAILURE on error. + int process(const std::vector &args); /// Command-line arguments to be sent to the compiler. Populated by @process. std::vector compilerArgs; diff --git a/backends/p4tools/common/p4ctool.h b/backends/p4tools/common/p4ctool.h index 79b921ba79..d61836ecae 100644 --- a/backends/p4tools/common/p4ctool.h +++ b/backends/p4tools/common/p4ctool.h @@ -36,15 +36,21 @@ class AbstractP4cTool { // Register supported compiler targets. registerTarget(); + // Initialize the target and the context. + auto context = Target::initializeTarget(toolName, args); + if (!context.has_value()) { + return EXIT_FAILURE; + } + AutoCompileContext autoContext(context.value()); + Options &toolOptions = dynamic_cast *>(context.value())->options(); + // Process command-line options. - auto &toolOptions = Options::get(); auto compileContext = toolOptions.process(args); - if (!compileContext) { + if (compileContext != EXIT_SUCCESS) { return EXIT_FAILURE; } // Set up the compilation context. - AutoCompileContext autoContext(*compileContext); // If not explicitly disabled, print basic information to standard output. if (!toolOptions.disableInformationLogging) { enableInformationLogging(); @@ -56,8 +62,7 @@ class AbstractP4cTool { } // Run the compiler to get an IR and invoke the tool. - const auto compilerResult = P4Tools::CompilerTarget::runCompiler( - CompileContext::get().options(), toolName); + const auto compilerResult = P4Tools::CompilerTarget::runCompiler(toolOptions, toolName); if (!compilerResult.has_value()) { return EXIT_FAILURE; } diff --git a/backends/p4tools/modules/smith/core/target.cpp b/backends/p4tools/modules/smith/core/target.cpp index b14aa8693c..e1f3cf09da 100644 --- a/backends/p4tools/modules/smith/core/target.cpp +++ b/backends/p4tools/modules/smith/core/target.cpp @@ -3,13 +3,19 @@ #include #include "backends/p4tools/common/compiler/compiler_target.h" +#include "backends/p4tools/common/compiler/context.h" #include "backends/p4tools/common/core/target.h" +#include "backends/p4tools/modules/smith/options.h" namespace P4::P4Tools::P4Smith { SmithTarget::SmithTarget(const std::string &deviceName, const std::string &archName) : P4Tools::CompilerTarget("smith", deviceName, archName) {} +ICompileContext *SmithTarget::makeContext() const { + return new P4Tools::CompileContext; +} + const SmithTarget &SmithTarget::get() { return P4Tools::Target::get("smith"); } } // namespace P4::P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/core/target.h b/backends/p4tools/modules/smith/core/target.h index 065edd44b8..f1cde9f35b 100644 --- a/backends/p4tools/modules/smith/core/target.h +++ b/backends/p4tools/modules/smith/core/target.h @@ -31,6 +31,8 @@ class SmithTarget : public CompilerTarget { [[nodiscard]] virtual ParserGenerator &parserGenerator() const = 0; [[nodiscard]] virtual TableGenerator &tableGenerator() const = 0; + [[nodiscard]] ICompileContext *makeContext() const override; + protected: explicit SmithTarget(const std::string &deviceName, const std::string &archName); diff --git a/backends/p4tools/modules/smith/options.cpp b/backends/p4tools/modules/smith/options.cpp index 2f2ea3da46..e4535eb06c 100644 --- a/backends/p4tools/modules/smith/options.cpp +++ b/backends/p4tools/modules/smith/options.cpp @@ -8,7 +8,6 @@ #include "backends/p4tools/modules/smith/toolname.h" #include "lib/compile_context.h" #include "lib/error.h" -#include "lib/exceptions.h" namespace P4::P4Tools { @@ -17,10 +16,6 @@ SmithOptions &SmithOptions::get() { return INSTANCE; } -const char *SmithOptions::getIncludePath() const { - P4C_UNIMPLEMENTED("getIncludePath is not implemented for P4Smith."); -} - void SmithOptions::processArgs(const std::vector &args) { // Convert to the standard (argc, argv) pair. int argc = 0; diff --git a/backends/p4tools/modules/smith/options.h b/backends/p4tools/modules/smith/options.h index a56bf5954f..137f49a2a8 100644 --- a/backends/p4tools/modules/smith/options.h +++ b/backends/p4tools/modules/smith/options.h @@ -8,18 +8,13 @@ namespace P4::P4Tools { class SmithOptions : public AbstractP4cToolOptions { public: + SmithOptions(); ~SmithOptions() override = default; static SmithOptions &get(); - const char *getIncludePath() const override; void processArgs(const std::vector &args); - - private: - SmithOptions(); }; -// using P4toZ3Context = P4CContextWithOptions; - } // namespace P4::P4Tools #endif /* BACKENDS_P4TOOLS_MODULES_SMITH_OPTIONS_H_ */ diff --git a/backends/p4tools/modules/smith/smith.cpp b/backends/p4tools/modules/smith/smith.cpp index ceb6f51628..81b8f4cddf 100644 --- a/backends/p4tools/modules/smith/smith.cpp +++ b/backends/p4tools/modules/smith/smith.cpp @@ -6,6 +6,7 @@ #include #include "backends/p4tools/common/compiler/compiler_result.h" +#include "backends/p4tools/common/compiler/context.h" #include "backends/p4tools/common/lib/logging.h" #include "backends/p4tools/common/lib/util.h" #include "backends/p4tools/modules/smith/common/probabilities.h" @@ -13,11 +14,11 @@ #include "backends/p4tools/modules/smith/core/target.h" #include "backends/p4tools/modules/smith/options.h" #include "backends/p4tools/modules/smith/register.h" +#include "backends/p4tools/modules/smith/toolname.h" #include "frontends/common/parser_options.h" #include "frontends/p4/toP4/toP4.h" #include "ir/ir.h" #include "lib/compile_context.h" -#include "lib/cstring.h" #include "lib/error.h" #include "lib/nullstream.h" @@ -29,10 +30,17 @@ int Smith::main(const std::vector &args) { // Register supported compiler targets. registerTarget(); + // Initialize the target and the context. + auto context = Target::initializeTarget(P4Tools::P4Smith::TOOL_NAME, args); + if (!context.has_value()) { + return EXIT_FAILURE; + } + // Set up the compilation context. + AutoCompileContext autoContext(context.value()); + // Process command-line options. auto &toolOptions = SmithOptions::get(); - auto compileContext = toolOptions.process(args); - if (!compileContext) { + if (toolOptions.process(args) != EXIT_SUCCESS) { return EXIT_FAILURE; } @@ -41,8 +49,6 @@ int Smith::main(const std::vector &args) { enableInformationLogging(); } - // Set up the compilation context. - AutoCompileContext autoContext(*compileContext); // Instantiate a dummy program for now. In the future this can be a skeleton. const IR::P4Program program; return mainImpl(CompilerResult(program)); diff --git a/backends/p4tools/modules/testgen/core/target.cpp b/backends/p4tools/modules/testgen/core/target.cpp index 439d62a0ab..a5ba0289a3 100644 --- a/backends/p4tools/modules/testgen/core/target.cpp +++ b/backends/p4tools/modules/testgen/core/target.cpp @@ -3,6 +3,7 @@ #include #include "backends/p4tools/common/compiler/compiler_target.h" +#include "backends/p4tools/common/compiler/context.h" #include "backends/p4tools/common/core/target.h" #include "ir/declaration.h" #include "ir/ir.h" @@ -88,4 +89,8 @@ CompilerResultOrError TestgenTarget::runCompilerImpl(const CompilerOptions &opti *new TestgenCompilerResult(CompilerResult(*program), coverage.getCoverableNodes(), dcg)}; } +ICompileContext *TestgenTarget::makeContext() const { + return new P4Tools::CompileContext(); +} + } // namespace P4::P4Tools::P4Testgen diff --git a/backends/p4tools/modules/testgen/core/target.h b/backends/p4tools/modules/testgen/core/target.h index a7fa162aa6..d29967b484 100644 --- a/backends/p4tools/modules/testgen/core/target.h +++ b/backends/p4tools/modules/testgen/core/target.h @@ -65,6 +65,8 @@ class TestgenTarget : public CompilerTarget { CompilerResultOrError runCompilerImpl(const CompilerOptions &options, const IR::P4Program *program) const override; + + [[nodiscard]] ICompileContext *makeContext() const override; }; } // namespace P4::P4Tools::P4Testgen diff --git a/backends/p4tools/modules/testgen/options.cpp b/backends/p4tools/modules/testgen/options.cpp index 34f720d0eb..0b160d18e6 100644 --- a/backends/p4tools/modules/testgen/options.cpp +++ b/backends/p4tools/modules/testgen/options.cpp @@ -8,6 +8,7 @@ #include #include +#include "backends/p4tools/common/compiler/context.h" #include "backends/p4tools/common/lib/util.h" #include "backends/p4tools/common/options.h" #include "lib/error.h" @@ -19,14 +20,7 @@ namespace P4::P4Tools::P4Testgen { using namespace P4::literals; -TestgenOptions &TestgenOptions::get() { - static TestgenOptions INSTANCE; - return INSTANCE; -} - -const char *TestgenOptions::getIncludePath() const { - P4C_UNIMPLEMENTED("getIncludePath not implemented for P4Testgen."); -} +TestgenOptions &TestgenOptions::get() { return CompileContext::get().options(); } const std::set TestgenOptions::SUPPORTED_STOP_METRICS = {"MAX_NODE_COVERAGE"_cs}; diff --git a/backends/p4tools/modules/testgen/options.h b/backends/p4tools/modules/testgen/options.h index f074b6c2e4..dfd68ce603 100644 --- a/backends/p4tools/modules/testgen/options.h +++ b/backends/p4tools/modules/testgen/options.h @@ -18,6 +18,7 @@ namespace P4::P4Tools::P4Testgen { /// Encapsulates and processes command-line options for P4Testgen. class TestgenOptions : public AbstractP4cToolOptions { public: + TestgenOptions(); virtual ~TestgenOptions() = default; /// Maximum number of tests to be generated. Defaults to 1. @@ -102,13 +103,8 @@ class TestgenOptions : public AbstractP4cToolOptions { /// Defaults to the name of the input program, if provided. std::optional testBaseName; - const char *getIncludePath() const override; - protected: bool validateOptions() const override; - - private: - TestgenOptions(); }; } // namespace P4::P4Tools::P4Testgen diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/gtest_utils.h b/backends/p4tools/modules/testgen/targets/bmv2/test/gtest_utils.h index 870950ecd2..9c5ba2e922 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/gtest_utils.h +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/gtest_utils.h @@ -7,14 +7,37 @@ namespace P4::P4Tools::Test { /// Sets up the correct context for a P4Testgen BMv2 test. -class P4TestgenBmv2Test : public P4TestgenTest {}; +class P4TestgenBmv2Test : public P4TestgenTest { + std::unique_ptr compileContext; + + public: + void SetUp() override { + auto result = P4TestgenTest::SetUp("bmv2", "v1model"); + if (!result.has_value()) { + FAIL() << "Failed to set up P4Testgen BMv2 test"; + return; + } + compileContext = std::move(result.value()); + } +}; /// Creates a test case with the @hdrFields for stepping on an @expr. std::optional createBmv2V1modelSmallStepExprTest( const std::string &hdrFields, const std::string &expr); -/// BMv2-specific version of a small step test. -class Bmv2SmallStepTest : public SmallStepTest {}; +class Bmv2SmallStepTest : public SmallStepTest { + std::unique_ptr compileContext; + + public: + void SetUp() override { + auto result = P4TestgenTest::SetUp("bmv2", "v1model"); + if (!result.has_value()) { + FAIL() << "Failed to set up P4Testgen BMv2 test"; + return; + } + compileContext = std::move(result.value()); + } +}; } // namespace P4::P4Tools::Test diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp index ff02f1f465..ea5116eda5 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp @@ -60,10 +60,9 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa )p4"; auto source = P4_SOURCE(P4Headers::V1MODEL, streamTest.str().c_str()); - auto compilerOptions = P4CContextWithOptions::get().options(); - compilerOptions.target = "bmv2"_cs; - compilerOptions.arch = "v1model"_cs; - auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); + auto &testgenOptions = P4Testgen::TestgenOptions::get(); + testgenOptions.target = "bmv2"_cs; + testgenOptions.arch = "v1model"_cs; testgenOptions.testBackend = "PROTOBUF_IR"_cs; testgenOptions.testBaseName = "dummy"_cs; // Create a bespoke packet for the Ethernet extract call. @@ -73,11 +72,10 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa testgenOptions.maxTests = 1; { - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); - auto testList = testListOpt.value(); + const auto &testList = testListOpt.value(); ASSERT_EQ(testList.size(), 1); const auto *protobufIrTest = testList[0]->checkedTo(); @@ -86,11 +84,10 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa /// Now try running again with the test back end set to Protobuf. The result should be the same. testgenOptions.testBackend = "PROTOBUF"_cs; - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); - auto testList = testListOpt.value(); + const auto &testList = testListOpt.value(); ASSERT_EQ(testList.size(), 1); const auto *protobufTest = testList[0]->checkedTo(); EXPECT_THAT(protobufTest->getFormattedTest(), ::testing::HasSubstr(R"(input_packet)")); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp index 798c549422..4c226628a9 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp @@ -18,19 +18,15 @@ using namespace P4::literals; class P4TestgenBenchmark : public P4TestgenBmv2Test {}; -TEST(P4TestgenBenchmark, SuccessfullyGenerate1000Tests) { - // Set the compiler options. - auto *context = new P4Tools::CompileContext(); - AutoCompileContext autoContext(context); - auto &compilerOptions = context->options(); - compilerOptions.target = "bmv2"_cs; - compilerOptions.arch = "v1model"_cs; +TEST_F(P4TestgenBenchmark, SuccessfullyGenerate1000Tests) { + auto &testgenOptions = P4Testgen::TestgenOptions::get(); + testgenOptions.target = "bmv2"_cs; + testgenOptions.arch = "v1model"_cs; auto includePath = P4CTestEnvironment::getProjectRoot() / "p4include"; - compilerOptions.preprocessor_options = "-I" + includePath.string(); + testgenOptions.preprocessor_options = "-I" + includePath.string(); auto fabricFile = P4CTestEnvironment::getProjectRoot() / "testdata/p4_16_samples/fabric_20190420/fabric.p4"; - compilerOptions.file = fabricFile.string(); - auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); + testgenOptions.file = fabricFile.string(); testgenOptions.testBackend = "PROTOBUF_IR"_cs; testgenOptions.testBaseName = "dummy"_cs; testgenOptions.seed = 1; @@ -44,7 +40,7 @@ TEST(P4TestgenBenchmark, SuccessfullyGenerate1000Tests) { // This enables performance printing. P4Tools::enablePerformanceLogging(); - auto testList = P4Tools::P4Testgen::Testgen::generateTests(compilerOptions, testgenOptions); + auto testList = P4Testgen::Testgen::generateTests(testgenOptions); ASSERT_TRUE(testList.has_value()); // Print the report. diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp index 9bffcc2ceb..9025a0aacf 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp @@ -66,17 +66,12 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa return P4_SOURCE(P4Headers::V1MODEL, templateString.str().c_str()); } -CompilerOptions generateDefaultApiTestCompilerOptions() { - auto compilerOptions = P4CContextWithOptions::get().options(); - compilerOptions.target = "bmv2"_cs; - compilerOptions.arch = "v1model"_cs; - return compilerOptions; -} - -P4Tools::P4Testgen::TestgenOptions &generateDefaultApiTestTestgenOptions() { - auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); +P4Testgen::TestgenOptions &generateDefaultApiTestTestgenOptions() { + auto &testgenOptions = P4Testgen::TestgenOptions::get(); testgenOptions.testBackend = "PROTOBUF_IR"_cs; testgenOptions.testBaseName = "dummy"_cs; + testgenOptions.target = "bmv2"_cs; + testgenOptions.arch = "v1model"_cs; testgenOptions.seed = 1; testgenOptions.maxTests = 0; // Create a bespoke packet for the Ethernet extract call. @@ -108,13 +103,11 @@ TEST_F(P4TestgenControlPlaneFilterTest, GeneratesCorrectTests) { drop_table.apply(); } })"); - auto compilerOptions = generateDefaultApiTestCompilerOptions(); auto &testgenOptions = generateDefaultApiTestTestgenOptions(); // First, we ensure that tests are generated correctly. We expect two tests. // One which exercises action acl_drop and one which exercises the default action, NoAction. - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); const auto &testList = testListOpt.value(); @@ -156,15 +149,13 @@ TEST_F(P4TestgenControlPlaneFilterTest, FiltersControlPlaneEntities) { drop_table.apply(); } })"); - auto compilerOptions = generateDefaultApiTestCompilerOptions(); auto &testgenOptions = generateDefaultApiTestTestgenOptions(); // We install a filter. // Since we can not generate a config for the table we should only generate one test. testgenOptions.skippedControlPlaneEntities = {"ingress.drop_table"_cs}; - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); const auto &testList = testListOpt.value(); @@ -196,15 +187,13 @@ TEST_F(P4TestgenControlPlaneFilterTest, IgnoresBogusControlPlaneEntities) { drop_table.apply(); } })"); - auto compilerOptions = generateDefaultApiTestCompilerOptions(); auto &testgenOptions = generateDefaultApiTestTestgenOptions(); // This is a bogus control plane element, which is ignored. We expect two tests. // One which exercises action acl_drop and one which exercises the default action, NoAction. testgenOptions.skippedControlPlaneEntities = {"ingress.bogus_table"_cs}; - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); const auto &testList = testListOpt.value(); @@ -262,7 +251,6 @@ TEST_F(P4TestgenControlPlaneFilterTest, FiltersMultipleControlPlaneEntities) { set_eth_table.apply(); } })"); - auto compilerOptions = generateDefaultApiTestCompilerOptions(); auto &testgenOptions = generateDefaultApiTestTestgenOptions(); // We install a filter. @@ -270,8 +258,7 @@ TEST_F(P4TestgenControlPlaneFilterTest, FiltersMultipleControlPlaneEntities) { testgenOptions.skippedControlPlaneEntities = {"ingress.drop_table"_cs, "ingress.set_eth_table"_cs}; - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); const auto &testList = testListOpt.value(); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp index 27a8b8a878..073ab6e85f 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp @@ -59,10 +59,9 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa )p4"; auto source = P4_SOURCE(P4Headers::V1MODEL, streamTest.str().c_str()); - auto compilerOptions = P4CContextWithOptions::get().options(); - compilerOptions.target = "bmv2"_cs; - compilerOptions.arch = "v1model"_cs; - auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); + auto &testgenOptions = P4Testgen::TestgenOptions::get(); + testgenOptions.target = "bmv2"_cs; + testgenOptions.arch = "v1model"_cs; testgenOptions.testBackend = "PROTOBUF_IR"_cs; testgenOptions.testBaseName = "dummy"_cs; testgenOptions.seed = 1; @@ -75,11 +74,10 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa { testgenOptions.droppedPacketOnly = true; - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); - auto testList = testListOpt.value(); + const auto &testList = testListOpt.value(); ASSERT_EQ(testList.size(), 1); const auto *protobufIrTest = testList[0]->checkedTo(); @@ -92,11 +90,10 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa testgenOptions.droppedPacketOnly = false; testgenOptions.outputPacketOnly = true; - auto testListOpt = - P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); + auto testListOpt = P4Testgen::Testgen::generateTests(source, testgenOptions); ASSERT_TRUE(testListOpt.has_value()); - auto testList = testListOpt.value(); + const auto &testList = testListOpt.value(); ASSERT_EQ(testList.size(), 1); const auto *protobufIrTest = testList[0]->checkedTo(); diff --git a/backends/p4tools/modules/testgen/test/gtest_utils.cpp b/backends/p4tools/modules/testgen/test/gtest_utils.cpp index 032c58506b..b3b52174b2 100644 --- a/backends/p4tools/modules/testgen/test/gtest_utils.cpp +++ b/backends/p4tools/modules/testgen/test/gtest_utils.cpp @@ -29,13 +29,18 @@ std::optional P4ToolsTestCase::create( deviceName, archName); // Set up the compilation context and set the source language. - AutoCompileContext autoCompileContext( - P4Tools::CompilerTarget::makeContext(P4Tools::P4Testgen::TOOL_NAME)); - P4CContext::get().options().langVersion = langVersion; + auto context = + P4Tools::Target::initializeTarget(P4Tools::P4Testgen::TOOL_NAME, deviceName, archName); + if (!context.has_value()) { + return std::nullopt; + } + AutoCompileContext autoContext(context.value()); + auto *compileContext = + dynamic_cast *>(context.value()); + compileContext->options().langVersion = langVersion; auto compilerResults = P4Tools::CompilerTarget::runCompiler( - P4Tools::CompileContext::get().options(), P4Tools::P4Testgen::TOOL_NAME, - source); + compileContext->options(), P4Tools::P4Testgen::TOOL_NAME, source); if (!compilerResults.has_value()) { return std::nullopt; } diff --git a/backends/p4tools/modules/testgen/test/gtest_utils.h b/backends/p4tools/modules/testgen/test/gtest_utils.h index fe4bc42dd1..9e64a8151f 100644 --- a/backends/p4tools/modules/testgen/test/gtest_utils.h +++ b/backends/p4tools/modules/testgen/test/gtest_utils.h @@ -3,12 +3,17 @@ #include +#include #include #include -#include "backends/p4tools/common/compiler/compiler_result.h" #include "frontends/common/options.h" #include "ir/ir.h" +#include "lib/compile_context.h" + +#include "backends/p4tools/modules/testgen/core/target.h" +#include "backends/p4tools/modules/testgen/register.h" +#include "backends/p4tools/modules/testgen/toolname.h" namespace P4::P4Tools::Test { @@ -47,7 +52,22 @@ class P4ToolsTestCase { static void ensureInit(); }; -class P4TestgenTest : public testing::Test {}; +class P4TestgenTest : public testing::Test { + public: + [[nodiscard]] static std::optional> SetUp( + std::string_view target, std::string_view archName) { + P4Tools::P4Testgen::registerTestgenTargets(); + /// Set up the appropriate compile context for P4Testgen tests. + /// TODO: Remove this once options are not initialized statically anymore. + auto ctxOpt = P4Testgen::TestgenTarget::initializeTarget(P4Tools::P4Testgen::TOOL_NAME, + target, archName); + + if (!ctxOpt.has_value()) { + return std::nullopt; + } + return std::make_unique(ctxOpt.value()); + } +}; /// Converts IR::Member into symbolic variables. class SymbolicConverter : public Transform { diff --git a/backends/p4tools/modules/testgen/testgen.cpp b/backends/p4tools/modules/testgen/testgen.cpp index f32411eb03..28d65b93ba 100644 --- a/backends/p4tools/modules/testgen/testgen.cpp +++ b/backends/p4tools/modules/testgen/testgen.cpp @@ -7,6 +7,7 @@ #include #include +#include "backends/p4tools/common/compiler/compiler_target.h" #include "backends/p4tools/common/core/z3_solver.h" #include "frontends/common/parser_options.h" #include "ir/solver.h" @@ -104,8 +105,8 @@ int generateAndWriteAbstractTests(const TestgenOptions &testgenOptions, /// If the test name is not provided, use the steam of the input file name as test name. if (testgenOptions.testBaseName.has_value()) { testPath = testgenOptions.testBaseName.value().c_str(); - } else if (!P4CContext::get().options().file.empty()) { - testPath = P4CContext::get().options().file.stem(); + } else if (!testgenOptions.file.empty()) { + testPath = testgenOptions.file.stem(); } else { ::P4::error("Neither a file nor test base name was set. Can not infer a test name."); } @@ -143,24 +144,22 @@ int generateAndWriteAbstractTests(const TestgenOptions &testgenOptions, } std::optional generateTestsImpl(std::optional program, - const CompilerOptions &compilerOptions, const TestgenOptions &testgenOptions, bool writeTests) { - registerTestgenTargets(); - P4Tools::Target::init(compilerOptions.target.c_str(), compilerOptions.arch.c_str()); + P4Tools::Target::init(testgenOptions.target.c_str(), testgenOptions.arch.c_str()); CompilerResultOrError compilerResultOpt; if (program.has_value()) { // Run the compiler to get an IR and invoke the tool. - compilerResultOpt = P4Tools::CompilerTarget::runCompiler(compilerOptions, TOOL_NAME, + compilerResultOpt = P4Tools::CompilerTarget::runCompiler(testgenOptions, TOOL_NAME, std::string(program.value())); } else { - if (compilerOptions.file.empty()) { + if (testgenOptions.file.empty()) { ::P4::error("Expected a file input."); return std::nullopt; } // Run the compiler to get an IR and invoke the tool. - compilerResultOpt = P4Tools::CompilerTarget::runCompiler(compilerOptions, TOOL_NAME); + compilerResultOpt = P4Tools::CompilerTarget::runCompiler(testgenOptions, TOOL_NAME); } if (!compilerResultOpt.has_value()) { @@ -207,10 +206,9 @@ int Testgen::mainImpl(const CompilerResult &compilerResult) { } std::optional Testgen::generateTests(std::string_view program, - const CompilerOptions &compilerOptions, const TestgenOptions &testgenOptions) { try { - return generateTestsImpl(program, compilerOptions, testgenOptions, false); + return generateTestsImpl(program, testgenOptions, false); } catch (const std::exception &e) { std::cerr << "Internal error: " << e.what() << "\n"; return std::nullopt; @@ -220,10 +218,9 @@ std::optional Testgen::generateTests(std::string_view program, return std::nullopt; } -std::optional Testgen::generateTests(const CompilerOptions &compilerOptions, - const TestgenOptions &testgenOptions) { +std::optional Testgen::generateTests(const TestgenOptions &testgenOptions) { try { - return generateTestsImpl(std::nullopt, compilerOptions, testgenOptions, false); + return generateTestsImpl(std::nullopt, testgenOptions, false); } catch (const std::exception &e) { std::cerr << "Internal error: " << e.what() << "\n"; return std::nullopt; @@ -233,10 +230,9 @@ std::optional Testgen::generateTests(const CompilerOptions &co return std::nullopt; } -int Testgen::writeTests(std::string_view program, const CompilerOptions &compilerOptions, - const TestgenOptions &testgenOptions) { +int Testgen::writeTests(std::string_view program, const TestgenOptions &testgenOptions) { try { - if (generateTestsImpl(program, compilerOptions, testgenOptions, true).has_value()) { + if (generateTestsImpl(program, testgenOptions, true).has_value()) { return EXIT_SUCCESS; } } catch (const std::exception &e) { @@ -248,10 +244,9 @@ int Testgen::writeTests(std::string_view program, const CompilerOptions &compile return EXIT_FAILURE; } -int Testgen::writeTests(const CompilerOptions &compilerOptions, - const TestgenOptions &testgenOptions) { +int Testgen::writeTests(const TestgenOptions &testgenOptions) { try { - if (generateTestsImpl(std::nullopt, compilerOptions, testgenOptions, true).has_value()) { + if (generateTestsImpl(std::nullopt, testgenOptions, true).has_value()) { return EXIT_SUCCESS; } } catch (const std::exception &e) { diff --git a/backends/p4tools/modules/testgen/testgen.h b/backends/p4tools/modules/testgen/testgen.h index 7da665d502..0140780d3e 100644 --- a/backends/p4tools/modules/testgen/testgen.h +++ b/backends/p4tools/modules/testgen/testgen.h @@ -3,6 +3,7 @@ #include "backends/p4tools/common/p4ctool.h" +#include "backends/p4tools/modules/testgen/core/target.h" #include "backends/p4tools/modules/testgen/lib/test_framework.h" #include "backends/p4tools/modules/testgen/options.h" @@ -20,15 +21,13 @@ class Testgen : public AbstractP4cTool { /// input TestgenOptions. The abstract tests can be further specialized depending on the select /// test back end. CompilerOptions is required to invoke the correct preprocessor and P4 /// compiler. It is assumed that `.file` in the compiler options is set. - static std::optional generateTests(const CompilerOptions &options, - const TestgenOptions &testgenOptions); + static std::optional generateTests(const TestgenOptions &testgenOptions); /// Invokes P4Testgen and returns a list of abstract tests which are generated based on the /// input TestgenOptions. The abstract tests can be further specialized depending on the select /// test back end. CompilerOptions is required to invoke the correct P4 compiler. This function /// assumes that @param program is already preprocessed. P4Testgen will directly parse the input /// program. static std::optional generateTests(std::string_view program, - const CompilerOptions &options, const TestgenOptions &testgenOptions); /// Invokes P4Testgen and writes a list of abstract tests to a specified output directory which @@ -36,14 +35,13 @@ class Testgen : public AbstractP4cTool { /// specialized depending on the select test back end. CompilerOptions is required to invoke the /// correct preprocessor and P4 compiler. It is assumed that `.file` in the compiler options is /// set. - static int writeTests(const CompilerOptions &options, const TestgenOptions &testgenOptions); + static int writeTests(const TestgenOptions &testgenOptions); /// Invokes P4Testgen and writes a list of abstract tests to a specified output directory which /// are generated based on the input TestgenOptions. CompilerOptions is required to invoke the /// correct P4 compiler. This function assumes that @param program is already preprocessed. /// P4Testgen will directly parse the input program. - static int writeTests(std::string_view program, const CompilerOptions &options, - const TestgenOptions &testgenOptions); + static int writeTests(std::string_view program, const TestgenOptions &testgenOptions); virtual ~Testgen() = default; };