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.
gimple
(gsbase)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:
Field | Size (bits)
|
code | 8
|
subcode | 16
|
no_warning | 1
|
visited | 1
|
nontemporal_move | 1
|
plf | 2
|
modified | 1
|
has_volatile_ops | 1
|
references_memory_p | 1
|
uid | 32
|
location | 32
|
num_ops | 32
|
bb | 64
|
block | 63
|
Total size | 32 bytes
|
code
Main identifier for a GIMPLE instruction.
subcode
Used to distinguish different variants of the same basic
instruction or provide flags applicable to a given code. The
subcode
flags 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_warning
Bitflag to indicate whether a warning has already been issued on
this statement.
visited
General purpose “visited” marker. Set and cleared by each pass
when needed.
nontemporal_move
Bitflag 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.
plf
Pass 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.
modified
Bitflag 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_ops
Bitflag to indicate whether this statement contains operands that
have been marked volatile.
references_memory_p
Bitflag 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).
uid
This 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.
location
This is a location_t
identifier to specify source code
location for this statement. It is inherited from the front
end.
num_ops
Number 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.
bb
Basic block holding the instruction.
block
Lexical block holding this statement. Also used for debug
information generation.
gimple_statement_with_ops
This tuple is actually split in two:
gimple_statement_with_ops_base
and
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 (gimple_alloc
) simply
allocates enough memory to hold the structure itself plus N
- 1
operands which run “off the end” of the structure. For
example, to allocate space for a tuple with 3 operands,
gimple_alloc
reserves sizeof (struct
gimple_statement_with_ops) + 2 * sizeof (tree)
bytes.
On the other hand, several fields in this tuple need to be shared
with the gimple_statement_with_memory_ops
tuple. So, these
common fields are placed in gimple_statement_with_ops_base
which
is then inherited from the other two tuples.
gsbase | 256
|
def_ops | 64
|
use_ops | 64
|
op | num_ops * 64
|
Total size | 48 + 8 * num_ops bytes
|
gsbase
Inherited from struct gimple
.
def_ops
Array 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.
use_ops
Similar to def_ops
but for variables read by the statement.
op
Array of trees with num_ops
slots.
gimple_statement_with_memory_ops
This tuple is essentially identical to gimple_statement_with_ops
,
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
vector (gimple_statement_with_memory_ops_base
and
gimple_statement_with_memory_ops
).
Field | Size (bits)
|
gsbase | 256
|
def_ops | 64
|
use_ops | 64
|
vdef_ops | 64
|
vuse_ops | 64
|
stores | 64
|
loads | 64
|
op | num_ops * 64
|
Total size | 80 + 8 * num_ops bytes
|
vdef_ops
Similar to def_ops
but for VDEF
operators. 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.
vuse_ops
Similar to use_ops
but for VUSE
operators. There is
one entry per memory symbol loaded by this statement. This is
used to maintain the memory SSA use-def chains.
stores
Bitset with all the UIDs for the symbols written-to by the
statement. This is different than vdef_ops
in that all the
affected symbols are mentioned in this set. If memory
partitioning is enabled, the vdef_ops
vector will refer to memory
partitions. Furthermore, no SSA information is stored in this
set.
loads
Similar to 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.