Skip to content

Commit

Permalink
Support table.apply().miss (#2051)
Browse files Browse the repository at this point in the history
* Support table.apply().miss
* Convert table.apply().miss to not table.apply.hit()
  • Loading branch information
Mihai Budiu authored Nov 6, 2019
1 parent df500ee commit bd0308a
Show file tree
Hide file tree
Showing 31 changed files with 497 additions and 16 deletions.
2 changes: 2 additions & 0 deletions backends/bmv2/psa_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ limitations under the License.
#include "midend/local_copyprop.h"
#include "midend/nestedStructs.h"
#include "midend/removeLeftSlices.h"
#include "midend/removeMiss.h"
#include "midend/removeParameters.h"
#include "midend/removeUnusedParameters.h"
#include "midend/simplifyKey.h"
Expand Down Expand Up @@ -93,6 +94,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions& options, std::ostream* outStre
if (BMV2::PsaSwitchContext::get().options().loadIRFromJson == false) {
std::initializer_list<Visitor *> midendPasses = {
options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr,
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateSerEnums(&refMap, &typeMap),
new P4::RemoveActionParameters(&refMap, &typeMap),
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 @@ -40,6 +40,7 @@ limitations under the License.
#include "midend/local_copyprop.h"
#include "midend/nestedStructs.h"
#include "midend/removeLeftSlices.h"
#include "midend/removeMiss.h"
#include "midend/removeParameters.h"
#include "midend/removeUnusedParameters.h"
#include "midend/simplifyKey.h"
Expand Down Expand Up @@ -69,6 +70,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions& options, std::ostream* o
std::initializer_list<Visitor *> midendPasses = {
options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr,
new P4::CheckTableSize(),
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateSerEnums(&refMap, &typeMap),
new P4::RemoveActionParameters(&refMap, &typeMap),
Expand Down
2 changes: 2 additions & 0 deletions backends/ebpf/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ limitations under the License.
#include "midend/noMatch.h"
#include "midend/removeExits.h"
#include "midend/removeLeftSlices.h"
#include "midend/removeMiss.h"
#include "midend/removeParameters.h"
#include "midend/removeSelectBooleans.h"
#include "midend/simplifyKey.h"
Expand Down Expand Up @@ -76,6 +77,7 @@ const IR::ToplevelBlock* MidEnd::run(EbpfOptions& options,
if (options.loadIRFromJson == false) {
std::initializer_list<Visitor *> midendPasses = {
new P4::ConvertEnums(&refMap, &typeMap, new EnumOn32Bits()),
new P4::RemoveMiss(&refMap, &typeMap),
new P4::ClearTypeMap(&typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::SimplifyControlFlow(&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 @@ -45,6 +45,7 @@ limitations under the License.
#include "midend/parserUnroll.h"
#include "midend/predication.h"
#include "midend/removeExits.h"
#include "midend/removeMiss.h"
#include "midend/removeParameters.h"
#include "midend/removeSelectBooleans.h"
#include "midend/simplifyKey.h"
Expand Down Expand Up @@ -80,6 +81,7 @@ MidEnd::MidEnd(CompilerOptions& options) {
// TODO: handle bit-slices as out arguments
addPasses({
options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr,
new P4::RemoveMiss(&refMap, &typeMap),
new P4::EliminateNewtype(&refMap, &typeMap),
new P4::EliminateSerEnums(&refMap, &typeMap),
new P4::RemoveActionParameters(&refMap, &typeMap),
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/def_use.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ bool ComputeWriteSet::preorder(const IR::Member* expression) {
if (type->is<IR::Type_Method>())
return false;
if (TableApplySolver::isHit(expression, storageMap->refMap, storageMap->typeMap) ||
TableApplySolver::isMiss(expression, storageMap->refMap, storageMap->typeMap) ||
TableApplySolver::isActionRun(expression, storageMap->refMap, storageMap->typeMap))
return false;
auto storage = getWrites(expression->expr);
Expand Down
8 changes: 5 additions & 3 deletions frontends/p4/sideEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,10 @@ class DismantleExpression : public Transform {
if (leftValue)
typeMap->setLeftValue(result->final);

// Special case for table.apply().hit, which is not dismantled by
// Special case for table.apply().hit/miss, which is not dismantled by
// the MethodCallExpression.
if (TableApplySolver::isHit(expression, refMap, typeMap)) {
if (TableApplySolver::isHit(expression, refMap, typeMap) ||
TableApplySolver::isMiss(expression, refMap, typeMap)) {
BUG_CHECK(type->is<IR::Type_Boolean>(), "%1%: not boolean", type);
auto tmp = result->createTemporary(type);
auto path = new IR::PathExpression(IR::ID(tmp, nullptr));
Expand Down Expand Up @@ -479,7 +480,8 @@ class DismantleExpression : public Transform {
if (auto mmbr = getParent<IR::Member>()) {
auto tbl = TableApplySolver::isActionRun(mmbr, refMap, typeMap);
auto tbl1 = TableApplySolver::isHit(mmbr, refMap, typeMap);
tbl_apply = tbl != nullptr || tbl1 != nullptr;
auto tbl2 = TableApplySolver::isMiss(mmbr, refMap, typeMap);
tbl_apply = tbl != nullptr || tbl1 != nullptr || tbl2 != nullptr;
}
// Simplified method call, with arguments substituted
auto simplified = new IR::MethodCallExpression(
Expand Down
22 changes: 22 additions & 0 deletions frontends/p4/tableApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,28 @@ TableApplySolver::isHit(const IR::Expression* expression,
return am->object->to<IR::P4Table>();
}

const IR::P4Table*
TableApplySolver::isMiss(const IR::Expression* expression,
ReferenceMap* refMap,
TypeMap* typeMap) {
if (!expression->is<IR::Member>())
return nullptr;
auto mem = expression->to<IR::Member>();
if (!mem->expr->is<IR::MethodCallExpression>())
return nullptr;
if (mem->member != IR::Type_Table::miss)
return nullptr;
auto mce = mem->expr->to<IR::MethodCallExpression>();
auto mi = P4::MethodInstance::resolve(mce, refMap, typeMap);
if (!mi->isApply())
return nullptr;

auto am = mi->to<P4::ApplyMethod>();
if (!am->object->is<IR::P4Table>())
return nullptr;
return am->object->to<IR::P4Table>();
}

const IR::P4Table*
TableApplySolver::isActionRun(const IR::Expression* expression,
ReferenceMap* refMap,
Expand Down
5 changes: 4 additions & 1 deletion frontends/p4/tableApply.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ limitations under the License.
namespace P4 {

// These are used to figure out whether an expression has the form:
// table.apply().hit
// table.apply().hit,
// table.apply().miss,
// or
// table.apply().action_run
class TableApplySolver {
public:
static const IR::P4Table* isHit(const IR::Expression* expression,
ReferenceMap* refMap, TypeMap* typeMap);
static const IR::P4Table* isMiss(const IR::Expression* expression,
ReferenceMap* refMap, TypeMap* typeMap);
static const IR::P4Table* isActionRun(const IR::Expression* expression,
ReferenceMap* refMap, TypeMap* typeMap);
};
Expand Down
3 changes: 2 additions & 1 deletion ir/ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,9 @@ P4Table::getApplyMethodType() const {
actions);
auto alv = actions->value->to<IR::ActionList>();
auto hit = new IR::StructField(IR::Type_Table::hit, IR::Type_Boolean::get());
auto miss = new IR::StructField(IR::Type_Table::miss, IR::Type_Boolean::get());
auto label = new IR::StructField(IR::Type_Table::action_run, new IR::Type_ActionEnum(alv));
auto rettype = new IR::Type_Struct(ID(name), { hit, label });
auto rettype = new IR::Type_Struct(ID(name), { hit, miss, label });
auto applyMethod = new IR::Type_Method(rettype, new IR::ParameterList());
return applyMethod;
}
Expand Down
1 change: 1 addition & 0 deletions ir/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const cstring IR::Type_StructLike::minSizeInBits = "minSizeInBits";
const cstring IR::Type_StructLike::minSizeInBytes = "minSizeInBytes";

const IR::ID IR::Type_Table::hit = ID("hit");
const IR::ID IR::Type_Table::miss = ID("miss");
const IR::ID IR::Type_Table::action_run = ID("action_run");

const cstring IR::Annotation::nameAnnotation = "name";
Expand Down
1 change: 1 addition & 0 deletions ir/type.def
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ class Type_Table : Type, IApply {
/// names for the fields of the struct returned
/// by applying a table
static const ID hit;
static const ID miss;
static const ID action_run;
const IR::Type* getP4Type() const override { return nullptr; }
dbprint { out << table->name; }
Expand Down
16 changes: 9 additions & 7 deletions midend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ set (MIDEND_SRCS
complexComparison.cpp
convertEnums.cpp
copyStructures.cpp
eliminateTuples.cpp
eliminateNewtype.cpp
eliminateSerEnums.cpp
eliminateTuples.cpp
expandEmit.cpp
expandLookahead.cpp
fillEnumMap.cpp
flattenHeaders.cpp
flattenInterfaceStructs.cpp
interpreter.cpp
Expand All @@ -31,8 +32,10 @@ set (MIDEND_SRCS
orderArguments.cpp
parserUnroll.cpp
predication.cpp
removeAssertAssume.cpp
removeExits.cpp
removeLeftSlices.cpp
removeMiss.cpp
removeParameters.cpp
removeSelectBooleans.cpp
removeUnusedParameters.cpp
Expand All @@ -43,8 +46,6 @@ set (MIDEND_SRCS
singleArgumentSelect.cpp
tableHit.cpp
validateProperties.cpp
fillEnumMap.cpp
removeAssertAssume.cpp
)

set (MIDEND_HDRS
Expand All @@ -54,14 +55,15 @@ set (MIDEND_HDRS
complexComparison.h
convertEnums.h
copyStructures.h
eliminateTuples.h
eliminateNewtype.h
eliminateSerEnums.h
eliminateTuples.h
expandEmit.h
expandLookahead.h
expr_uses.h
flattenInterfaceStructs.h
fillEnumMap.h
flattenHeaders.h
flattenInterfaceStructs.h
has_side_effects.h
interpreter.h
local_copyprop.h
Expand All @@ -71,8 +73,10 @@ set (MIDEND_HDRS
orderArguments.h
parserUnroll.h
predication.h
removeAssertAssume.h
removeExits.h
removeLeftSlices.h
removeMiss.h
removeParameters.h
removeSelectBooleans.h
removeUnusedParameters.h
Expand All @@ -83,8 +87,6 @@ set (MIDEND_HDRS
singleArgumentSelect.h
tableHit.h
validateProperties.h
fillEnumMap.h
removeAssertAssume.h
)

add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${MIDEND_SRCS};${MIDEND_HDRS}")
Expand Down
29 changes: 29 additions & 0 deletions midend/removeMiss.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Copyright 2019 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 "removeMiss.h"
#include "frontends/p4/tableApply.h"

namespace P4 {

const IR::Node* DoRemoveMiss::preorder(IR::Member* expression) {
if (!TableApplySolver::isMiss(expression, refMap, typeMap))
return expression;
auto hit = new IR::Member(expression->expr, IR::Type_Table::hit);
return new IR::LNot(hit);
}

} // namespace P4
54 changes: 54 additions & 0 deletions midend/removeMiss.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Copyright 2019 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_REMOVEMISS_H_
#define _MIDEND_REMOVEMISS_H_

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

namespace P4 {

/**
* This visitor converts table.apply().miss into !table.apply().hit.
*/
class DoRemoveMiss : public Transform {
ReferenceMap* refMap;
TypeMap* typeMap;
public:
DoRemoveMiss(ReferenceMap* refMap, TypeMap* typeMap) :
refMap(refMap), typeMap(typeMap)
{ visitDagOnce = false; CHECK_NULL(typeMap); setName("DoRemoveMiss"); }
const IR::Node* preorder(IR::Member* expression) override;
};

class RemoveMiss : public PassManager {
public:
RemoveMiss(ReferenceMap* refMap, TypeMap* typeMap,
TypeChecking* typeChecking = nullptr) {
if (!typeChecking)
typeChecking = new TypeChecking(refMap, typeMap);
passes.push_back(typeChecking);
passes.push_back(new DoRemoveMiss(refMap, typeMap));
setName("RemoveMiss");
}
};

} // namespace P4

#endif /* _MIDEND_REMOVEMISS_H_ */
17 changes: 13 additions & 4 deletions midend/tableHit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,25 @@ namespace P4 {

const IR::Node* DoTableHit::postorder(IR::AssignmentStatement* statement) {
LOG3("Visiting " << getOriginal());
if (!TableApplySolver::isHit(statement->right, refMap, typeMap))
auto right = statement->right;
bool negated = false;
if (auto neg = right->to<IR::LNot>()) {
// We handle !hit, which may have been created by the removal of miss
negated = true;
right = neg->expr;
}

if (!TableApplySolver::isHit(right, refMap, typeMap))
return statement;

auto tstat = new IR::AssignmentStatement(
statement->left->clone(), new IR::BoolLiteral(true));
auto fstat = new IR::AssignmentStatement(
statement->left->clone(), new IR::BoolLiteral(false));
auto ifStatement = new IR::IfStatement(
statement->right, tstat, fstat);
return ifStatement;
if (negated)
return new IR::IfStatement(right, fstat, tstat);
else
return new IR::IfStatement(right, tstat, fstat);
}

} // namespace P4
File renamed without changes.
42 changes: 42 additions & 0 deletions testdata/p4_16_samples/issue2044-bmv2.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <core.p4>
#include <v1model.p4>

header hdr {
bit<32> b;
}

struct Headers {
hdr h;
}

struct Meta {}

parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) {
state start {
transition accept;
}
}

control vrfy(inout Headers h, inout Meta m) { apply {} }
control update(inout Headers h, inout Meta m) { apply {} }

control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { apply {} }

control deparser(packet_out b, in Headers h) {
apply { b.emit(h); }
}

control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) {
table t {
key = { h.h.b : exact; }
actions = { NoAction; }
default_action = NoAction;
}
apply {
if (t.apply().miss) {
h.h.setInvalid();
}
}
}

V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main;
File renamed without changes.
Loading

0 comments on commit bd0308a

Please sign in to comment.