OSDN Git Service

* config/rs6000/rs6000.h (MAX_FIXED_MODE_SIZE): Define.
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index be81723..b34844d 100644 (file)
@@ -122,7 +122,6 @@ typedef struct inline_data
    decisions about when a function is too big to inline.  */
 #define INSNS_PER_STMT (10)
 
-static tree declare_return_variable (inline_data *, tree, tree *);
 static tree copy_body_r (tree *, int *, void *);
 static tree copy_body (inline_data *);
 static tree expand_call_inline (tree *, int *, void *);
@@ -155,7 +154,7 @@ insert_decl_map (inline_data *id, tree key, tree value)
                       (splay_tree_value) value);
 }
 
-/* Remap DECL during the copying of the BLOCK tree for the function. 
+/* Remap DECL during the copying of the BLOCK tree for the function.
    We are only called to remap local variables in the current function.  */
 
 static tree
@@ -244,7 +243,7 @@ remap_type (tree type, inline_data *id)
       insert_decl_map (id, type, type);
       return type;
     }
-  
+
   /* We do need a copy.  build and register it now.  If this is a pointer or
      reference type, remap the designated type and make a new pointer or
      reference type.  */
@@ -304,7 +303,7 @@ remap_type (tree type, inline_data *id)
       if (t && TREE_CODE (t) != INTEGER_CST)
         walk_tree (&TYPE_MAX_VALUE (new), copy_body_r, id, NULL);
       return new;
-    
+
     case FUNCTION_TYPE:
       TREE_TYPE (new) = remap_type (TREE_TYPE (new), id);
       walk_tree (&TYPE_ARG_TYPES (new), copy_body_r, id, NULL);
@@ -519,9 +518,6 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
     copy_statement_list (tp);
   else if (TREE_CODE (*tp) == SAVE_EXPR)
     remap_save_expr (tp, id->decl_map, walk_subtrees);
-  else if (TREE_CODE (*tp) == UNSAVE_EXPR)
-    /* UNSAVE_EXPRs should not be generated until expansion time.  */
-    abort ();
   else if (TREE_CODE (*tp) == BIND_EXPR)
     copy_bind_expr (tp, walk_subtrees, id);
   else if (TREE_CODE (*tp) == LABELED_BLOCK_EXPR)
@@ -577,33 +573,6 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data)
                }
            }
        }
-      else if (TREE_CODE (*tp) == ADDR_EXPR
-              && (lang_hooks.tree_inlining.auto_var_in_fn_p
-                  (TREE_OPERAND (*tp, 0), fn)))
-       {
-         /* Get rid of &* from inline substitutions.  It can occur when
-            someone takes the address of a parm or return slot passed by
-            invisible reference.  */
-         tree decl = TREE_OPERAND (*tp, 0), value;
-         splay_tree_node n;
-
-         n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl);
-         if (n)
-           {
-             value = (tree) n->value;
-             if (TREE_CODE (value) == INDIRECT_REF)
-               {
-                 if  (!lang_hooks.types_compatible_p
-                      (TREE_TYPE (*tp), TREE_TYPE (TREE_OPERAND (value, 0))))
-                   *tp = fold_convert (TREE_TYPE (*tp),
-                                       TREE_OPERAND (value, 0));
-                 else
-                   *tp = TREE_OPERAND (value, 0);
-
-                 return copy_body_r (tp, walk_subtrees, data);
-               }
-           }
-       }
       else if (TREE_CODE (*tp) == INDIRECT_REF)
        {
          /* Get rid of *& from inline substitutions that can happen when a
@@ -694,7 +663,6 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
 {
   tree init_stmt;
   tree var;
-  tree var_sub;
 
   /* If the parameter is never assigned to, we may not need to
      create a new variable here at all.  Instead, we may be able
@@ -725,23 +693,10 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
      function. */
   var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0));
 
-  /* See if the frontend wants to pass this by invisible reference.  If
-     so, our new VAR_DECL will have REFERENCE_TYPE, and we need to
-     replace uses of the PARM_DECL with dereferences.  */
-  if (TREE_TYPE (var) != TREE_TYPE (p)
-      && POINTER_TYPE_P (TREE_TYPE (var))
-      && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p))
-    {
-      insert_decl_map (id, var, var);
-      var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var);
-    }
-  else
-    var_sub = var;
-
   /* Register the VAR_DECL as the equivalent for the PARM_DECL;
      that way, when the PARM_DECL is encountered, it will be
      automatically replaced by the VAR_DECL.  */
-  insert_decl_map (id, p, var_sub);
+  insert_decl_map (id, p, var);
 
   /* Declare this new variable.  */
   TREE_CHAIN (var) = *vars;
@@ -851,35 +806,105 @@ initialize_inlined_parameters (inline_data *id, tree args, tree static_chain,
   return init_stmts;
 }
 
-/* Declare a return variable to replace the RESULT_DECL for the
-   function we are calling.  An appropriate decl is returned.
-   ??? Needs documentation of parameters. */
+/* Declare a return variable to replace the RESULT_DECL for the function we
+   are calling.  RETURN_SLOT_ADDR, if non-null, was a fake parameter that
+   took the address of the result.  MODIFY_DEST, if non-null, was the LHS of
+   the MODIFY_EXPR to which this call is the RHS.
+
+   The return value is a (possibly null) value that is the result of the
+   function as seen by the callee.  *USE_P is a (possibly null) value that
+   holds the result as seen by the caller.  */
 
 static tree
-declare_return_variable (inline_data *id, tree return_slot_addr, tree *use_p)
+declare_return_variable (inline_data *id, tree return_slot_addr,
+                        tree modify_dest, tree *use_p)
 {
-  tree fn = VARRAY_TOP_TREE (id->fns);
-  tree result = DECL_RESULT (fn);
-  int need_return_decl = 1;
-  tree var;
+  tree callee = VARRAY_TOP_TREE (id->fns);
+  tree caller = VARRAY_TREE (id->fns, 0);
+  tree result = DECL_RESULT (callee);
+  tree callee_type = TREE_TYPE (result);
+  tree caller_type = TREE_TYPE (TREE_TYPE (callee));
+  tree var, use;
 
   /* We don't need to do anything for functions that don't return
      anything.  */
-  if (!result || VOID_TYPE_P (TREE_TYPE (result)))
+  if (!result || VOID_TYPE_P (callee_type))
     {
       *use_p = NULL_TREE;
       return NULL_TREE;
     }
 
-  var = (lang_hooks.tree_inlining.copy_res_decl_for_inlining
-        (result, fn, VARRAY_TREE (id->fns, 0), id->decl_map,
-         &need_return_decl, return_slot_addr));
-  
+  /* If there was a return slot, then the return value is the
+     dereferenced address of that object.  */
+  if (return_slot_addr)
+    {
+      /* The front end shouldn't have used both return_slot_addr and
+        a modify expression.  */
+      if (modify_dest)
+       abort ();
+      if (DECL_BY_REFERENCE (result))
+       var = return_slot_addr;
+      else
+       var = build_fold_indirect_ref (return_slot_addr);
+      use = NULL;
+      goto done;
+    }
+
+  /* All types requiring non-trivial constructors should have been handled.  */
+  if (TREE_ADDRESSABLE (callee_type))
+    abort ();
+
+  /* Attempt to avoid creating a new temporary variable.  */
+  if (modify_dest)
+    {
+      bool use_it = false;
+
+      /* We can't use MODIFY_DEST if there's type promotion involved.  */
+      if (!lang_hooks.types_compatible_p (caller_type, callee_type))
+       use_it = false;
+
+      /* ??? If we're assigning to a variable sized type, then we must
+        reuse the destination variable, because we've no good way to
+        create variable sized temporaries at this point.  */
+      else if (TREE_CODE (TYPE_SIZE_UNIT (caller_type)) != INTEGER_CST)
+       use_it = true;
+
+      /* If the callee cannot possibly modify MODIFY_DEST, then we can
+        reuse it as the result of the call directly.  Don't do this if
+        it would promote MODIFY_DEST to addressable.  */
+      else if (!TREE_STATIC (modify_dest)
+              && !TREE_ADDRESSABLE (modify_dest)
+              && !TREE_ADDRESSABLE (result))
+       use_it = true;
+
+      if (use_it)
+       {
+         var = modify_dest;
+         use = NULL;
+         goto done;
+       }
+    }
+
+  if (TREE_CODE (TYPE_SIZE_UNIT (callee_type)) != INTEGER_CST)
+    abort ();
+
+  var = copy_decl_for_inlining (result, callee, caller);
+  DECL_SEEN_IN_BIND_EXPR_P (var) = 1;
+  DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list
+    = tree_cons (NULL_TREE, var,
+                DECL_STRUCT_FUNCTION (caller)->unexpanded_var_list);
+
   /* Do not have the rest of GCC warn about this variable as it should
      not be visible to the user.   */
   TREE_NO_WARNING (var) = 1;
 
+  /* Build the use expr.  If the return type of the function was
+     promoted, convert it back to the expected type.  */
+  use = var;
+  if (!lang_hooks.types_compatible_p (TREE_TYPE (var), caller_type))
+    use = fold_convert (caller_type, var);
+
+ done:
   /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that
      way, when the RESULT_DECL is encountered, it will be
      automatically replaced by the VAR_DECL.  */
@@ -888,30 +913,8 @@ declare_return_variable (inline_data *id, tree return_slot_addr, tree *use_p)
   /* Remember this so we can ignore it in remap_decls.  */
   id->retvar = var;
 
-  /* Build the use expr.  If the return type of the function was
-     promoted, convert it back to the expected type.  */
-  if (return_slot_addr)
-    /* The function returns through an explicit return slot, not a normal
-       return value.  */
-    *use_p = NULL_TREE;
-  else if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE (fn)))
-    *use_p = var;
-  else if (TREE_CODE (var) == INDIRECT_REF)
-    *use_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (fn)),
-                    TREE_OPERAND (var, 0));
-  else if (TREE_ADDRESSABLE (TREE_TYPE (var)))
-    abort ();
-  else
-    *use_p = build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), var);
-
-  /* Build the declaration statement if FN does not return an
-     aggregate.  */
-  if (need_return_decl)
-    return var;
-  /* If FN does return an aggregate, there's no need to declare the
-     return variable; we're using a variable in our caller's frame.  */
-  else
-    return NULL_TREE;
+  *use_p = use;
+  return var;
 }
 
 /* Returns nonzero if a function can be inlined as a tree.  */
@@ -1176,7 +1179,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     return NULL;
 
   switch (TREE_CODE (x))
-    { 
+    {
     /* Containers have no cost.  */
     case TREE_LIST:
     case TREE_VEC:
@@ -1184,7 +1187,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case COMPONENT_REF:
     case BIT_FIELD_REF:
     case INDIRECT_REF:
-    case BUFFER_REF:
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
     case OBJ_TYPE_REF:
@@ -1197,7 +1199,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case NOP_EXPR:
     case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
-    case UNSAVE_EXPR:
     case ADDR_EXPR:
     case COMPLEX_EXPR:
     case EXIT_BLOCK_EXPR:
@@ -1208,7 +1209,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case STATEMENT_LIST:
     case ERROR_MARK:
     case NON_LVALUE_EXPR:
-    case ENTRY_VALUE_EXPR:
     case FDESC_EXPR:
     case VA_ARG_EXPR:
     case TRY_CATCH_EXPR:
@@ -1219,6 +1219,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case EXIT_EXPR:
     case LOOP_EXPR:
     case PHI_NODE:
+    case WITH_SIZE_EXPR:
       break;
 
     /* We don't account constants for now.  Assume that the cost is amortized
@@ -1320,7 +1321,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case ASM_EXPR:
 
     case RESX_EXPR:
-      *count++;
+      *count += 1;
       break;
 
     /* Few special cases of expensive operations.  This is useful
@@ -1386,10 +1387,10 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
   tree fn;
   tree arg_inits;
   tree *inlined_body;
-  tree inline_result;
   splay_tree st;
   tree args;
   tree return_slot_addr;
+  tree modify_dest;
   location_t saved_location;
   struct cgraph_edge *edge;
   const char *reason;
@@ -1518,7 +1519,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
      statements within the function to jump to.  The type of the
      statement expression is the return type of the function call.  */
   stmt = NULL;
-  expr = build (BIND_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE,
+  expr = build (BIND_EXPR, void_type_node, NULL_TREE,
                stmt, make_node (BLOCK));
   BLOCK_ABSTRACT_ORIGIN (BIND_EXPR_BLOCK (expr)) = fn;
 
@@ -1550,7 +1551,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
         Note we need to save and restore the saved tree statement iterator
         to avoid having it clobbered by expand_calls_inline.  */
       tree_stmt_iterator save_tsi;
-     
+
       save_tsi = id->tsi;
       expand_calls_inline (&arg_inits, id);
       id->tsi = save_tsi;
@@ -1587,10 +1588,16 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
       || TREE_CODE (DECL_INITIAL (fn)) != BLOCK)
     abort ();
 
+  /* Find the lhs to which the result of this call is assigned.  */
+  modify_dest = tsi_stmt (id->tsi);
+  if (TREE_CODE (modify_dest) == MODIFY_EXPR)
+    modify_dest = TREE_OPERAND (modify_dest, 0);
+  else
+    modify_dest = NULL;
+
   /* Declare the return variable for the function.  */
-  decl = declare_return_variable (id, return_slot_addr, &use_retvar);
-  if (decl)
-    declare_inline_vars (expr, decl);
+  decl = declare_return_variable (id, return_slot_addr,
+                                 modify_dest, &use_retvar);
 
   /* After we've initialized the parameters, we insert the body of the
      function itself.  */
@@ -1612,12 +1619,6 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
       append_to_statement_list (label, &BIND_EXPR_BODY (expr));
     }
 
-  /* Finally, mention the returned value so that the value of the
-     statement-expression is the returned value of the function.  */
-  if (use_retvar)
-    /* Set TREE_TYPE on BIND_EXPR?  */
-    append_to_statement_list_force (use_retvar, &BIND_EXPR_BODY (expr));
-
   /* Clean up.  */
   splay_tree_delete (id->decl_map);
   id->decl_map = st;
@@ -1625,28 +1626,16 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
   /* The new expression has side-effects if the old one did.  */
   TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t);
 
-  /* We want to create a new variable to hold the result of the inlined
-     body.  This new variable needs to be added to the function which we
-     are inlining into, thus the saving and restoring of
-     current_function_decl.  */
-  {
-    tree save_decl = current_function_decl;
-    current_function_decl = id->node->decl;
-    inline_result = voidify_wrapper_expr (expr, NULL);
-    current_function_decl = save_decl;
-  }
+  tsi_link_before (&id->tsi, expr, TSI_SAME_STMT);
 
   /* If the inlined function returns a result that we care about,
      then we're going to need to splice in a MODIFY_EXPR.  Otherwise
      the call was a standalone statement and we can just replace it
      with the BIND_EXPR inline representation of the called function.  */
-  if (TREE_CODE (tsi_stmt (id->tsi)) != CALL_EXPR)
-    {
-      tsi_link_before (&id->tsi, expr, TSI_SAME_STMT);
-      *tp = inline_result;
-    }
+  if (!use_retvar || !modify_dest)
+    *tsi_stmt_ptr (id->tsi) = build_empty_stmt ();
   else
-    *tp = expr;
+    *tp = use_retvar;
 
   /* When we gimplify a function call, we may clear TREE_SIDE_EFFECTS on
      the call if it is to a "const" function.  Thus the copy of
@@ -1661,11 +1650,6 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
      the toplevel expression.  */
   recalculate_side_effects (expr);
 
-  /* If the value of the new expression is ignored, that's OK.  We
-     don't warn about this for CALL_EXPRs, so we shouldn't warn about
-     the equivalent inlined version either.  */
-  TREE_USED (*tp) = 1;
-
   /* Update callgraph if needed.  */
   cgraph_remove_node (edge->callee);
 
@@ -1688,7 +1672,7 @@ static void
 expand_calls_inline (tree *stmt_p, inline_data *id)
 {
   tree stmt = *stmt_p;
-  enum tree_code code = TREE_CODE (stmt); 
+  enum tree_code code = TREE_CODE (stmt);
   int dummy;
 
   switch (code)
@@ -1753,6 +1737,11 @@ expand_calls_inline (tree *stmt_p, inline_data *id)
     case MODIFY_EXPR:
       stmt_p = &TREE_OPERAND (stmt, 1);
       stmt = *stmt_p;
+      if (TREE_CODE (stmt) == WITH_SIZE_EXPR)
+       {
+         stmt_p = &TREE_OPERAND (stmt, 0);
+         stmt = *stmt_p;
+       }
       if (TREE_CODE (stmt) != CALL_EXPR)
        break;
 
@@ -1774,6 +1763,7 @@ optimize_inline_calls (tree fn)
 {
   inline_data id;
   tree prev_fn;
+  tree ifn;
 
   /* There is no point in performing inlining if errors have already
      occurred -- and we might crash if we try to inline invalid
@@ -1812,15 +1802,11 @@ optimize_inline_calls (tree fn)
 
   /* Clean up.  */
   htab_delete (id.tree_pruner);
-  if (DECL_LANG_SPECIFIC (fn))
-    {
-      tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
-
-      if (VARRAY_ACTIVE_SIZE (id.inlined_fns))
-       memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
-               VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
-      DECL_INLINED_FNS (fn) = ifn;
-    }
+  ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
+  if (VARRAY_ACTIVE_SIZE (id.inlined_fns))
+    memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
+           VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
+  DECL_INLINED_FNS (fn) = ifn;
 
 #ifdef ENABLE_CHECKING
     {
@@ -1862,10 +1848,11 @@ clone_body (tree clone, tree fn, void *arg_map)
   append_to_statement_list_force (copy_body (&id), &DECL_SAVED_TREE (clone));
 }
 
-/* Save duplicate of body in FN.  MAP is used to pass around splay tree
-   used to update arguments in restore_body.  */
+/* Make and return duplicate of body in FN.  Put copies of DECL_ARGUMENTS
+   in *arg_copy and of the static chain, if any, in *sc_copy.  */
+
 tree
-save_body (tree fn, tree *arg_copy)
+save_body (tree fn, tree *arg_copy, tree *sc_copy)
 {
   inline_data id;
   tree body, *parg;
@@ -1889,6 +1876,18 @@ save_body (tree fn, tree *arg_copy)
       *parg = new;
     }
 
+  *sc_copy = DECL_STRUCT_FUNCTION (fn)->static_chain_decl;
+  if (*sc_copy)
+    {
+      tree new = copy_node (*sc_copy);
+
+      lang_hooks.dup_lang_specific_decl (new);
+      DECL_ABSTRACT_ORIGIN (new) = DECL_ORIGIN (*sc_copy);
+      insert_decl_map (&id, *sc_copy, new);
+      TREE_CHAIN (new) = TREE_CHAIN (*sc_copy);
+      *sc_copy = new;
+    }
+
   insert_decl_map (&id, DECL_RESULT (fn), DECL_RESULT (fn));
 
   /* Actually copy the body.  */
@@ -2298,7 +2297,7 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       if (TREE_CODE (*tp) == BIND_EXPR)
        BIND_EXPR_BLOCK (*tp) = NULL_TREE;
     }
+
   else if (TREE_CODE_CLASS (code) == 't')
     *walk_subtrees = 0;
   else if (TREE_CODE_CLASS (code) == 'd')
@@ -2364,7 +2363,7 @@ mark_local_for_remap_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
 
       /* Copy the decl and remember the copy.  */
       insert_decl_map (id, decl,
-                      copy_decl_for_inlining (decl, DECL_CONTEXT (decl), 
+                      copy_decl_for_inlining (decl, DECL_CONTEXT (decl),
                                               DECL_CONTEXT (decl)));
     }
 
@@ -2388,7 +2387,7 @@ unsave_r (tree *tp, int *walk_subtrees, void *data)
     {
       /* Lookup the declaration.  */
       n = splay_tree_lookup (st, (splay_tree_key) *tp);
-      
+
       /* If it's there, remap it.  */
       if (n)
        *tp = (tree) n->value;