Skip to content

Commit

Permalink
Support lookahead in ebpf backend (#1602)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mihai Budiu authored Nov 28, 2018
1 parent 355499a commit 975c15b
Show file tree
Hide file tree
Showing 13 changed files with 854 additions and 18 deletions.
94 changes: 76 additions & 18 deletions backends/ebpf/ebpfParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class StateTranslationVisitor : public CodeGenInspector {

void compileExtractField(const IR::Expression* expr, cstring name,
unsigned alignment, EBPFType* type);
void compileExtract(const IR::Vector<IR::Argument>* args);
void compileExtract(const IR::Expression* destination);
void compileLookahead(const IR::Expression* destination);

public:
explicit StateTranslationVisitor(const EBPFParserState* state) :
Expand All @@ -43,9 +44,51 @@ class StateTranslationVisitor : public CodeGenInspector {
bool preorder(const IR::MethodCallExpression* expression) override;
bool preorder(const IR::MethodCallStatement* stat) override
{ visit(stat->methodCall); return false; }
bool preorder(const IR::AssignmentStatement* stat) override;
};
} // namespace

void
StateTranslationVisitor::compileLookahead(const IR::Expression* destination) {
builder->emitIndent();
builder->blockStart();
builder->emitIndent();
builder->appendFormat("%s_save = %s",
state->parser->program->offsetVar.c_str(),
state->parser->program->offsetVar.c_str());
builder->endOfStatement(true);
compileExtract(destination);
builder->emitIndent();
builder->appendFormat("%s = %s_save",
state->parser->program->offsetVar.c_str(),
state->parser->program->offsetVar.c_str());
builder->endOfStatement(true);
builder->blockEnd(true);
}

bool StateTranslationVisitor::preorder(const IR::AssignmentStatement* statement) {
if (auto mce = statement->right->to<IR::MethodCallExpression>()) {
auto mi = P4::MethodInstance::resolve(mce,
state->parser->program->refMap,
state->parser->program->typeMap);
auto extMethod = mi->to<P4::ExternMethod>();
if (extMethod == nullptr)
BUG("Unhandled method %1%", mce);

auto decl = extMethod->object;
if (decl == state->parser->packet) {
if (extMethod->method->name.name == p4lib.packetIn.lookahead.name) {
compileLookahead(statement->left);
return false;
}
}
::error("Unexpected method call in parser %1%", statement->right);
}

CodeGenInspector::visit(statement);
return false;
}

bool StateTranslationVisitor::preorder(const IR::ParserState* parserState) {
if (parserState->isBuiltin()) return false;

Expand Down Expand Up @@ -211,17 +254,11 @@ StateTranslationVisitor::compileExtractField(
}

void
StateTranslationVisitor::compileExtract(const IR::Vector<IR::Argument>* args) {
if (args->size() != 1) {
::error("Variable-sized header fields not yet supported %1%", args);
return;
}

auto expr = args->at(0)->expression;
auto type = state->parser->typeMap->getType(expr);
auto ht = type->to<IR::Type_Header>();
StateTranslationVisitor::compileExtract(const IR::Expression* destination) {
auto type = state->parser->typeMap->getType(destination);
auto ht = type->to<IR::Type_StructLike>();
if (ht == nullptr) {
::error("Cannot extract to a non-header type %1%", expr);
::error("Cannot extract to a non-struct type %1%", destination);
return;
}

Expand Down Expand Up @@ -253,15 +290,16 @@ StateTranslationVisitor::compileExtract(const IR::Vector<IR::Argument>* args) {
::error("Only headers with fixed widths supported %1%", f);
return;
}
compileExtractField(expr, f->name, alignment, etype);
compileExtractField(destination, f->name, alignment, etype);
alignment += et->widthInBits();
alignment %= 8;
}

builder->emitIndent();
visit(expr);
builder->appendLine(".ebpf_valid = 1;");
return;
if (ht->is<IR::Type_Header>()) {
builder->emitIndent();
visit(destination);
builder->appendLine(".ebpf_valid = 1;");
}
}

bool StateTranslationVisitor::preorder(const IR::MethodCallExpression* expression) {
Expand All @@ -287,10 +325,13 @@ bool StateTranslationVisitor::preorder(const IR::MethodCallExpression* expressio
auto decl = extMethod->object;
if (decl == state->parser->packet) {
if (extMethod->method->name.name == p4lib.packetIn.extract.name) {
compileExtract(expression->arguments);
if (expression->arguments->size() != 1) {
::error("Variable-sized header fields not yet supported %1%", expression);
return false;
}
compileExtract(expression->arguments->at(0)->expression);
return false;
}

BUG("Unhandled packet method %1%", expression->method);
return false;
}
Expand Down Expand Up @@ -329,7 +370,24 @@ EBPFParser::EBPFParser(const EBPFProgram* program, const IR::ParserBlock* block,
program(program), typeMap(typeMap), parserBlock(block),
packet(nullptr), headers(nullptr), headerType(nullptr) {}

void EBPFParser::emitDeclaration(CodeBuilder* builder, const IR::Declaration* decl) {
if (decl->is<IR::Declaration_Variable>()) {
auto vd = decl->to<IR::Declaration_Variable>();
auto etype = EBPFTypeFactory::instance->create(vd->type);
builder->emitIndent();
etype->declare(builder, vd->name, false);
builder->endOfStatement(true);
BUG_CHECK(vd->initializer == nullptr,
"%1%: declarations with initializers not supported", decl);
return;
}
BUG("%1%: not yet handled", decl);
}


void EBPFParser::emit(CodeBuilder* builder) {
for (auto l : parserBlock->container->parserLocals)
emitDeclaration(builder, l);
for (auto s : states)
s->emit(builder);
builder->newline();
Expand Down
1 change: 1 addition & 0 deletions backends/ebpf/ebpfParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class EBPFParser : public EBPFObject {

explicit EBPFParser(const EBPFProgram* program, const IR::ParserBlock* block,
const P4::TypeMap* typeMap);
void emitDeclaration(CodeBuilder* builder, const IR::Declaration* decl);
void emit(CodeBuilder* builder);
bool build();
};
Expand Down
1 change: 1 addition & 0 deletions backends/ebpf/ebpfProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ void EBPFProgram::emitPreamble(CodeBuilder* builder) {
void EBPFProgram::emitLocalVariables(CodeBuilder* builder) {
builder->emitIndent();
builder->appendFormat("unsigned %s = 0;", offsetVar.c_str());
builder->appendFormat("unsigned %s_save = 0;", offsetVar.c_str());
builder->newline();

builder->emitIndent();
Expand Down
5 changes: 5 additions & 0 deletions backends/ebpf/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ limitations under the License.
#include "midend/removeExits.h"
#include "midend/removeLeftSlices.h"
#include "midend/removeParameters.h"
#include "midend/removeSelectBooleans.h"
#include "midend/simplifyKey.h"
#include "midend/simplifySelectCases.h"
#include "midend/simplifySelectList.h"
#include "midend/singleArgumentSelect.h"
#include "midend/tableHit.h"
#include "midend/validateProperties.h"
#include "lower.h"
Expand Down Expand Up @@ -90,6 +92,9 @@ const IR::ToplevelBlock* MidEnd::run(EbpfOptions& options, const IR::P4Program*
new P4::LocalCopyPropagation(&refMap, &typeMap),
new P4::SimplifySelectList(&refMap, &typeMap),
new P4::MoveDeclarations(), // more may have been introduced
new P4::RemoveSelectBooleans(&refMap, &typeMap),
new P4::SingleArgumentSelect(),
new P4::ConstantFolding(&refMap, &typeMap),
new P4::SimplifyControlFlow(&refMap, &typeMap),
new P4::TableHit(&refMap, &typeMap),
new P4::ValidateTableProperties({"implementation"}),
Expand Down
2 changes: 2 additions & 0 deletions midend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ set (MIDEND_SRCS
simplifyKey.cpp
simplifySelectCases.cpp
simplifySelectList.cpp
singleArgumentSelect.cpp
tableHit.cpp
validateProperties.cpp
)
Expand Down Expand Up @@ -75,6 +76,7 @@ set (MIDEND_HDRS
simplifyKey.h
simplifySelectCases.h
simplifySelectList.h
singleArgumentSelect.h
tableHit.h
validateProperties.h
)
Expand Down
31 changes: 31 additions & 0 deletions midend/singleArgumentSelect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "singleArgumentSelect.h"

namespace P4 {

static const IR::Expression* convertList(const IR::Expression* expression) {
auto list = expression->to<IR::ListExpression>();
if (list == nullptr)
return expression;
BUG_CHECK(list->components.size() > 0, "%1%: No components", list);
auto expr = list->components.at(0);
for (size_t i = 1; i < list->components.size(); i++)
expr = new IR::Concat(expr, list->components.at(i));
return expr;
}

bool SingleArgumentSelect::preorder(IR::SelectExpression* expression) {
if (expression->select->size() <= 1)
return false;
auto conv = convertList(expression->select);
auto list = new IR::ListExpression(IR::Vector<IR::Expression>());
list->push_back(conv);
expression->select = list;
return true;
}

bool SingleArgumentSelect::preorder(IR::SelectCase* selCase) {
selCase->keyset = convertList(selCase->keyset);
return false;
}

} // namespace P4
43 changes: 43 additions & 0 deletions midend/singleArgumentSelect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright 2018 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.
*/

#ifndef _MIDEND_SINGLEARGUMENTSELECT_H_
#define _MIDEND_SINGLEARGUMENTSELECT_H_

#include "ir/ir.h"

namespace P4 {

/**
Converts select(a, b, c) into select(a ++ b ++ c).
A similar transformation is done for the labels.
@pre
This should be run after SimplifySelectList and RemoveSelectBooleans.
It assumes that all select arguments are scalar values.
*/
class SingleArgumentSelect : public Modifier {
public:
SingleArgumentSelect() {
setName("SingleArgumentSelect");
}

bool preorder(IR::SelectCase* selCase) override;
bool preorder(IR::SelectExpression* expression) override;
};

} // namespace P4

#endif /* _MIDEND_SINGLEARGUMENTSELECT_H_ */
Loading

0 comments on commit 975c15b

Please sign in to comment.