P4C
The P4 Compiler
Loading...
Searching...
No Matches
MauAsmOutput Class Referenceabstract
Inheritance diagram for MauAsmOutput:
[legend]

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::Nodeapply_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 Visitorclone () const
 
virtual ControlFlowVisitorcontrolFlowVisitor ()
 
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 Visitorflow_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 ContextgetChildContext () const
 
int getChildrenVisited () const
 
const ContextgetContext () const
 
int getContextDepth () const
 
const IR::NodegetCurrentNode () const
 
template<class T >
const T * getCurrentNode () const
 
const IR::NodegetOriginal () 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 VisitorsetCalledBy (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< UniqueIdfind_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 NextTablenxt_tbl
 
const BFN_Optionsoptions
 
const PhvInfophv
 
const IR::BFN::Pipe * pipe
 
const MauPower::FinalizeMauPredDepsPowerpower_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 Visitorcalled_by = nullptr
 
cstring internalName
 
SplitFlowVisit_base *& split_link
 
SplitFlowVisit_basesplit_link_mem = nullptr
 

Member Function Documentation

◆ build_call()

std::string MauAsmOutput::build_call ( const IR::MAU::AttachedMemory * at_mem,
const IR::MAU::BackendAttached * ba,
const IR::MAU::Table * tbl ) const
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:

  • address position - the location of the address bits
  • pfe position - the location of the per flow enable bit
  • type position - the location of the meter type

With this come some keywords:

  1. $DIRECT - The table is directly addressed
  2. $DEFAULT - the parameter is defaulted on through the default register

◆ build_meter_color_call()

std::string MauAsmOutput::build_meter_color_call ( const IR::MAU::Meter * mtr,
const IR::MAU::BackendAttached * ba,
const IR::MAU::Table * tbl ) const
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.

◆ build_sel_len_call()

std::string MauAsmOutput::build_sel_len_call ( const IR::MAU::Selector * sel) const
protected

The call for the assembler to determine the selector length

◆ emit_action_data_alias()

void MauAsmOutput::emit_action_data_alias ( std::ostream & out,
indent_t indent,
const IR::MAU::Table * tbl,
const IR::MAU::Action * af ) const
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:

  1. An alias to combine multiple P4 parameters into a single aliased P4 parameter, if these multiple parameters are used in the same action: -set f1, arg1 -set f2, arg2 where f1 and f2 are in the same container. arg1 and arg2 will be aliased to something like $data0
  2. A location in the Action Ram/Match Ram alias, i.e. $adf_h0 or immediate(lo..hi)

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

◆ emit_action_data_bus()

void MauAsmOutput::emit_action_data_bus ( std::ostream & out,
indent_t indent,
const IR::MAU::Table * tbl,
bitvec source ) const
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

◆ emit_gateway()

bool MauAsmOutput::emit_gateway ( std::ostream & out,
indent_t gw_indent,
const IR::MAU::Table * tbl,
bool no_match,
NextTableSet next_hit,
NextTableSet & gw_miss ) const
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:

  • A match to compare the search bus/hash bus
  • An inhibit bit
  • A next table lookup
  • A payload shared between all 5 rows.

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

◆ emit_no_match_gateway()

void MauAsmOutput::emit_no_match_gateway ( std::ostream & out,
indent_t gw_indent,
const IR::MAU::Table * tbl ) const
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).

◆ emit_table_hitmap()

void MauAsmOutput::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
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

◆ indirect_address()

std::string MauAsmOutput::indirect_address ( const IR::MAU::AttachedMemory * am) const
protected

Indirect address type.