P4C
The P4 Compiler
Loading...
Searching...
No Matches
ActionData::RamSection Class Reference

#include <action_format.h>

Public Member Functions

 RamSection (int s)
 
 RamSection (int s, PackingConstraint &pc)
 
void add_alu_req (const ALUOperation *rv)
 
void add_param (int bit, const Parameter *)
 
const RamSectionbetter_merge_cand (const RamSection *) const
 
bitvec bits_in_use () const
 
BusInputs bus_inputs () const
 
size_t byte_sz () const
 
const RamSectioncan_rotate (int init_bit, int final_bit) const
 
const RamSectioncondense (const RamSection *) const
 
bool contains (const ALUOperation *ad_alu, int *first_phv_bit_pos=nullptr) const
 
bool contains (const RamSection *ad_small, int init_bit_pos, int *final_bit_pos) const
 
bool contains_any_rotation_from_0 (const RamSection *ad_small, int init_bit_pos, int *final_bit_pos) const
 
void dbprint_multiline () const
 
const RamSectionexpand_to_size (size_t expand_size) const
 
void gather_shared_params (const RamSection *ad, safe_vector< SharedParameter > &shared_params, bool only_one_overlap_solution) const
 
std::string get_action_data_bits_str () const
 
PackingConstraint get_pack_info () const
 
size_t index () const
 
bool is_data_subset_of (const RamSection *ad) const
 
const RamSectionmerge (const RamSection *ad) const
 
const RamSectionno_overlap_merge (const RamSection *ad) const
 
safe_vector< le_bitrangeopen_holes () const
 
ParameterPositions parameter_positions (bool same_alias=false) const
 
std::string parameter_positions_to_string (bool from_p4_program) const
 
const RamSectionrotate_in_range (le_bitrange range) const
 
size_t size () const
 

Public Attributes

safe_vector< const ALUOperation * > alu_requirements
 

Friends

std::ostream & operator<< (std::ostream &out, const RamSection &rs)
 

Detailed Description

This class represents the positions of data in an entry of RAM.

During the condense portion of the algorithm, each RamSection has not been assigned a position on either an ActionData RAM, or a portion of immediate. Rather each RamSection can be thought of as a vector of bits that have a size, and that this size constrains where this data can eventually appear on a RAM line.

Note the following constraint on ALU operations:

- For an ALU operation PHV_Container[hi..lo] = f(ADB[adb_hi..adb_lo])
  the action data source must appear at most in a single action data bus location

This adb_hi and adb_lo coordinate to a action_RAM_hi and action_RAM_lo, as data gets pulled from the Action Data Table through the Action Data Bus and finally to an ALU.

The constraint arising is: action_RAM_hi / size(PHV_Container) == action_RAM_lo / size(PHV_Container), integer division

This guarantees that the data appears in the same action data bus slot.

Thus the action_data_bits vector, which will be of size 8, 16, or 32 (or 64 explained later), will eventually have to be packed in the Action RAM on a mod_offset of its size, as it can be thought of as a source of RAM bits for an ALU operation.

It is more extensible than the ALUOperation, as a section of RAM can be sent to multiple ALUs. Furthermore, portions of a ActionDataRAMSection can be sent to a single ALU. Say for instance, the following happens.

32 bits of action data: The first byte can be sent to an 8 bit ALU. The third and fourth byte can be sent to a 16 bit ALU. The entire four bytes can be sent to a 32 bit ALU.

This would capture 3 separate ALUOperation operations within an RamSection. Furthermore, the constraints mentioned about action_RAM_lo and action_RAM_hi would have to be captured for all 3 ALUOperation operations. This is the purpose of the PackingConstraint, which has recursive information on how data can possibly be moved in order to more efficiently pack data.

Lastly, because bitmasked-sets need to appear in even-odd pairs of ActionDataBus slots, the algorithm currently requires the allocation of these to be contiguous, as contiguous RAM bytes/half-words/full-words are much easier to enforce contiguity on the ActionDataBus. This leads to up to 64 bit (2 * 32 bit sources)

Member Function Documentation

◆ bus_inputs()

BusInputs ActionData::RamSection::bus_inputs ( ) const

Given that a RamSection contains potentially multiple ALUOperation object the purpose of this function is to determine the inputs to the ActionDataBus. Essentially the return value is the action data inputs if this section was allocated at bit 0 of an action data table.

◆ condense()

const RamSection * ActionData::RamSection::condense ( const RamSection * ad) const

The algorithm to determine if (and the best way of) two RamSections can be merged, (if two sections can be merged).

The steps are:

  1. Expand the RAMSections so that they are the same size
  2. Look for shared parameters and rotate the sections so that this data overlaps
  3. Try to rotate data so that no fields overlap
  4. Pick the best choice based on heuristics

◆ contains() [1/2]

bool ActionData::RamSection::contains ( const ALUOperation * ad_alu,
int * final_first_phv_bit_pos = nullptr ) const

The purpose of this check is to resolve the position of an ALUOperation within an RamSection. During the condense algorithm, the action data could be repositioned in order to more tightly pack within RAM space. This returns that the ActionDataForSingleALU is still within this container, as well as calculates the right shift and the offset within the ALU operation.

In order to solve this problem, one could in theory think that the ad_alu has parameters, and the algorithm can just rotate to overlap those parameters and see if the data is a subset of those parameters. However, this only works efficiently if a single overlap is possible.

Arguments can only overlap in one way, i.e. arg1[7:0] and arg1[12:4] only have one overlap arg1[7:4]. However for constants, each have possibly multiple overlaps, i.e. 0b00111000111 and 0b000111 would have multiple overlaps. Thus instead, by trying all possible rotations of the original ALU and trying to find a subset, this is the only possible way to determine exactly that the overlap is possible.

The other goal is to potentially find the position of the first phv_bit after a rotation in order to eventually determine the position of action data. The *final_first_phv_bit_pos is the position of this bit.

◆ contains() [2/2]

bool ActionData::RamSection::contains ( const RamSection * ad_small,
int init_bit_pos,
int * final_bit_pos ) const

Uses shared parameters to see if the ad_small is contained within *this Full Description:

See also
contains(const ALUOperation *)

◆ contains_any_rotation_from_0()

bool ActionData::RamSection::contains_any_rotation_from_0 ( const RamSection * ad_small,
int init_bit_pos,
int * final_bit_pos ) const

Uses rotations from 0 to see if ad_small is contained within *this Full Description:

See also
contains(const ALUOperation *)

◆ expand_to_size()

const RamSection * ActionData::RamSection::expand_to_size ( size_t expand_size) const

In order to perform the merge function, the two RamSections have to be the same size, i.e. the same number of bits wide.

The example would be to move a 8-bit data to move 16-bit data. The byte size data now has 8 empty bits appended to it. The new 16 bit section is also now byte-by-byte rotational, which is done through the expansion of the PackingConstraint

◆ gather_shared_params()

void ActionData::RamSection::gather_shared_params ( const RamSection * ad,
safe_vector< SharedParameter > & shared_params,
bool only_one_overlap_solution ) const

Calculate the positions of the parameters that both RamSection

◆ is_data_subset_of()

bool ActionData::RamSection::is_data_subset_of ( const RamSection * ad) const

A check to guarantee that the bits of this is a subset of bits on RamSection *ad:

  • arg[2:4] at bit 2 would be a subset of arg[0:7] at bit 0
  • arg[2:4] at bit 0 would not be a subset of arg[0:7] at bit 0
  • arg[0:4] at bit 0 would not be a subset of arg[1:7] at bit 1

◆ no_overlap_merge()

const RamSection * ActionData::RamSection::no_overlap_merge ( const RamSection * ad) const

Returns a merged RamSection of two independent ranges, if the merge was possible. For a constraint explanation, please look at PackingConstraint::merge

◆ open_holes()

safe_vector< le_bitrange > ActionData::RamSection::open_holes ( ) const

Return the open ranges of data within an RamSection

◆ parameter_positions()

ParameterPositions ActionData::RamSection::parameter_positions ( bool from_p4_program = false) const

Building a map of slices of parameters in order to look for identical ranges of data within two RamSections.

The from_p4_program boolean is a flag to (if necessary) only return values that are part of the p4 program as either arguments or constants, and not implicit 0s. This is for specifically assembly generation, not to output the implict zeros when detailing action data packing of the program

◆ rotate_in_range()

const RamSection * ActionData::RamSection::rotate_in_range ( le_bitrange hole) const

Returns a rotated RamSection that fits within the bitrange provided, if possible. For a constraint explanation, please look at PackingConstraint::rotate_in_range

Member Data Documentation

◆ alu_requirements

safe_vector<const ALUOperation *> ActionData::RamSection::alu_requirements

‍map of ALUOperation operations with their action data requirements allocated in this RAMSection