Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[P4Testgen] Extend the CompilerTarget runProgram function with data structures which can pass on more information. #4323

Merged
merged 2 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions backends/p4tools/common/compiler/compiler_target.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "backends/p4tools/common/compiler/compiler_target.h"

#include <functional>
#include <string>
#include <utility>
#include <vector>

#include "backends/p4tools/common/compiler/context.h"
#include "backends/p4tools/common/compiler/convert_hs_index.h"
#include "backends/p4tools/common/compiler/midend.h"
#include "backends/p4tools/common/core/target.h"
#include "frontends/common/applyOptionsPragmas.h"
Expand All @@ -18,13 +18,17 @@

namespace P4Tools {

const IR::P4Program &CompilerResult::getProgram() const { return program; }

CompilerResult::CompilerResult(const IR::P4Program &program) : program(program) {}

ICompileContext *CompilerTarget::makeContext() { return get().makeContextImpl(); }

std::vector<const char *> *CompilerTarget::initCompiler(int argc, char **argv) {
return get().initCompilerImpl(argc, argv);
}

std::optional<const IR::P4Program *> CompilerTarget::runCompiler() {
CompilerResultOrError CompilerTarget::runCompiler() {
const auto *program = P4Tools::CompilerTarget::runParser();
if (program == nullptr) {
return std::nullopt;
Expand All @@ -33,7 +37,7 @@ std::optional<const IR::P4Program *> CompilerTarget::runCompiler() {
return runCompiler(program);
}

std::optional<const IR::P4Program *> CompilerTarget::runCompiler(const std::string &source) {
CompilerResultOrError CompilerTarget::runCompiler(const std::string &source) {
const auto *program = P4::parseP4String(source, P4CContext::get().options().langVersion);
if (program == nullptr) {
return std::nullopt;
Expand All @@ -42,12 +46,11 @@ std::optional<const IR::P4Program *> CompilerTarget::runCompiler(const std::stri
return runCompiler(program);
}

std::optional<const IR::P4Program *> CompilerTarget::runCompiler(const IR::P4Program *program) {
CompilerResultOrError CompilerTarget::runCompiler(const IR::P4Program *program) {
return get().runCompilerImpl(program);
}

std::optional<const IR::P4Program *> CompilerTarget::runCompilerImpl(
const IR::P4Program *program) const {
CompilerResultOrError CompilerTarget::runCompilerImpl(const IR::P4Program *program) const {
const auto &self = get();

program = self.runFrontend(program);
Expand All @@ -60,7 +63,7 @@ std::optional<const IR::P4Program *> CompilerTarget::runCompilerImpl(
return std::nullopt;
}

return program;
return *new CompilerResult(*program);
}

ICompileContext *CompilerTarget::makeContextImpl() const {
Expand Down Expand Up @@ -119,5 +122,4 @@ CompilerTarget::CompilerTarget(std::string deviceName, std::string archName)
: Target("compiler", std::move(deviceName), std::move(archName)) {}

const CompilerTarget &CompilerTarget::get() { return Target::get<CompilerTarget>("compiler"); }

} // namespace P4Tools
36 changes: 29 additions & 7 deletions backends/p4tools/common/compiler/compiler_target.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef BACKENDS_P4TOOLS_COMMON_COMPILER_COMPILER_TARGET_H_
#define BACKENDS_P4TOOLS_COMMON_COMPILER_COMPILER_TARGET_H_

#include <functional>
#include <optional>
#include <string>
#include <vector>
Expand All @@ -10,10 +11,30 @@
#include "frontends/common/options.h"
#include "frontends/p4/frontend.h"
#include "ir/ir.h"
#include "lib/castable.h"
#include "lib/compile_context.h"

namespace P4Tools {

/// An extensible result object which is returned by the CompilerTarget.
/// In its simplest form, this holds the transformed P4 program after the front- and midend passes.
class CompilerResult : public ICastable {
private:
/// The reference to the input P4 program, after it has been transformed by the compiler.
std::reference_wrapper<const IR::P4Program> program;

public:
explicit CompilerResult(const IR::P4Program &program);

/// @returns the reference to the input P4 program, after it has been transformed by the
/// compiler.
[[nodiscard]] const IR::P4Program &getProgram() const;
};

/// P4Tools compilers may return an error instead of a compiler result.
/// This is a convenience definition for the return value.
using CompilerResultOrError = std::optional<std::reference_wrapper<const CompilerResult>>;

/// Encapsulates the details of invoking the P4 compiler for a target device and architecture.
class CompilerTarget : public Target {
public:
Expand All @@ -25,28 +46,29 @@ class CompilerTarget : public Target {
/// @returns any unprocessed arguments, or nullptr if there was an error.
static std::vector<const char *> *initCompiler(int argc, char **argv);

/// Runs the P4 compiler to produce an IR.
/// Runs the P4 compiler to produce an IR and various other kinds of information on the input
/// program.
///
/// @returns std::nullopt if an error occurs during compilation.
static std::optional<const IR::P4Program *> runCompiler();
static CompilerResultOrError runCompiler();

/// Runs the P4 compiler to produce an IR for the given source code.
/// Runs the P4 compiler to produce an IR and other information for the given source code.
///
/// @returns std::nullopt if an error occurs during compilation.
static std::optional<const IR::P4Program *> runCompiler(const std::string &source);
static CompilerResultOrError runCompiler(const std::string &source);

private:
/// Runs the front and mid ends on the given parsed program.
///
/// @returns std::nullopt if an error occurs during compilation.
static std::optional<const IR::P4Program *> runCompiler(const IR::P4Program *);
static CompilerResultOrError runCompiler(const IR::P4Program *);

protected:
/// @see @makeContext.
virtual ICompileContext *makeContextImpl() const;
[[nodiscard]] virtual ICompileContext *makeContextImpl() const;

/// @see runCompiler.
virtual std::optional<const IR::P4Program *> runCompilerImpl(const IR::P4Program *) const;
virtual CompilerResultOrError runCompilerImpl(const IR::P4Program *) const;

/// This implementation just forwards the given arguments to the compiler.
///
Expand Down
13 changes: 6 additions & 7 deletions backends/p4tools/common/p4ctool.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#ifndef BACKENDS_P4TOOLS_COMMON_P4CTOOL_H_
#define BACKENDS_P4TOOLS_COMMON_P4CTOOL_H_

#include <cstdlib>
#include <vector>

#include "backends/p4tools/common/compiler/compiler_target.h"
#include "backends/p4tools/common/core/target.h"
#include "ir/ir.h"

namespace P4Tools {

Expand All @@ -19,7 +18,7 @@ class AbstractP4cTool {
/// Provides the implementation of the tool.
///
/// @param program The P4 program after mid-end processing.
virtual int mainImpl(const IR::P4Program *program) = 0;
virtual int mainImpl(const CompilerResult &compilerResult) = 0;

virtual void registerTarget() = 0;

Expand All @@ -41,11 +40,11 @@ class AbstractP4cTool {
AutoCompileContext autoContext(*compileContext);

// Run the compiler to get an IR and invoke the tool.
const auto program = P4Tools::CompilerTarget::runCompiler();
if (!program) {
return 1;
const auto compilerResult = P4Tools::CompilerTarget::runCompiler();
if (!compilerResult.has_value()) {
return EXIT_FAILURE;
}
return mainImpl(*program);
return mainImpl(compilerResult.value());
}
};

Expand Down
1 change: 0 additions & 1 deletion backends/p4tools/modules/testgen/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <vector>

#include "lib/crash.h"
#include "lib/exceptions.h"

#include "backends/p4tools/modules/testgen/testgen.h"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ TEST_F(SmallStepTest, Binary01) {
const auto test = createSmallStepExprTest("bit<8> f;", "8w42 + hdr.h.f");
ASSERT_TRUE(test);

const auto *opBin = extractExpr<IR::Operation_Binary>(test->program);
const auto *opBin = extractExpr<IR::Operation_Binary>(test->getProgram());
ASSERT_TRUE(opBin);

// Step on the binary operation and examine the resulting continuation
// to include the rebuilt IR::Add node.
stepAndExamineOp(opBin, opBin->right, test->program, [opBin](const IR::PathExpression *expr) {
return new IR::Add(opBin->left, expr);
});
stepAndExamineOp(
opBin, opBin->right, test->getProgram(),
[opBin](const IR::PathExpression *expr) { return new IR::Add(opBin->left, expr); });
}

/// Test the step function for e + e binary operation.
Expand All @@ -39,44 +39,44 @@ TEST_F(SmallStepTest, Binary02) {
"hdr.h.f1 + hdr.h.f2");
ASSERT_TRUE(test);

const auto *opBin = extractExpr<IR::Operation_Binary>(test->program);
const auto *opBin = extractExpr<IR::Operation_Binary>(test->getProgram());
ASSERT_TRUE(opBin);

// Step on the binary operation and examine the resulting continuation
// to include the rebuilt IR::Add node.
stepAndExamineOp(opBin, opBin->left, test->program, [opBin](const IR::PathExpression *expr) {
return new IR::Add(expr, opBin->right);
});
stepAndExamineOp(
opBin, opBin->left, test->getProgram(),
[opBin](const IR::PathExpression *expr) { return new IR::Add(expr, opBin->right); });
}

/// Test the step function for e == v binary operation.
TEST_F(SmallStepTest, Binary03) {
const auto test = createSmallStepExprTest("bit<8> f;", "hdr.h.f == 8w42");
ASSERT_TRUE(test);

const auto *opBin = extractExpr<IR::Operation_Binary>(test->program);
const auto *opBin = extractExpr<IR::Operation_Binary>(test->getProgram());
ASSERT_TRUE(opBin);

// Step on the binary operation and examine the resulting continuation
// to include the rebuilt IR::Equ node.
stepAndExamineOp(opBin, opBin->left, test->program, [opBin](const IR::PathExpression *expr) {
return new IR::Equ(expr, opBin->right);
});
stepAndExamineOp(
opBin, opBin->left, test->getProgram(),
[opBin](const IR::PathExpression *expr) { return new IR::Equ(expr, opBin->right); });
}

/// Test the step function for v ++ e binary operation.
TEST_F(SmallStepTest, Binary04) {
const auto test = createSmallStepExprTest("bit<8> f;", "8w42 ++ hdr.h.f");
ASSERT_TRUE(test);

const auto *opBin = extractExpr<IR::Operation_Binary>(test->program);
const auto *opBin = extractExpr<IR::Operation_Binary>(test->getProgram());
ASSERT_TRUE(opBin);

// Step on the binary operation and examine the resulting continuation
// to include the rebuilt IR::Concat node.
stepAndExamineOp(opBin, opBin->right, test->program, [opBin](const IR::PathExpression *expr) {
return new IR::Concat(opBin->left, expr);
});
stepAndExamineOp(
opBin, opBin->right, test->getProgram(),
[opBin](const IR::PathExpression *expr) { return new IR::Concat(opBin->left, expr); });
}

} // anonymous namespace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ TEST_F(SmallStepTest, Unary01) {
const auto test = createSmallStepExprTest("bit<8> f;", "-(hdr.h.f)");
ASSERT_TRUE(test);

const auto *opUn = extractExpr<IR::Operation_Unary>(test->program);
const auto *opUn = extractExpr<IR::Operation_Unary>(test->getProgram());
ASSERT_TRUE(opUn);

// Step on the unary operation and examine the resulting continuation
// to include the rebuilt IR::Neg node.
stepAndExamineOp(opUn, opUn->expr, test->program,
stepAndExamineOp(opUn, opUn->expr, test->getProgram(),
[](const IR::PathExpression *expr) { return new IR::Neg(expr); });
}

Expand All @@ -35,12 +35,12 @@ TEST_F(SmallStepTest, Unary02) {
const auto test = createSmallStepExprTest("bool f;", "!(hdr.h.f)");
ASSERT_TRUE(test);

const auto *opUn = extractExpr<IR::Operation_Unary>(test->program);
const auto *opUn = extractExpr<IR::Operation_Unary>(test->getProgram());
ASSERT_TRUE(opUn);

// Step on the unary operation and examine the resulting continuation
// to include the rebuilt IR::LNot node.
stepAndExamineOp(opUn, opUn->expr, test->program, [](const IR::PathExpression *expr) {
stepAndExamineOp(opUn, opUn->expr, test->getProgram(), [](const IR::PathExpression *expr) {
return new IR::LNot(IR::Type_Boolean::get(), expr);
});
}
Expand All @@ -50,12 +50,12 @@ TEST_F(SmallStepTest, Unary03) {
const auto test = createSmallStepExprTest("bit<8> f;", "~(hdr.h.f)");
ASSERT_TRUE(test);

const auto *opUn = extractExpr<IR::Operation_Unary>(test->program);
const auto *opUn = extractExpr<IR::Operation_Unary>(test->getProgram());
ASSERT_TRUE(opUn);

// Step on the unary operation and examine the resulting continuation
// to include the rebuilt IR::Cmpl node.
stepAndExamineOp(opUn, opUn->expr, test->program,
stepAndExamineOp(opUn, opUn->expr, test->getProgram(),
[](const IR::PathExpression *expr) { return new IR::Cmpl(expr); });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@ TEST_F(SmallStepTest, Value01) {
const auto test = createSmallStepExprTest("bit<8> f;", "8w42");
ASSERT_TRUE(test);

const auto *opValue = extractExpr<IR::Constant>(test->program);
const auto *opValue = extractExpr<IR::Constant>(test->getProgram());
ASSERT_TRUE(opValue);

// Step on the value and examine the resulting state.
stepAndExamineValue(opValue, test->program);
stepAndExamineValue(opValue, test->getProgram());
}

/// Test the step function for a bool value.
TEST_F(SmallStepTest, Value02) {
const auto test = createSmallStepExprTest("bit<1> f;", "true");
ASSERT_TRUE(test);

const auto *opValue = extractExpr<IR::BoolLiteral>(test->program);
const auto *opValue = extractExpr<IR::BoolLiteral>(test->getProgram());
ASSERT_TRUE(opValue);

// Step on the value and examine the resulting state.
stepAndExamineValue(opValue, test->program);
stepAndExamineValue(opValue, test->getProgram());
}

} // anonymous namespace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ class Z3SolverSatTests : public ::testing::Test {
}

// Produce a ProgramInfo, which is needed to create a SmallStepEvaluator.
const auto *progInfo = TestgenTarget::initProgram(test->program);
const auto *progInfo = TestgenTarget::initProgram(&test->getProgram());
if (progInfo == nullptr) {
return;
}

// Extract the binary operation from the P4Program
auto *const declVector = test->program->getDeclsByName("mau")->toVector();
auto *const declVector = test->getProgram().getDeclsByName("mau")->toVector();
const auto *decl = (*declVector)[0];
const auto *control = decl->to<IR::P4Control>();
for (const auto *st : control->body->components) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <gtest/gtest.h>

#include <algorithm>
#include <optional>
#include <string>
#include <vector>
Expand All @@ -13,13 +12,11 @@
#include "backends/p4tools/common/core/z3_solver.h"
#include "backends/p4tools/common/lib/model.h"
#include "ir/declaration.h"
#include "ir/indexed_vector.h"
#include "ir/ir.h"
#include "lib/big_int_util.h"
#include "lib/cstring.h"
#include "lib/enumerator.h"
#include "lib/exceptions.h"
#include "lib/log.h"
#include "test/gtest/helpers.h"

#include "backends/p4tools/modules/testgen/core/target.h"
Expand Down Expand Up @@ -90,13 +87,13 @@ class Z3SolverTest : public P4ToolsTest {
}

// Produce a ProgramInfo, which is needed to create a SmallStepEvaluator.
const auto *progInfo = TestgenTarget::initProgram(test->program);
const auto *progInfo = TestgenTarget::initProgram(&test->getProgram());
if (progInfo == nullptr) {
return;
}

// Extract the binary operation from the P4Program
auto *const declVector = test->program->getDeclsByName("mau")->toVector();
auto *const declVector = test->getProgram().getDeclsByName("mau")->toVector();
const auto *decl = (*declVector)[0];
const auto *control = decl->to<IR::P4Control>();
SymbolicConverter converter;
Expand Down
Loading
Loading