Previous: Conditional Expressions, Up: Operands


12.5.4 Logical Operators

Except when they appear in the condition operand of a GIMPLE_COND, logical `and' and `or' operators are simplified as follows: a = b && c becomes

     T1 = (bool)b;
     if (T1 == true)
       T1 = (bool)c;
     a = T1;

Note that T1 in this example cannot be an expression temporary, because it has two different assignments.

12.5.5 Manipulating operands

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 enum gimple_rhs_class

For tree nodes in the categories GIMPLE_TERNARY_RHS, GIMPLE_BINARY_RHS and 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 expression

     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 PLUS_EXPR on the RHS of the assignment is not represented as a tree, instead the two operands are taken out of the PLUS_EXPR sub-tree and flattened into the GIMPLE tuple as follows:

     GIMPLE_ASSIGN <PLUS_EXPR, VAR_DECL <a>, VAR_DECL <b>, VAR_DECL <c>>

12.5.6 Operand vector allocation

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

— GIMPLE function: unsigned gimple_num_ops (gimple g)

Returns the number of operands in statement G.

— GIMPLE function: tree gimple_op (gimple g, unsigned i)

Returns operand I from statement G.

— GIMPLE function: tree * gimple_ops (gimple g)

Returns a pointer into the operand vector for statement G. This is computed using an internal table called gimple_ops_offset_[]. This table is indexed by the gimple code of G.

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 (struct-of C) - sizeof (tree).

This mechanism adds one memory indirection to every access when using 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.

12.5.7 Operand validation

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):

— GIMPLE function: bool is_gimple_val (tree t)

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).

— GIMPLE function: bool is_gimple_addressable (tree t)

Returns true if t is a symbol or memory reference whose address can be taken.

— GIMPLE function: bool is_gimple_asm_val (tree t)

Similar to is_gimple_val but it also accepts hard registers.

— GIMPLE function: bool is_gimple_call_addr (tree t)

Return true if t is a valid expression to use as the function called by a GIMPLE_CALL.

— GIMPLE function: bool is_gimple_mem_ref_addr (tree t)

Return true if t is a valid expression to use as first operand of a MEM_REF expression.

— GIMPLE function: bool is_gimple_constant (tree t)

Return true if t is a valid gimple constant.

— GIMPLE function: bool is_gimple_min_invariant (tree t)

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).

— GIMPLE function: bool is_gimple_ip_invariant (tree t)

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).

— GIMPLE function: bool is_gimple_ip_invariant_address (tree t)

Return true if t is an ADDR_EXPR that does not change once the program is running (and which is valid in all functions).

12.5.8 Statement validation

— GIMPLE function: bool is_gimple_assign (gimple g)

Return true if the code of g is GIMPLE_ASSIGN.

— GIMPLE function: bool is_gimple_call (gimple g)

Return true if the code of g is GIMPLE_CALL.

— GIMPLE function: bool is_gimple_debug (gimple g)

Return true if the code of g is GIMPLE_DEBUG.

— GIMPLE function: bool gimple_assign_cast_p (gimple g)

Return true if g is a GIMPLE_ASSIGN that performs a type cast operation.

— GIMPLE function: bool gimple_debug_bind_p (gimple g)

Return true if g is a GIMPLE_DEBUG that binds the value of an expression to a variable.