|GNU Compiler Collection (GCC) Internals: Logical Operators|
Except when they appear in the condition operand of a
GIMPLE_COND, logical ‘and’ and ‘or’ operators are simplified
a = b && c becomes
T1 = (bool)b; if (T1 == true) T1 = (bool)c; a = T1;
T1 in this example cannot be an expression temporary,
because it has two different assignments.
All gimple operands are of type
tree. But only certain
types of trees are allowed to be used as operand tuples. Basic
validation is controlled by the function
get_gimple_rhs_class, which given a tree code, returns an
enum with the following values of type
GIMPLE_INVALID_RHSThe tree cannot be used as a GIMPLE operand.
GIMPLE_TERNARY_RHSThe tree is a valid GIMPLE ternary operation.
GIMPLE_BINARY_RHSThe tree is a valid GIMPLE binary operation.
GIMPLE_UNARY_RHSThe tree is a valid GIMPLE unary operation.
GIMPLE_SINGLE_RHSThe tree is a single object, that cannot be split into simpler operands (for instance,
This operand class also acts as an escape hatch for tree nodes
that may be flattened out into the operand vector, but would need
more than two slots on the RHS. For instance, a
expression of the form
(a op b) ? x : y could be flattened
out on the operand vector using 4 slots, but it would also
require additional processing to distinguish
c = a op b
c = a op b ? x : y. Something similar occurs with
ASSERT_EXPR. In time, these special case tree
expressions should be flattened into the operand vector.
For tree nodes in the categories
GIMPLE_UNARY_RHS, they cannot be
stored inside tuples directly. They first need to be flattened and
separated into individual components. For instance, given the GENERIC
a = b + c
its tree representation is:
MODIFY_EXPR <VAR_DECL <a>, PLUS_EXPR <VAR_DECL <b>, VAR_DECL <c>>>
In this case, the GIMPLE form for this statement is logically
identical to its GENERIC form but in GIMPLE, the
on the RHS of the assignment is not represented as a tree,
instead the two operands are taken out of the
and flattened into the GIMPLE tuple as follows:
GIMPLE_ASSIGN <PLUS_EXPR, VAR_DECL <a>, VAR_DECL <b>, VAR_DECL <c>>
The operand vector is stored at the bottom of the three tuple structures that accept operands. This means, that depending on the code of a given statement, its operand vector will be at different offsets from the base of the structure. To access tuple operands use the following accessors
Returns a pointer into the operand vector for statement
is computed using an internal table called
This table is indexed by the gimple code of
When the compiler is built, this table is filled-in using the
sizes of the structures used by each statement code defined in
gimple.def. Since the operand vector is at the bottom of the
structure, for a gimple code
C the offset is computed as sizeof
C) - sizeof (tree).
This mechanism adds one memory indirection to every access when
gimple_op(), if this becomes a bottleneck, a pass can
choose to memoize the result from
gimple_ops() and use that to
access the operands.
When adding a new operand to a gimple statement, the operand will
be validated according to what each tuple accepts in its operand
vector. These predicates are called by the
gimple_name_set_...(). Each tuple will use one of the
following predicates (Note, this list is not exhaustive):
Returns true if t is a "GIMPLE value", which are all the
non-addressable stack variables (variables for which
is_gimple_reg returns true) and constants (expressions for which
is_gimple_min_invariant returns true).
Returns true if t is a symbol or memory reference whose address can be taken.
is_gimple_val but it also accepts hard registers.
Return true if t is a valid expression to use as the function
called by a
Return true if t is a valid expression to use as first operand
Return true if t is a valid minimal invariant. This is different from constants, in that the specific value of t may not be known at compile time, but it is known that it doesn’t change (e.g., the address of a function local variable).
Return true if t is an interprocedural invariant. This means that t is a valid invariant in all functions (e.g. it can be an address of a global variable but not of a local one).
Return true if t is an
ADDR_EXPR that does not change once the
program is running (and which is valid in all functions).
Return true if g is a
GIMPLE_ASSIGN that performs a type cast
Return true if g is a
GIMPLE_DEBUG that binds the value of an
expression to a variable.