/* Functions to analyze and validate GIMPLE trees.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
Rewritten by Jason Merrill <jason@redhat.com>
#include "expr.h"
#include "bitmap.h"
-/* GCC GIMPLE structure
-
- Inspired by the SIMPLE C grammar at
-
- http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html
-
- function : FUNCTION_DECL
- DECL_SAVED_TREE -> compound-stmt
-
- compound-stmt: STATEMENT_LIST
- members -> stmt
-
- stmt : block
- | if-stmt
- | switch-stmt
- | goto-stmt
- | return-stmt
- | resx-stmt
- | label-stmt
- | try-stmt
- | modify-stmt
- | call-stmt
-
- block : BIND_EXPR
- BIND_EXPR_VARS -> chain of DECLs
- BIND_EXPR_BLOCK -> BLOCK
- BIND_EXPR_BODY -> compound-stmt
-
- if-stmt : COND_EXPR
- op0 -> condition
- op1 -> compound-stmt
- op2 -> compound-stmt
-
- switch-stmt : SWITCH_EXPR
- op0 -> val
- op1 -> NULL
- op2 -> TREE_VEC of CASE_LABEL_EXPRs
- The CASE_LABEL_EXPRs are sorted by CASE_LOW,
- and default is last.
-
- goto-stmt : GOTO_EXPR
- op0 -> LABEL_DECL | val
-
- return-stmt : RETURN_EXPR
- op0 -> return-value
-
- return-value : NULL
- | RESULT_DECL
- | MODIFY_EXPR
- op0 -> RESULT_DECL
- op1 -> lhs
-
- resx-stmt : RESX_EXPR
-
- label-stmt : LABEL_EXPR
- op0 -> LABEL_DECL
-
- try-stmt : TRY_CATCH_EXPR
- op0 -> compound-stmt
- op1 -> handler
- | TRY_FINALLY_EXPR
- op0 -> compound-stmt
- op1 -> compound-stmt
-
- handler : catch-seq
- | EH_FILTER_EXPR
- | compound-stmt
-
- catch-seq : STATEMENT_LIST
- members -> CATCH_EXPR
-
- modify-stmt : MODIFY_EXPR
- op0 -> lhs
- op1 -> rhs
-
- call-stmt : CALL_EXPR
- op0 -> val | OBJ_TYPE_REF
- op1 -> call-arg-list
-
- call-arg-list: TREE_LIST
- members -> lhs
-
- addr-expr-arg: ID
- | compref
-
- addressable : addr-expr-arg
- | indirectref
-
- with-size-arg: addressable
- | call-stmt
-
- indirectref : INDIRECT_REF
- op0 -> val
-
- lhs : addressable
- | bitfieldref
- | WITH_SIZE_EXPR
- op0 -> with-size-arg
- op1 -> val
-
- min-lval : ID
- | indirectref
-
- bitfieldref : BIT_FIELD_REF
- op0 -> inner-compref
- op1 -> CONST
- op2 -> var
-
- compref : inner-compref
- | REALPART_EXPR
- op0 -> inner-compref
- | IMAGPART_EXPR
- op0 -> inner-compref
-
- inner-compref: min-lval
- | COMPONENT_REF
- op0 -> inner-compref
- op1 -> FIELD_DECL
- op2 -> val
- | ARRAY_REF
- op0 -> inner-compref
- op1 -> val
- op2 -> val
- op3 -> val
- | ARRAY_RANGE_REF
- op0 -> inner-compref
- op1 -> val
- op2 -> val
- op3 -> val
- | VIEW_CONVERT_EXPR
- op0 -> inner-compref
-
- condition : val
- | RELOP
- op0 -> val
- op1 -> val
-
- val : ID
- | CONST
-
- rhs : lhs
- | CONST
- | call-stmt
- | ADDR_EXPR
- op0 -> addr-expr-arg
- | UNOP
- op0 -> val
- | BINOP
- op0 -> val
- op1 -> val
- | RELOP
- op0 -> val
- op1 -> val
-*/
+/* For the definitive definition of GIMPLE, see doc/tree-ssa.texi. */
static inline bool is_gimple_id (tree);
switch (TREE_CODE_CLASS (code))
{
- case '1':
- case '2':
- case '<':
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_comparison:
return true;
default:
bool
is_gimple_mem_rhs (tree t)
{
- /* If we're dealing with a renamable type, either source or dest
- must be a renamed variable. */
- if (is_gimple_reg_type (TREE_TYPE (t)))
+ /* If we're dealing with a renamable type, either source or dest must be
+ a renamed variable. Also force a temporary if the type doesn't need
+ to be stored in memory, since it's cheap and prevents erroneous
+ tailcalls (PR 17526). */
+ if (is_gimple_reg_type (TREE_TYPE (t))
+ || TYPE_MODE (TREE_TYPE (t)) != BLKmode)
return is_gimple_val (t);
else
return is_gimple_formal_tmp_rhs (t);
return is_gimple_mem_rhs;
}
-/* Returns true if T is a valid CONSTRUCTOR component in GIMPLE, either
- a val or another CONSTRUCTOR. */
-
-bool
-is_gimple_constructor_elt (tree t)
-{
- return (is_gimple_val (t)
- || TREE_CODE (t) == CONSTRUCTOR);
-}
-
/* Return true if T is a valid LHS for a GIMPLE assignment expression. */
bool
bool
is_gimple_condexpr (tree t)
{
- return (is_gimple_val (t)
- || TREE_CODE_CLASS (TREE_CODE (t)) == '<');
+ return (is_gimple_val (t) || COMPARISON_CLASS_P (t));
}
/* Return true if T is something whose address can be taken. */
is_gimple_addressable (tree t)
{
return (is_gimple_id (t) || handled_component_p (t)
- || TREE_CODE (t) == REALPART_EXPR
- || TREE_CODE (t) == IMAGPART_EXPR
- || TREE_CODE (t) == INDIRECT_REF);
+ || INDIRECT_REF_P (t));
}
/* Return true if T is function invariant. Or rather a restricted
case STRING_CST:
case COMPLEX_CST:
case VECTOR_CST:
- return !TREE_OVERFLOW (t);
+ return true;
default:
return false;
if (TREE_CODE (t) == SSA_NAME)
t = SSA_NAME_VAR (t);
- return (is_gimple_variable (t)
- && is_gimple_reg_type (TREE_TYPE (t))
- /* A volatile decl is not acceptable because we can't reuse it as
- needed. We need to copy it into a temp first. */
- && ! TREE_THIS_VOLATILE (t)
- && ! needs_to_live_in_memory (t));
+ if (!is_gimple_variable (t))
+ return false;
+ if (!is_gimple_reg_type (TREE_TYPE (t)))
+ return false;
+
+ /* A volatile decl is not acceptable because we can't reuse it as
+ needed. We need to copy it into a temp first. */
+ if (TREE_THIS_VOLATILE (t))
+ return false;
+
+ /* We define "registers" as things that can be renamed as needed,
+ which with our infrastructure does not apply to memory. */
+ if (needs_to_live_in_memory (t))
+ return false;
+
+ /* Hard register variables are an interesting case. For those that
+ are call-clobbered, we don't know where all the calls are, since
+ we don't (want to) take into account which operations will turn
+ into libcalls at the rtl level. For those that are call-saved,
+ we don't currently model the fact that calls may in fact change
+ global hard registers, nor do we examine ASM_CLOBBERS at the tree
+ level, and so miss variable changes that might imply. All around,
+ it seems safest to not do too much optimization with these at the
+ tree level at all. We'll have to rely on the rtl optimizers to
+ clean this up, as there we've got all the appropriate bits exposed. */
+ if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+ return false;
+
+ return true;
}
/* Returns true if T is a GIMPLE formal temporary variable. */
bool
is_gimple_formal_tmp_var (tree t)
{
+ if (TREE_CODE (t) == SSA_NAME)
+ return true;
+
return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t);
}
return (is_gimple_variable (t) || is_gimple_min_invariant (t));
}
+/* Similarly, but accept hard registers as inputs to asm statements. */
+
+bool
+is_gimple_asm_val (tree t)
+{
+ if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
+ return true;
+
+ return is_gimple_val (t);
+}
/* Return true if T is a GIMPLE minimal lvalue. */
return NULL_TREE;
}
-/* Given a memory reference expression, return the base address. Note that,
- in contrast with get_base_var, this will not recurse inside INDIRECT_REF
- expressions. Therefore, given the reference PTR->FIELD, this function
- will return *PTR. Whereas get_base_var would've returned PTR. */
+/* Given a memory reference expression T, return its base address.
+ The base address of a memory reference expression is the main
+ object being referenced. For instance, the base address for
+ 'array[i].fld[j]' is 'array'. You can think of this as stripping
+ away the offset part from a memory address.
+
+ This function calls handled_component_p to strip away all the inner
+ parts of the memory reference until it reaches the base object. */
tree
get_base_address (tree t)
{
- while (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR
- || handled_component_p (t))
+ while (handled_component_p (t))
t = TREE_OPERAND (t, 0);
if (SSA_VAR_P (t)
|| TREE_CODE (t) == STRING_CST
|| TREE_CODE (t) == CONSTRUCTOR
- || TREE_CODE (t) == INDIRECT_REF)
+ || INDIRECT_REF_P (t))
return t;
else
return NULL_TREE;
recalculate_side_effects (tree t)
{
enum tree_code code = TREE_CODE (t);
- int fro = first_rtl_op (code);
+ int len = TREE_CODE_LENGTH (code);
int i;
switch (TREE_CODE_CLASS (code))
{
- case 'e':
+ case tcc_expression:
switch (code)
{
case INIT_EXPR:
}
/* Fall through. */
- case '<': /* a comparison expression */
- case '1': /* a unary arithmetic expression */
- case '2': /* a binary arithmetic expression */
- case 'r': /* a reference */
+ case tcc_comparison: /* a comparison expression */
+ case tcc_unary: /* a unary arithmetic expression */
+ case tcc_binary: /* a binary arithmetic expression */
+ case tcc_reference: /* a reference */
TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t);
- for (i = 0; i < fro; ++i)
+ for (i = 0; i < len; ++i)
{
tree op = TREE_OPERAND (t, i);
if (op && TREE_SIDE_EFFECTS (op))
TREE_SIDE_EFFECTS (t) = 1;
}
break;
+
+ default:
+ /* Can never be used with non-expressions. */
+ gcc_unreachable ();
}
}