OSDN Git Service

gcc:
[pf3gnuchains/gcc-fork.git] / gcc / tree-gimple.c
index 2b119fd..5d1edce 100644 (file)
@@ -1,5 +1,5 @@
 /* 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>
 
@@ -33,159 +33,7 @@ Boston, MA 02111-1307, USA.  */
 #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
-
-   with-size-arg: addr-expr-arg
-               | indirectref
-               | call-stmt
-
-   indirectref : INDIRECT_REF
-                       op0 -> val
-
-   lhs         : addr-expr-arg
-               | bitfieldref
-               | indirectref
-               | 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);
 
@@ -194,15 +42,15 @@ static inline bool is_gimple_id (tree);
 /* Return true if T is a GIMPLE RHS for an assignment to a temporary.  */
 
 bool
-is_gimple_tmp_rhs (tree t)
+is_gimple_formal_tmp_rhs (tree t)
 {
   enum tree_code code = TREE_CODE (t);
 
   switch (TREE_CODE_CLASS (code))
     {
-    case '1':
-    case '2':
-    case '<':
+    case tcc_unary:
+    case tcc_binary:
+    case tcc_comparison:
       return true;
 
     default:
@@ -234,28 +82,27 @@ is_gimple_tmp_rhs (tree t)
   return is_gimple_lvalue (t) || is_gimple_val (t);
 }
 
-/* Returns true iff T is a valid RHS for an assignment to a renamed user
-   variable.  */
+/* Returns true iff T is a valid RHS for an assignment to a renamed
+   user -- or front-end generated artificial -- variable.  */
 
 bool
 is_gimple_reg_rhs (tree t)
 {
-  /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto and
-     the LHS is a user variable, then we need to introduce a temporary.
-     ie temp = RHS; LHS = temp.
+  /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto
+     and the LHS is a user variable, then we need to introduce a formal
+     temporary.  This way the optimizers can determine that the user
+     variable is only modified if evaluation of the RHS does not throw.
+
+     Don't force a temp of a non-renamable type; the copy could be
+     arbitrarily expensive.  Instead we will generate a V_MAY_DEF for
+     the assignment.  */
 
-     This way the optimizers can determine that the user variable is
-     only modified if evaluation of the RHS does not throw.  */
   if (is_gimple_reg_type (TREE_TYPE (t))
-      && TREE_SIDE_EFFECTS (t)
-      && (TREE_CODE (t) == CALL_EXPR
-         || (flag_non_call_exceptions && tree_could_trap_p (t))))
-    return is_gimple_val (t);
-  else
-    /* Don't force a temp of a non-renamable type; the copy could be
-       arbitrarily expensive.  Instead we will generate a V_MAY_DEF for
-       the assignment.  */
-    return is_gimple_tmp_rhs (t);
+      && ((TREE_CODE (t) == CALL_EXPR && TREE_SIDE_EFFECTS (t))
+         || tree_could_throw_p (t)))
+    return false;
+
+  return is_gimple_formal_tmp_rhs (t);
 }
 
 /* Returns true iff T is a valid RHS for an assignment to an un-renamed
@@ -264,12 +111,15 @@ is_gimple_reg_rhs (tree t)
 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_tmp_rhs (t);
+    return is_gimple_formal_tmp_rhs (t);
 }
 
 /* Returns the appropriate RHS predicate for this LHS.  */
@@ -277,31 +127,20 @@ is_gimple_mem_rhs (tree t)
 gimple_predicate
 rhs_predicate_for (tree lhs)
 {
-  if (is_gimple_tmp_var (lhs))
-    return is_gimple_tmp_rhs;
+  if (is_gimple_formal_tmp_var (lhs))
+    return is_gimple_formal_tmp_rhs;
   else if (is_gimple_reg (lhs))
     return is_gimple_reg_rhs;
   else
     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
 is_gimple_lvalue (tree t)
 {
-  return (is_gimple_addr_expr_arg (t)
-         || TREE_CODE (t) == INDIRECT_REF
+  return (is_gimple_addressable (t)
          || TREE_CODE (t) == WITH_SIZE_EXPR
          /* These are complex lvalues, but don't have addresses, so they
             go here.  */
@@ -313,22 +152,16 @@ is_gimple_lvalue (tree t)
 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 a valid operand for ADDR_EXPR.  */
+/*  Return true if T is something whose address can be taken.  */
 
 bool
-is_gimple_addr_expr_arg (tree t)
+is_gimple_addressable (tree t)
 {
-  return (is_gimple_id (t)
-         || TREE_CODE (t) == ARRAY_REF
-         || TREE_CODE (t) == ARRAY_RANGE_REF
-         || TREE_CODE (t) == COMPONENT_REF
-         || TREE_CODE (t) == REALPART_EXPR
-         || TREE_CODE (t) == IMAGPART_EXPR
-         || TREE_CODE (t) == INDIRECT_REF);
+  return (is_gimple_id (t) || handled_component_p (t)
+         || INDIRECT_REF_P (t));
 }
 
 /* Return true if T is function invariant.  Or rather a restricted
@@ -347,7 +180,7 @@ is_gimple_min_invariant (tree t)
     case STRING_CST:
     case COMPLEX_CST:
     case VECTOR_CST:
-      return !TREE_OVERFLOW (t);
+      return true;
 
     default:
       return false;
@@ -416,6 +249,7 @@ is_gimple_id (tree t)
   return (is_gimple_variable (t)
          || TREE_CODE (t) == FUNCTION_DECL
          || TREE_CODE (t) == LABEL_DECL
+         || TREE_CODE (t) == CONST_DECL
          /* Allow string constants, since they are addressable.  */
          || TREE_CODE (t) == STRING_CST);
 }
@@ -438,29 +272,52 @@ is_gimple_reg (tree t)
   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)
-         && ! TREE_ADDRESSABLE (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 temporary variable, false otherwise.  */
+/* Returns true if T is a GIMPLE formal temporary variable.  */
 
 bool
-is_gimple_tmp_var (tree t)
+is_gimple_formal_tmp_var (tree t)
 {
-  /* FIXME this could trigger for other local artificials, too.  */
-  return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t)
-         && !TREE_STATIC (t) && !DECL_EXTERNAL (t));
+  if (TREE_CODE (t) == SSA_NAME)
+    return true;
+
+  return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t);
 }
 
-/* Returns true if T is a GIMPLE temporary register variable.  */
+/* Returns true if T is a GIMPLE formal temporary register variable.  */
 
 bool
-is_gimple_tmp_reg (tree t)
+is_gimple_formal_tmp_reg (tree t)
 {
   /* The intent of this is to get hold of a value that won't change.
      An SSA_NAME qualifies no matter if its of a user variable or not.  */
@@ -468,7 +325,7 @@ is_gimple_tmp_reg (tree t)
     return true;
 
   /* We don't know the lifetime characteristics of user variables.  */
-  if (TREE_CODE (t) != VAR_DECL || !DECL_ARTIFICIAL (t))
+  if (!is_gimple_formal_tmp_var (t))
     return false;
 
   /* Finally, it must be capable of being placed in a register.  */
@@ -483,9 +340,7 @@ is_gimple_non_addressable (tree t)
   if (TREE_CODE (t) == SSA_NAME)
     t = SSA_NAME_VAR (t);
 
-  return (is_gimple_variable (t)
-         && ! TREE_ADDRESSABLE (t)
-         && ! needs_to_live_in_memory (t));
+  return (is_gimple_variable (t) && ! needs_to_live_in_memory (t));
 }
 
 /* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant.  */
@@ -507,6 +362,16 @@ is_gimple_val (tree 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.  */
 
@@ -554,22 +419,25 @@ get_call_expr_in (tree t)
   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;
@@ -579,12 +447,12 @@ void
 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:
@@ -603,17 +471,21 @@ recalculate_side_effects (tree t)
        }
       /* 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 ();
    }
 }