OSDN Git Service

PR debug/43983
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 7ad5b09..9c51f1a 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert function calls to rtl insns, for GNU C compiler.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "sbitmap.h"
 #include "langhooks.h"
 #include "target.h"
+#include "debug.h"
 #include "cgraph.h"
 #include "except.h"
 #include "dbgcnt.h"
@@ -166,7 +167,7 @@ static void restore_fixed_argument_area (rtx, rtx, int, int);
    CALL_INSN_FUNCTION_USAGE information.  */
 
 rtx
-prepare_call_address (rtx funexp, rtx static_chain_value,
+prepare_call_address (tree fndecl, rtx funexp, rtx static_chain_value,
                      rtx *call_fusage, int reg_parm_seen, int sibcallp)
 {
   /* Make a valid memory address and copy constants through pseudo-regs,
@@ -174,7 +175,8 @@ prepare_call_address (rtx funexp, rtx static_chain_value,
   if (GET_CODE (funexp) != SYMBOL_REF)
     /* If we are using registers for parameters, force the
        function address into a register now.  */
-    funexp = ((SMALL_REGISTER_CLASSES && reg_parm_seen)
+    funexp = ((reg_parm_seen
+              && targetm.small_register_classes_for_mode_p (FUNCTION_MODE))
              ? force_not_mem (memory_address (FUNCTION_MODE, funexp))
              : memory_address (FUNCTION_MODE, funexp));
   else if (! sibcallp)
@@ -187,11 +189,15 @@ prepare_call_address (rtx funexp, rtx static_chain_value,
 
   if (static_chain_value != 0)
     {
+      rtx chain;
+
+      gcc_assert (fndecl);
+      chain = targetm.calls.static_chain (fndecl, false);
       static_chain_value = convert_memory_address (Pmode, static_chain_value);
-      emit_move_insn (static_chain_rtx, static_chain_value);
 
-      if (REG_P (static_chain_rtx))
-       use_reg (call_fusage, static_chain_rtx);
+      emit_move_insn (chain, static_chain_value);
+      if (REG_P (chain))
+       use_reg (call_fusage, chain);
     }
 
   return funexp;
@@ -238,7 +244,7 @@ prepare_call_address (rtx funexp, rtx static_chain_value,
    denote registers used by the called function.  */
 
 static void
-emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
+emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNUSED,
             tree funtype ATTRIBUTE_UNUSED,
             HOST_WIDE_INT stack_size ATTRIBUTE_UNUSED,
             HOST_WIDE_INT rounded_stack_size,
@@ -251,10 +257,6 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
   rtx call_insn;
   int already_popped = 0;
   HOST_WIDE_INT n_popped = RETURN_POPS_ARGS (fndecl, funtype, stack_size);
-#if defined (HAVE_call) && defined (HAVE_call_value)
-  rtx struct_value_size_rtx;
-  struct_value_size_rtx = GEN_INT (struct_value_size);
-#endif
 
 #ifdef CALL_POPS_ARGS
   n_popped += CALL_POPS_ARGS (* args_so_far);
@@ -336,7 +338,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
       else
        emit_call_insn (GEN_SIBCALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
                                     rounded_stack_size_rtx, next_arg_reg,
-                                    struct_value_size_rtx));
+                                    GEN_INT (struct_value_size)));
     }
   else
 #endif
@@ -352,7 +354,7 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
       else
        emit_call_insn (GEN_CALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
                                  rounded_stack_size_rtx, next_arg_reg,
-                                 struct_value_size_rtx));
+                                 GEN_INT (struct_value_size)));
     }
   else
 #endif
@@ -376,19 +378,8 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
   if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
     RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1;
 
-  /* If this call can't throw, attach a REG_EH_REGION reg note to that
-     effect.  */
-  if (ecf_flags & ECF_NOTHROW)
-    add_reg_note (call_insn, REG_EH_REGION, const0_rtx);
-  else
-    {
-      int rn = lookup_expr_eh_region (fntree);
-
-      /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't
-        throw, which we already took care of.  */
-      if (rn > 0)
-       add_reg_note (call_insn, REG_EH_REGION, GEN_INT (rn));
-    }
+  /* Create a nothrow REG_EH_REGION note, if needed.  */
+  make_reg_eh_region_note (call_insn, ecf_flags, 0);
 
   if (ecf_flags & ECF_NORETURN)
     add_reg_note (call_insn, REG_NORETURN, const0_rtx);
@@ -401,6 +392,11 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
 
   SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
 
+  /* Record debug information for virtual calls.  */
+  if (flag_enable_icf_debug && fndecl == NULL)
+    (*debug_hooks->virtual_call_token) (CALL_EXPR_FN (fntree),
+                                        INSN_UID (call_insn));
+
   /* Restore this now, so that we do defer pops for this call's args
      if the context of the call as a whole permits.  */
   inhibit_defer_pop = old_inhibit_defer_pop;
@@ -590,12 +586,9 @@ int
 flags_from_decl_or_type (const_tree exp)
 {
   int flags = 0;
-  const_tree type = exp;
 
   if (DECL_P (exp))
     {
-      type = TREE_TYPE (exp);
-
       /* The function exp may have the `malloc' attribute.  */
       if (DECL_IS_MALLOC (exp))
        flags |= ECF_MALLOC;
@@ -719,7 +712,8 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
                 && args[i].mode != BLKmode
                 && rtx_cost (args[i].value, SET, optimize_insn_for_speed_p ())
                    > COSTS_N_INSNS (1)
-                && ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
+                && ((*reg_parm_seen
+                     && targetm.small_register_classes_for_mode_p (args[i].mode))
                     || optimize))
          args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
       }
@@ -907,7 +901,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
 }
 
 /* Fill in ARGS_SIZE and ARGS array based on the parameters found in
-   CALL_EXPR EXP.  
+   CALL_EXPR EXP.
 
    NUM_ACTUALS is the total number of parameters.
 
@@ -1018,11 +1012,12 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
       if (type == error_mark_node || !COMPLETE_TYPE_P (type))
        args[i].tree_value = integer_zero_node, type = integer_type_node;
 
-      /* If TYPE is a transparent union, pass things the way we would
-        pass the first field of the union.  We have already verified that
-        the modes are the same.  */
-      if (TREE_CODE (type) == UNION_TYPE && TYPE_TRANSPARENT_UNION (type))
-       type = TREE_TYPE (TYPE_FIELDS (type));
+      /* If TYPE is a transparent union or record, pass things the way
+        we would pass the first field of the union or record.  We have
+        already verified that the modes are the same.  */
+      if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE)
+          && TYPE_TRANSPARENT_AGGR (type))
+       type = TREE_TYPE (first_field (type));
 
       /* Decide where to pass this arg.
 
@@ -1347,7 +1342,7 @@ precompute_arguments (int num_actuals, struct arg_data *args)
    compute and return the final value for MUST_PREALLOCATE.  */
 
 static int
-finalize_must_preallocate (int must_preallocate, int num_actuals, 
+finalize_must_preallocate (int must_preallocate, int num_actuals,
                           struct arg_data *args, struct args_size *args_size)
 {
   /* See if we have or want to preallocate stack space.
@@ -1927,6 +1922,7 @@ expand_call (tree exp, rtx target, int ignore)
   /* Data type of the function.  */
   tree funtype;
   tree type_arg_types;
+  tree rettype;
   /* Declaration of the function being called,
      or 0 if the function is computed (not known by name).  */
   tree fndecl = 0;
@@ -2022,7 +2018,6 @@ expand_call (tree exp, rtx target, int ignore)
   int old_stack_pointer_delta = 0;
 
   rtx call_fusage;
-  tree p = CALL_EXPR_FN (exp);
   tree addr = CALL_EXPR_FN (exp);
   int i;
   /* The alignment of the stack, in bits.  */
@@ -2045,15 +2040,16 @@ expand_call (tree exp, rtx target, int ignore)
     }
   else
     {
-      fntype = TREE_TYPE (TREE_TYPE (p));
+      fntype = TREE_TYPE (TREE_TYPE (addr));
       flags |= flags_from_decl_or_type (fntype);
     }
+  rettype = TREE_TYPE (exp);
 
   struct_value = targetm.calls.struct_value_rtx (fntype, 0);
 
   /* Warn if this value is an aggregate type,
      regardless of which calling convention we are using for it.  */
-  if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
+  if (AGGREGATE_TYPE_P (rettype))
     warning (OPT_Waggregate_return, "function call has aggregate value");
 
   /* If the result of a non looping pure or const function call is
@@ -2063,7 +2059,7 @@ expand_call (tree exp, rtx target, int ignore)
   if ((flags & (ECF_CONST | ECF_PURE))
       && (!(flags & ECF_LOOPING_CONST_OR_PURE))
       && (ignore || target == const0_rtx
-         || TYPE_MODE (TREE_TYPE (exp)) == VOIDmode))
+         || TYPE_MODE (rettype) == VOIDmode))
     {
       bool volatilep = false;
       tree arg;
@@ -2095,7 +2091,7 @@ expand_call (tree exp, rtx target, int ignore)
   /* Set up a place to return a structure.  */
 
   /* Cater to broken compilers.  */
-  if (aggregate_value_p (exp, (!fndecl ? fntype : fndecl)))
+  if (aggregate_value_p (exp, fntype))
     {
       /* This call returns a big structure.  */
       flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
@@ -2106,7 +2102,7 @@ expand_call (tree exp, rtx target, int ignore)
       }
 #else /* not PCC_STATIC_STRUCT_RETURN */
       {
-       struct_value_size = int_size_in_bytes (TREE_TYPE (exp));
+       struct_value_size = int_size_in_bytes (rettype);
 
        if (target && MEM_P (target) && CALL_EXPR_RETURN_SLOT_OPT (exp))
          structure_value_addr = XEXP (target, 0);
@@ -2115,7 +2111,7 @@ expand_call (tree exp, rtx target, int ignore)
            /* For variable-sized objects, we must be called with a target
               specified.  If we were to allocate space on the stack here,
               we would have no way of knowing when to free it.  */
-           rtx d = assign_temp (TREE_TYPE (exp), 0, 1, 1);
+           rtx d = assign_temp (rettype, 0, 1, 1);
 
            mark_temp_addr_taken (d);
            structure_value_addr = XEXP (d, 0);
@@ -2286,7 +2282,6 @@ expand_call (tree exp, rtx target, int ignore)
   if (currently_expanding_call++ != 0
       || !flag_optimize_sibling_calls
       || args_size.var
-      || lookup_expr_eh_region (exp) >= 0
       || dbg_cnt (tail_call) == false)
     try_tail_call = 0;
 
@@ -2353,9 +2348,9 @@ expand_call (tree exp, rtx target, int ignore)
                                 &caller_unsignedp,
                                 TREE_TYPE (current_function_decl), 1);
       callee_promoted_mode
-       = promote_function_mode (TREE_TYPE (caller_res), callee_mode,
+       = promote_function_mode (TREE_TYPE (funtype), callee_mode,
                                 &callee_unsignedp,
-                                TREE_TYPE (funtype), 1);
+                                funtype, 1);
       if (caller_mode != VOIDmode
          && (caller_promoted_mode != callee_promoted_mode
              || ((caller_mode != caller_promoted_mode
@@ -2693,14 +2688,14 @@ expand_call (tree exp, rtx target, int ignore)
 
       /* Figure out the register where the value, if any, will come back.  */
       valreg = 0;
-      if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode
+      if (TYPE_MODE (rettype) != VOIDmode
          && ! structure_value_addr)
        {
          if (pcc_struct_value)
-           valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
+           valreg = hard_function_value (build_pointer_type (rettype),
                                          fndecl, NULL, (pass == 0));
          else
-           valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype,
+           valreg = hard_function_value (rettype, fndecl, fntype,
                                          (pass == 0));
 
          /* If VALREG is a PARALLEL whose first member has a zero
@@ -2818,7 +2813,7 @@ expand_call (tree exp, rtx target, int ignore)
        }
 
       after_args = get_last_insn ();
-      funexp = prepare_call_address (funexp, static_chain_value,
+      funexp = prepare_call_address (fndecl, funexp, static_chain_value,
                                     &call_fusage, reg_parm_seen, pass == 0);
 
       load_register_parameters (args, num_actuals, &call_fusage, flags,
@@ -2865,12 +2860,12 @@ expand_call (tree exp, rtx target, int ignore)
         group load/store machinery below.  */
       if (!structure_value_addr
          && !pcc_struct_value
-         && TYPE_MODE (TREE_TYPE (exp)) != BLKmode
-         && targetm.calls.return_in_msb (TREE_TYPE (exp)))
+         && TYPE_MODE (rettype) != BLKmode
+         && targetm.calls.return_in_msb (rettype))
        {
-         if (shift_return_value (TYPE_MODE (TREE_TYPE (exp)), false, valreg))
+         if (shift_return_value (TYPE_MODE (rettype), false, valreg))
            sibcall_failure = 1;
-         valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg));
+         valreg = gen_rtx_REG (TYPE_MODE (rettype), REGNO (valreg));
        }
 
       if (pass && (flags & ECF_MALLOC))
@@ -2879,7 +2874,7 @@ expand_call (tree exp, rtx target, int ignore)
          rtx last, insns;
 
          /* The return value from a malloc-like function is a pointer.  */
-         if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
+         if (TREE_CODE (rettype) == POINTER_TYPE)
            mark_reg_pointer (temp, BIGGEST_ALIGNMENT);
 
          emit_move_insn (temp, valreg);
@@ -2929,7 +2924,7 @@ expand_call (tree exp, rtx target, int ignore)
 
       /* If value type not void, return an rtx for the value.  */
 
-      if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
+      if (TYPE_MODE (rettype) == VOIDmode
          || ignore)
        target = const0_rtx;
       else if (structure_value_addr)
@@ -2937,10 +2932,10 @@ expand_call (tree exp, rtx target, int ignore)
          if (target == 0 || !MEM_P (target))
            {
              target
-               = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
-                              memory_address (TYPE_MODE (TREE_TYPE (exp)),
+               = gen_rtx_MEM (TYPE_MODE (rettype),
+                              memory_address (TYPE_MODE (rettype),
                                               structure_value_addr));
-             set_mem_attributes (target, exp, 1);
+             set_mem_attributes (target, rettype, 1);
            }
        }
       else if (pcc_struct_value)
@@ -2948,9 +2943,9 @@ expand_call (tree exp, rtx target, int ignore)
          /* This is the special C++ case where we need to
             know what the true target was.  We take care to
             never use this value more than once in one expression.  */
-         target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
+         target = gen_rtx_MEM (TYPE_MODE (rettype),
                                copy_to_reg (valreg));
-         set_mem_attributes (target, exp, 1);
+         set_mem_attributes (target, rettype, 1);
        }
       /* Handle calls that return values in multiple non-contiguous locations.
         The Irix 6 ABI has examples of this.  */
@@ -2959,22 +2954,22 @@ expand_call (tree exp, rtx target, int ignore)
          if (target == 0)
            {
              /* This will only be assigned once, so it can be readonly.  */
-             tree nt = build_qualified_type (TREE_TYPE (exp),
-                                             (TYPE_QUALS (TREE_TYPE (exp))
+             tree nt = build_qualified_type (rettype,
+                                             (TYPE_QUALS (rettype)
                                               | TYPE_QUAL_CONST));
 
              target = assign_temp (nt, 0, 1, 1);
            }
 
          if (! rtx_equal_p (target, valreg))
-           emit_group_store (target, valreg, TREE_TYPE (exp),
-                             int_size_in_bytes (TREE_TYPE (exp)));
+           emit_group_store (target, valreg, rettype,
+                             int_size_in_bytes (rettype));
 
          /* We can not support sibling calls for this case.  */
          sibcall_failure = 1;
        }
       else if (target
-              && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))
+              && GET_MODE (target) == TYPE_MODE (rettype)
               && GET_MODE (target) == GET_MODE (valreg))
        {
          bool may_overlap = false;
@@ -3019,9 +3014,12 @@ expand_call (tree exp, rtx target, int ignore)
                sibcall_failure = 1;
            }
        }
-      else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+      else if (TYPE_MODE (rettype) == BLKmode)
        {
-         target = copy_blkmode_from_reg (target, valreg, TREE_TYPE (exp));
+         rtx val = valreg;
+         if (GET_MODE (val) != BLKmode)
+           val = avoid_likely_spilled_reg (val);
+         target = copy_blkmode_from_reg (target, val, rettype);
 
          /* We can not support sibling calls for this case.  */
          sibcall_failure = 1;
@@ -3032,10 +3030,10 @@ expand_call (tree exp, rtx target, int ignore)
       /* If we promoted this return value, make the proper SUBREG.
          TARGET might be const0_rtx here, so be careful.  */
       if (REG_P (target)
-         && TYPE_MODE (TREE_TYPE (exp)) != BLKmode
-         && GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+         && TYPE_MODE (rettype) != BLKmode
+         && GET_MODE (target) != TYPE_MODE (rettype))
        {
-         tree type = TREE_TYPE (exp);
+         tree type = rettype;
          int unsignedp = TYPE_UNSIGNED (type);
          int offset = 0;
          enum machine_mode pmode;
@@ -3746,7 +3744,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   else
     argnum = 0;
 
-  fun = prepare_call_address (fun, NULL, &call_fusage, 0, 0);
+  fun = prepare_call_address (NULL, fun, NULL, &call_fusage, 0, 0);
 
   /* Now load any reg parms into their regs.  */