Skip to content

Commit

Permalink
Support for 128 bit operations
Browse files Browse the repository at this point in the history
Signed-off-by: Sosutha Sethuramapandian
<[email protected]>

* Added movh statement definition
* Added support for 128 bitwise operation
* Added support for 128 bit equal and not equal operators.
* Updated testcase and output
  • Loading branch information
Sosutha committed Oct 22, 2024
1 parent b4a9df0 commit fd67889
Show file tree
Hide file tree
Showing 23 changed files with 4,584 additions and 28 deletions.
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
214 changes: 208 additions & 6 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 @@ -966,7 +983,7 @@ bool ConvertStatementToDpdk::preorder(const IR::IfStatement *s) {
auto true_label = refmap->newName("label_true");
auto false_label = refmap->newName("label_false");
auto end_label = refmap->newName("label_end");
auto gen = new BranchingInstructionGeneration(refmap, typemap);
auto gen = new BranchingInstructionGeneration(this, refmap, typemap);
bool res = gen->generate(s->condition, true_label, false_label, true);

instructions.append(gen->instructions);
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
18 changes: 15 additions & 3 deletions backends/dpdk/dpdkHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ limitations under the License.

namespace P4::DPDK {

class ConvertStatementToDpdk;

/// @brief Name of the metadata used as output port.
///
/// PNA specification does not contain standard metadata for specifying output port.
Expand Down Expand Up @@ -115,6 +117,7 @@ const char DirectResourceTableEntryIndex[] = "table_entry_index";
* optmized.
*/
class BranchingInstructionGeneration {
ConvertStatementToDpdk *convert;
P4::ReferenceMap *refMap;
P4::TypeMap *typeMap;
bool nested(const IR::Node *n) {
Expand All @@ -127,8 +130,9 @@ class BranchingInstructionGeneration {

public:
IR::IndexedVector<IR::DpdkAsmStatement> instructions;
BranchingInstructionGeneration(P4::ReferenceMap *refMap, P4::TypeMap *typeMap)
: refMap(refMap), typeMap(typeMap) {}
BranchingInstructionGeneration(ConvertStatementToDpdk *convert, P4::ReferenceMap *refMap,
P4::TypeMap *typeMap)
: convert(convert), refMap(refMap), typeMap(typeMap) {}
bool generate(const IR::Expression *, cstring, cstring, bool);
};

Expand All @@ -150,13 +154,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 +193,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
Loading

0 comments on commit fd67889

Please sign in to comment.