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

Support for 128 bit bitwise operation #4952

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
3 changes: 2 additions & 1 deletion backends/dpdk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ set (P4_16_SUITES
"${P4C_SOURCE_DIR}/testdata/p4_16_samples/pna-*.p4"
"${P4C_SOURCE_DIR}/testdata/p4_16_psa_errors/*.p4"
"${P4C_SOURCE_DIR}/testdata/p4_16_dpdk_errors/*.p4"
"${P4C_SOURCE_DIR}/testdata/p4_16_pna_errors/*.p4")
"${P4C_SOURCE_DIR}/testdata/p4_16_pna_errors/*.p4"
"${P4C_SOURCE_DIR}/testdata/p4_16_samples/dash/dash-pipeline-pna-dpdk.p4")
p4c_add_tests("dpdk" ${DPDK_COMPILER_DRIVER} "${P4_16_SUITES}" "" "--bfrt")

#### DPDK-PTF Tests
Expand Down
1 change: 1 addition & 0 deletions backends/dpdk/DpdkXfail.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ p4c_add_xfail_reason("dpdk"
testdata/p4_16_samples/pna-dpdk-invalid-hdr-warnings5.p4
testdata/p4_16_samples/pna-dpdk-invalid-hdr-warnings6.p4
testdata/p4_16_samples/pna-dpdk-header-union-stack2.p4
testdata/p4_16_samples/dash/dash-pipeline-pna-dpdk.p4
)

p4c_add_xfail_reason("dpdk"
Expand Down
4 changes: 4 additions & 0 deletions backends/dpdk/dbprint-dpdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,8 @@ void IR::DpdkMovStatement::dbprint(std::ostream &out) const {
out << "mov " << dst << " " << src << std::endl;
}

void IR::DpdkMovhStatement::dbprint(std::ostream &out) const {
out << "movh " << dst << " " << src << std::endl;
}

} // namespace P4
14 changes: 14 additions & 0 deletions backends/dpdk/dpdk.def
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ class DpdkHeaderType : Type_Header, IDPDKNode {
#nodbprint
}

class DpdkHeaderInstance : IDPDKNode {
Declaration_Variable name;
Type_Header headerType;
std::ostream& toSpec(std::ostream& out) const override;
#nodbprint
}

class DpdkStructType : Type_Struct, IDPDKNode {
std::ostream& toSpec(std::ostream& out) const override;
#nodbprint
Expand Down Expand Up @@ -99,6 +106,7 @@ class DpdkLearner {
class DpdkAsmProgram {
inline IndexedVector<DpdkHeaderType> headerType;
inline IndexedVector<DpdkStructType> structType;
inline IndexedVector<DpdkHeaderInstance> headerInstance;
inline IndexedVector<DpdkExternDeclaration> externDeclarations;
inline IndexedVector<DpdkAction> actions;
inline IndexedVector<DpdkTable> tables;
Expand Down Expand Up @@ -304,6 +312,12 @@ class DpdkMovStatement : DpdkUnaryStatement {
#noconstructor
}

class DpdkMovhStatement : DpdkUnaryStatement {
DpdkMovhStatement(Expression dst, Expression src) :
DpdkUnaryStatement("movh"_cs, dst, src) { }
#noconstructor
}

abstract DpdkBinaryStatement : DpdkAssignmentStatement {
Expression src1;
Expression src2;
Expand Down
6 changes: 6 additions & 0 deletions backends/dpdk/dpdkArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,12 @@ class ValidateOperandSize : public Inspector {
}

void postorder(const IR::Operation_Binary *binop) override {
if (binop->is<IR::BOr>() || binop->is<IR::BAnd>() || binop->is<IR::BXor>() ||
binop->is<IR::Equ>() || binop->is<IR::Neq>()) {
if (auto src1Type = binop->left->type->to<IR::Type_Bits>()) {
if (src1Type->width_bits() == 128) return;
}
}
isValidOperandSize(binop->left);
isValidOperandSize(binop->right);
}
Expand Down
212 changes: 207 additions & 5 deletions backends/dpdk/dpdkHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,17 @@ void ConvertStatementToDpdk::process_relation_operation(const IR::Expression *ds
cstring label2 = true_label;
bool condNegated = false;
if (op->is<IR::Equ>()) {
add_instr(new IR::DpdkJmpEqualStatement(true_label, op->left, op->right));
if (checkIf128bitOp(op->left, op->right)) {
add128ComparisonInstr(true_label, op->left, op->right, "equ");
} else {
add_instr(new IR::DpdkJmpEqualStatement(true_label, op->left, op->right));
}
} else if (op->is<IR::Neq>()) {
add_instr(new IR::DpdkJmpNotEqualStatement(true_label, op->left, op->right));
if (checkIf128bitOp(op->left, op->right)) {
add128ComparisonInstr(true_label, op->left, op->right, "neq");
} else {
add_instr(new IR::DpdkJmpNotEqualStatement(true_label, op->left, op->right));
}
} else if (op->is<IR::Lss>()) {
add_instr(new IR::DpdkJmpLessStatement(true_label, op->left, op->right));
} else if (op->is<IR::Grt>()) {
Expand Down Expand Up @@ -212,11 +220,20 @@ bool ConvertStatementToDpdk::preorder(const IR::AssignmentStatement *a) {
} else if (right->is<IR::LOr>() || right->is<IR::LAnd>()) {
process_logical_operation(left, r);
} else if (right->is<IR::BOr>()) {
add_instr(new IR::DpdkOrStatement(left, src1Op, src2Op));
if (checkIf128bitOp(src1Op, src2Op))
add128bitwiseInstr(src1Op, src2Op, "or");
else
add_instr(new IR::DpdkOrStatement(left, src1Op, src2Op));
} else if (right->is<IR::BAnd>()) {
add_instr(new IR::DpdkAndStatement(left, src1Op, src2Op));
if (checkIf128bitOp(src1Op, src2Op))
add128bitwiseInstr(src1Op, src2Op, "and");
else
add_instr(new IR::DpdkAndStatement(left, src1Op, src2Op));
} else if (right->is<IR::BXor>()) {
add_instr(new IR::DpdkXorStatement(left, src1Op, src2Op));
if (checkIf128bitOp(src1Op, src2Op))
add128bitwiseInstr(src1Op, src2Op, "xor");
else
add_instr(new IR::DpdkXorStatement(left, src1Op, src2Op));
} else if (right->is<IR::ArrayIndex>()) {
add_instr(new IR::DpdkMovStatement(a->left, a->right));
} else {
Expand Down Expand Up @@ -1460,4 +1477,189 @@ bool ConvertStatementToDpdk::preorder(const IR::SwitchStatement *s) {
return false;
}

bool ConvertStatementToDpdk::checkIf128bitOp(const IR::Expression *src1Op,
const IR::Expression *src2Op) {
if (auto src1Type = src1Op->type->to<IR::Type_Bits>()) {
if (src1Type->width_bits() == 128) {
if (auto src2Type = src2Op->type->to<IR::Type_Bits>()) {
if (src2Type->width_bits() == 128) return true;
}
}
}
return false;
}

void ConvertStatementToDpdk::add128bitwiseInstr(const IR::Expression *src1Op,
const IR::Expression *src2Op, const char *op) {
// check bool variable to check and create sandbox struct
// sandbox tmp variable creation
if (!createTmpVar) {
createTmpVar = true;
createTmpVarForSandbox();
}
if (!createSandboxHeaderType) {
createSandboxHeaderType = true;
createSandboxHeader();
}
const IR::Type_Header *Type_Header = nullptr;
const IR::Type_Header *Type_Tmp = nullptr;
for (auto header : structure->header_types) {
if (strcmp(header.first, "_p4c_sandbox_header_t") == 0) {
Type_Header = header.second;
} else if (strcmp(header.first, "_p4c_tmp128_t") == 0) {
Type_Tmp = header.second;
}
}
if (Type_Header == nullptr || Type_Tmp == nullptr) {
BUG("Header type not found");
}
auto src1OpHeaderName = src1Op->toString();
if (src1Op->is<IR::Member>()) {
src1OpHeaderName = src1Op->to<IR::Member>()->member.name;
}
auto tmpVarOpName = src1OpHeaderName + "_tmp";
src1OpHeaderName = src1OpHeaderName + "_128";
auto src1OpHeader = new IR::Declaration_Variable(src1OpHeaderName, Type_Header);
auto tmpVarOp = new IR::Declaration_Variable(tmpVarOpName, Type_Tmp);
auto src1OpHeaderInstance = new IR::DpdkHeaderInstance(src1OpHeader, Type_Header);
auto tmpVarOpInstance = new IR::DpdkHeaderInstance(tmpVarOp, Type_Tmp);
structure->addHeaderInstances(src1OpHeaderInstance);
structure->addHeaderInstances(tmpVarOpInstance);
auto src1OpUpper =
new IR::Member(new IR::PathExpression("h." + src1OpHeader->name), IR::ID("upper_half"));
auto src1OpLower =
new IR::Member(new IR::PathExpression("h." + src1OpHeader->name), IR::ID("lower_half"));
auto tmp = new IR::Member(new IR::PathExpression("h." + tmpVarOp->name), IR::ID("inter"));
add_instr(new IR::DpdkMovhStatement(src1OpUpper, src1Op));
add_instr(new IR::DpdkMovStatement(src1OpLower, src1Op));
if (src2Op->is<IR::Constant>()) {
add_instr(new IR::DpdkMovStatement(tmp, src1OpLower));
if (strcmp(op, "xor") == 0) {
add_instr(new IR::DpdkXorStatement(tmp, tmp, src2Op));
} else if (strcmp(op, "or") == 0) {
add_instr(new IR::DpdkOrStatement(tmp, tmp, src2Op));
} else if (strcmp(op, "and") == 0) {
add_instr(new IR::DpdkAndStatement(tmp, tmp, src2Op));
}
add_instr(new IR::DpdkMovStatement(src1Op, tmp));
add_instr(new IR::DpdkMovStatement(tmp, src1OpUpper));
if (strcmp(op, "xor") == 0) {
add_instr(new IR::DpdkXorStatement(tmp, tmp, src2Op));
} else if (strcmp(op, "or") == 0) {
add_instr(new IR::DpdkOrStatement(tmp, tmp, src2Op));
} else if (strcmp(op, "and") == 0) {
add_instr(new IR::DpdkAndStatement(tmp, tmp, src2Op));
}
add_instr(new IR::DpdkMovhStatement(src1Op, tmp));
} else {
auto src2OpHeaderName = src2Op->toString();
if (src2Op->is<IR::Member>()) {
src2OpHeaderName = src2Op->to<IR::Member>()->member.name;
}
src2OpHeaderName = src2OpHeaderName + "_128";
auto src2OpHeader = new IR::Declaration_Variable(src2OpHeaderName, Type_Header);
auto src2OpHeaderInstance = new IR::DpdkHeaderInstance(src2OpHeader, Type_Header);
structure->addHeaderInstances(src2OpHeaderInstance);
auto src2OpUpper =
new IR::Member(new IR::PathExpression("h." + src2OpHeader->name), IR::ID("upper_half"));
auto src2OpLower =
new IR::Member(new IR::PathExpression("h." + src2OpHeader->name), IR::ID("lower_half"));
add_instr(new IR::DpdkMovhStatement(src2OpUpper, src2Op));
add_instr(new IR::DpdkMovStatement(src2OpLower, src2Op));
add_instr(new IR::DpdkMovStatement(tmp, src1OpLower));
if (strcmp(op, "xor") == 0) {
add_instr(new IR::DpdkXorStatement(tmp, tmp, src2OpLower));
} else if (strcmp(op, "or") == 0) {
add_instr(new IR::DpdkOrStatement(tmp, tmp, src2OpLower));
} else if (strcmp(op, "and") == 0) {
add_instr(new IR::DpdkAndStatement(tmp, tmp, src2OpLower));
}
add_instr(new IR::DpdkMovStatement(src1Op, tmp));
add_instr(new IR::DpdkMovStatement(tmp, src1OpUpper));
if (strcmp(op, "xor") == 0) {
add_instr(new IR::DpdkXorStatement(tmp, tmp, src2OpUpper));
} else if (strcmp(op, "or") == 0) {
add_instr(new IR::DpdkOrStatement(tmp, tmp, src2OpUpper));
} else if (strcmp(op, "and") == 0) {
add_instr(new IR::DpdkAndStatement(tmp, tmp, src2OpUpper));
}
add_instr(new IR::DpdkMovhStatement(src1Op, tmp));
}
}

void ConvertStatementToDpdk::createSandboxHeader() {
auto fields = new IR::IndexedVector<IR::StructField>;
fields->push_back(new IR::StructField("upper_half", IR::Type_Bits::get(64)));
fields->push_back(new IR::StructField("lower_half", IR::Type_Bits::get(64)));
const IR::Type_Header *headerStruct =
new IR::Type_Header(IR::ID("_p4c_sandbox_header_t"), *fields);
structure->header_types.emplace(cstring("_p4c_sandbox_header_t"), headerStruct);
}

void ConvertStatementToDpdk::createTmpVarForSandbox() {
auto fields = new IR::IndexedVector<IR::StructField>;
fields->push_back(new IR::StructField("tmp", IR::Type_Bits::get(64)));
const IR::Type_Header *headerStruct = new IR::Type_Header(IR::ID("_p4c_tmp128_t"), *fields);
structure->header_types.emplace(cstring("_p4c_tmp128_t"), headerStruct);
}

void ConvertStatementToDpdk::add128ComparisonInstr(cstring true_label,
const IR::Expression *src1Op, const IR::Expression *src2Op, const char *op) {
if (!createSandboxHeaderType) {
createSandboxHeaderType = true;
createSandboxHeader();
}
const IR::Type_Header *Type_Header = nullptr;
for (auto header : structure->header_types) {
if (strcmp(header.first, "_p4c_sandbox_header_t") == 0) {
Type_Header = header.second;
}
}
if (Type_Header == nullptr) {
BUG("Header type not found");
}
auto src1OpHeaderName = src1Op->toString();
if (src1Op->is<IR::Member>()) {
src1OpHeaderName = src1Op->to<IR::Member>()->member.name;
}
src1OpHeaderName = src1OpHeaderName + "_128";
auto src1OpHeader = new IR::Declaration_Variable(src1OpHeaderName, Type_Header);
auto src1OpHeaderInstance = new IR::DpdkHeaderInstance(src1OpHeader, Type_Header);
structure->addHeaderInstances(src1OpHeaderInstance);
auto src1OpUpper =
new IR::Member(new IR::PathExpression("h." + src1OpHeader->name), IR::ID("upper_half"));
auto src1OpLower =
new IR::Member(new IR::PathExpression("h." + src1OpHeader->name), IR::ID("lower_half"));
add_instr(new IR::DpdkMovhStatement(src1OpUpper, src1Op));
add_instr(new IR::DpdkMovStatement(src1OpLower, src1Op));
if (src2Op->is<IR::Constant>()) {
add_instr(new IR::DpdkXorStatement(src1OpUpper, src1OpUpper, src2Op));
add_instr(new IR::DpdkXorStatement(src1OpLower, src1OpLower, src2Op));
} else {
auto src2OpHeaderName = src2Op->toString();
if (src2Op->is<IR::Member>()) {
src2OpHeaderName = src2Op->to<IR::Member>()->member.name;
}
src2OpHeaderName = src2OpHeaderName + "_128";
auto src2OpHeader = new IR::Declaration_Variable(src2OpHeaderName, Type_Header);
auto src2OpHeaderInstance = new IR::DpdkHeaderInstance(src2OpHeader, Type_Header);
structure->addHeaderInstances(src2OpHeaderInstance);
auto src2OpUpper =
new IR::Member(new IR::PathExpression("h." + src2OpHeader->name), IR::ID("upper_half"));
auto src2OpLower =
new IR::Member(new IR::PathExpression("h." + src2OpHeader->name), IR::ID("lower_half"));
add_instr(new IR::DpdkMovhStatement(src2OpUpper, src2Op));
add_instr(new IR::DpdkMovStatement(src2OpLower, src2Op));
add_instr(new IR::DpdkXorStatement(src1OpUpper, src1OpUpper, src2OpUpper));
add_instr(new IR::DpdkXorStatement(src1OpLower, src1OpLower, src2OpLower));
add_instr(new IR::DpdkXorStatement(src1OpUpper, src1OpUpper, src1OpLower));
}
add_instr(new IR::DpdkXorStatement(src1OpUpper, src1OpUpper, src1OpLower));
if (strcmp(op, "equ") == 0) {
add_instr(new IR::DpdkJmpEqualStatement(true_label, src1OpUpper, new IR::Constant(0)));
} else {
add_instr(new IR::DpdkJmpNotEqualStatement(true_label, src1OpUpper, new IR::Constant(0)));
}
}

} // namespace P4::DPDK
10 changes: 9 additions & 1 deletion backends/dpdk/dpdkHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,17 @@ class ConvertStatementToDpdk : public Inspector {
const IR::P4Parser *parser = nullptr;
const IR::Node *parent = nullptr;
IR::Type_Struct *metadataStruct = nullptr;
bool createSandboxHeaderType = false;
bool createTmpVar = false;

private:
void processHashParams(const IR::Argument *field, IR::Vector<IR::Expression> &components);
bool checkIfBelongToSameHdrMdStructure(const IR::Argument *field);
void updateMdStrAndGenInstr(const IR::Argument *field, IR::Vector<IR::Expression> &components);
cstring getHdrMdStrName(const IR::Member *mem);
bool checkIfConsecutiveHdrMdfields(const IR::Argument *field);
void createSandboxHeader();
void createTmpVarForSandbox();

public:
ConvertStatementToDpdk(P4::ReferenceMap *refmap, P4::TypeMap *typemap,
Expand Down Expand Up @@ -185,8 +189,12 @@ class ConvertStatementToDpdk : public Inspector {
void set_parser(const IR::P4Parser *p) { parser = p; }
void set_parent(const IR::Node *p) { parent = p; }
bool handleConstSwitch(const IR::SwitchStatement *a);
bool checkIf128bitOp(const IR::Expression *, const IR::Expression *);
void add128bitwiseInstr(const IR::Expression *src1Op, const IR::Expression *src2Op,
const char *op);
void add128ComparisonInstr(cstring true_label, const IR::Expression *src1Op,
const IR::Expression *src2Op, const char *op);
};

/// Only simplify complex expression in ingress/egress.
class ProcessControls : public P4::RemoveComplexExpressionsPolicy {
const std::set<cstring> *process;
Expand Down
11 changes: 9 additions & 2 deletions backends/dpdk/dpdkProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,15 @@ const IR::DpdkAsmProgram *ConvertToDpdkProgram::create(IR::P4Program *prog) {
learners.append(egress_converter->getLearners());
}

return new IR::DpdkAsmProgram(headerType, structType, dpdkExternDecls, actions, tables,
selectors, learners, statements, structure->get_globals());
IR::IndexedVector<IR::DpdkHeaderInstance> headerInstances;

for (auto it : structure->header_instances) {
headerInstances.push_back(it.second);
}

return new IR::DpdkAsmProgram(headerType, structType, headerInstances, dpdkExternDecls, actions,
tables, selectors, learners, statements,
structure->get_globals());
}

const IR::Node *ConvertToDpdkProgram::preorder(IR::P4Program *prog) {
Expand Down
7 changes: 7 additions & 0 deletions backends/dpdk/dpdkProgramStructure.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct DpdkProgramStructure {
ordered_map<cstring, const IR::P4Table *> learner_action_table;
ordered_map<cstring, enum InternalTableType> table_type_map;
ordered_map<cstring, const IR::P4Table *> direct_resource_map;
ordered_map<cstring, const IR::DpdkHeaderInstance *> header_instances;

IR::IndexedVector<IR::DpdkDeclaration> variables;

Expand Down Expand Up @@ -70,6 +71,12 @@ struct DpdkProgramStructure {
void push_variable(const IR::DpdkDeclaration *d) { variables.push_back(d); }
IR::IndexedVector<IR::DpdkDeclaration> &get_globals() { return variables; }

void addHeaderInstances(const IR::DpdkHeaderInstance *d) {
if (header_instances.find(d->name->toString()) == header_instances.end()) {
header_instances.emplace(d->name->toString(), d);
}
}

bool hasVisited(const IR::Type_StructLike *st) {
if (auto h = st->to<IR::Type_Header>())
return header_types.count(h->getName());
Expand Down
Loading
Loading