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

Experimental: literal for invalid header #3667

Merged
merged 3 commits into from
Nov 10, 2022
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
2 changes: 2 additions & 0 deletions backends/bmv2/psa_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ limitations under the License.
#include "midend/complexComparison.h"
#include "midend/convertEnums.h"
#include "midend/copyStructures.h"
#include "midend/eliminateInvalidHeaders.h"
#include "midend/eliminateTuples.h"
#include "midend/eliminateNewtype.h"
#include "midend/eliminateSerEnums.h"
Expand Down Expand Up @@ -116,6 +117,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions& options, std::ostream* outStre
options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr,
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateInvalidHeaders(&refMap, &typeMap),
new P4::EliminateSerEnums(&refMap, &typeMap),
convertEnums,
[this, convertEnums]() { enumMap = convertEnums->getEnumMapping(); },
Expand Down
2 changes: 2 additions & 0 deletions backends/bmv2/simple_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ limitations under the License.
#include "midend/complexComparison.h"
#include "midend/convertEnums.h"
#include "midend/copyStructures.h"
#include "midend/eliminateInvalidHeaders.h"
#include "midend/eliminateTuples.h"
#include "midend/eliminateNewtype.h"
#include "midend/eliminateSerEnums.h"
Expand Down Expand Up @@ -75,6 +76,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions& options, std::ostream* o
new P4::CheckTableSize(),
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateInvalidHeaders(&refMap, &typeMap),
new P4::EliminateSerEnums(&refMap, &typeMap),
convertEnums,
[this, convertEnums]() { enumMap = convertEnums->getEnumMapping(); },
Expand Down
2 changes: 2 additions & 0 deletions backends/dpdk/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ limitations under the License.
#include "midend/convertEnums.h"
#include "midend/convertErrors.h"
#include "midend/copyStructures.h"
#include "midend/eliminateInvalidHeaders.h"
#include "midend/eliminateNewtype.h"
#include "midend/eliminateSerEnums.h"
#include "midend/eliminateTuples.h"
Expand Down Expand Up @@ -176,6 +177,7 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options,
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateSerEnums(&refMap, &typeMap),
new P4::EliminateInvalidHeaders(&refMap, &typeMap),
convertEnums,
new VisitFunctor([this, convertEnums]() {
enumMap = convertEnums->getEnumMapping();
Expand Down
2 changes: 2 additions & 0 deletions backends/ebpf/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ limitations under the License.
#include "midend/complexComparison.h"
#include "midend/copyStructures.h"
#include "midend/convertEnums.h"
#include "midend/eliminateInvalidHeaders.h"
#include "midend/eliminateNewtype.h"
#include "midend/eliminateTuples.h"
#include "midend/expandEmit.h"
Expand Down Expand Up @@ -80,6 +81,7 @@ const IR::ToplevelBlock* MidEnd::run(EbpfOptions& options,
new P4::ConvertEnums(&refMap, &typeMap, new EnumOn32Bits()),
new P4::ClearTypeMap(&typeMap),
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateInvalidHeaders(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::SimplifyControlFlow(&refMap, &typeMap),
new P4::SimplifyKey(&refMap, &typeMap,
Expand Down
2 changes: 2 additions & 0 deletions backends/p4test/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ limitations under the License.
#include "midend/compileTimeOps.h"
#include "midend/complexComparison.h"
#include "midend/copyStructures.h"
#include "midend/eliminateInvalidHeaders.h"
#include "midend/eliminateTuples.h"
#include "midend/eliminateNewtype.h"
#include "midend/eliminateSerEnums.h"
Expand Down Expand Up @@ -84,6 +85,7 @@ MidEnd::MidEnd(CompilerOptions& options, std::ostream* outStream) {
options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr,
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateInvalidHeaders(&refMap, &typeMap),
new P4::EliminateSerEnums(&refMap, &typeMap),
new P4::SimplifyKey(&refMap, &typeMap,
new P4::OrPolicy(
Expand Down
2 changes: 2 additions & 0 deletions backends/ubpf/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ limitations under the License.
#include "midend/complexComparison.h"
#include "midend/copyStructures.h"
#include "midend/convertEnums.h"
#include "midend/eliminateInvalidHeaders.h"
#include "midend/eliminateNewtype.h"
#include "midend/eliminateTuples.h"
#include "midend/local_copyprop.h"
Expand Down Expand Up @@ -79,6 +80,7 @@ MidEnd::run(EbpfOptions& options, const IR::P4Program* program, std::ostream* ou
new P4::RemoveMiss(&refMap, &typeMap),
new P4::ClearTypeMap(&typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateInvalidHeaders(&refMap, &typeMap),
new P4::SimplifyControlFlow(&refMap, &typeMap),
new P4::SimplifyKey(&refMap, &typeMap,
new P4::OrPolicy(
Expand Down
4 changes: 4 additions & 0 deletions frontends/p4/alias.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ class ReadsWrites : public Inspector {
rw.emplace(expression, new SetOfLocations());
}

void postorder(const IR::InvalidHeader* expression) override {
rw.emplace(expression, new SetOfLocations());
}

void postorder(const IR::TypeNameExpression* expression) override {
rw.emplace(expression, new SetOfLocations());
}
Expand Down
5 changes: 5 additions & 0 deletions frontends/p4/def_use.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,11 @@ bool ComputeWriteSet::preorder(const IR::DefaultExpression* expression) {
return false;
}

bool ComputeWriteSet::preorder(const IR::InvalidHeader* expression) {
expressionWrites(expression, LocationSet::empty);
return false;
}

bool ComputeWriteSet::preorder(const IR::Literal* expression) {
expressionWrites(expression, LocationSet::empty);
return false;
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/def_use.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ class ComputeWriteSet : public Inspector, public IHasDbPrint {
bool preorder(const IR::MethodCallExpression* expression) override;
bool preorder(const IR::DefaultExpression* expression) override;
bool preorder(const IR::Expression* expression) override;
bool preorder(const IR::InvalidHeader* expression) override;
// statements
bool preorder(const IR::P4Parser* parser) override;
bool preorder(const IR::P4Control* control) override;
Expand Down
4 changes: 3 additions & 1 deletion frontends/p4/simplifyDefUse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,9 @@ class FindUninitialized : public Inspector {
return;

if (dst_type->is<IR::Type_Header>()) {
if (src->is<IR::StructExpression>() || src->is<IR::MethodCallExpression>()) {
if (src->is<IR::InvalidHeader>()) {
headerDefs->update(dst, TernaryBool::No);
} else if (src->is<IR::StructExpression>() || src->is<IR::MethodCallExpression>()) {
headerDefs->update(dst, TernaryBool::Yes);
} else if (src_type->is<IR::Type_Header>()) {
auto valid = headerDefs->find(src);
Expand Down
14 changes: 14 additions & 0 deletions frontends/p4/toP4/toP4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,20 @@ bool ToP4::preorder(const IR::StructExpression* e) {
return false;
}

bool ToP4::preorder(const IR::InvalidHeader* e) {
if (expressionPrecedence > DBPrint::Prec_Prefix)
builder.append("(");
if (e->headerType != nullptr) {
builder.append("(");
visit(e->headerType);
builder.append(")");
}
builder.append("{#}");
if (expressionPrecedence > DBPrint::Prec_Prefix)
builder.append(")");
return false;
}

bool ToP4::preorder(const IR::MethodCallExpression* e) {
int prec = expressionPrecedence;
bool useParens = (prec > DBPrint::Prec_Postfix) ||
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/toP4/toP4.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ class ToP4 : public Inspector {
bool preorder(const IR::SelectExpression* e) override;
bool preorder(const IR::ListExpression* e) override;
bool preorder(const IR::StructExpression* e) override;
bool preorder(const IR::InvalidHeader* e) override;
bool preorder(const IR::MethodCallExpression* e) override;
bool preorder(const IR::DefaultExpression* e) override;
bool preorder(const IR::This* e) override;
Expand Down
36 changes: 36 additions & 0 deletions frontends/p4/typeChecking/typeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2115,6 +2115,29 @@ const IR::Node* TypeInference::postorder(IR::ListExpression* expression) {
return expression;
}

const IR::Node* TypeInference::postorder(IR::InvalidHeader* expression) {
if (done()) return expression;
if (!expression->headerType) {
// This expression should be enclosed within a cast.
// Processing the cast will replace this expression with an
// InvalidHeader expression with a known type.
setType(expression, IR::Type_Unknown::get());
setType(getOriginal(), IR::Type_Unknown::get());
return expression;
}
auto type = getTypeType(expression->headerType);
if (!type->is<IR::Type_Header>()) {
typeError("%1%: invalid header expression has a non-header type `%2%`",
expression, type);
return expression;
}
setType(getOriginal(), type);
setType(expression, type);
setCompileTimeConstant(expression);
setCompileTimeConstant(getOriginal<IR::Expression>());
return expression;
}

const IR::Node* TypeInference::postorder(IR::StructExpression* expression) {
if (done()) return expression;
bool constant = true;
Expand Down Expand Up @@ -2736,6 +2759,19 @@ const IR::Node* TypeInference::postorder(IR::Cast* expression) {
expression, st->fields.size(), le->components.size());
return expression;
}
} else if (auto ih = expression->expr->to<IR::InvalidHeader>()) {
if (!ih->headerType) {
auto type = castType->getP4Type();
if (!castType->is<IR::Type_Header>()) {
typeError("%1%: invalid header expression has a non-header type `%2%`",
expression, castType);
return expression;
}
setType(type, new IR::Type_Type(castType));
auto result = new IR::InvalidHeader(ih->srcInfo, type, type);
setType(result, castType);
return result;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions frontends/p4/typeChecking/typeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ class TypeInference : public Transform {
const IR::Node* postorder(IR::Member* expression) override;
const IR::Node* postorder(IR::TypeNameExpression* expression) override;
const IR::Node* postorder(IR::ListExpression* expression) override;
const IR::Node* postorder(IR::InvalidHeader* expression) override;
const IR::Node* postorder(IR::StructExpression* expression) override;
const IR::Node* postorder(IR::MethodCallExpression* expression) override;
const IR::Node* postorder(IR::ConstructorCallExpression* expression) override;
Expand Down
1 change: 1 addition & 0 deletions frontends/parsers/p4/p4lexer.ll
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ using Parser = P4::P4Parser;
"++" { BEGIN(driver.saveState); driver.template_args = false; return makeToken(PP); }

"+" { BEGIN(driver.saveState); driver.template_args = false; return makeToken(PLUS); }
"#" { BEGIN(driver.saveState); driver.template_args = false; return makeToken(SHARP); }
"|+|" { BEGIN(driver.saveState); driver.template_args = false; return makeToken(PLUS_SAT); }
"-" { BEGIN(driver.saveState); driver.template_args = false; return makeToken(MINUS); }
"|-|" { BEGIN(driver.saveState); driver.template_args = false; return makeToken(MINUS_SAT); }
Expand Down
3 changes: 3 additions & 0 deletions frontends/parsers/p4/p4parser.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ inline std::ostream& operator<<(std::ostream& out, const P4::Token& t) {
%token<Token> PLUS_SAT "|+|"
%token<Token> MINUS_SAT "|-|"
%token<Token> MUL "*"
%token<Token> SHARP "#"
%token<Token> DIV "/"
%token<Token> MOD "%"
%token<Token> BIT_OR "|"
Expand Down Expand Up @@ -1422,6 +1423,8 @@ expression
| expression "[" expression "]" { $$ = new IR::ArrayIndex(@1 + @4, $1, $3); }
| expression "[" expression ":" expression "]" { $$ = new IR::Slice(@1 + @6, $1, $3, $5); }
| "{" expressionList "}" { $$ = new IR::ListExpression(@1 + @3, *$2); }
| "{" SHARP "}" { $$ = new IR::InvalidHeader(
@1 + @3, IR::Type::Unknown::get(), nullptr); }
| "{" kvList "}" { $$ = new IR::StructExpression(
@1 + @3, IR::Type::Unknown::get(), (IR::Type_Name*)nullptr, *$2); }
| "(" expression ")" { $$ = $2; }
Expand Down
4 changes: 4 additions & 0 deletions ir/dbprint-expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ void IR::ConstructorCallExpression::dbprint(std::ostream &out) const {
dbsetflags(out, flags);
}

void IR::InvalidHeader::dbprint(std::ostream &out) const {
out << "(" << type << "){#}" << ";";
}

void IR::ListExpression::dbprint(std::ostream &out) const {
int prec = getprec(out);
if (prec > Prec_Postfix) out << '(';
Expand Down
6 changes: 6 additions & 0 deletions ir/expression.def
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,12 @@ class StructExpression : Expression {
size_t size() const { return components.size(); }
}

/// An expression that evaluates to an invalid header with the specified type.
class InvalidHeader : Expression {
/// May only be known after type checking; so it can be nullptr.
NullOK Type headerType;
}

/// A ListExpression where all the components are compile-time values.
/// This is used by the evaluator pass.
class ListCompileTimeValue : CompileTimeValue {
Expand Down
2 changes: 2 additions & 0 deletions midend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set (MIDEND_SRCS
complexComparison.cpp
convertEnums.cpp
copyStructures.cpp
eliminateInvalidHeaders.cpp
eliminateNewtype.cpp
eliminateSerEnums.cpp
eliminateSwitch.cpp
Expand Down Expand Up @@ -64,6 +65,7 @@ set (MIDEND_HDRS
convertEnums.h
convertErrors.h
copyStructures.h
eliminateInvalidHeaders.h
eliminateNewtype.h
eliminateSerEnums.h
eliminateSwitch.h
Expand Down
75 changes: 75 additions & 0 deletions midend/eliminateInvalidHeaders.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2020 VMware, 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 "eliminateInvalidHeaders.h"

namespace P4 {

const IR::Node* DoEliminateInvalidHeaders::postorder(IR::P4Control* control) {
control->controlLocals.prepend(variables);
auto vec = new IR::IndexedVector<IR::StatOrDecl>();
vec->srcInfo = control->body->srcInfo;
vec->append(statements);
vec->append(control->body->components);
control->body = new IR::BlockStatement(
control->body->srcInfo, control->body->annotations, *vec);
statements.clear();
variables.clear();
return control;
}

const IR::Node* DoEliminateInvalidHeaders::postorder(IR::ParserState* state) {
state->components.prepend(statements);
state->components.prepend(variables);
variables.clear();
statements.clear();
return state;
}

const IR::Node* DoEliminateInvalidHeaders::postorder(IR::P4Action* action) {
auto vec = new IR::IndexedVector<IR::StatOrDecl>();
vec->append(variables);
vec->append(statements);
vec->append(action->body->components);
action->body = new IR::BlockStatement(
action->body->srcInfo, action->body->annotations, *vec);
variables.clear();
statements.clear();
return action;
}

const IR::Node* DoEliminateInvalidHeaders::postorder(IR::InvalidHeader* expression) {
if (!findContext<IR::BlockStatement>() &&
!findContext<IR::P4Action>() &&
!findContext<IR::ParserState>()) {
// We need some place to insert the setInvalid call.
::error("%1%: Cannot eliminate invalid header", expression);
return expression;
}
cstring name = refMap->newName("ih");
auto src = expression->srcInfo;
auto decl = new IR::Declaration_Variable(name, expression->headerType->getP4Type());
variables.push_back(decl);
auto setInv = new IR::MethodCallStatement(
src, new IR::MethodCallExpression(
new IR::Member(src, new IR::PathExpression(src, new IR::Path(name)),
IR::Type_Header::setInvalid)));
statements.push_back(setInv);
LOG2("Replacing " << expression << " with " << decl << " and " << setInv);
return new IR::PathExpression(src, new IR::Path(name));
}

} // namespace P4
Loading