OSDN Git Service

2009-04-09 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 02d4923..515c58e 100644 (file)
@@ -107,12 +107,14 @@ static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool);
 
 /* Mark X addressable.  Unlike the langhook we expect X to be in gimple
    form and we don't do any syntax checking.  */
-static void
+void
 mark_addressable (tree x)
 {
   while (handled_component_p (x))
     x = TREE_OPERAND (x, 0);
-  if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
+  if (TREE_CODE (x) != VAR_DECL
+      && TREE_CODE (x) != PARM_DECL
+      && TREE_CODE (x) != RESULT_DECL)
     return ;
   TREE_ADDRESSABLE (x) = 1;
 }
@@ -212,16 +214,12 @@ void
 pop_gimplify_context (gimple body)
 {
   struct gimplify_ctx *c = gimplify_ctxp;
-  tree t;
 
   gcc_assert (c && (c->bind_expr_stack == NULL
                    || VEC_empty (gimple, c->bind_expr_stack)));
   VEC_free (gimple, heap, c->bind_expr_stack);
   gimplify_ctxp = c->prev_context;
 
-  for (t = c->temps; t ; t = TREE_CHAIN (t))
-    DECL_GIMPLE_FORMAL_TEMP_P (t) = 0;
-
   if (body)
     declare_vars (c->temps, body, false);
   else
@@ -607,9 +605,6 @@ lookup_tmp_var (tree val, bool is_formal)
        }
     }
 
-  if (is_formal)
-    DECL_GIMPLE_FORMAL_TEMP_P (ret) = 1;
-
   return ret;
 }
 
@@ -620,32 +615,10 @@ lookup_tmp_var (tree val, bool is_formal)
    gimplify_modify_expr.  */
 
 static bool
-is_gimple_formal_tmp_or_call_rhs (tree t)
+is_gimple_reg_rhs_or_call (tree t)
 {
-  return TREE_CODE (t) == CALL_EXPR || is_gimple_formal_tmp_rhs (t);
-}
-
-/* Returns true iff T is a valid RHS for an assignment to a renamed
-   user -- or front-end generated artificial -- variable.  */
-
-static bool
-is_gimple_reg_or_call_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 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 VDEF for
-     the assignment.  */
-
-  if (is_gimple_reg_type (TREE_TYPE (t))
-      && ((TREE_CODE (t) == CALL_EXPR && TREE_SIDE_EFFECTS (t))
-         || tree_could_throw_p (t)))
-    return false;
-
-  return is_gimple_formal_tmp_or_call_rhs (t);
+  return (get_gimple_rhs_class (TREE_CODE (t)) != GIMPLE_INVALID_RHS
+         || TREE_CODE (t) == CALL_EXPR);
 }
 
 /* Return true if T is a valid memory RHS or a CALL_EXPR.  Note that
@@ -653,28 +626,18 @@ is_gimple_reg_or_call_rhs (tree t)
    rationale for this in gimplify_modify_expr.  */
 
 static bool
-is_gimple_mem_or_call_rhs (tree t)
+is_gimple_mem_rhs_or_call (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)))
     return is_gimple_val (t);
   else
-    return is_gimple_formal_tmp_or_call_rhs (t);
+    return (is_gimple_val (t) || is_gimple_lvalue (t)
+           || TREE_CODE (t) == CALL_EXPR);
 }
 
-
-/* Returns a formal temporary variable initialized with VAL.  PRE_P is as
-   in gimplify_expr.  Only use this function if:
-
-   1) The value of the unfactored expression represented by VAL will not
-      change between the initialization and use of the temporary, and
-   2) The temporary will not be otherwise modified.
-
-   For instance, #1 means that this is inappropriate for SAVE_EXPR temps,
-   and #2 means it is inappropriate for && temps.
-
-   For other cases, use get_initialized_tmp_var instead.  */
+/* Helper for get_formal_tmp_var and get_initialized_tmp_var.  */
 
 static tree
 internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
@@ -684,7 +647,7 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
 
   /* Notice that we explicitly allow VAL to be a CALL_EXPR so that we
      can create an INIT_EXPR and convert it into a GIMPLE_CALL below.  */
-  gimplify_expr (&val, pre_p, post_p, is_gimple_formal_tmp_or_call_rhs,
+  gimplify_expr (&val, pre_p, post_p, is_gimple_reg_rhs_or_call,
                 fb_rvalue);
 
   t = lookup_tmp_var (val, is_formal);
@@ -705,11 +668,11 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
              SET_DECL_RESTRICT_BASE (t, u);
            }
        }
-    }
 
-  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
-      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
-    DECL_GIMPLE_REG_P (t) = 1;
+      if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+         || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+       DECL_GIMPLE_REG_P (t) = 1;
+    }
 
   mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val));
 
@@ -733,9 +696,17 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
   return t;
 }
 
-/* Returns a formal temporary variable initialized with VAL.  PRE_P
-   points to a sequence where side-effects needed to compute VAL should be
-   stored.  */
+/* Returns a formal temporary variable initialized with VAL.  PRE_P is as
+   in gimplify_expr.  Only use this function if:
+
+   1) The value of the unfactored expression represented by VAL will not
+      change between the initialization and use of the temporary, and
+   2) The temporary will not be otherwise modified.
+
+   For instance, #1 means that this is inappropriate for SAVE_EXPR temps,
+   and #2 means it is inappropriate for && temps.
+
+   For other cases, use get_initialized_tmp_var instead.  */
 
 tree
 get_formal_tmp_var (tree val, gimple_seq *pre_p)
@@ -2004,7 +1975,7 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                {
                  TREE_OPERAND (t, 2) = low;
                  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p,
-                                       post_p, is_gimple_formal_tmp_reg,
+                                       post_p, is_gimple_reg,
                                        fb_rvalue);
                  ret = MIN (ret, tret);
                }
@@ -2024,7 +1995,7 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                {
                  TREE_OPERAND (t, 3) = elmt_size;
                  tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p,
-                                       post_p, is_gimple_formal_tmp_reg,
+                                       post_p, is_gimple_reg,
                                        fb_rvalue);
                  ret = MIN (ret, tret);
                }
@@ -2047,7 +2018,7 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                {
                  TREE_OPERAND (t, 2) = offset;
                  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p,
-                                       post_p, is_gimple_formal_tmp_reg,
+                                       post_p, is_gimple_reg,
                                        fb_rvalue);
                  ret = MIN (ret, tret);
                }
@@ -2070,19 +2041,11 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
       if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
        {
-         /* Gimplify the dimension.
-            Temporary fix for gcc.c-torture/execute/20040313-1.c.
-            Gimplify non-constant array indices into a temporary
-            variable.
-            FIXME - The real fix is to gimplify post-modify
-            expressions into a minimal gimple lvalue.  However, that
-            exposes bugs in alias analysis.  The alias analyzer does
-            not handle &PTR->FIELD very well.  Will fix after the
-            branch is merged into mainline (dnovillo 2004-05-03).  */
+         /* Gimplify the dimension.  */
          if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)))
            {
              tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
-                                   is_gimple_formal_tmp_reg, fb_rvalue);
+                                   is_gimple_val, fb_rvalue);
              ret = MIN (ret, tret);
            }
        }
@@ -2174,9 +2137,18 @@ gimplify_self_mod_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
   rhs = TREE_OPERAND (*expr_p, 1);
 
   /* For postfix operator, we evaluate the LHS to an rvalue and then use
-     that as the result value and in the postqueue operation.  */
+     that as the result value and in the postqueue operation.  We also
+     make sure to make lvalue a minimal lval, see
+     gcc.c-torture/execute/20040313-1.c for an example where this matters.  */
   if (postfix)
     {
+      if (!is_gimple_min_lval (lvalue))
+       {
+         mark_addressable (lvalue);
+         lvalue = build_fold_addr_expr (lvalue);
+         gimplify_expr (&lvalue, pre_p, post_p, is_gimple_val, fb_rvalue);
+         lvalue = build_fold_indirect_ref (lvalue);
+       }
       ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue);
       if (ret == GS_ERROR)
        return ret;
@@ -2355,11 +2327,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
   else if (parms)
     p = parms;
   else
-    {
-      if (nargs != 0)
-       CALL_CANNOT_INLINE_P (*expr_p) = 1;
-      p = NULL_TREE;
-    }
+    p = NULL_TREE;
   for (i = 0; i < nargs && p; i++, p = TREE_CHAIN (p))
     ;
 
@@ -3060,9 +3028,11 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value,
   to = TREE_OPERAND (*expr_p, 0);
   from = TREE_OPERAND (*expr_p, 1);
 
+  mark_addressable (from);
   from_ptr = build_fold_addr_expr (from);
   gimplify_arg (&from_ptr, seq_p, EXPR_LOCATION (*expr_p));
 
+  mark_addressable (to);
   to_ptr = build_fold_addr_expr (to);
   gimplify_arg (&to_ptr, seq_p, EXPR_LOCATION (*expr_p));
 
@@ -3448,14 +3418,89 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
 gimple_predicate
 rhs_predicate_for (tree lhs)
 {
-  if (is_gimple_formal_tmp_var (lhs))
-    return is_gimple_formal_tmp_or_call_rhs;
-  else if (is_gimple_reg (lhs))
-    return is_gimple_reg_or_call_rhs;
+  if (is_gimple_reg (lhs))
+    return is_gimple_reg_rhs_or_call;
   else
-    return is_gimple_mem_or_call_rhs;
+    return is_gimple_mem_rhs_or_call;
 }
 
+/* Gimplify a C99 compound literal expression.  This just means adding
+   the DECL_EXPR before the current statement and using its anonymous
+   decl instead.  */
+
+static enum gimplify_status
+gimplify_compound_literal_expr (tree *expr_p, gimple_seq *pre_p)
+{
+  tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (*expr_p);
+  tree decl = DECL_EXPR_DECL (decl_s);
+  /* Mark the decl as addressable if the compound literal
+     expression is addressable now, otherwise it is marked too late
+     after we gimplify the initialization expression.  */
+  if (TREE_ADDRESSABLE (*expr_p))
+    TREE_ADDRESSABLE (decl) = 1;
+
+  /* Preliminarily mark non-addressed complex variables as eligible
+     for promotion to gimple registers.  We'll transform their uses
+     as we find them.  */
+  if ((TREE_CODE (TREE_TYPE (decl)) == COMPLEX_TYPE
+       || TREE_CODE (TREE_TYPE (decl)) == VECTOR_TYPE)
+      && !TREE_THIS_VOLATILE (decl)
+      && !needs_to_live_in_memory (decl))
+    DECL_GIMPLE_REG_P (decl) = 1;
+
+  /* This decl isn't mentioned in the enclosing block, so add it to the
+     list of temps.  FIXME it seems a bit of a kludge to say that
+     anonymous artificial vars aren't pushed, but everything else is.  */
+  if (DECL_NAME (decl) == NULL_TREE && !DECL_SEEN_IN_BIND_EXPR_P (decl))
+    gimple_add_tmp_var (decl);
+
+  gimplify_and_add (decl_s, pre_p);
+  *expr_p = decl;
+  return GS_OK;
+}
+
+/* Optimize embedded COMPOUND_LITERAL_EXPRs within a CONSTRUCTOR,
+   return a new CONSTRUCTOR if something changed.  */
+
+static tree
+optimize_compound_literals_in_ctor (tree orig_ctor)
+{
+  tree ctor = orig_ctor;
+  VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (ctor);
+  unsigned int idx, num = VEC_length (constructor_elt, elts);
+
+  for (idx = 0; idx < num; idx++)
+    {
+      tree value = VEC_index (constructor_elt, elts, idx)->value;
+      tree newval = value;
+      if (TREE_CODE (value) == CONSTRUCTOR)
+       newval = optimize_compound_literals_in_ctor (value);
+      else if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR)
+       {
+         tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (value);
+         tree decl = DECL_EXPR_DECL (decl_s);
+         tree init = DECL_INITIAL (decl);
+
+         if (!TREE_ADDRESSABLE (value)
+             && !TREE_ADDRESSABLE (decl)
+             && init)
+           newval = optimize_compound_literals_in_ctor (init);
+       }
+      if (newval == value)
+       continue;
+
+      if (ctor == orig_ctor)
+       {
+         ctor = copy_node (orig_ctor);
+         CONSTRUCTOR_ELTS (ctor) = VEC_copy (constructor_elt, gc, elts);
+         elts = CONSTRUCTOR_ELTS (ctor);
+       }
+      VEC_index (constructor_elt, elts, idx)->value = newval;
+    }
+  return ctor;
+}
+
+
 
 /* A subroutine of gimplify_modify_expr.  Break out elements of a
    CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs.
@@ -3474,7 +3519,7 @@ static enum gimplify_status
 gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                           bool want_value, bool notify_temp_creation)
 {
-  tree object;
+  tree object, new_ctor;
   tree ctor = TREE_OPERAND (*expr_p, 1);
   tree type = TREE_TYPE (ctor);
   enum gimplify_status ret;
@@ -3492,7 +3537,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
     }
 
   object = TREE_OPERAND (*expr_p, 0);
-  elts = CONSTRUCTOR_ELTS (ctor);
+  new_ctor = optimize_compound_literals_in_ctor (ctor);
+  elts = CONSTRUCTOR_ELTS (new_ctor);
   ret = GS_ALL_DONE;
 
   switch (TREE_CODE (type))
@@ -4042,11 +4088,6 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
                     || (DECL_P (*to_p) && DECL_REGISTER (*to_p)))
              /* Don't force regs into memory.  */
              use_target = false;
-           else if (TREE_CODE (*to_p) == VAR_DECL
-                    && DECL_GIMPLE_FORMAL_TEMP_P (*to_p))
-             /* Don't use the original target if it's a formal temp; we
-                don't want to take their addresses.  */
-             use_target = false;
            else if (TREE_CODE (*expr_p) == INIT_EXPR)
              /* It's OK to use the target directly if it's being
                 initialized. */
@@ -4099,6 +4140,26 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
          return GS_OK;
        }
        
+      case COMPOUND_LITERAL_EXPR:
+       {
+         tree complit = TREE_OPERAND (*expr_p, 1);
+         tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit);
+         tree decl = DECL_EXPR_DECL (decl_s);
+         tree init = DECL_INITIAL (decl);
+
+         /* struct T x = (struct T) { 0, 1, 2 } can be optimized
+            into struct T x = { 0, 1, 2 } if the address of the
+            compound literal has never been taken.  */
+         if (!TREE_ADDRESSABLE (complit)
+             && !TREE_ADDRESSABLE (decl)
+             && init)
+           {
+             *expr_p = copy_node (*expr_p);
+             TREE_OPERAND (*expr_p, 1) = init;
+             return GS_OK;
+           }
+       }
+
       default:
        ret = GS_UNHANDLED;
        break;
@@ -4546,7 +4607,7 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
         This mostly happens if the frontend passed us something that
         it could not mark addressable yet, like a fortran
         pass-by-reference parameter (int) floatvar.  */
-      if (is_gimple_formal_tmp_var (TREE_OPERAND (expr, 0)))
+      if (is_gimple_reg (TREE_OPERAND (expr, 0)))
        TREE_OPERAND (expr, 0)
          = get_initialized_tmp_var (TREE_OPERAND (expr, 0), pre_p, post_p);
 
@@ -6218,16 +6279,12 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
   if (gimple_test_f == is_gimple_reg)
     gcc_assert (fallback & (fb_rvalue | fb_lvalue));
   else if (gimple_test_f == is_gimple_val
-           || gimple_test_f == is_gimple_formal_tmp_rhs
-           || gimple_test_f == is_gimple_formal_tmp_or_call_rhs
-           || gimple_test_f == is_gimple_formal_tmp_reg
-           || gimple_test_f == is_gimple_formal_tmp_var
            || gimple_test_f == is_gimple_call_addr
            || gimple_test_f == is_gimple_condexpr
            || gimple_test_f == is_gimple_mem_rhs
-           || gimple_test_f == is_gimple_mem_or_call_rhs
+           || gimple_test_f == is_gimple_mem_rhs_or_call
            || gimple_test_f == is_gimple_reg_rhs
-           || gimple_test_f == is_gimple_reg_or_call_rhs
+           || gimple_test_f == is_gimple_reg_rhs_or_call
            || gimple_test_f == is_gimple_asm_val)
     gcc_assert (fallback & fb_rvalue);
   else if (gimple_test_f == is_gimple_min_lval
@@ -6361,6 +6418,10 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
          break;
 
+       case COMPOUND_LITERAL_EXPR:
+         ret = gimplify_compound_literal_expr (expr_p, pre_p);
+         break;
+
        case MODIFY_EXPR:
        case INIT_EXPR:
          ret = gimplify_modify_expr (expr_p, pre_p, post_p,
@@ -7026,7 +7087,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue);
       *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp);
     }
-  else if ((fallback & fb_rvalue) && is_gimple_formal_tmp_or_call_rhs (*expr_p))
+  else if ((fallback & fb_rvalue) && is_gimple_reg_rhs_or_call (*expr_p))
     {
       /* An rvalue will do.  Assign the gimplified expression into a
         new temporary TMP and replace the original expression with
@@ -7041,9 +7102,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
        *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
       else
        *expr_p = get_formal_tmp_var (*expr_p, pre_p);
-
-      if (TREE_CODE (*expr_p) != SSA_NAME)
-       DECL_GIMPLE_FORMAL_TEMP_P (*expr_p) = 1;
     }
   else
     {
@@ -7141,6 +7199,8 @@ gimplify_type_sizes (tree type, gimple_seq *list_p)
        if (TREE_CODE (field) == FIELD_DECL)
          {
            gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
+           gimplify_one_sizepos (&DECL_SIZE (field), list_p);
+           gimplify_one_sizepos (&DECL_SIZE_UNIT (field), list_p);
            gimplify_type_sizes (TREE_TYPE (field), list_p);
          }
       break;
@@ -7493,7 +7553,7 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p)
       lhs = gimple_get_lhs (stmt);
       /* If the LHS changed it in a way that requires a simple RHS,
         create temporary.  */
-      if (lhs && !is_gimple_formal_tmp_var (lhs))
+      if (lhs && !is_gimple_reg (lhs))
        {
          bool need_temp = false;
 
@@ -7542,7 +7602,6 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p)
            {
              tree temp = create_tmp_var (TREE_TYPE (lhs), NULL);
 
-             DECL_GIMPLE_FORMAL_TEMP_P (temp) = 1;
              if (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE
                  || TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE)
                DECL_GIMPLE_REG_P (temp) = 1;