OSDN Git Service

2011-11-10 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index c3d7639..382de7f 100644 (file)
@@ -1,7 +1,7 @@
 /* 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
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -32,7 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "libfuncs.h"
 #include "function.h"
 #include "regs.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "output.h"
 #include "tm_p.h"
 #include "timevar.h"
@@ -88,7 +88,7 @@ struct arg_data
   rtx stack;
   /* Location on the stack of the start of this argument slot.  This can
      differ from STACK if this arg pads downward.  This location is known
-     to be aligned to FUNCTION_ARG_BOUNDARY.  */
+     to be aligned to TARGET_FUNCTION_ARG_BOUNDARY.  */
   rtx stack_slot;
   /* Place that this stack area has been saved, if needed.  */
   rtx save_area;
@@ -125,7 +125,7 @@ static int stack_arg_under_construction;
 
 static void emit_call_1 (rtx, tree, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT,
                         HOST_WIDE_INT, rtx, rtx, int, rtx, int,
-                        CUMULATIVE_ARGS *);
+                        cumulative_args_t);
 static void precompute_register_parameters (int, struct arg_data *, int *);
 static int store_one_arg (struct arg_data *, rtx, int, int, int);
 static void store_unaligned_arguments_into_pseudos (struct arg_data *, int);
@@ -136,7 +136,7 @@ static int compute_argument_block_size (int, struct args_size *, tree, tree, int
 static void initialize_argument_information (int, struct arg_data *,
                                             struct args_size *, int,
                                             tree, tree,
-                                            tree, tree, CUMULATIVE_ARGS *, int,
+                                            tree, tree, cumulative_args_t, int,
                                             rtx *, int *, int *, int *,
                                             bool *, bool);
 static void compute_argument_addresses (struct arg_data *, rtx, int);
@@ -166,7 +166,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 +174,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 +188,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;
@@ -202,13 +207,15 @@ prepare_call_address (rtx funexp, rtx static_chain_value,
    The CALL_INSN is the first insn generated.
 
    FNDECL is the declaration node of the function.  This is given to the
-   macro RETURN_POPS_ARGS to determine whether this function pops its own args.
+   hook TARGET_RETURN_POPS_ARGS to determine whether this function pops
+   its own args.
 
-   FUNTYPE is the data type of the function.  This is given to the macro
-   RETURN_POPS_ARGS to determine whether this function pops its own args.
-   We used to allow an identifier for library functions, but that doesn't
-   work when the return type is an aggregate type and the calling convention
-   says that the pointer to this aggregate is to be popped by the callee.
+   FUNTYPE is the data type of the function.  This is given to the hook
+   TARGET_RETURN_POPS_ARGS to determine whether this function pops its
+   own args.  We used to allow an identifier for library functions, but
+   that doesn't work when the return type is an aggregate type and the
+   calling convention says that the pointer to this aggregate is to be
+   popped by the callee.
 
    STACK_SIZE is the number of bytes of arguments on the stack,
    ROUNDED_STACK_SIZE is that number rounded up to
@@ -220,7 +227,7 @@ prepare_call_address (rtx funexp, rtx static_chain_value,
    It is zero if this call doesn't want a structure value.
 
    NEXT_ARG_REG is the rtx that results from executing
-     FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1)
+     targetm.calls.function_arg (&args_so_far, VOIDmode, void_type_node, true)
    just after all the args have had their registers assigned.
    This could be whatever you like, but normally it is the first
    arg-register beyond those used for args in this call,
@@ -238,26 +245,23 @@ 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,
             HOST_WIDE_INT struct_value_size ATTRIBUTE_UNUSED,
             rtx next_arg_reg ATTRIBUTE_UNUSED, rtx valreg,
             int old_inhibit_defer_pop, rtx call_fusage, int ecf_flags,
-            CUMULATIVE_ARGS *args_so_far ATTRIBUTE_UNUSED)
+            cumulative_args_t args_so_far ATTRIBUTE_UNUSED)
 {
   rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
-  rtx call_insn;
+  rtx call_insn, call, funmem;
   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
+  HOST_WIDE_INT n_popped
+    = targetm.calls.return_pops_args (fndecl, funtype, stack_size);
 
 #ifdef CALL_POPS_ARGS
-  n_popped += CALL_POPS_ARGS (* args_so_far);
+  n_popped += CALL_POPS_ARGS (*get_cumulative_args (args_so_far));
 #endif
 
   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
@@ -266,6 +270,30 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
   if (GET_CODE (funexp) != SYMBOL_REF)
     funexp = memory_address (FUNCTION_MODE, funexp);
 
+  funmem = gen_rtx_MEM (FUNCTION_MODE, funexp);
+  if (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL)
+    {
+      tree t = fndecl;
+
+      /* Although a built-in FUNCTION_DECL and its non-__builtin
+        counterpart compare equal and get a shared mem_attrs, they
+        produce different dump output in compare-debug compilations,
+        if an entry gets garbage collected in one compilation, then
+        adds a different (but equivalent) entry, while the other
+        doesn't run the garbage collector at the same spot and then
+        shares the mem_attr with the equivalent entry. */
+      if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL)
+       {
+         tree t2 = builtin_decl_explicit (DECL_FUNCTION_CODE (t));
+         if (t2)
+           t = t2;
+       }
+
+       set_mem_expr (funmem, t);
+    }
+  else if (fntree)
+    set_mem_expr (funmem, build_simple_mem_ref (CALL_EXPR_FN (fntree)));
+
 #if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop)
   if ((ecf_flags & ECF_SIBCALL)
       && HAVE_sibcall_pop && HAVE_sibcall_value_pop
@@ -278,13 +306,11 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
         if possible, for the sake of frame pointer elimination.  */
 
       if (valreg)
-       pat = GEN_SIBCALL_VALUE_POP (valreg,
-                                    gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                    rounded_stack_size_rtx, next_arg_reg,
-                                    n_pop);
+       pat = GEN_SIBCALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
+                                    next_arg_reg, n_pop);
       else
-       pat = GEN_SIBCALL_POP (gen_rtx_MEM (FUNCTION_MODE, funexp),
-                              rounded_stack_size_rtx, next_arg_reg, n_pop);
+       pat = GEN_SIBCALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
+                              n_pop);
 
       emit_call_insn (pat);
       already_popped = 1;
@@ -311,12 +337,11 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
         if possible, for the sake of frame pointer elimination.  */
 
       if (valreg)
-       pat = GEN_CALL_VALUE_POP (valreg,
-                                 gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                 rounded_stack_size_rtx, next_arg_reg, n_pop);
+       pat = GEN_CALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
+                                 next_arg_reg, n_pop);
       else
-       pat = GEN_CALL_POP (gen_rtx_MEM (FUNCTION_MODE, funexp),
-                           rounded_stack_size_rtx, next_arg_reg, n_pop);
+       pat = GEN_CALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
+                           n_pop);
 
       emit_call_insn (pat);
       already_popped = 1;
@@ -329,14 +354,13 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
       && HAVE_sibcall && HAVE_sibcall_value)
     {
       if (valreg)
-       emit_call_insn (GEN_SIBCALL_VALUE (valreg,
-                                          gen_rtx_MEM (FUNCTION_MODE, funexp),
+       emit_call_insn (GEN_SIBCALL_VALUE (valreg, funmem,
                                           rounded_stack_size_rtx,
                                           next_arg_reg, NULL_RTX));
       else
-       emit_call_insn (GEN_SIBCALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                    rounded_stack_size_rtx, next_arg_reg,
-                                    struct_value_size_rtx));
+       emit_call_insn (GEN_SIBCALL (funmem, rounded_stack_size_rtx,
+                                    next_arg_reg,
+                                    GEN_INT (struct_value_size)));
     }
   else
 #endif
@@ -345,14 +369,11 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
   if (HAVE_call && HAVE_call_value)
     {
       if (valreg)
-       emit_call_insn (GEN_CALL_VALUE (valreg,
-                                       gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                       rounded_stack_size_rtx, next_arg_reg,
-                                       NULL_RTX));
+       emit_call_insn (GEN_CALL_VALUE (valreg, funmem, rounded_stack_size_rtx,
+                                       next_arg_reg, NULL_RTX));
       else
-       emit_call_insn (GEN_CALL (gen_rtx_MEM (FUNCTION_MODE, funexp),
-                                 rounded_stack_size_rtx, next_arg_reg,
-                                 struct_value_size_rtx));
+       emit_call_insn (GEN_CALL (funmem, rounded_stack_size_rtx, next_arg_reg,
+                                 GEN_INT (struct_value_size)));
     }
   else
 #endif
@@ -361,6 +382,19 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
   /* Find the call we just emitted.  */
   call_insn = last_call_insn ();
 
+  /* Some target create a fresh MEM instead of reusing the one provided
+     above.  Set its MEM_EXPR.  */
+  call = PATTERN (call_insn);
+  if (GET_CODE (call) == PARALLEL)
+    call = XVECEXP (call, 0, 0);
+  if (GET_CODE (call) == SET)
+    call = SET_SRC (call);
+  if (GET_CODE (call) == CALL
+      && MEM_P (XEXP (call, 0))
+      && MEM_EXPR (XEXP (call, 0)) == NULL_TREE
+      && MEM_EXPR (funmem) != NULL_TREE)
+    set_mem_expr (XEXP (call, 0), MEM_EXPR (funmem));
+
   /* Put the register usage information there.  */
   add_function_usage_to (call_insn, call_fusage);
 
@@ -376,19 +410,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);
@@ -416,6 +439,8 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
       rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
       stack_pointer_delta -= n_popped;
 
+      add_reg_note (call_insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+
       /* If popup is needed, stack realign must use DRAP  */
       if (SUPPORTS_STACK_ALIGNMENT)
         crtl->need_drap = true;
@@ -549,6 +574,8 @@ special_function_p (const_tree fndecl, int flags)
 int
 setjmp_call_p (const_tree fndecl)
 {
+  if (DECL_IS_RETURNS_TWICE (fndecl))
+    return ECF_RETURNS_TWICE;
   return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
 }
 
@@ -584,18 +611,78 @@ alloca_call_p (const_tree exp)
   return false;
 }
 
+/* Return TRUE if FNDECL is either a TM builtin or a TM cloned
+   function.  Return FALSE otherwise.  */
+
+static bool
+is_tm_builtin (const_tree fndecl)
+{
+  if (fndecl == NULL)
+    return false;
+
+  if (decl_is_tm_clone (fndecl))
+    return true;
+
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    {
+      switch (DECL_FUNCTION_CODE (fndecl))
+       {
+       case BUILT_IN_TM_COMMIT:
+       case BUILT_IN_TM_COMMIT_EH:
+       case BUILT_IN_TM_ABORT:
+       case BUILT_IN_TM_IRREVOCABLE:
+       case BUILT_IN_TM_GETTMCLONE_IRR:
+       case BUILT_IN_TM_MEMCPY:
+       case BUILT_IN_TM_MEMMOVE:
+       case BUILT_IN_TM_MEMSET:
+       CASE_BUILT_IN_TM_STORE (1):
+       CASE_BUILT_IN_TM_STORE (2):
+       CASE_BUILT_IN_TM_STORE (4):
+       CASE_BUILT_IN_TM_STORE (8):
+       CASE_BUILT_IN_TM_STORE (FLOAT):
+       CASE_BUILT_IN_TM_STORE (DOUBLE):
+       CASE_BUILT_IN_TM_STORE (LDOUBLE):
+       CASE_BUILT_IN_TM_STORE (M64):
+       CASE_BUILT_IN_TM_STORE (M128):
+       CASE_BUILT_IN_TM_STORE (M256):
+       CASE_BUILT_IN_TM_LOAD (1):
+       CASE_BUILT_IN_TM_LOAD (2):
+       CASE_BUILT_IN_TM_LOAD (4):
+       CASE_BUILT_IN_TM_LOAD (8):
+       CASE_BUILT_IN_TM_LOAD (FLOAT):
+       CASE_BUILT_IN_TM_LOAD (DOUBLE):
+       CASE_BUILT_IN_TM_LOAD (LDOUBLE):
+       CASE_BUILT_IN_TM_LOAD (M64):
+       CASE_BUILT_IN_TM_LOAD (M128):
+       CASE_BUILT_IN_TM_LOAD (M256):
+       case BUILT_IN_TM_LOG:
+       case BUILT_IN_TM_LOG_1:
+       case BUILT_IN_TM_LOG_2:
+       case BUILT_IN_TM_LOG_4:
+       case BUILT_IN_TM_LOG_8:
+       case BUILT_IN_TM_LOG_FLOAT:
+       case BUILT_IN_TM_LOG_DOUBLE:
+       case BUILT_IN_TM_LOG_LDOUBLE:
+       case BUILT_IN_TM_LOG_M64:
+       case BUILT_IN_TM_LOG_M128:
+       case BUILT_IN_TM_LOG_M256:
+         return true;
+       default:
+         break;
+       }
+    }
+  return false;
+}
+
 /* Detect flags (function attributes) from the function decl or type node.  */
 
 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;
@@ -605,7 +692,7 @@ flags_from_decl_or_type (const_tree exp)
        flags |= ECF_RETURNS_TWICE;
 
       /* Process the pure and const attributes.  */
-      if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
+      if (TREE_READONLY (exp))
        flags |= ECF_CONST;
       if (DECL_PURE_P (exp))
        flags |= ECF_PURE;
@@ -614,17 +701,41 @@ flags_from_decl_or_type (const_tree exp)
 
       if (DECL_IS_NOVOPS (exp))
        flags |= ECF_NOVOPS;
+      if (lookup_attribute ("leaf", DECL_ATTRIBUTES (exp)))
+       flags |= ECF_LEAF;
 
       if (TREE_NOTHROW (exp))
        flags |= ECF_NOTHROW;
 
+      if (flag_tm)
+       {
+         if (is_tm_builtin (exp))
+           flags |= ECF_TM_BUILTIN;
+         else if ((flags & ECF_CONST) != 0
+                  || lookup_attribute ("transaction_pure",
+                                       TYPE_ATTRIBUTES (TREE_TYPE (exp))))
+           flags |= ECF_TM_PURE;
+       }
+
       flags = special_function_p (exp, flags);
     }
-  else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
-    flags |= ECF_CONST;
+  else if (TYPE_P (exp))
+    {
+      if (TYPE_READONLY (exp))
+       flags |= ECF_CONST;
+
+      if (flag_tm
+         && ((flags & ECF_CONST) != 0
+             || lookup_attribute ("transaction_pure", TYPE_ATTRIBUTES (exp))))
+       flags |= ECF_TM_PURE;
+    }
 
   if (TREE_THIS_VOLATILE (exp))
-    flags |= ECF_NORETURN;
+    {
+      flags |= ECF_NORETURN;
+      if (flags & (ECF_CONST|ECF_PURE))
+       flags |= ECF_LOOPING_CONST_OR_PURE;
+    }
 
   return flags;
 }
@@ -679,12 +790,6 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
            pop_temp_slots ();
          }
 
-       /* If the value is a non-legitimate constant, force it into a
-          pseudo now.  TLS symbols sometimes need a call to resolve.  */
-       if (CONSTANT_P (args[i].value)
-           && !LEGITIMATE_CONSTANT_P (args[i].value))
-         args[i].value = force_reg (args[i].mode, args[i].value);
-
        /* If we are to promote the function arg to a wider mode,
           do it now.  */
 
@@ -694,6 +799,12 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
                             TYPE_MODE (TREE_TYPE (args[i].tree_value)),
                             args[i].value, args[i].unsignedp);
 
+       /* If the value is a non-legitimate constant, force it into a
+          pseudo now.  TLS symbols sometimes need a call to resolve.  */
+       if (CONSTANT_P (args[i].value)
+           && !targetm.legitimate_constant_p (args[i].mode, args[i].value))
+         args[i].value = force_reg (args[i].mode, args[i].value);
+
        /* If we're going to have to load the value by parts, pull the
           parts into pseudos.  The part extraction process can involve
           non-trivial computation.  */
@@ -717,9 +828,10 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
                     || (GET_CODE (args[i].value) == SUBREG
                         && REG_P (SUBREG_REG (args[i].value)))))
                 && args[i].mode != BLKmode
-                && rtx_cost (args[i].value, SET, optimize_insn_for_speed_p ())
+                && set_src_cost (args[i].value, 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);
       }
@@ -883,7 +995,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
            int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD);
 
            args[i].aligned_regs[j] = reg;
-           word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX,
+           word = extract_bit_field (word, bitsize, 0, 1, false, NULL_RTX,
                                      word_mode, word_mode);
 
            /* There is no need to restrict this code to loading items
@@ -900,14 +1012,14 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
            emit_move_insn (reg, const0_rtx);
 
            bytes -= bitsize / BITS_PER_UNIT;
-           store_bit_field (reg, bitsize, endian_correction, word_mode,
-                            word);
+           store_bit_field (reg, bitsize, endian_correction, 0, 0,
+                            word_mode, word);
          }
       }
 }
 
 /* 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.
 
@@ -943,12 +1055,14 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                                 int n_named_args ATTRIBUTE_UNUSED,
                                 tree exp, tree struct_value_addr_value,
                                 tree fndecl, tree fntype,
-                                CUMULATIVE_ARGS *args_so_far,
+                                cumulative_args_t args_so_far,
                                 int reg_parm_stack_space,
                                 rtx *old_stack_level, int *old_pending_adj,
                                 int *must_preallocate, int *ecf_flags,
                                 bool *may_tailcall, bool call_from_thunk_p)
 {
+  CUMULATIVE_ARGS *args_so_far_pnt = get_cumulative_args (args_so_far);
+  location_t loc = EXPR_LOCATION (exp);
   /* 1 if scanning parms front to back, -1 if scanning back to front.  */
   int inc;
 
@@ -1017,11 +1131,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.
 
@@ -1038,14 +1153,14 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
         with those made by function.c.  */
 
       /* See if this argument should be passed by invisible reference.  */
-      if (pass_by_reference (args_so_far, TYPE_MODE (type),
+      if (pass_by_reference (args_so_far_pnt, TYPE_MODE (type),
                             type, argpos < n_named_args))
        {
          bool callee_copies;
          tree base;
 
          callee_copies
-           = reference_callee_copied (args_so_far, TYPE_MODE (type),
+           = reference_callee_copied (args_so_far_pnt, TYPE_MODE (type),
                                       type, argpos < n_named_args);
 
          /* If we're compiling a thunk, pass through invisible references
@@ -1057,12 +1172,15 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                  && TREE_CODE (base) != SSA_NAME
                  && (!DECL_P (base) || MEM_P (DECL_RTL (base)))))
            {
+             mark_addressable (args[i].tree_value);
+
              /* We can't use sibcalls if a callee-copied argument is
                 stored in the current function's frame.  */
              if (!call_from_thunk_p && DECL_P (base) && !TREE_STATIC (base))
                *may_tailcall = false;
 
-             args[i].tree_value = build_fold_addr_expr (args[i].tree_value);
+             args[i].tree_value = build_fold_addr_expr_loc (loc,
+                                                        args[i].tree_value);
              type = TREE_TYPE (args[i].tree_value);
 
              if (*ecf_flags & ECF_CONST)
@@ -1086,14 +1204,19 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
 
                  if (*old_stack_level == 0)
                    {
-                     emit_stack_save (SAVE_BLOCK, old_stack_level, NULL_RTX);
+                     emit_stack_save (SAVE_BLOCK, old_stack_level);
                      *old_pending_adj = pending_stack_adjust;
                      pending_stack_adjust = 0;
                    }
 
-                 copy = gen_rtx_MEM (BLKmode,
-                                     allocate_dynamic_stack_space
-                                     (size_rtx, NULL_RTX, TYPE_ALIGN (type)));
+                 /* We can pass TRUE as the 4th argument because we just
+                    saved the stack pointer and will restore it right after
+                    the call.  */
+                 copy = allocate_dynamic_stack_space (size_rtx,
+                                                      TYPE_ALIGN (type),
+                                                      TYPE_ALIGN (type),
+                                                      true);
+                 copy = gen_rtx_MEM (BLKmode, copy);
                  set_mem_attributes (copy, type, 1);
                }
              else
@@ -1114,34 +1237,31 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                *ecf_flags &= ~(ECF_PURE | ECF_LOOPING_CONST_OR_PURE);
 
              args[i].tree_value
-               = build_fold_addr_expr (make_tree (type, copy));
+               = build_fold_addr_expr_loc (loc, make_tree (type, copy));
              type = TREE_TYPE (args[i].tree_value);
              *may_tailcall = false;
            }
        }
 
-      mode = TYPE_MODE (type);
       unsignedp = TYPE_UNSIGNED (type);
-
-      if (targetm.calls.promote_function_args (fndecl
-                                              ? TREE_TYPE (fndecl)
-                                              : fntype))
-       mode = promote_mode (type, mode, &unsignedp, 1);
+      mode = promote_function_mode (type, TYPE_MODE (type), &unsignedp,
+                                   fndecl ? TREE_TYPE (fndecl) : fntype, 0);
 
       args[i].unsignedp = unsignedp;
       args[i].mode = mode;
 
-      args[i].reg = FUNCTION_ARG (*args_so_far, mode, type,
-                                 argpos < n_named_args);
-#ifdef FUNCTION_INCOMING_ARG
+      args[i].reg = targetm.calls.function_arg (args_so_far, mode, type,
+                                               argpos < n_named_args);
+
       /* If this is a sibling call and the machine has register windows, the
         register window has to be unwinded before calling the routine, so
         arguments have to go into the incoming registers.  */
-      args[i].tail_call_reg = FUNCTION_INCOMING_ARG (*args_so_far, mode, type,
-                                                    argpos < n_named_args);
-#else
-      args[i].tail_call_reg = args[i].reg;
-#endif
+      if (targetm.calls.function_incoming_arg != targetm.calls.function_arg)
+       args[i].tail_call_reg
+         = targetm.calls.function_incoming_arg (args_so_far, mode, type,
+                                                argpos < n_named_args);
+      else
+       args[i].tail_call_reg = args[i].reg;
 
       if (args[i].reg)
        args[i].partial
@@ -1196,8 +1316,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
       /* Increment ARGS_SO_FAR, which has info about which arg-registers
         have been used, etc.  */
 
-      FUNCTION_ARG_ADVANCE (*args_so_far, TYPE_MODE (type), type,
-                           argpos < n_named_args);
+      targetm.calls.function_arg_advance (args_so_far, TYPE_MODE (type),
+                                         type, argpos < n_named_args);
     }
 }
 
@@ -1306,29 +1426,33 @@ precompute_arguments (int num_actuals, struct arg_data *args)
 
   for (i = 0; i < num_actuals; i++)
     {
+      tree type;
       enum machine_mode mode;
 
       if (TREE_CODE (args[i].tree_value) != CALL_EXPR)
        continue;
 
       /* If this is an addressable type, we cannot pre-evaluate it.  */
-      gcc_assert (!TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)));
+      type = TREE_TYPE (args[i].tree_value);
+      gcc_assert (!TREE_ADDRESSABLE (type));
 
       args[i].initial_value = args[i].value
        = expand_normal (args[i].tree_value);
 
-      mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
+      mode = TYPE_MODE (type);
       if (mode != args[i].mode)
        {
+         int unsignedp = args[i].unsignedp;
          args[i].value
            = convert_modes (args[i].mode, mode,
                             args[i].value, args[i].unsignedp);
-#if defined(PROMOTE_FUNCTION_MODE) && !defined(PROMOTE_MODE)
+
          /* CSE will replace this only if it contains args[i].value
             pseudo, so convert it down to the declared mode using
             a SUBREG.  */
          if (REG_P (args[i].value)
-             && GET_MODE_CLASS (args[i].mode) == MODE_INT)
+             && GET_MODE_CLASS (args[i].mode) == MODE_INT
+             && promote_mode (type, mode, &unsignedp) != args[i].mode)
            {
              args[i].initial_value
                = gen_lowpart_SUBREG (mode, args[i].value);
@@ -1336,7 +1460,6 @@ precompute_arguments (int num_actuals, struct arg_data *args)
              SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
                                            args[i].unsignedp);
            }
-#endif
        }
     }
 }
@@ -1346,7 +1469,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.
@@ -1446,7 +1569,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
              partial_mode = mode_for_size (units_on_stack * BITS_PER_UNIT,
                                            MODE_INT, 1);
              args[i].stack = gen_rtx_MEM (partial_mode, addr);
-             set_mem_size (args[i].stack, GEN_INT (units_on_stack));
+             set_mem_size (args[i].stack, units_on_stack);
            }
          else
            {
@@ -1478,7 +1601,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
                 Generate a simple memory reference of the correct size.
               */
              args[i].stack_slot = gen_rtx_MEM (partial_mode, addr);
-             set_mem_size (args[i].stack_slot, GEN_INT (units_on_stack));
+             set_mem_size (args[i].stack_slot, units_on_stack);
            }
          else
            {
@@ -1556,6 +1679,10 @@ mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size)
           && (XEXP (addr, 0) == crtl->args.internal_arg_pointer
               || XEXP (addr, 1) == crtl->args.internal_arg_pointer))
     return true;
+  /* If the address comes in a register, we have no idea of its origin so
+     give up and conservatively return true.  */
+  else if (REG_P(addr))
+    return true;
   else
     return false;
 
@@ -1651,9 +1778,7 @@ load_register_parameters (struct arg_data *args, int num_actuals,
                     call only uses SIZE bytes at the msb end, but it doesn't
                     seem worth generating rtl to say that.  */
                  reg = gen_rtx_REG (word_mode, REGNO (reg));
-                 x = expand_shift (LSHIFT_EXPR, word_mode, reg,
-                                   build_int_cst (NULL_TREE, shift),
-                                   reg, 1);
+                 x = expand_shift (LSHIFT_EXPR, word_mode, reg, shift, reg, 1);
                  if (x != reg)
                    emit_move_insn (reg, x);
                }
@@ -1672,10 +1797,12 @@ load_register_parameters (struct arg_data *args, int num_actuals,
            {
              rtx mem = validize_mem (args[i].value);
 
-             /* Check for overlap with already clobbered argument area.  */
+             /* Check for overlap with already clobbered argument area,
+                providing that this has non-zero size.  */
              if (is_sibcall
-                 && mem_overlaps_already_clobbered_arg_p (XEXP (args[i].value, 0),
-                                                          size))
+                 && (size == 0
+                     || mem_overlaps_already_clobbered_arg_p 
+                                          (XEXP (args[i].value, 0), size)))
                *sibcall_failure = 1;
 
              /* Handle a BLKmode that needs shifting.  */
@@ -1695,9 +1822,7 @@ load_register_parameters (struct arg_data *args, int num_actuals,
                                                        : LSHIFT_EXPR;
 
                  emit_move_insn (x, tem);
-                 x = expand_shift (dir, word_mode, x,
-                                   build_int_cst (NULL_TREE, shift),
-                                   ri, 1);
+                 x = expand_shift (dir, word_mode, x, shift, ri, 1);
                  if (x != ri)
                    emit_move_insn (ri, x);
                }
@@ -1717,7 +1842,8 @@ load_register_parameters (struct arg_data *args, int num_actuals,
          if (GET_CODE (reg) == PARALLEL)
            use_group_regs (call_fusage, reg);
          else if (nregs == -1)
-           use_reg (call_fusage, reg);
+           use_reg_mode (call_fusage, reg,
+                         TYPE_MODE (TREE_TYPE (args[i].tree_value)));
          else if (nregs > 0)
            use_regs (call_fusage, REGNO (reg), nregs);
        }
@@ -1798,6 +1924,10 @@ check_sibcall_argument_overlap_1 (rtx x)
 
   code = GET_CODE (x);
 
+  /* We need not check the operands of the CALL expression itself.  */
+  if (code == CALL)
+    return 0;
+
   if (code == MEM)
     return mem_overlaps_already_clobbered_arg_p (XEXP (x, 0),
                                                 GET_MODE_SIZE (GET_MODE (x)));
@@ -1890,7 +2020,7 @@ avoid_likely_spilled_reg (rtx x)
 
   if (REG_P (x)
       && HARD_REGISTER_P (x)
-      && CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (REGNO (x))))
+      && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (x))))
     {
       /* Make sure that we generate a REG rather than a CONCAT.
         Moves into CONCATs can need nontrivial instructions,
@@ -1926,6 +2056,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;
@@ -1974,7 +2105,8 @@ expand_call (tree exp, rtx target, int ignore)
   /* Size of arguments before any adjustments (such as rounding).  */
   int unadjusted_args_size;
   /* Data on reg parms scanned so far.  */
-  CUMULATIVE_ARGS args_so_far;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
   /* Nonzero if a reg parm has been scanned.  */
   int reg_parm_seen;
   /* Nonzero if this is an indirect function call.  */
@@ -2021,7 +2153,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.  */
@@ -2044,15 +2175,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
@@ -2062,7 +2194,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;
@@ -2094,7 +2226,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);
@@ -2105,7 +2237,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);
@@ -2114,7 +2246,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);
@@ -2212,7 +2344,8 @@ expand_call (tree exp, rtx target, int ignore)
      calling convention than normal calls.  The fourth argument in
      INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call
      or not.  */
-  INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, fndecl, n_named_args);
+  INIT_CUMULATIVE_ARGS (args_so_far_v, funtype, NULL_RTX, fndecl, n_named_args);
+  args_so_far = pack_cumulative_args (&args_so_far_v);
 
   /* Now possibly adjust the number of named args.
      Normally, don't include the last named arg if anonymous args follow.
@@ -2233,10 +2366,10 @@ expand_call (tree exp, rtx target, int ignore)
      registers, so we must force them into memory.  */
 
   if (type_arg_types != 0
-      && targetm.calls.strict_argument_naming (&args_so_far))
+      && targetm.calls.strict_argument_naming (args_so_far))
     ;
   else if (type_arg_types != 0
-          && ! targetm.calls.pretend_outgoing_varargs_named (&args_so_far))
+          && ! targetm.calls.pretend_outgoing_varargs_named (args_so_far))
     /* Don't include the last named arg.  */
     --n_named_args;
   else
@@ -2252,7 +2385,7 @@ expand_call (tree exp, rtx target, int ignore)
   initialize_argument_information (num_actuals, args, &args_size,
                                   n_named_args, exp,
                                   structure_value_addr_value, fndecl, fntype,
-                                  &args_so_far, reg_parm_stack_space,
+                                  args_so_far, reg_parm_stack_space,
                                   &old_stack_level, &old_pending_adj,
                                   &must_preallocate, &flags,
                                   &try_tail_call, CALL_FROM_THUNK_P (exp));
@@ -2285,7 +2418,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;
 
@@ -2327,10 +2459,10 @@ expand_call (tree exp, rtx target, int ignore)
                               - crtl->args.pretend_args_size)
       /* If the callee pops its own arguments, then it must pop exactly
         the same number of arguments as the current function.  */
-      || (RETURN_POPS_ARGS (fndecl, funtype, args_size.constant)
-         != RETURN_POPS_ARGS (current_function_decl,
-                              TREE_TYPE (current_function_decl),
-                              crtl->args.size))
+      || (targetm.calls.return_pops_args (fndecl, funtype, args_size.constant)
+         != targetm.calls.return_pops_args (current_function_decl,
+                                            TREE_TYPE (current_function_decl),
+                                            crtl->args.size))
       || !lang_hooks.decls.ok_for_sibcall (fndecl))
     try_tail_call = 0;
 
@@ -2344,17 +2476,17 @@ expand_call (tree exp, rtx target, int ignore)
       tree caller_res = DECL_RESULT (current_function_decl);
 
       caller_unsignedp = TYPE_UNSIGNED (TREE_TYPE (caller_res));
-      caller_mode = caller_promoted_mode = DECL_MODE (caller_res);
+      caller_mode = DECL_MODE (caller_res);
       callee_unsignedp = TYPE_UNSIGNED (TREE_TYPE (funtype));
-      callee_mode = callee_promoted_mode = TYPE_MODE (TREE_TYPE (funtype));
-      if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
-       caller_promoted_mode
-         = promote_mode (TREE_TYPE (caller_res), caller_mode,
-                         &caller_unsignedp, 1);
-      if (targetm.calls.promote_function_return (funtype))
-       callee_promoted_mode
-         = promote_mode (TREE_TYPE (funtype), callee_mode,
-                         &callee_unsignedp, 1);
+      callee_mode = TYPE_MODE (TREE_TYPE (funtype));
+      caller_promoted_mode
+       = promote_function_mode (TREE_TYPE (caller_res), caller_mode,
+                                &caller_unsignedp,
+                                TREE_TYPE (current_function_decl), 1);
+      callee_promoted_mode
+       = promote_function_mode (TREE_TYPE (funtype), callee_mode,
+                                &callee_unsignedp,
+                                funtype, 1);
       if (caller_mode != VOIDmode
          && (caller_promoted_mode != callee_promoted_mode
              || ((caller_mode != caller_promoted_mode
@@ -2475,7 +2607,7 @@ expand_call (tree exp, rtx target, int ignore)
        {
          if (old_stack_level == 0)
            {
-             emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+             emit_stack_save (SAVE_BLOCK, &old_stack_level);
              old_stack_pointer_delta = stack_pointer_delta;
              old_pending_adj = pending_stack_adjust;
              pending_stack_adjust = 0;
@@ -2486,6 +2618,8 @@ expand_call (tree exp, rtx target, int ignore)
              stack_arg_under_construction = 0;
            }
          argblock = push_block (ARGS_SIZE_RTX (adjusted_args_size), 0, 0);
+         if (flag_stack_usage_info)
+           current_function_has_unbounded_dynamic_stack_size = 1;
        }
       else
        {
@@ -2534,8 +2668,7 @@ expand_call (tree exp, rtx target, int ignore)
                  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
                                                     needed);
 #endif
-                 if (stack_usage_map_buf)
-                   free (stack_usage_map_buf);
+                 free (stack_usage_map_buf);
                  stack_usage_map_buf = XNEWVEC (char, highest_outgoing_arg_in_use);
                  stack_usage_map = stack_usage_map_buf;
 
@@ -2628,8 +2761,7 @@ expand_call (tree exp, rtx target, int ignore)
                              : reg_parm_stack_space));
              if (old_stack_level == 0)
                {
-                 emit_stack_save (SAVE_BLOCK, &old_stack_level,
-                                  NULL_RTX);
+                 emit_stack_save (SAVE_BLOCK, &old_stack_level);
                  old_stack_pointer_delta = stack_pointer_delta;
                  old_pending_adj = pending_stack_adjust;
                  pending_stack_adjust = 0;
@@ -2641,14 +2773,16 @@ expand_call (tree exp, rtx target, int ignore)
                    = stack_arg_under_construction;
                  stack_arg_under_construction = 0;
                  /* Make a new map for the new argument list.  */
-                 if (stack_usage_map_buf)
-                   free (stack_usage_map_buf);
+                 free (stack_usage_map_buf);
                  stack_usage_map_buf = XCNEWVEC (char, highest_outgoing_arg_in_use);
                  stack_usage_map = stack_usage_map_buf;
                  highest_outgoing_arg_in_use = 0;
                }
-             allocate_dynamic_stack_space (push_size, NULL_RTX,
-                                           BITS_PER_UNIT);
+             /* We can pass TRUE as the 4th argument because we just
+                saved the stack pointer and will restore it right after
+                the call.  */
+             allocate_dynamic_stack_space (push_size, 0,
+                                           BIGGEST_ALIGNMENT, true);
            }
 
          /* If argument evaluation might modify the stack pointer,
@@ -2688,18 +2822,31 @@ expand_call (tree exp, rtx target, int ignore)
         be deferred during the evaluation of the arguments.  */
       NO_DEFER_POP;
 
+      /* Record the maximum pushed stack space size.  We need to delay
+        doing it this far to take into account the optimization done
+        by combine_pending_stack_adjustment_and_call.  */
+      if (flag_stack_usage_info
+         && !ACCUMULATE_OUTGOING_ARGS
+         && pass
+         && adjusted_args_size.var == 0)
+       {
+         int pushed = adjusted_args_size.constant + pending_stack_adjust;
+         if (pushed > current_function_pushed_stack_size)
+           current_function_pushed_stack_size = pushed;
+       }
+
       funexp = rtx_for_function_call (fndecl, addr);
 
       /* 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
@@ -2754,13 +2901,11 @@ expand_call (tree exp, rtx target, int ignore)
                sibcall_failure = 1;
              }
 
-         if (((flags & ECF_CONST)
-              || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
-             && args[i].stack)
-           call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
-                                            gen_rtx_USE (VOIDmode,
-                                                         args[i].stack),
-                                            call_fusage);
+         if (args[i].stack)
+           call_fusage
+             = gen_rtx_EXPR_LIST (TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+                                  gen_rtx_USE (VOIDmode, args[i].stack),
+                                  call_fusage);
        }
 
       /* If we have a parm that is passed in registers but not in memory
@@ -2817,7 +2962,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,
@@ -2829,14 +2974,15 @@ expand_call (tree exp, rtx target, int ignore)
 
       /* Set up next argument register.  For sibling calls on machines
         with register windows this should be the incoming register.  */
-#ifdef FUNCTION_INCOMING_ARG
       if (pass == 0)
-       next_arg_reg = FUNCTION_INCOMING_ARG (args_so_far, VOIDmode,
-                                             void_type_node, 1);
+       next_arg_reg = targetm.calls.function_incoming_arg (args_so_far,
+                                                           VOIDmode,
+                                                           void_type_node,
+                                                           true);
       else
-#endif
-       next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode,
-                                    void_type_node, 1);
+       next_arg_reg = targetm.calls.function_arg (args_so_far,
+                                                  VOIDmode, void_type_node,
+                                                  true);
 
       /* All arguments and registers used for the call must be set up by
         now!  */
@@ -2849,7 +2995,7 @@ expand_call (tree exp, rtx target, int ignore)
       emit_call_1 (funexp, exp, fndecl, funtype, unadjusted_args_size,
                   adjusted_args_size.constant, struct_value_size,
                   next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
-                  flags, args_so_far);
+                  flags, args_so_far);
 
       /* If the call setup or the call itself overlaps with anything
         of the argument setup we probably clobbered our call address.
@@ -2864,12 +3010,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))
@@ -2878,7 +3024,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);
@@ -2928,7 +3074,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)
@@ -2936,10 +3082,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)
@@ -2947,9 +3093,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.  */
@@ -2958,22 +3104,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;
@@ -3018,9 +3164,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;
@@ -3028,38 +3177,37 @@ expand_call (tree exp, rtx target, int ignore)
       else
        target = copy_to_reg (avoid_likely_spilled_reg (valreg));
 
-      if (targetm.calls.promote_function_return(funtype))
+      /* 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 (rettype) != BLKmode
+         && GET_MODE (target) != TYPE_MODE (rettype))
        {
-         /* 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)))
+         tree type = rettype;
+         int unsignedp = TYPE_UNSIGNED (type);
+         int offset = 0;
+         enum machine_mode pmode;
+
+         /* Ensure we promote as expected, and get the new unsignedness.  */
+         pmode = promote_function_mode (type, TYPE_MODE (type), &unsignedp,
+                                        funtype, 1);
+         gcc_assert (GET_MODE (target) == pmode);
+
+         if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
+             && (GET_MODE_SIZE (GET_MODE (target))
+                 > GET_MODE_SIZE (TYPE_MODE (type))))
            {
-             tree type = TREE_TYPE (exp);
-             int unsignedp = TYPE_UNSIGNED (type);
-             int offset = 0;
-             enum machine_mode pmode;
-
-             pmode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
-             /* If we don't promote as expected, something is wrong.  */
-             gcc_assert (GET_MODE (target) == pmode);
-
-             if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
-                 && (GET_MODE_SIZE (GET_MODE (target))
-                     > GET_MODE_SIZE (TYPE_MODE (type))))
-               {
-                 offset = GET_MODE_SIZE (GET_MODE (target))
-                   - GET_MODE_SIZE (TYPE_MODE (type));
-                 if (! BYTES_BIG_ENDIAN)
-                   offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
-                 else if (! WORDS_BIG_ENDIAN)
-                   offset %= UNITS_PER_WORD;
-               }
-             target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
-             SUBREG_PROMOTED_VAR_P (target) = 1;
-             SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp);
+             offset = GET_MODE_SIZE (GET_MODE (target))
+               - GET_MODE_SIZE (TYPE_MODE (type));
+             if (! BYTES_BIG_ENDIAN)
+               offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
+             else if (! WORDS_BIG_ENDIAN)
+               offset %= UNITS_PER_WORD;
            }
+
+         target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
+         SUBREG_PROMOTED_VAR_P (target) = 1;
+         SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp);
        }
 
       /* If size of args is variable or this was a constructor call for a stack
@@ -3067,8 +3215,13 @@ expand_call (tree exp, rtx target, int ignore)
 
       if (old_stack_level)
        {
-         emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
+         rtx prev = get_last_insn ();
+
+         emit_stack_restore (SAVE_BLOCK, old_stack_level);
          stack_pointer_delta = old_stack_pointer_delta;
+
+         fixup_args_size_notes (prev, get_last_insn (), stack_pointer_delta);
+
          pending_stack_adjust = old_pending_adj;
          old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
          stack_arg_under_construction = old_stack_arg_under_construction;
@@ -3115,8 +3268,7 @@ expand_call (tree exp, rtx target, int ignore)
 
       /* Free up storage we no longer need.  */
       for (i = 0; i < num_actuals; ++i)
-       if (args[i].aligned_regs)
-         free (args[i].aligned_regs);
+       free (args[i].aligned_regs);
 
       insns = get_insns ();
       end_sequence ();
@@ -3171,8 +3323,7 @@ expand_call (tree exp, rtx target, int ignore)
 
   currently_expanding_call--;
 
-  if (stack_usage_map_buf)
-    free (stack_usage_map_buf);
+  free (stack_usage_map_buf);
 
   return target;
 }
@@ -3280,7 +3431,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   int inc;
   int count;
   rtx argblock = 0;
-  CUMULATIVE_ARGS args_so_far;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
   struct arg
   {
     rtx value;
@@ -3392,10 +3544,11 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   memset (argvec, 0, (nargs + 1) * sizeof (struct arg));
 
 #ifdef INIT_CUMULATIVE_LIBCALL_ARGS
-  INIT_CUMULATIVE_LIBCALL_ARGS (args_so_far, outmode, fun);
+  INIT_CUMULATIVE_LIBCALL_ARGS (args_so_far_v, outmode, fun);
 #else
-  INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0, nargs);
+  INIT_CUMULATIVE_ARGS (args_so_far_v, NULL_TREE, fun, 0, nargs);
 #endif
+  args_so_far = pack_cumulative_args (&args_so_far_v);
 
   args_size.constant = 0;
   args_size.var = 0;
@@ -3414,15 +3567,17 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
       /* Make sure it is a reasonable operand for a move or push insn.  */
       if (!REG_P (addr) && !MEM_P (addr)
-         && ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr)))
+         && !(CONSTANT_P (addr)
+              && targetm.legitimate_constant_p (Pmode, addr)))
        addr = force_operand (addr, NULL_RTX);
 
       argvec[count].value = addr;
       argvec[count].mode = Pmode;
       argvec[count].partial = 0;
 
-      argvec[count].reg = FUNCTION_ARG (args_so_far, Pmode, NULL_TREE, 1);
-      gcc_assert (targetm.calls.arg_partial_bytes (&args_so_far, Pmode,
+      argvec[count].reg = targetm.calls.function_arg (args_so_far,
+                                                     Pmode, NULL_TREE, true);
+      gcc_assert (targetm.calls.arg_partial_bytes (args_so_far, Pmode,
                                                   NULL_TREE, 1) == 0);
 
       locate_and_pad_parm (Pmode, NULL_TREE,
@@ -3437,7 +3592,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
          || reg_parm_stack_space > 0)
        args_size.constant += argvec[count].locate.size.constant;
 
-      FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree) 0, 1);
+      targetm.calls.function_arg_advance (args_so_far, Pmode, (tree) 0, true);
 
       count++;
     }
@@ -3446,6 +3601,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
     {
       rtx val = va_arg (p, rtx);
       enum machine_mode mode = (enum machine_mode) va_arg (p, int);
+      int unsigned_p = 0;
 
       /* We cannot convert the arg value to the mode the library wants here;
         must do it earlier where we know the signedness of the arg.  */
@@ -3454,14 +3610,14 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
       /* Make sure it is a reasonable operand for a move or push insn.  */
       if (!REG_P (val) && !MEM_P (val)
-         && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
+         && !(CONSTANT_P (val) && targetm.legitimate_constant_p (mode, val)))
        val = force_operand (val, NULL_RTX);
 
-      if (pass_by_reference (&args_so_far, mode, NULL_TREE, 1))
+      if (pass_by_reference (&args_so_far_v, mode, NULL_TREE, 1))
        {
          rtx slot;
          int must_copy
-           = !reference_callee_copied (&args_so_far, mode, NULL_TREE, 1);
+           = !reference_callee_copied (&args_so_far_v, mode, NULL_TREE, 1);
 
          /* If this was a CONST function, it is now PURE since it now
             reads memory.  */
@@ -3472,7 +3628,12 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
            }
 
          if (MEM_P (val) && !must_copy)
-           slot = val;
+           {
+             tree val_expr = MEM_EXPR (val);
+             if (val_expr)
+               mark_addressable (val_expr);
+             slot = val;
+           }
          else
            {
              slot = assign_temp (lang_hooks.types.type_for_mode (mode, 0),
@@ -3493,30 +3654,40 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
          val = force_operand (XEXP (slot, 0), NULL_RTX);
        }
 
-      argvec[count].value = val;
+      mode = promote_function_mode (NULL_TREE, mode, &unsigned_p, NULL_TREE, 0);
       argvec[count].mode = mode;
-
-      argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
+      argvec[count].value = convert_modes (mode, GET_MODE (val), val, unsigned_p);
+      argvec[count].reg = targetm.calls.function_arg (args_so_far, mode,
+                                                     NULL_TREE, true);
 
       argvec[count].partial
-       = targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL_TREE, 1);
+       = targetm.calls.arg_partial_bytes (args_so_far, mode, NULL_TREE, 1);
 
-      locate_and_pad_parm (mode, NULL_TREE,
+      if (argvec[count].reg == 0
+         || argvec[count].partial != 0
+         || reg_parm_stack_space > 0)
+       {
+         locate_and_pad_parm (mode, NULL_TREE,
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
-                          1,
+                              1,
 #else
-                          argvec[count].reg != 0,
+                              argvec[count].reg != 0,
+#endif
+                              argvec[count].partial,
+                              NULL_TREE, &args_size, &argvec[count].locate);
+         args_size.constant += argvec[count].locate.size.constant;
+         gcc_assert (!argvec[count].locate.size.var);
+       }
+#ifdef BLOCK_REG_PADDING
+      else
+       /* The argument is passed entirely in registers.  See at which
+          end it should be padded.  */
+       argvec[count].locate.where_pad =
+         BLOCK_REG_PADDING (mode, NULL_TREE,
+                            GET_MODE_SIZE (mode) <= UNITS_PER_WORD);
 #endif
-                          argvec[count].partial,
-                          NULL_TREE, &args_size, &argvec[count].locate);
-
-      gcc_assert (!argvec[count].locate.size.var);
-
-      if (argvec[count].reg == 0 || argvec[count].partial != 0
-         || reg_parm_stack_space > 0)
-       args_size.constant += argvec[count].locate.size.constant;
 
-      FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
+      targetm.calls.function_arg_advance (args_so_far, mode, (tree) 0, true);
     }
 
   /* If this machine requires an external definition for library
@@ -3540,6 +3711,13 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   if (args_size.constant > crtl->outgoing_args_size)
     crtl->outgoing_args_size = args_size.constant;
 
+  if (flag_stack_usage_info && !ACCUMULATE_OUTGOING_ARGS)
+    {
+      int pushed = args_size.constant + pending_stack_adjust;
+      if (pushed > current_function_pushed_stack_size)
+       current_function_pushed_stack_size = pushed;
+    }
+
   if (ACCUMULATE_OUTGOING_ARGS)
     {
       /* Since the stack pointer will never be pushed, it is possible for
@@ -3640,6 +3818,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
       if (! (reg != 0 && partial == 0))
        {
+         rtx use;
+
          if (ACCUMULATE_OUTGOING_ARGS)
            {
              /* If this is being stored into a pre-allocated, fixed-size,
@@ -3710,28 +3890,22 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
          NO_DEFER_POP;
 
-         if ((flags & ECF_CONST)
-             || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
-           {
-             rtx use;
-
-             /* Indicate argument access so that alias.c knows that these
-                values are live.  */
-             if (argblock)
-               use = plus_constant (argblock,
-                                    argvec[argnum].locate.offset.constant);
-             else
-               /* When arguments are pushed, trying to tell alias.c where
-                  exactly this argument is won't work, because the
-                  auto-increment causes confusion.  So we merely indicate
-                  that we access something with a known mode somewhere on
-                  the stack.  */
-               use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
-                                   gen_rtx_SCRATCH (Pmode));
-             use = gen_rtx_MEM (argvec[argnum].mode, use);
-             use = gen_rtx_USE (VOIDmode, use);
-             call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
-           }
+         /* Indicate argument access so that alias.c knows that these
+            values are live.  */
+         if (argblock)
+           use = plus_constant (argblock,
+                                argvec[argnum].locate.offset.constant);
+         else
+           /* When arguments are pushed, trying to tell alias.c where
+              exactly this argument is won't work, because the
+              auto-increment causes confusion.  So we merely indicate
+              that we access something with a known mode somewhere on
+              the stack.  */
+           use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
+                               gen_rtx_SCRATCH (Pmode));
+         use = gen_rtx_MEM (argvec[argnum].mode, use);
+         use = gen_rtx_USE (VOIDmode, use);
+         call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
        }
     }
 
@@ -3746,7 +3920,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.  */
 
@@ -3758,13 +3932,43 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
-
+#ifdef BLOCK_REG_PADDING
+      int size = 0;
+#endif
+      
       /* Handle calls that pass values in multiple non-contiguous
         locations.  The PA64 has examples of this for library calls.  */
       if (reg != 0 && GET_CODE (reg) == PARALLEL)
        emit_group_load (reg, val, NULL_TREE, GET_MODE_SIZE (mode));
       else if (reg != 0 && partial == 0)
-       emit_move_insn (reg, val);
+        {
+         emit_move_insn (reg, val);
+#ifdef BLOCK_REG_PADDING
+         size = GET_MODE_SIZE (argvec[argnum].mode);
+
+         /* Copied from load_register_parameters.  */
+
+         /* Handle case where we have a value that needs shifting
+            up to the msb.  eg. a QImode value and we're padding
+            upward on a BYTES_BIG_ENDIAN machine.  */
+         if (size < UNITS_PER_WORD
+             && (argvec[argnum].locate.where_pad
+                 == (BYTES_BIG_ENDIAN ? upward : downward)))
+           {
+             rtx x;
+             int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
+
+             /* Assigning REG here rather than a temp makes CALL_FUSAGE
+                report the whole reg as used.  Strictly speaking, the
+                call only uses SIZE bytes at the msb end, but it doesn't
+                seem worth generating rtl to say that.  */
+             reg = gen_rtx_REG (word_mode, REGNO (reg));
+             x = expand_shift (LSHIFT_EXPR, word_mode, reg, shift, reg, 1);
+             if (x != reg)
+               emit_move_insn (reg, x);
+           }
+#endif
+       }
 
       NO_DEFER_POP;
     }
@@ -3805,7 +4009,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
      cse'ing of library calls could delete a call and leave the pop.  */
   NO_DEFER_POP;
   valreg = (mem_value == 0 && outmode != VOIDmode
-           ? hard_libcall_value (outmode) : NULL_RTX);
+           ? hard_libcall_value (outmode, orgfun) : NULL_RTX);
 
   /* Stack must be properly aligned now.  */
   gcc_assert (!(stack_pointer_delta
@@ -3825,9 +4029,19 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
               build_function_type (tfom, NULL_TREE),
               original_args_size.constant, args_size.constant,
               struct_value_size,
-              FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
+              targetm.calls.function_arg (args_so_far,
+                                          VOIDmode, void_type_node, true),
               valreg,
-              old_inhibit_defer_pop + 1, call_fusage, flags, & args_so_far);
+              old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far);
+
+  /* Right-shift returned value if necessary.  */
+  if (!pcc_struct_value
+      && TYPE_MODE (tfom) != BLKmode
+      && targetm.calls.return_in_msb (tfom))
+    {
+      shift_return_value (TYPE_MODE (tfom), false, valreg);
+      valreg = gen_rtx_REG (TYPE_MODE (tfom), REGNO (valreg));
+    }
 
   /* For calls to `setjmp', etc., inform function.c:setjmp_warnings
      that it should complain if nonvolatile values are live.  For
@@ -3874,15 +4088,14 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
        }
       else
        {
-         /* Convert to the proper mode if PROMOTE_MODE has been active.  */
+         /* Convert to the proper mode if a promotion has been active.  */
          if (GET_MODE (valreg) != outmode)
            {
              int unsignedp = TYPE_UNSIGNED (tfom);
 
-             gcc_assert (targetm.calls.promote_function_return (tfom));
-             gcc_assert (promote_mode (tfom, outmode, &unsignedp, 0)
+             gcc_assert (promote_function_mode (tfom, outmode, &unsignedp,
+                                                fndecl ? TREE_TYPE (fndecl) : fntype, 1)
                          == GET_MODE (valreg));
-
              valreg = convert_modes (outmode, GET_MODE (valreg), valreg, 0);
            }
 
@@ -3924,8 +4137,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       stack_usage_map = initial_stack_usage_map;
     }
 
-  if (stack_usage_map_buf)
-    free (stack_usage_map_buf);
+  free (stack_usage_map_buf);
 
   return value;