|GNU Compiler Collection (GCC) Internals: Tuple representation|
GIMPLE instructions are tuples of variable size divided in two groups: a header describing the instruction and its locations, and a variable length body with all the operands. Tuples are organized into a hierarchy with 3 main classes of tuples.
This is the root of the hierarchy, it holds basic information needed by most GIMPLE statements. There are some fields that may not be relevant to every GIMPLE statement, but those were moved into the base structure to take advantage of holes left by other fields (thus making the structure more compact). The structure takes 4 words (32 bytes) on 64 bit hosts:
|Total size||32 bytes|
codeMain identifier for a GIMPLE instruction.
subcodeUsed to distinguish different variants of the same basic instruction or provide flags applicable to a given code. The
subcodeflags field has different uses depending on the code of the instruction, but mostly it distinguishes instructions of the same family. The most prominent use of this field is in assignments, where subcode indicates the operation done on the RHS of the assignment. For example, a = b + c is encoded as
GIMPLE_ASSIGN <PLUS_EXPR, a, b, c>.
no_warningBitflag to indicate whether a warning has already been issued on this statement.
visitedGeneral purpose “visited” marker. Set and cleared by each pass when needed.
nontemporal_moveBitflag used in assignments that represent non-temporal moves. Although this bitflag is only used in assignments, it was moved into the base to take advantage of the bit holes left by the previous fields.
plfPass Local Flags. This 2-bit mask can be used as general purpose markers by any pass. Passes are responsible for clearing and setting these two flags accordingly.
modifiedBitflag to indicate whether the statement has been modified. Used mainly by the operand scanner to determine when to re-scan a statement for operands.
has_volatile_opsBitflag to indicate whether this statement contains operands that have been marked volatile.
references_memory_pBitflag to indicate whether this statement contains memory references (i.e., its operands are either global variables, or pointer dereferences or anything that must reside in memory).
uidThis is an unsigned integer used by passes that want to assign IDs to every statement. These IDs must be assigned and used by each pass.
locationThis is a
location_tidentifier to specify source code location for this statement. It is inherited from the front end.
num_opsNumber of operands that this statement has. This specifies the size of the operand vector embedded in the tuple. Only used in some tuples, but it is declared in the base tuple to take advantage of the 32-bit hole left by the previous fields.
bbBasic block holding the instruction.
blockLexical block holding this statement. Also used for debug information generation.
This tuple is actually split in two:
gimple_statement_with_ops. This is needed to accommodate the
way the operand vector is allocated. The operand vector is
defined to be an array of 1 element. So, to allocate a dynamic
number of operands, the memory allocator (
allocates enough memory to hold the structure itself plus
- 1 operands which run “off the end” of the structure. For
example, to allocate space for a tuple with 3 operands,
gimple_statement_with_ops) + 2 * sizeof (tree) bytes.
On the other hand, several fields in this tuple need to be shared
gimple_statement_with_memory_ops tuple. So, these
common fields are placed in
is then inherited from the other two tuples.
|Total size||48 + 8 * |
def_opsArray of pointers into the operand array indicating all the slots that contain a variable written-to by the statement. This array is also used for immediate use chaining. Note that it would be possible to not rely on this array, but the changes required to implement this are pretty invasive.
def_opsbut for variables read by the statement.
opArray of trees with
This tuple is essentially identical to
except that it contains 4 additional fields to hold vectors
related memory stores and loads. Similar to the previous case,
the structure is split in two to accommodate for the operand
|Total size||80 + 8 * |
VDEFoperators. There is one entry per memory symbol written by this statement. This is used to maintain the memory SSA use-def and def-def chains.
VUSEoperators. There is one entry per memory symbol loaded by this statement. This is used to maintain the memory SSA use-def chains.
storesBitset with all the UIDs for the symbols written-to by the statement. This is different than
vdef_opsin that all the affected symbols are mentioned in this set. If memory partitioning is enabled, the
vdef_opsvector will refer to memory partitions. Furthermore, no SSA information is stored in this set.
stores, but for memory loads. (Note that there is some amount of redundancy here, it should be possible to reduce memory utilization further by removing these sets).
All the other tuples are defined in terms of these three basic ones. Each tuple will add some fields.