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

A few gtest cases for PSA #459

Merged
merged 4 commits into from
Apr 9, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 3 additions & 2 deletions frontends/p4/p4-parse.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,13 +1035,14 @@ const IR::P4Program *parse_P4_16_file(const char *name, FILE *in) {

const IR::P4Program *parse_string(const std::string &pgm) {
int errors = 0;
Util::InputSources::reset();
clearErrorReporter();
structure.clear();
allErrors = nullptr;
declarations = new IR::IndexedVector<IR::Node>();
YY_BUFFER_STATE state = yy_scan_string(pgm.c_str());
errors |= yyparse();
yy_delete_buffer(state);
structure.clear();
allErrors = nullptr;
if (errors) {
return nullptr;
}
Expand Down
5 changes: 5 additions & 0 deletions lib/source_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ InputSources::InputSources() :
this->contents.push_back("");
}

/* static */
void InputSources::reset() {
instance = new InputSources;
}

// prevent further changes
void InputSources::seal() {
if (this->sealed)
Expand Down
3 changes: 3 additions & 0 deletions lib/source_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ class InputSources final {

cstring toDebugString() const;

// Reset all source information, so that a new file can be parsed.
static void reset();

static InputSources* instance;

private:
Expand Down
4 changes: 2 additions & 2 deletions test/gtest/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
# elsewhere in the codebase.
gtest_unittest_UNIFIED = \
test/gtest/opeq_test.cpp \
test/gtest/typecheck_test.cpp \
test/gtest/midend_test.cpp
test/gtest/midend_test.cpp \
test/gtest/arch_test.cpp

cpplint_FILES += $(gtest_unittest_UNIFIED)
gtest_SOURCES += $(gtest_unittest_SOURCES)
318 changes: 318 additions & 0 deletions test/gtest/arch_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
/*
Copyright 2013-present Barefoot Networks, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "gtest/gtest.h"
#include "ir/ir.h"
#include "helper.h"
#include "lib/log.h"

#include "frontends/p4/typeMap.h"
#include "frontends/common/resolveReferences/referenceMap.h"
#include "frontends/common/resolveReferences/resolveReferences.h"

#include "p4/createBuiltins.h"
#include "p4/typeChecking/typeChecker.h"

using namespace P4;

TEST(arch, packet_out) {
std::string program = R"(
// simplified core.p4
extern packet_out {
void emit<T> (in T hdr);
}
// simplified v1model.p4
control Deparser<H> (packet_out b, in H hdr);
package PSA<H> (Deparser<H> p);
// user program
struct ParsedHeaders {
bit<32> hdr;
}
control MyDeparser(packet_out b, in ParsedHeaders h){
apply {
b.emit(h.hdr);
}
}
PSA(MyDeparser()) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});

pgm = pgm->apply(passes);
ASSERT_NE(nullptr, pgm);
}

// Potential bug
TEST(arch, duplicatedDeclarationBug) {
std::string program = R"(
// simplified core.p4
extern packet_out {
void emit<T> (in T hdr);
}
// simplified v1model.p4
control Deparser<H> (packet_out b, in H hdr);
package PSA<H> (Deparser<H> p);
// user program
struct ParsedHeaders {
bit<32> hdr;
}
// BUG: duplicated name with 'Deparser'
control Deparser(packet_out b, in ParsedHeaders h){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this is truly wasteful.
It is much simpler to just add a file containing the two declarations into testdata/p4_16_errors.

This will not only test that the compilation fails, but it will also check that the error message is the correct one. It also requires much less code: no c++, no "simplified" core.p4.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is to test the simplified core/psa stuff. The goal is ultimately to get a p4c-bmv2 that can generate code for either simple_switch or psa (depending on which header is included) and have it "just work"

apply {
b.emit(h.hdr);
}
}
PSA(Deparser()) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});

pgm = pgm->apply(passes);
ASSERT_EQ(nullptr, pgm);
}

TEST(arch, instantiation) {
std::string program = R"(
// simplified core.p4
extern packet_in {
void extract<T> (out T hdr);
}
extern packet_out {
void emit<T> (in T hdr);
}
// simplified v1model.p4
parser Parser<M> (packet_in b, out M meta);
control Ingress<H, M> (inout H hdr, inout M meta);
control Deparser<H> (packet_out b, in H hdr);
package PSA<H, M> (Parser<M> p, Ingress<H, M> ig, Deparser<H> dp);
// user program
struct ParsedHeaders {
bit<32> hdr;
}
struct Metadata {
bit<32> hdr;
}
parser MyParser(packet_in b, out Metadata m) {
state start {}
}
control MyIngress(inout ParsedHeaders h, inout Metadata m) {
apply {
}
}
control MyDeparser(packet_out b, in ParsedHeaders h){
apply {
b.emit(h.hdr);
}
}
MyParser() p;
MyIngress() ig;
MyDeparser() dp;
PSA(p, ig, dp) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});

pgm = pgm->apply(passes);
ASSERT_NE(nullptr, pgm);
}

TEST(arch, package_with_body) {
std::string program = R"(
// simplified core.p4
// simplified v1model.p4
control Ingress<H, M> (inout H hdr, inout M meta);
package PSA<H, M> (Ingress<H, M> ig) {}
// user program
struct ParsedHeaders {
bit<32> hdr;
}
struct Metadata {
bit<32> hdr;
}
control MyIngress(inout ParsedHeaders h, inout Metadata m) (bit<32> x) {
apply {
}
}
MyIngress(2) ig;
PSA(ig) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});
pgm = pgm->apply(passes);
ASSERT_EQ(nullptr, pgm);
}

TEST(arch, control_in_control) {
std::string program = R"(
// simplified core.p4
// simplified v1model.p4
control Ingress<H, M> (inout H hdr, inout M meta);
control Egress<H, M> (inout M meta);
package PSA<H, M> (Ingress<H, M> ig);
// user program
struct ParsedHeaders {
bit<32> hdr;
}
struct Metadata {
bit<32> hdr;
}
control MyIngress(inout ParsedHeaders h, inout Metadata m) {
apply {
}
}
control MyEgress(inout Metadata m) (MyIngress ig) {
apply {}
}
MyIngress() ig;
MyEgress(ig) eg;
PSA(ig) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});
pgm = pgm->apply(passes);
ASSERT_NE(nullptr, pgm);
}

TEST(arch, psa_clone_as_param_to_package) {
std::string program = R"(
extern clone {
clone();
void execute(in bit<32> sessions);
}
package PSA<H, M> (clone c);
// user program
struct ParsedHeaders {
bit<32> hdr;
}
clone() c;
PSA(c) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});
pgm = pgm->apply(passes);
ASSERT_NE(nullptr, pgm);
}

TEST(arch, psa_clone_as_param_to_control) {
std::string program = R"(
extern clone<T> {
// constructor
clone();
// methods
void clone(in bit<32> sessions);
void clone(in bit<32> sessions, in T data);
}
control ingress<H, M> (inout H hdr, inout M meta);
package PSA<H, M> (ingress<H,M> ig);
// user program
struct ParsedHeaders {
bit<32> hdr;
}
struct Metadata {
bit<32> md;
}
control MyIngress (inout ParsedHeaders p, inout Metadata m) (clone<bit<32>> c) {
apply{}
}
MyIngress(clone<bit<32>>()) ig;
PSA(ig) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});
pgm = pgm->apply(passes);
ASSERT_NE(nullptr, pgm);

dump(pgm);
}

TEST(arch, psa_clone_as_param_to_extern) {
std::string program = R"(
extern clone<T> {
// constructor
clone();
// methods
void clone(in bit<32> sessions);
void clone(in bit<32> sessions, in T data);
}
extern PRE<T> {
PRE();
void clone(in bit<32> sessions); /* same as invoking c.clone(sessions); */
void clone(in bit<32> sessions, in T data); /* same as invoking c.clone(sessions, data) */
// ...
// drop, multicast api here
}
control ingress<H, M> (inout H hdr, inout M meta);
package PSA<H, M> (ingress<H,M> ig);
// user program
struct ParsedHeaders {
bit<32> hdr;
}
struct Metadata {
bit<32> md;
}
control MyIngress (inout ParsedHeaders p, inout Metadata m) (PRE<bit<32>> pre) {
apply{}
}
PRE<bit<32>>() pre;
MyIngress(pre) ig;
PSA(ig) main;
)";
const IR::P4Program* pgm = parse_string(program);

ReferenceMap refMap;
TypeMap typeMap;
PassManager passes ({
new TypeChecking(&refMap, &typeMap)
});
pgm = pgm->apply(passes);
ASSERT_NE(nullptr, pgm);
}

Loading