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

[P4TC] Align key components to the nearest 8-bit size #5024

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
120 changes: 95 additions & 25 deletions backends/ebpf/codeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,6 @@ void CodeGenInspector::emitAssignStatement(const IR::Type *ltype, const IR::Expr
width = scalar->implementationWidthInBits();
memcpy = !EBPFScalarType::generatesScalar(width);
}

builder->emitIndent();
if (memcpy) {
builder->append("__builtin_memcpy(&");
Expand All @@ -368,15 +367,15 @@ void CodeGenInspector::emitAssignStatement(const IR::Type *ltype, const IR::Expr
visit(rexpr);
builder->appendFormat(", %d)", scalar->bytesRequired());
} else {
if (lexpr != nullptr) {
visit(lexpr);
} else {
builder->append(lpath);
}
builder->append(" = ");
if (builder->target->name == "P4TC") {
emitTCAssignmentEndianessConversion(lexpr, rexpr);
emitTCAssignmentEndianessConversion(ltype, lexpr, rexpr, lpath);
} else {
if (lexpr != nullptr) {
visit(lexpr);
} else {
builder->append(lpath);
}
builder->append(" = ");
visit(rexpr);
}
}
Expand Down Expand Up @@ -493,7 +492,7 @@ void CodeGenInspector::emitAndConvertByteOrder(const IR::Expression *expr, cstri
}
unsigned shift = loadSize - widthToEmit;
builder->appendFormat("%v(", emit);
visit(expr);
getBitAlignment(expr);
if (shift != 0 && byte_order == "HOST") builder->appendFormat(" << %d", shift);
builder->append(")");
}
Expand All @@ -513,7 +512,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
rByteOrder = tcTarget->getByteOrder(typeMap, action, rexpr);
}
if (lByteOrder == rByteOrder) {
visit(lexpr);
getBitAlignment(lexpr);
if (isScalar) {
builder->spc();
builder->append(stringop);
Expand All @@ -522,7 +521,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
builder->append(", &");
}
if (!b->is<IR::Operation_Relation>()) expressionPrecedence = b->getPrecedence() + 1;
visit(rexpr);
getBitAlignment(rexpr);
return;
}
if (lByteOrder == "NETWORK") {
Expand All @@ -543,14 +542,14 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
builder->append(", &");
}
if (!b->is<IR::Operation_Relation>()) expressionPrecedence = b->getPrecedence() + 1;
visit(rexpr);
getBitAlignment(rexpr);
return;
} else if (rByteOrder == "NETWORK") {
// ConvertRight
auto ftype = typeMap->getType(rexpr);
auto et = EBPFTypeFactory::instance->create(ftype);
unsigned width = dynamic_cast<IHasWidth *>(et)->widthInBits();
visit(lexpr);
getBitAlignment(rexpr);
if (isScalar) {
builder->spc();
builder->append(stringop);
Expand All @@ -568,8 +567,19 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool
return;
}

void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression *lexpr,
const IR::Expression *rexpr) {
void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Type *ltype,
const IR::Expression *lexpr,
const IR::Expression *rexpr,
cstring lpath) {
bool needsBitAlignment = storeBitAlignment(ltype, lexpr, lpath);
if (!needsBitAlignment) {
if (lexpr != nullptr) {
visit(lexpr);
} else {
builder->append(lpath);
}
builder->append(" = ");
}
auto action = findContext<IR::P4Action>();
auto b = dynamic_cast<const P4TCTarget *>(builder->target);
cstring lByteOrder = "HOST"_cs, rByteOrder = "HOST"_cs;
Expand All @@ -579,27 +589,22 @@ void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression
if (rexpr) {
rByteOrder = b->getByteOrder(typeMap, action, rexpr);
}
if (lByteOrder == rByteOrder) {
visit(rexpr);
return;
}
auto ftype = typeMap->getType(rexpr);
auto et = EBPFTypeFactory::instance->create(ftype);
unsigned width = dynamic_cast<IHasWidth *>(et)->widthInBits();
if (width <= 8) {
visit(rexpr);
return;
}
if (rByteOrder == "NETWORK") {
} else if (lByteOrder == rByteOrder) {
getBitAlignment(rexpr);
} else if (rByteOrder == "NETWORK") {
// If left side of assignment is not annotated field i.e host endian and right expression
// is annotated field i.e network endian, we need to convert rexp to host order.
// Example -
// select_0 = hdr.ipv4.diffserv
// select_0 = bntoh(hdr.ipv4.diffserv)
//
emitAndConvertByteOrder(rexpr, "HOST"_cs);
}
if (lByteOrder == "NETWORK") {
} else if (lByteOrder == "NETWORK") {
// If left side of assignment is annotated field i.e network endian, we need to convert
// right expression to network order.
// Example -
Expand All @@ -608,8 +613,73 @@ void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression
//
emitAndConvertByteOrder(rexpr, "NETWORK"_cs);
}
if (needsBitAlignment) {
builder->append("))");
}
}

return;
bool CodeGenInspector::storeBitAlignment(const IR::Type *ltype, const IR::Expression *lexpr,
cstring lpath) {
auto tcTarget = dynamic_cast<const P4TCTarget *>(builder->target);
if (lexpr != nullptr) {
if (!(lexpr->is<IR::Member>() || lexpr->is<IR::PathExpression>())) {
return false;
}
}
auto ebpfType = EBPFTypeFactory::instance->create(ltype);
EBPFScalarType *scalar = nullptr;
if (ebpfType->is<EBPFScalarType>()) {
scalar = ebpfType->to<EBPFScalarType>();
bool primitive = tcTarget->isPrimitiveByteAligned(scalar->implementationWidthInBits());
if (primitive) {
return false;
} else {
cstring storePrimitive = scalar->implementationWidthInBits() < 32
? "storePrimitive32"_cs
: "storePrimitive64"_cs;
builder->appendFormat("%v((u8 *)&", storePrimitive);
if (lexpr != nullptr) {
visit(lexpr);
} else {
builder->append(lpath);
}
builder->appendFormat(", %d, (", scalar->implementationWidthInBits());
return true;
}
}
return false;
}

void CodeGenInspector::getBitAlignment(const IR::Expression *expression) {
if (expression->is<IR::Member>() || expression->is<IR::PathExpression>()) {
auto ftype = typeMap->getType(expression);
if (!ftype) {
visit(expression);
return;
}
auto tcTarget = dynamic_cast<const P4TCTarget *>(builder->target);
auto ebpfType = EBPFTypeFactory::instance->create(ftype);
EBPFScalarType *scalar = nullptr;
if (ebpfType->is<EBPFScalarType>()) {
scalar = ebpfType->to<EBPFScalarType>();
bool isPrimitive =
tcTarget->isPrimitiveByteAligned(scalar->implementationWidthInBits());
if (!isPrimitive) {
cstring getPrimitive = scalar->implementationWidthInBits() < 32
? "getPrimitive32"_cs
: "getPrimitive64"_cs;
builder->appendFormat("%v((u8 *)", getPrimitive);
visit(expression);
builder->appendFormat(", %d)", scalar->implementationWidthInBits());
} else {
visit(expression);
}
} else {
visit(expression);
}
} else {
visit(expression);
}
}

unsigned EBPFInitializerUtils::ebpfTypeWidth(P4::TypeMap *typeMap, const IR::Expression *expr) {
Expand Down
6 changes: 4 additions & 2 deletions backends/ebpf/codeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ class CodeGenInspector : public Inspector {
void widthCheck(const IR::Node *node) const;
void emitAndConvertByteOrder(const IR::Expression *expr, cstring byte_order);
void emitTCBinaryOperation(const IR::Operation_Binary *b, bool isScalar);
void emitTCAssignmentEndianessConversion(const IR::Expression *lexpr,
const IR::Expression *rexpr);
void emitTCAssignmentEndianessConversion(const IR::Type *ltype, const IR::Expression *lexpr,
const IR::Expression *rexpr, cstring lpath);
void getBitAlignment(const IR::Expression *expression);
bool storeBitAlignment(const IR::Type *ltype, const IR::Expression *lexpr, cstring lpath);
};

class EBPFInitializerUtils {
Expand Down
2 changes: 1 addition & 1 deletion backends/ebpf/ebpfBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void emitFilterModel(const EbpfOptions &options, Target *target, const IR::Tople
CodeBuilder c(target);
CodeBuilder h(target);

EBPFTypeFactory::createFactory(typeMap);
EBPFTypeFactory::createFactory(typeMap, false);
auto ebpfprog = new EBPFProgram(options, toplevel->getProgram(), refMap, typeMap, toplevel);
if (!ebpfprog->build()) return;

Expand Down
10 changes: 5 additions & 5 deletions backends/ebpf/ebpfParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,17 +185,17 @@ bool StateTranslationVisitor::preorder(const IR::SelectExpression *expression) {
BUG_CHECK(expression->select->components.size() == 1, "%1%: tuple not eliminated in select",
expression->select);
selectValue = state->parser->program->refMap->newName("select");
auto type = state->parser->program->typeMap->getType(expression->select, true);
if (auto list = type->to<IR::Type_List>()) {
selectType = state->parser->program->typeMap->getType(expression->select, true);
if (auto list = selectType->to<IR::Type_List>()) {
BUG_CHECK(list->components.size() == 1, "%1% list type with more than 1 element", list);
type = list->components.at(0);
selectType = list->components.at(0);
}
auto etype = EBPFTypeFactory::instance->create(type);
auto etype = EBPFTypeFactory::instance->create(selectType);
builder->emitIndent();
etype->declare(builder, selectValue, false);
builder->endOfStatement(true);

emitAssignStatement(type, nullptr, selectValue, expression->select->components.at(0));
emitAssignStatement(selectType, nullptr, selectValue, expression->select->components.at(0));
builder->newline();

// Init value_sets
Expand Down
1 change: 1 addition & 0 deletions backends/ebpf/ebpfParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class StateTranslationVisitor : public CodeGenInspector {
protected:
/// Stores the result of evaluating the select argument.
cstring selectValue;
const IR::Type *selectType;

P4::P4CoreLibrary &p4lib;
const EBPFParserState *state;
Expand Down
62 changes: 61 additions & 1 deletion backends/ebpf/ebpfType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ limitations under the License.
namespace P4::EBPF {

EBPFTypeFactory *EBPFTypeFactory::instance;
bool EBPFTypeFactory::isTC;

EBPFType *EBPFTypeFactory::create(const IR::Type *type) {
CHECK_NULL(type);
Expand All @@ -27,7 +28,11 @@ EBPFType *EBPFTypeFactory::create(const IR::Type *type) {
if (type->is<IR::Type_Boolean>()) {
result = new EBPFBoolType();
} else if (auto bt = type->to<IR::Type_Bits>()) {
result = new EBPFScalarType(bt);
if (EBPFTypeFactory::isTC) {
result = new EBPFScalarTypePNA(bt);
} else {
result = new EBPFScalarType(bt);
}
} else if (auto st = type->to<IR::Type_StructLike>()) {
result = new EBPFStructType(st);
} else if (auto tt = type->to<IR::Type_Typedef>()) {
Expand Down Expand Up @@ -384,4 +389,59 @@ void EBPFMethodDeclaration::emit(CodeBuilder *builder) {
builder->newline();
}

unsigned EBPFScalarTypePNA::alignment() const {
if (width <= 8)
return 1;
else if (width <= 16)
return 2;
else if (width <= 24)
return 1; // compiled as u8*
else if (width <= 32)
return 4;
else if (width <= 56)
return 1; // compiled as u8*
else if (width <= 64)
return 8;
else
// compiled as u8*
return 1;
}

void EBPFScalarTypePNA::declare(CodeBuilder *builder, cstring id, bool asPointer) {
if (generatesScalar(width) && isPrimitiveByteAligned == true) {
emit(builder);
if (asPointer) builder->append("*");
builder->spc();
builder->append(id);
} else {
if (asPointer)
builder->appendFormat("u8* %s", id.c_str());
else
builder->appendFormat("u8 %s[%d]", id.c_str(), bytesRequired());
}
}

void EBPFScalarTypePNA::declareInit(CodeBuilder *builder, cstring id, bool asPointer) {
if (generatesScalar(width) && isPrimitiveByteAligned == true) {
emit(builder);
if (asPointer) builder->append("*");
builder->spc();
id = id + cstring(" = 0");
builder->append(id);
} else {
if (asPointer)
builder->appendFormat("u8* %s = NULL", id.c_str());
else
builder->appendFormat("u8 %s[%d] = {0}", id.c_str(), bytesRequired());
}
}

void EBPFScalarTypePNA::emitInitializer(CodeBuilder *builder) {
if (generatesScalar(width) && isPrimitiveByteAligned == true) {
builder->append("0");
} else {
builder->append("{ 0 }");
}
}

} // namespace P4::EBPF
18 changes: 17 additions & 1 deletion backends/ebpf/ebpfType.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ class EBPFTypeFactory {

public:
static EBPFTypeFactory *instance;
static void createFactory(const P4::TypeMap *typeMap) {
static bool isTC;
static void createFactory(const P4::TypeMap *typeMap, bool TC) {
EBPFTypeFactory::instance = new EBPFTypeFactory(typeMap);
EBPFTypeFactory::isTC = TC;
}
virtual EBPFType *create(const IR::Type *type);
};
Expand Down Expand Up @@ -223,6 +225,20 @@ class EBPFMethodDeclaration : public EBPFObject {
DECLARE_TYPEINFO(EBPFMethodDeclaration, EBPFObject);
};

class EBPFScalarTypePNA : public EBPFScalarType {
bool isPrimitiveByteAligned = false;

public:
explicit EBPFScalarTypePNA(const IR::Type_Bits *bits) : EBPFScalarType(bits) {
isPrimitiveByteAligned = (width <= 8 || width <= 16 || (width > 24 && width <= 32) ||
(width > 56 && width <= 64));
}
unsigned alignment() const;
void declare(CodeBuilder *builder, cstring id, bool asPointer);
void declareInit(CodeBuilder *builder, cstring id, bool asPointer);
void emitInitializer(CodeBuilder *builder);
};

} // namespace P4::EBPF

#endif /* BACKENDS_EBPF_EBPFTYPE_H_ */
2 changes: 1 addition & 1 deletion backends/ebpf/psa/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void PSASwitchBackend::convert(const IR::ToplevelBlock *tlb) {
main->apply(*parsePsaArch);
program = toplevel->getProgram();

EBPFTypeFactory::createFactory(typeMap);
EBPFTypeFactory::createFactory(typeMap, false);
auto *convertToEbpfPSA = new ConvertToEbpfPSA(options, refMap, typeMap);
PassManager toEBPF = {
new P4::DiscoverStructure(&structure),
Expand Down
5 changes: 5 additions & 0 deletions backends/ebpf/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ class P4TCTarget : public KernelSamplesTarget {
}
return "HOST"_cs;
}

bool isPrimitiveByteAligned(int width) const {
return (width <= 8 || width <= 16 || (width > 24 && width <= 32) ||
(width > 56 && width <= 64));
}
};

/// Target XDP.
Expand Down
1 change: 1 addition & 0 deletions backends/tc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ set(P4TC_BACKEND_HEADERS
pnaProgramStructure.h
tcAnnotations.h
tcExterns.h
handleBitAlignment.h
version.h
../ebpf/codeGen.h
../ebpf/ebpfBackend.h
Expand Down
Loading
Loading