![]() |
P4C
The P4 Compiler
|
#include <simplifyBitwise.h>
Public Member Functions | |
const IR::Node * | preorder (IR::BAndAssign *as) override |
const IR::Node * | preorder (IR::BaseAssignmentStatement *as) override |
const IR::Node * | preorder (IR::BOrAssign *as) override |
const IR::Node * | preorder (IR::BXorAssign *as) override |
const IR::Node * | preorder (IR::OpAssignmentStatement *as) override |
![]() | |
const IR::Node * | apply_visitor (const IR::Node *, const char *name=0) override |
profile_t | init_apply (const IR::Node *root) override |
virtual void | loop_revisit (const IR::Node *) |
virtual const IR::Node * | postorder (IR::Node *n) |
virtual const IR::Node * | preorder (IR::Node *n) |
void | prune () |
virtual void | revisit (const IR::Node *, const IR::Node *) |
void | revisit_visited () |
bool | visit_in_progress (const IR::Node *) const |
void | visitAgain () const override |
void | visitOnce () const override |
![]() | |
virtual bool | check_global (cstring) |
virtual void | clear_globals () |
virtual Visitor * | clone () const |
virtual ControlFlowVisitor * | controlFlowVisitor () |
virtual void | end_apply () |
virtual void | end_apply (const IR::Node *root) |
virtual void | erase_global (cstring) |
template<class T> | |
const T * | findContext () const |
template<class T> | |
const T * | findContext (const Context *&c) const |
template<class T> | |
const T * | findOrigCtxt () const |
template<class T> | |
const T * | findOrigCtxt (const Context *&c) const |
virtual Visitor & | flow_clone () |
virtual void | flow_merge (Visitor &) |
virtual bool | flow_merge_closure (Visitor &) |
virtual void | flow_merge_global_from (cstring) |
virtual void | flow_merge_global_to (cstring) |
const Context * | getChildContext () const |
int | getChildrenVisited () const |
const Context * | getContext () const |
int | getContextDepth () const |
const IR::Node * | getCurrentNode () const |
template<class T> | |
const T * | getCurrentNode () const |
const IR::Node * | getOriginal () const |
template<class T> | |
const T * | getOriginal () const |
template<class T> | |
const T * | getParent () const |
virtual bool | has_flow_joins () const |
profile_t | init_apply (const IR::Node *root, const Context *parent_context) |
template<class T> | |
bool | isInContext () const |
template<class T> | |
bool | isInContext (const Context *&c) const |
bool | isInContext (const IR::Node *n) const |
virtual const char * | name () const |
template<class T> | |
void | parallel_visit (const IR::Vector< T > &v, const char *name, int cidx) |
template<class T> | |
void | parallel_visit (const IR::Vector< T > &v, const char *name=0) |
template<class T> | |
void | parallel_visit (IR::Vector< T > &v, const char *name, int cidx) |
template<class T> | |
void | parallel_visit (IR::Vector< T > &v, const char *name=0) |
void | print_context () const |
const Visitor & | setCalledBy (const Visitor *visitor) |
void | setName (const char *name) |
void | visit (const IR::Node &n, const char *name, int cidx) |
void | visit (const IR::Node &n, const char *name=0) |
void | visit (const IR::Node *&n, const char *name, int cidx) |
void | visit (const IR::Node *&n, const char *name=0) |
void | visit (const IR::Node *const &n, const char *name, int cidx) |
void | visit (const IR::Node *const &n, const char *name=0) |
void | visit (IR::Node &n, const char *name, int cidx) |
void | visit (IR::Node &n, const char *name=0) |
void | visit (IR::Node *&, const char *=0, int=0) |
template<class T, typename = std::enable_if_t<Util::has_SourceInfo_v<T> && !std::is_pointer_v<T>>, class... Args> | |
void | warn (const int kind, const char *format, const T &node, Args &&...args) |
The const ref variant of the above. | |
template<class T, typename = std::enable_if_t<Util::has_SourceInfo_v<T>>, class... Args> | |
void | warn (const int kind, const char *format, const T *node, Args &&...args) |
bool | warning_enabled (int warning_kind) const |
Additional Inherited Members | |
![]() | |
typedef Visitor_Context | Context |
![]() | |
static cstring | demangle (const char *) |
static bool | warning_enabled (const Visitor *visitor, int warning_kind) |
![]() | |
const Visitor * | called_by = nullptr |
cstring | internalName |
SplitFlowVisit_base *& | split_link |
SplitFlowVisit_base * | split_link_mem = nullptr |
![]() | |
const IR::Node * | transform_child (const IR::Node *child) |
![]() | |
virtual void | init_join_flows (const IR::Node *) |
virtual bool | join_flows (const IR::Node *) |
virtual void | post_join_flows (const IR::Node *, const IR::Node *) |
void | visit_children (const IR::Node *, std::function< void()> fn) |
![]() | |
bool | forceClone = false |
![]() | |
bool | dontForwardChildrenBeforePreorder = false |
bool | joinFlows = false |
bool | visitDagOnce = true |
The purpose of this pass is to simplify the translation of the p4-16 translation of the following p4_14 primitive: modify_field(hdr.field, parameter, mask);
This gets translated to the following p4_16: hdr.field = hdr.field & ~mask | parameter & mask;
which in term can be further simplified to a vector of simple assignments over slices. This extensions could be folded to any combinations of Binary Ors and Binary Ands as long as the masks never have any collisions.
Currently we deal with any assignment of the form
dest = (srcA & maskA) | (srcB & maskB);
where ‘maskA’ and ‘maskB’ are constants such that maskA & maskB == 0. This gets converted into
dest[slice_A1] = srcA[slice_A1] : dest[slice_An] = srcA[slice_An] dest[slice_B1] = srcA[slice_B1] : dest[slice_Bn] = srcA[slice_Bn] dest[slice_X1] = 0 :
where the slice_Ai/Bi values are slices corresponding to each range of contiguous 1 bits in maskA and maskB, and the slice_Xi values are any remaing bits where both masks are 0. For example if maskA == 0xff00ff and maskB = 0xff00 they will be:
slice_A1 == 7:0 slice_A2 == 23:16 slice_B1 == 15:8 slice_X1 == 31:24 (assuming bit<32> types involved)
Naturally, if there are no uncovered bits, there will be no X slices. The most common case will end up with one A slice and one B slice and no X slice, but if the masks are sparse/pessimal this will generate a lot of small slices which may be worse than the original code, so perhaps there should be a knob targets can use to limit that.
This works equally well for ‘&=’, ‘|=’ and ‘^=’ as it does for simple assignments. Any resulting ‘dest[slice] |= 0’ or ‘des[slice] ^= 0’ should later be eliminated by constant folding.