Skip to content

Commit

Permalink
Support for 128 bit bitwise operation
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
* Updated testcase and output
  • Loading branch information
Sosutha committed Oct 9, 2024
1 parent d0b05cf commit 30b7c86
Show file tree
Hide file tree
Showing 18 changed files with 396 additions and 16 deletions.
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
13 changes: 13 additions & 0 deletions backends/dpdk/dpdkArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -1101,10 +1101,23 @@ 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>())
if (checkIf128bitOp(binop->left, binop->right)) return;
isValidOperandSize(binop->left);
isValidOperandSize(binop->right);
}

bool 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;
}

// Reject all operations except typecast if the operand size is beyond the supported limit
void postorder(const IR::Operation_Unary *unop) override {
if (unop->is<IR::Cast>()) return;
Expand Down
148 changes: 145 additions & 3 deletions backends/dpdk/dpdkHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,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(left, src1Op, src2Op))
add128bitInstr(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(left, src1Op, src2Op))
add128bitInstr(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(left, src1Op, src2Op))
add128bitInstr(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 +1469,137 @@ bool ConvertStatementToDpdk::preorder(const IR::SwitchStatement *s) {
return false;
}

bool ConvertStatementToDpdk::checkIf128bitOp(const IR::Expression *left,
const IR::Expression *src1Op,
const IR::Expression *src2Op) {
if (auto t = left->type->to<IR::Type_Bits>()) {
auto leftWidth = t->width_bits();
if (leftWidth == 128) {
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::add128bitInstr(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, "sandbox_header_t") == 0) {
Type_Header = header.second;
} else if (strcmp(header.first, "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"));
if (src2Op->is<IR::Constant>()) {
add_instr(new IR::DpdkMovhStatement(src1OpUpper, src1Op));
add_instr(new IR::DpdkMovStatement(src1OpLower, src1Op));
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(src1OpUpper, src1Op));
add_instr(new IR::DpdkMovStatement(src1OpLower, src1Op));
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("sandbox_header_t"), *fields);
structure->header_types.emplace(cstring("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("tmp128_t"), *fields);
structure->header_types.emplace(cstring("tmp128_t"), headerStruct);
}

} // namespace P4::DPDK
7 changes: 6 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,9 @@ 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 *, const IR::Expression *);
void add128bitInstr(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
9 changes: 9 additions & 0 deletions backends/dpdk/spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ std::ostream &IR::DpdkAsmProgram::toSpec(std::ostream &out) const {
add_comment(out, s->name.toString());
s->toSpec(out) << std::endl;
}
for (auto hi : headerInstance) {
add_comment(out, hi->name->toString());
hi->toSpec(out) << std::endl;
}
for (auto s : externDeclarations) {
add_comment(out, s->name.toString());
s->toSpec(out);
Expand Down Expand Up @@ -213,6 +217,11 @@ std::ostream &IR::DpdkHeaderType::toSpec(std::ostream &out) const {
return out;
}

std::ostream &IR::DpdkHeaderInstance::toSpec(std::ostream &out) const {
out << "header " << name->toString() << " instanceof " << headerType->toString();
return out;
}

std::ostream &IR::DpdkStructType::toSpec(std::ostream &out) const {
if (getAnnotations()->getSingle("__packet_data__"_cs)) {
for (auto it = fields.begin(); it != fields.end(); ++it) {
Expand Down
15 changes: 15 additions & 0 deletions testdata/p4_16_samples/pna-ipv6-actions.p4
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ control MainControlImpl(
tmp1 = (bit<32>)headers.ipv6.srcAddr;
}

action ipv6_addr_or() {
headers.ipv6.dstAddr = headers.ipv6.dstAddr | headers.ipv6.srcAddr;
}

action ipv6_addr_and() {
headers.ipv6.dstAddr = tmp & headers.ipv6.srcAddr;
}

action ipv6_addr_xor() {
headers.ipv6.dstAddr = headers.ipv6.dstAddr ^ tmp;
}

action ipv6_swap_addr() {
headers.ipv6.dstAddr = headers.ipv6.srcAddr;
headers.ipv6.srcAddr = tmp;
Expand Down Expand Up @@ -156,6 +168,9 @@ control MainControlImpl(
ipv6_modify_dstAddr;
ipv6_swap_addr;
set_flowlabel;
ipv6_addr_or;
ipv6_addr_xor;
ipv6_addr_and;
set_traffic_class_flow_label;
set_ipv6_version;
set_next_hdr;
Expand Down
12 changes: 12 additions & 0 deletions testdata/p4_16_samples_outputs/pna-ipv6-actions-first.p4
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ control MainControlImpl(inout headers_t headers, inout main_metadata_t meta, in
headers.ipv6.dstAddr = (bit<128>)dstAddr;
tmp1 = (bit<32>)headers.ipv6.srcAddr;
}
action ipv6_addr_or() {
headers.ipv6.dstAddr = headers.ipv6.dstAddr | headers.ipv6.srcAddr;
}
action ipv6_addr_and() {
headers.ipv6.dstAddr = tmp & headers.ipv6.srcAddr;
}
action ipv6_addr_xor() {
headers.ipv6.dstAddr = headers.ipv6.dstAddr ^ tmp;
}
action ipv6_swap_addr() {
headers.ipv6.dstAddr = headers.ipv6.srcAddr;
headers.ipv6.srcAddr = tmp;
Expand Down Expand Up @@ -123,6 +132,9 @@ control MainControlImpl(inout headers_t headers, inout main_metadata_t meta, in
ipv6_modify_dstAddr();
ipv6_swap_addr();
set_flowlabel();
ipv6_addr_or();
ipv6_addr_xor();
ipv6_addr_and();
set_traffic_class_flow_label();
set_ipv6_version();
set_next_hdr();
Expand Down
Loading

0 comments on commit 30b7c86

Please sign in to comment.