Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
10 changes: 6 additions & 4 deletions backends/bmv2/pna_nic/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ PnaNicMidEnd::PnaNicMidEnd(CompilerOptions &options, std::ostream *outStream)
: PortableMidEnd(options) {
auto convertEnums = new P4::ConvertEnums(&typeMap, new PnaEnumOn32Bits("pna.p4"_cs));
auto evaluator = new P4::EvaluatorPass(&refMap, &typeMap);
auto *strengthReductionPolicy = new P4::StrengthReductionPolicy();
strengthReductionPolicy->enablePlusSliceToShiftTransform = true;
Comment thread
anovotarsk marked this conversation as resolved.
P4::LocalCopyPropPolicyCallbackFn policy = [=](const Context *, const IR::Expression *e,
const DeclarationLookup *refMap) -> bool {
auto mce = e->to<IR::MethodCallExpression>();
Expand Down Expand Up @@ -116,12 +118,12 @@ PnaNicMidEnd::PnaNicMidEnd(CompilerOptions &options, std::ostream *outStream)
new P4::SimplifyKey(&typeMap,
new P4::OrPolicy(new P4::IsValid(&typeMap), new P4::IsMask())),
new P4::ConstantFolding(&typeMap),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
new P4::SimplifySelectCases(&typeMap, true), // require constant keysets
new P4::ExpandLookahead(&typeMap),
new P4::ExpandEmit(&typeMap),
new P4::SimplifyParsers(),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap),
Expand All @@ -135,8 +137,8 @@ PnaNicMidEnd::PnaNicMidEnd(CompilerOptions &options, std::ostream *outStream)
new P4::MoveDeclarations(), // more may have been introduced
new P4::ConstantFolding(&typeMap),
new P4::LocalCopyPropagation(&typeMap, nullptr, policy),
new PassRepeated(
{new P4::ConstantFolding(&typeMap), new P4::StrengthReduction(&typeMap)}),
new PassRepeated({new P4::ConstantFolding(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy)}),
new P4::MoveDeclarations(),
new P4::ValidateTableProperties({"pna_implementation"_cs, "pna_direct_counter"_cs,
"pna_direct_meter"_cs, "pna_idle_timeout"_cs,
Expand Down
8 changes: 5 additions & 3 deletions backends/bmv2/psa_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre
: PortableMidEnd(options) {
auto convertEnums = new P4::ConvertEnums(&typeMap, new PsaEnumOn32Bits("psa.p4"_cs));
auto evaluator = new P4::EvaluatorPass(&refMap, &typeMap);
auto *strengthReductionPolicy = new P4::StrengthReductionPolicy();
strengthReductionPolicy->enablePlusSliceToShiftTransform = true;
Comment thread
anovotarsk marked this conversation as resolved.
P4::LocalCopyPropPolicyCallbackFn policy = [=](const Context *, const IR::Expression *e,
const DeclarationLookup *refMap) -> bool {
auto mce = e->to<IR::MethodCallExpression>();
Expand Down Expand Up @@ -116,12 +118,12 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre
new P4::SimplifyKey(&typeMap,
new P4::OrPolicy(new P4::IsValid(&typeMap), new P4::IsMask())),
new P4::ConstantFolding(&typeMap),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
new P4::SimplifySelectCases(&typeMap, true), // require constant keysets
new P4::ExpandLookahead(&typeMap),
new P4::ExpandEmit(&typeMap),
new P4::SimplifyParsers(),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap),
Expand All @@ -138,7 +140,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre
new P4::LocalCopyPropagation(&typeMap, nullptr, policy),
new PassRepeated({
new P4::ConstantFolding(&typeMap),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
}),
new P4::MoveDeclarations(),
new P4::ValidateTableProperties({
Expand Down
8 changes: 5 additions & 3 deletions backends/bmv2/simple_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ using namespace P4::literals;
SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *outStream)
: MidEnd(options) {
auto *evaluator = new P4::EvaluatorPass(&refMap, &typeMap);
auto *strengthReductionPolicy = new P4::StrengthReductionPolicy();
strengthReductionPolicy->enablePlusSliceToShiftTransform = true;
Comment thread
anovotarsk marked this conversation as resolved.
if (!BMV2::SimpleSwitchContext::get().options().loadIRFromJson) {
auto *convertEnums = new P4::ConvertEnums(&typeMap, new EnumOn32Bits("v1model.p4"_cs));
ParserConfig config;
Expand All @@ -83,12 +85,12 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *o
new P4::SimplifyKey(&typeMap,
new P4::OrPolicy(new P4::IsValid(&typeMap), new P4::IsMask())),
new P4::ConstantFolding(&typeMap),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
new P4::SimplifySelectCases(&typeMap, true), // require constant keysets
new P4::ExpandLookahead(&typeMap),
new P4::ExpandEmit(&typeMap),
new P4::SimplifyParsers(),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
new P4::EliminateTuples(&typeMap),
new P4::SimplifyComparisons(&typeMap),
new P4::CopyStructures(&typeMap),
Expand All @@ -103,7 +105,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *o
new P4::LocalCopyPropagation(&typeMap),
new PassRepeated({
new P4::ConstantFolding(&typeMap),
new P4::StrengthReduction(&typeMap),
new P4::StrengthReduction(&typeMap, strengthReductionPolicy),
}),
new P4::SimplifyKey(&typeMap,
new P4::OrPolicy(new P4::IsValid(&typeMap), new P4::IsMask())),
Expand Down
11 changes: 11 additions & 0 deletions frontends/p4/strengthReduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,17 @@ const IR::Node *DoStrengthReduction::postorder(IR::PlusSlice *expr) {
auto *rv = new IR::Slice(expr->srcInfo, expr->e0, expr->getH(), expr->getL());
return postorder(rv);
}
if (policy->enablePlusSliceToShiftTransform) {
if (isWrite()) return expr;

auto *width = expr->e2->checkedTo<IR::Constant>();
if (width->value == 0) return expr;

const IR::Expression *source = expr->e0;
if (!source->type->is<IR::Type_Bits>()) return expr;
auto *shift = new IR::Shr(expr->srcInfo, source->type, source, expr->e1);
return new IR::Slice(expr->srcInfo, shift, width->asInt() - 1, 0);
}
if (auto sh = expr->e0->to<IR::Shr>()) {
if (!sh->left->type->is<IR::Type_Bits>()) return expr;
if (sh->left->type->to<IR::Type_Bits>()->isSigned) return expr;
Expand Down
12 changes: 9 additions & 3 deletions frontends/p4/strengthReduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ class StrengthReductionPolicy {
public:
StrengthReductionPolicy() {}
StrengthReductionPolicy(bool enableSubConstToAddTransform,
Comment thread
fruffy marked this conversation as resolved.
bool enableNarrowingCastToSliceTransform)
bool enableNarrowingCastToSliceTransform,
bool enablePlusSliceToShiftTransform = false)
: enableSubConstToAddTransform(enableSubConstToAddTransform),
enableNarrowingCastToSliceTransform(enableNarrowingCastToSliceTransform) {}
enableNarrowingCastToSliceTransform(enableNarrowingCastToSliceTransform),
enablePlusSliceToShiftTransform(enablePlusSliceToShiftTransform) {}

/// Enable the subtract constant to add negative constant transform.
/// Replaces `a - constant` with `a + (-constant)`.
Expand All @@ -33,6 +35,10 @@ class StrengthReductionPolicy {
/// Replace narrowing casts with slices.
/// i.e. replaces (bit<n>)(expr) with expr[n-1:0] when n is smaller than the width of expr.
bool enableNarrowingCastToSliceTransform = false;

/// Replace slices with a variable offset with a shift followed by a constant slice.
/// i.e. replaces expr[offset+:width] with (expr >> offset)[width-1:0].
bool enablePlusSliceToShiftTransform = false;
};

/** Implements a pass that replaces expensive arithmetic and boolean
Expand All @@ -52,7 +58,7 @@ class StrengthReductionPolicy {
* - division and modulus by `0`
*
*/
class DoStrengthReduction final : public Transform {
class DoStrengthReduction final : public Transform, P4WriteContext {
protected:
TypeMap *typeMap = nullptr;
StrengthReductionPolicy *policy;
Expand Down
65 changes: 63 additions & 2 deletions test/gtest/strength_reduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ struct GTestStrengthReductionPolicy : public P4::FrontEndPolicy {
P4::StrengthReductionPolicy *getStrengthReductionPolicy() const override { return policy_; }

GTestStrengthReductionPolicy(bool enableSubConstToAddTransform = true,
bool enableCastToSliceTransform = false) {
bool enableCastToSliceTransform = false,
bool enablePlusSliceToShiftTransform = false) {
policy_ = new P4::StrengthReductionPolicy(enableSubConstToAddTransform,
enableCastToSliceTransform);
enableCastToSliceTransform,
enablePlusSliceToShiftTransform);
}

private:
Expand Down Expand Up @@ -146,4 +148,63 @@ TEST_F(StrengthReductionTest, EnableNarrowingCastToSliceTransform) {
EXPECT_FALSE(program_string.find(value2) == std::string::npos);
}

TEST_F(StrengthReductionTest, DefaultDisablePlusSliceToShiftTransform) {
auto test = createStrengthReductionTestCase(
P4_SOURCE(R"(headers.h.f4 = headers.h.f1[headers.h.f2+:16];)"));

Util::SourceCodeBuilder builder;
ToP4 top4(builder, false);
test->program->apply(top4);

std::string program_string = builder.toString();
EXPECT_NE(program_string.find("headers.h.f1[headers.h.f2+:16]"), std::string::npos);
EXPECT_EQ(program_string.find("(headers.h.f1 >> headers.h.f2)[15:0]"), std::string::npos);
}

TEST_F(StrengthReductionTest, EnablePlusSliceToShiftTransform) {
GTestStrengthReductionPolicy policy(true, false, true);
auto test = createStrengthReductionTestCase(
P4_SOURCE(R"(headers.h.f4 = headers.h.f1[headers.h.f2+:16];)"), &policy);

Util::SourceCodeBuilder builder;
ToP4 top4(builder, false);
test->program->apply(top4);

std::string program_string = builder.toString();
EXPECT_EQ(program_string.find("headers.h.f1[headers.h.f2+:16]"), std::string::npos);
EXPECT_NE(program_string.find("(headers.h.f1 >> headers.h.f2)[15:0]"), std::string::npos);
}

TEST_F(StrengthReductionTest, PreservePlusSliceToShiftTransformOnWrite) {
GTestStrengthReductionPolicy policy(true, false, true);
auto test = createStrengthReductionTestCase(
P4_SOURCE(R"(headers.h.f1[headers.h.f2+:16] = headers.h.f4;)"), &policy);

Util::SourceCodeBuilder builder;
ToP4 top4(builder, false);
test->program->apply(top4);

std::string program_string = builder.toString();
EXPECT_NE(program_string.find("headers.h.f1[headers.h.f2+:16] = headers.h.f4"),
std::string::npos);
}

TEST_F(StrengthReductionTest, EnablePlusSliceToShiftTransformOnSignedSource) {
GTestStrengthReductionPolicy policy(true, false, true);
auto test = createStrengthReductionTestCase(P4_SOURCE(R"(
int<32> signedValue = -1;
headers.h.f4 = signedValue[headers.h.f2+:16];
)"),
&policy);

Util::SourceCodeBuilder builder;
ToP4 top4(builder, false);
test->program->apply(top4);

std::string program_string = builder.toString();
EXPECT_EQ(program_string.find("[headers.h.f2+:16]"), std::string::npos);
EXPECT_EQ(program_string.find("(bit<32>)signedValue"), std::string::npos);
EXPECT_NE(program_string.find(" >> headers.h.f2)[15:0]"), std::string::npos);
}

} // namespace P4::Test
44 changes: 44 additions & 0 deletions testdata/p4_16_samples/issue5558-bmv2.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2026 The P4 Language Consortium
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <core.p4>
#include <v1model.p4>

header Hdr {
bit<8> a;
}

struct Headers {
Hdr op;
}

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 ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) {
apply {
bit<8> x = 0x00;
h.op.a[3:0] = x[h.op.a+:4];
}
}

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.op);
}
}

V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main;
51 changes: 51 additions & 0 deletions testdata/p4_16_samples_outputs/issue5558-bmv2-first.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <core.p4>

#define V1MODEL_VERSION 20180101
#include <v1model.p4>

header Hdr {
bit<8> a;
}

struct Headers {
Hdr op;
}

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 ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) {
apply {
bit<8> x = 8w0x0;
h.op.a[3:0] = x[h.op.a+:4];
}
}

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<Hdr>(h.op);
}
}

V1Switch<Headers, Meta>(p(), vrfy(), ingress(), egress(), update(), deparser()) main;
52 changes: 52 additions & 0 deletions testdata/p4_16_samples_outputs/issue5558-bmv2-frontend.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <core.p4>

#define V1MODEL_VERSION 20180101
#include <v1model.p4>

header Hdr {
bit<8> a;
}

struct Headers {
Hdr op;
}

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 ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) {
@name("ingress.x") bit<8> x_0;
apply {
x_0 = 8w0x0;
h.op.a[3:0] = x_0[h.op.a+:4];
}
}

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<Hdr>(h.op);
}
}

V1Switch<Headers, Meta>(p(), vrfy(), ingress(), egress(), update(), deparser()) main;
Loading
Loading