P4C
The P4 Compiler
|
#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 RamSection * | better_merge_cand (const RamSection *) const |
bitvec | bits_in_use () const |
BusInputs | bus_inputs () const |
size_t | byte_sz () const |
const RamSection * | can_rotate (int init_bit, int final_bit) const |
const RamSection * | condense (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 RamSection * | expand_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 RamSection * | merge (const RamSection *ad) const |
const RamSection * | no_overlap_merge (const RamSection *ad) const |
safe_vector< le_bitrange > | open_holes () const |
ParameterPositions | parameter_positions (bool same_alias=false) const |
std::string | parameter_positions_to_string (bool from_p4_program) const |
const RamSection * | rotate_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) |
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)
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.
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:
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.
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:
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:
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
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
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:
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
safe_vector< le_bitrange > ActionData::RamSection::open_holes | ( | ) | const |
Return the open ranges of data within an RamSection
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
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
safe_vector<const ALUOperation *> ActionData::RamSection::alu_requirements |
map of ALUOperation operations with their action data requirements allocated in this RAMSection