P4C
The P4 Compiler
|
Classes | |
class | EmitAction |
class | EmitAlwaysRunAction |
class | EmitAttached |
class | NextTableSet |
Public Member Functions | |
MauAsmOutput (const PhvInfo &phv, const IR::BFN::Pipe *pipe, const NextTable *nxts, const MauPower::FinalizeMauPredDepsPower *pmpr, const BFN_Options &options) | |
virtual void | emit_table_format (std::ostream &out, indent_t, const TableFormat::Use &use, const TableMatch *tm, bool ternary, bool no_match) const |
Public Member Functions inherited from P4::Inspector | |
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 void | postorder (const IR::Node *) |
virtual bool | preorder (const IR::Node *) |
virtual void | revisit (const IR::Node *) |
void | revisit_visited () |
bool | visit_in_progress (const IR::Node *n) const |
void | visitAgain () const override |
void | visitOnce () const override |
Public Member Functions inherited from P4::Visitor | |
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) |
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 |
Static Public Member Functions | |
static ordered_set< UniqueId > | find_attached_ids (const IR::MAU::Table *tbl, const IR::MAU::AttachedMemory *am) |
static cstring | find_attached_name (const IR::MAU::Table *tbl, const IR::MAU::AttachedMemory *am) |
Static Public Member Functions inherited from P4::Visitor | |
static cstring | demangle (const char *) |
static bool | warning_enabled (const Visitor *visitor, int warning_kind) |
Protected Member Functions | |
std::string | build_call (const IR::MAU::AttachedMemory *at_mem, const IR::MAU::BackendAttached *ba, const IR::MAU::Table *tbl) const |
std::string | build_meter_color_call (const IR::MAU::Meter *mtr, const IR::MAU::BackendAttached *ba, const IR::MAU::Table *tbl) const |
std::string | build_sel_len_call (const IR::MAU::Selector *as) const |
void | emit_action_data_alias (std::ostream &out, indent_t, const IR::MAU::Table *tbl, const IR::MAU::Action *af) const |
void | emit_action_data_bus (std::ostream &out, indent_t, const IR::MAU::Table *tbl, bitvec source) const |
void | emit_action_data_format (std::ostream &out, indent_t, const IR::MAU::Table *tbl, const IR::MAU::Action *af) const |
void | emit_always_run_action (std::ostream &out, const IR::MAU::Table *tbl, int stage, gress_t gress) const |
void | emit_atcam_match (std::ostream &out, indent_t, const IR::MAU::Table *tbl, std::stringstream &context_json_entries) const |
bool | emit_gateway (std::ostream &out, indent_t gw_indent, const IR::MAU::Table *tbl, bool hash_action, NextTableSet next_hit, NextTableSet &gw_miss) const |
void | emit_hash_dist (std::ostream &out, indent_t indent, const safe_vector< Tofino::IXBar::HashDistUse > *hash_dist_use, bool hashmod) const |
bool | emit_idletime (std::ostream &out, indent_t indent, const IR::MAU::Table *tbl, const IR::MAU::IdleTime *id) const |
void | emit_indirect_res_context_json (std::ostream &, indent_t indent, const IR::MAU::Table *tbl, std::stringstream &context_json_entries) const |
void | emit_ixbar (std::ostream &out, indent_t indent, const IR::MAU::Table *tbl, IXBar::Use::type_t type) const |
void | emit_ixbar (std::ostream &out, indent_t indent, const IR::MAU::Table *tbl, std::initializer_list< IXBar::Use::type_t > types) const |
virtual void | emit_memory (std::ostream &out, indent_t, const Memories::Use &, const IR::MAU::Table::Layout *l=nullptr, const TableFormat::Use *f=nullptr) const =0 |
void | emit_no_match_gateway (std::ostream &out, indent_t gw_indent, const IR::MAU::Table *tbl) const |
void | emit_random_seed (std::ostream &out, indent_t indent, const TableMatch *fmt) const |
void | emit_single_alias (std::ostream &out, std::string &sep, const ActionData::Parameter *param, le_bitrange adt_range, cstring alias, safe_vector< ActionData::Argument > &full_args, cstring action_name) const |
void | emit_static_entries (std::ostream &, indent_t indent, const IR::MAU::Table *tbl, std::stringstream &context_json_entries) const |
void | emit_table (std::ostream &out, const IR::MAU::Table *tbl, int stage, gress_t gress) const |
void | emit_table_context_json (std::ostream &out, indent_t, const IR::MAU::Table *tbl) const |
void | emit_table_hitmap (std::ostream &out, indent_t indent, const IR::MAU::Table *tbl, NextTableSet &next_hit, NextTableSet &gw_miss, bool no_match_hit, bool gw_can_miss) const |
void | emit_table_indir (std::ostream &out, indent_t, const IR::MAU::Table *tbl, const IR::MAU::TernaryIndirect *ti) const |
void | emit_ternary_match (std::ostream &out, indent_t, const TableFormat::Use &use) const |
virtual void | emit_ways (std::ostream &out, indent_t indent, const IXBar::Use *use, const Memories::Use *mem) const |
virtual bool | gateway_uses_inhibit_index (const IR::MAU::Table *) const |
std::string | indirect_address (const IR::MAU::AttachedMemory *) const |
std::string | indirect_pfe (const IR::MAU::AttachedMemory *) const |
NextTableSet | next_for (const IR::MAU::Table *tbl, cstring what) const |
void | next_table_non_action_map (const IR::MAU::Table *, safe_vector< NextTableSet > &next_table_map) const |
bool | require_ixbar (const IR::MAU::Table *tbl, IXBar::Use::type_t) const |
bool | require_ixbar (const IR::MAU::Table *tbl, std::initializer_list< IXBar::Use::type_t >) const |
std::string | stateful_counter_addr (IR::MAU::StatefulUse use) const |
Protected Member Functions inherited from P4::Visitor | |
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) |
Protected Attributes | |
const NextTable * | nxt_tbl |
const BFN_Options & | options |
const PhvInfo & | phv |
const IR::BFN::Pipe * | pipe |
const MauPower::FinalizeMauPredDepsPower * | power_and_mpr |
Protected Attributes inherited from P4::Visitor | |
bool | dontForwardChildrenBeforePreorder = false |
bool | joinFlows = false |
bool | visitDagOnce = true |
Friends | |
std::ostream & | operator<< (std::ostream &out, const MauAsmOutput &mauasm) |
Additional Inherited Members | |
Public Types inherited from P4::Visitor | |
typedef Visitor_Context | Context |
Public Attributes inherited from P4::Visitor | |
const Visitor * | called_by = nullptr |
cstring | internalName |
SplitFlowVisit_base *& | split_link |
SplitFlowVisit_base * | split_link_mem = nullptr |
|
protected |
Figure out which overhead field in the table is being used to index an attached indirect table (counter, meter, stateful, action data) and return its asm name. Contained now within the actual IR for Hash Distribution.
Addressed are built up of up to 3 arguments:
With this come some keywords:
|
protected |
Due to the color mapram possibly having a different address, due to the address coming from hash being different, as the shift and mask happens in the hash distribution unit, a separate call is built for color maprams. The enable bit should always be the same as the meter address enable bit.
|
protected |
The call for the assembler to determine the selector length
|
protected |
Function that emits the action data aliases needed for consistency across the action data bus. The aliases are to be used to set up parameters for the Context JSON, and if necessary rename multiple action data parameters as one parameter name. This must be done in order to have one parameter used in a container in the action
The constants converted to action data parameters are also printed here for the Context JSON.
The determination of the names is done by the action_format code, in order to simplify this function significantly. This just outputs information for either immediate or action data tables.
Currently, there are two levels of aliasing:
Due to the current way instruction adjustment works, either the parameter, or the first alias, i.e. $data0, appear in the actual instructions. One could make an argument that this isn't needed, and that may be true, but would require further work in Instruction Adjustment
|
protected |
This function is used to generate action_data_bus info for TernaryIndirect, ActionData and MAU::Table The 'source' field is used to control which action data bus slot to emit for each type of caller. 'source' is the OR-ed result of (1 << ActionFormat::ad_source_t)
For anything that is not an ActionArg or a Constant, the old action format is currently deferred until the new format is used to determine their allocation
|
protected |
Gateways in Tofino are 4 44 bit TCAM rows used to compare conditionals. A comparison will be done on a row by row basis. If that row hits, then the gateway matches on that particular row. Lastly all gateways have a miss row, which will automatically match if the none of the programmed gateway rows match
Gateways rows have the following structure:
If the row is inhibited, this means when the row matches, the payload is placed onto the match result bus, overriding whatever was previously on the result bus. This could have been the result of a match table. The next table is then used in the predication vector. However, if the row is not inhibited, the gateway does nothing to the match bus, and the next table comes from either the hit or miss path. Inhibit is turned on by providing a next table for a gateway row.
Let me provide two examples. The first is a gateway table using the same logical table as an exact match table:
if (f == 2) { apply(exact_match); apply(x); } apply(y);
Let's take a look at the gateway:
____match____|__inhibit__|__next_table__|__payload___ f == 2 false N/A N/A (0x2 : run_table) miss true y 0x0 (miss : y)
In this case, if f == 1, then we want the exact_match table to use it's results to determine what to do. By not inhibiting, the exact_match table will determine what happens, including the next table.
However, the case is actual reversed when we need a table with no match data linked with a gateway (A HashAction table):
if (f == 2) { apply(no_match_hit_path); apply(x); } apply(y);
____match____|__inhibit__|__next_table__|__payload___ f == 2 true x 0x1 (0x2 : x) miss false N/A 0x0 (miss : run_table)
A table with no match will always go down the miss path, as the result bus will be labeled a miss coming out of the RAM array. The only way to go down the hit path is to inhibit the gateway. Thus if the f == 1, the result bus goes through the hit bus with the payload 0x1. This bit is then used a per flow enable bit, for things like finding the action instruction address or an address from hash distribution. It will then use next table in the gateway. When f != 1, the gateway will not override, and the table will automatically miss. Then, the miss next table is used to determine where to go next
|
protected |
This allocates a gateway that always hits, with a single (possible noop) action, in order for the table to always go through the the hit pathway. FIXME – why do we use this for a noop action? A noop does not require the hit path, so could use the miss path and save the gateway (power if nothing else).
|
protected |
The purpose of this function is to print out the value of the next table hitmap for this table, which should coordinate to the following registers
In Tofino: rams.match.merge.next_table_map_data
In JBay: rams.match.merge.pred_map_loca rams.match.merge.pred_map_glob
This is the 8 entry table that can be used as an indirection table from an address stored in the RAM entry to the next table/next table set to run. For Tofino, only one next table is stored per entry, while for JBay a set of next tables is stored per entry. The implementation of this is described in the comments of jbay_next_table.cpp
A next table pointer by itself is 8 bits, and so would require each entry to store up to 8 bits per entry. However, if there are only 2 choices for next table, then by saving a single bit with the entry, and by using this table to convert a single bit to an 8 bit address. significant overhead in the entry can be saved. Furthermore, this is the only hardware that can enable local_exec, global_exec, and long branch.
This table is really only necessary for action chaining, or next table being based on which action is to run. In P4, this looks like:
switch (t1.apply().action_run) { a1 : { t2.apply(); } a2 : { t3.apply(); } default : { t4.apply(); } }
This means that when an entry is written with a particular action, the entry also saves a next table pointer (or a pointer into this 8-entry table).
There are multiple levels to this optimization. If t1 for instance had less than 8 hit actions, then (as instructions have the same type of indirection table), the instruction pointer and the next table pointer can be the same hardware. If t1 has more than 8 actions, but has less than 8 next tables (in the example, it has 3 next tables), then the next table pointer can look into this table. If it has more than 8 next table choices, then the hardware must use the direct next table pointer, and not use this hardware, so this table will be empty.
A couple of notes:
If a table is linked with a gateway, then this gateway is considered one of the hit actions. This is currently done as the gateway uses the hit pathway on inhibit, and sends a signal to be extracted. Currently, with an all 0 payload, the instruction that is extracted will be the 0 index. If the table is sharing the next table and instruction overhead as the same index, then the entry in the next table cannot be used for a match-entry's next table.
For Tofino and JBay, gateways do not use their payload when they inhibit for their next table. Instead the register they use is:
rams.match.merge.gateway_next_table_lut
This contains the next table pointer for each gateway row. However, in JBay, if the gateway needs to use local_exec/global_exec/long_branch, which in general is true because of the way jbay_next_table.cpp is run, then the gateway also needs to access these registers, as this is the only hardware that contains local_exec, global_exec, and long branch. This means that potentially one and possibly more entries must be saved in the hitmap. The gateway can access them by instead of saving a next table pointer in the gateway_next_table_lut, instead saving a pointer into the indirection table.
Unfortunately, because nothing is simple in the compiler, I can't just add the entries to the table, as the program uses whether this table has more than one entry to determine if the address has to store the next table, instead of through a call like all other tables. The assembler currently just appends them to the back of the table, and crashes if it cannot.
This lead to an odd corner case where an action chain table had 7 actions and a gateway attached. Now, because the all 0th next table entry is unused, a gateway entry can populate that particular entry. This runs a BUG_CHECK to guarantee this.
TODO: table_format.cpp must be updated for this to determine the next table requirements for the combination of gateway and match table next table requirements. Also just put both the gateway and match table's NextTableSets in here, which means adjusting the assembler's assumption that a hitmap.size() > 1 means that the next table must be saved
|
protected |
Indirect address type.