Skip to content

Commit

Permalink
Implement P4_16 conformant stack support
Browse files Browse the repository at this point in the history
For header stacks and header union stacks. We support both behaviors at
the moment (legacy and P4_16). The legacy implementation is the default
one and will be the default for the 1.10 release. The P4_16 conformant
behavior can be toggled by using the `--enable-WP4-16-stacks` configure
flag. The plan is to have the new implementation be the default after
the 1.10 release.

The new implementation differs from the legacy one as follows:
push_front and pop_front shift the entire stack (not just until the next
index), and pushed headers are marked as invalid instead of valid.

We have tried to minimize the amount of code guarded by ifdef
directives. We used the CRTP to implement both behaviors and both
implementations are always compiled. We have unit tests for both
implementations as well.
  • Loading branch information
antoninbas committed Jan 4, 2018
1 parent 9e4a70e commit 5d3e2f2
Show file tree
Hide file tree
Showing 5 changed files with 409 additions and 119 deletions.
8 changes: 8 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ AC_ARG_ENABLE([Werror],
AS_HELP_STRING([--enable-Werror], [Make all compiler warnings fatal]),
[enable_Werror="$enableval"], [enable_Werror=no])

AC_ARG_ENABLE([WP4-16-stacks],
AS_HELP_STRING([--enable-WP4-16-stacks],
[Implement stacks strictly as per the P4_16 specification instead of legacy behavior]),
[enable_WP4_16_stacks="$enableval"], [enable_WP4_16_stacks=no])

AS_IF([test "$enable_WP4_16_stacks" = "yes"],
[MY_CPPFLAGS="$MY_CPPFLAGS -DBM_WP4_16_STACKS"])

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
Expand Down
64 changes: 56 additions & 8 deletions include/bm/bm_sim/stacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ class StackIface {
virtual ~StackIface() { }

//! Removes the first element of the stack. Returns the number of elements
//! removed, which is `0` if the stack is empty and `1` otherwise. The second
//! element of the stack becomes the first element, and so on...
//! removed. The second element of the stack becomes the first element, and so
//! on...
virtual size_t pop_front() = 0;

//! Removes the first \p num element of the stack. Returns the number of
//! elements removed, which is `0` if the stack is empty. Calling this
//! function is more efficient than calling pop_front() multiple times.
//! elements removed. Calling this function is more efficient than calling
//! pop_front() multiple times.
virtual size_t pop_front(size_t num) = 0;

//! Pushes an element to the front of the stack. If the stack is already full,
Expand Down Expand Up @@ -88,12 +88,16 @@ class StackIface {
virtual void reset() = 0;
};

// We use CRTP for Stack class to implement either legacy behavior or strict
// P4_16 behavior by providing different implementations of push_front and
// pop_front.

//! Stack is used to represent header and union stacks in P4. The Stack class
//! itself does not store any union / header / field data itself, but stores
//! references to the HeaderUnion / Header instances which constitute the stack,
//! as well as the stack internal state (e.g. number of valid headers in the
//! stack).
template <typename T>
template <typename T, typename ShiftImpl>
class Stack : public StackIface, public NamedP4Object {
public:
friend class PHV;
Expand Down Expand Up @@ -125,7 +129,7 @@ class Stack : public StackIface, public NamedP4Object {
T &at(size_t idx);
const T &at(size_t idx) const;

private:
protected:
using TRef = std::reference_wrapper<T>;

// To be called by PHV class
Expand All @@ -138,6 +142,48 @@ class Stack : public StackIface, public NamedP4Object {
size_t next{0};
};

namespace detail {

// Implements legacy behavior for stacks. push_front and pop_front only shift
// the portion of the stack up to the next index. Pushed elements are marked as
// valid.
template <typename T>
class StackLegacy : public Stack<T, StackLegacy<T> > {
public:
StackLegacy(const std::string &name, p4object_id_t id);

size_t pop_front();
size_t pop_front(size_t num);

size_t push_front();
size_t push_front(size_t num);
};

// Implements strict P4_16 behavior for stacks. push_front and pop_front shift
// the entire stack. Pushed elements are marked as invalid.
template <typename T>
class StackP4_16 : public Stack<T, StackP4_16<T> > {
public:
StackP4_16(const std::string &name, p4object_id_t id);

size_t pop_front();
size_t pop_front(size_t num);

size_t push_front();
size_t push_front(size_t num);
};

#ifdef BM_WP4_16_STACKS
template <typename T>
// using MyStack = StackP4_16<T>;
using MyStack = StackP4_16<T>;
#else
template <typename T>
using MyStack = StackLegacy<T>;
#endif // BM_WP4_16_STACKS

} // namespace detail

using header_stack_id_t = p4object_id_t;
using header_union_stack_id_t = p4object_id_t;

Expand All @@ -149,7 +195,7 @@ using header_union_stack_id_t = p4object_id_t;
//! // ...
//! };
//! @endcode
using HeaderStack = Stack<Header>;
using HeaderStack = detail::MyStack<Header>;
//! Convenience alias for stacks of header unions
//! A HeaderUnionStack reference can be used in an action primitive. For
//! example:
Expand All @@ -160,7 +206,9 @@ using HeaderStack = Stack<Header>;
//! // ...
//! };
//! @endcode
using HeaderUnionStack = Stack<HeaderUnion>;
using HeaderUnionStack = detail::MyStack<HeaderUnion>;

#undef _P4_16_STACKS

} // namespace bm

Expand Down
Loading

0 comments on commit 5d3e2f2

Please sign in to comment.