OSDN Git Service

* gcj.texi (Input and output files): Mention non-class entries.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index d86b0e0..1c51e1a 100644 (file)
@@ -21,6 +21,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -33,10 +35,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "timevar.h"
 #include "sbitmap.h"
-
-#if !defined FUNCTION_OK_FOR_SIBCALL
-#define FUNCTION_OK_FOR_SIBCALL(DECL) 1
-#endif
+#include "langhooks.h"
+#include "target.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -46,9 +46,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #ifdef PUSH_ROUNDING
 
+#ifndef PUSH_ARGS_REVERSED
 #if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
 #define PUSH_ARGS_REVERSED  PUSH_ARGS
 #endif
+#endif
 
 #endif
 
@@ -89,7 +91,7 @@ struct arg_data
   /* Number of registers to use.  0 means put the whole arg in registers.
      Also 0 if not passed in registers.  */
   int partial;
-  /* Non-zero if argument must be passed on stack.
+  /* Nonzero if argument must be passed on stack.
      Note that some arguments may be passed on the stack
      even though pass_on_stack is zero, just because FUNCTION_ARG says so.
      pass_on_stack identifies arguments that *cannot* go in registers.  */
@@ -124,7 +126,7 @@ struct arg_data
   struct args_size alignment_pad;
 };
 
-/* A vector of one char per byte of stack space.  A byte if non-zero if
+/* A vector of one char per byte of stack space.  A byte if nonzero if
    the corresponding stack location has been used.
    This vector is used to prevent a function call within an argument from
    clobbering any stack already set up.  */
@@ -150,36 +152,10 @@ int stack_arg_under_construction;
 static int calls_function      PARAMS ((tree, int));
 static int calls_function_1    PARAMS ((tree, int));
 
-/* Nonzero if this is a call to a `const' function.  */
-#define ECF_CONST              1
-/* Nonzero if this is a call to a `volatile' function.  */
-#define ECF_NORETURN           2
-/* Nonzero if this is a call to malloc or a related function.  */
-#define ECF_MALLOC             4
-/* Nonzero if it is plausible that this is a call to alloca.  */
-#define ECF_MAY_BE_ALLOCA      8
-/* Nonzero if this is a call to a function that won't throw an exception.  */
-#define ECF_NOTHROW            16
-/* Nonzero if this is a call to setjmp or a related function.  */
-#define ECF_RETURNS_TWICE      32
-/* Nonzero if this is a call to `longjmp'.  */
-#define ECF_LONGJMP            64
-/* Nonzero if this is a syscall that makes a new process in the image of
-   the current one.  */
-#define ECF_FORK_OR_EXEC       128
-#define ECF_SIBCALL            256
-/* Nonzero if this is a call to "pure" function (like const function,
-   but may read memory.  */
-#define ECF_PURE               512
-/* Nonzero if this is a call to a function that returns with the stack
-   pointer depressed.  */
-#define ECF_SP_DEPRESSED       1024
-/* Nonzero if this call is known to always return.  */
-#define ECF_ALWAYS_RETURN      2048
-
 static void emit_call_1                PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
                                         HOST_WIDE_INT, HOST_WIDE_INT, rtx,
-                                        rtx, int, rtx, int));
+                                        rtx, int, rtx, int,
+                                        CUMULATIVE_ARGS *));
 static void precompute_register_parameters     PARAMS ((int,
                                                         struct arg_data *,
                                                         int *));
@@ -206,20 +182,22 @@ static void compute_argument_addresses            PARAMS ((struct arg_data *,
                                                         rtx, int));
 static rtx rtx_for_function_call               PARAMS ((tree, tree));
 static void load_register_parameters           PARAMS ((struct arg_data *,
-                                                        int, rtx *, int));
+                                                        int, rtx *, int,
+                                                        int, int *));
 static rtx emit_library_call_value_1           PARAMS ((int, rtx, rtx,
                                                         enum libcall_type,
                                                         enum machine_mode,
                                                         int, va_list));
 static int special_function_p                  PARAMS ((tree, int));
-static int flags_from_decl_or_type             PARAMS ((tree));
 static rtx try_to_integrate                    PARAMS ((tree, tree, rtx,
                                                         int, tree, rtx));
 static int check_sibcall_argument_overlap_1    PARAMS ((rtx));
-static int check_sibcall_argument_overlap      PARAMS ((rtx, struct arg_data *));
+static int check_sibcall_argument_overlap      PARAMS ((rtx, struct arg_data *,
+                                                        int));
 
 static int combine_pending_stack_adjustment_and_call
                                                 PARAMS ((int, struct args_size *, int));
+static tree fix_unsafe_tree            PARAMS ((tree));
 
 #ifdef REG_PARM_STACK_SPACE
 static rtx save_fixed_argument_area    PARAMS ((int, rtx, int *, int *));
@@ -442,7 +420,7 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen, sibcallp)
 static void
 emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
             struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop,
-            call_fusage, ecf_flags)
+            call_fusage, ecf_flags, args_so_far)
      rtx funexp;
      tree fndecl ATTRIBUTE_UNUSED;
      tree funtype ATTRIBUTE_UNUSED;
@@ -454,6 +432,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
      int old_inhibit_defer_pop;
      rtx call_fusage;
      int ecf_flags;
+     CUMULATIVE_ARGS *args_so_far ATTRIBUTE_UNUSED;
 {
   rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
   rtx call_insn;
@@ -464,6 +443,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
   struct_value_size_rtx = GEN_INT (struct_value_size);
 #endif
 
+#ifdef CALL_POPS_ARGS
+  n_popped += CALL_POPS_ARGS (* args_so_far);
+#endif
+  
   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
      and we don't want to load it into a register as an optimization,
      because prepare_call_address already did it if it should be done.  */
@@ -646,9 +629,12 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
         If returning from the subroutine does pop the args, indicate that the
         stack pointer will be changed.  */
 
-      if (rounded_stack_size != 0 && ! (ecf_flags & ECF_SP_DEPRESSED))
+      if (rounded_stack_size != 0)
        {
-         if (flag_defer_pop && inhibit_defer_pop == 0
+         if (ecf_flags & ECF_SP_DEPRESSED)
+           /* Just pretend we did the pop.  */
+           stack_pointer_delta -= rounded_stack_size;
+         else if (flag_defer_pop && inhibit_defer_pop == 0
              && ! (ecf_flags & (ECF_CONST | ECF_PURE)))
            pending_stack_adjust += rounded_stack_size;
          else
@@ -786,35 +772,60 @@ setjmp_call_p (fndecl)
   return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
 }
 
-/* Detect flags (function attributes) from the function type node.  */
+/* Return true when exp contains alloca call.  */
+bool
+alloca_call_p (exp)
+     tree exp;
+{
+  if (TREE_CODE (exp) == CALL_EXPR
+      && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+      && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+         == FUNCTION_DECL)
+      && (special_function_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+                             0) & ECF_MAY_BE_ALLOCA))
+    return true;
+  return false;
+}
+
+/* Detect flags (function attributes) from the function decl or type node.  */
 
-static int
+int
 flags_from_decl_or_type (exp)
      tree exp;
 {
   int flags = 0;
-
+  tree type = exp;
   /* ??? We can't set IS_MALLOC for function types?  */
   if (DECL_P (exp))
     {
+      type = TREE_TYPE (exp);
+
       /* The function exp may have the `malloc' attribute.  */
       if (DECL_P (exp) && DECL_IS_MALLOC (exp))
        flags |= ECF_MALLOC;
 
       /* The function exp may have the `pure' attribute.  */
       if (DECL_P (exp) && DECL_IS_PURE (exp))
-       flags |= ECF_PURE;
+       flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
 
       if (TREE_NOTHROW (exp))
        flags |= ECF_NOTHROW;
     }
 
   if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
-    flags |= ECF_CONST;
+    flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
 
   if (TREE_THIS_VOLATILE (exp))
     flags |= ECF_NORETURN;
 
+  /* Mark if the function returns with the stack pointer depressed.   We
+     cannot consider it pure or constant in that case.  */
+  if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
+    {
+      flags |= ECF_SP_DEPRESSED;
+      flags &= ~(ECF_PURE | ECF_CONST | ECF_LIBCALL_BLOCK);
+    }
+
   return flags;
 }
 
@@ -853,6 +864,12 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen)
            emit_queue ();
          }
 
+       /* 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.  */
 
@@ -944,11 +961,8 @@ save_fixed_argument_area (reg_parm_stack_space, argblock,
       if (save_mode == BLKmode)
        {
          save_area = assign_stack_temp (BLKmode, num_to_save, 0);
-         /* Cannot use emit_block_move here because it can be done by a
-            library call which in turn gets into this place again and deadly
-            infinite recursion happens.  */
-         move_by_pieces (validize_mem (save_area), stack_area, num_to_save,
-                         PARM_BOUNDARY);
+         emit_block_move (validize_mem (save_area), stack_area,
+                          GEN_INT (num_to_save), BLOCK_OP_CALL_PARM);
        }
       else
        {
@@ -985,11 +999,9 @@ restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save)
   if (save_mode != BLKmode)
     emit_move_insn (stack_area, save_area);
   else
-    /* Cannot use emit_block_move here because it can be done by a library
-       call which in turn gets into this place again and deadly infinite
-       recursion happens.  */
-    move_by_pieces (stack_area, validize_mem (save_area),
-                   high_to_save - low_to_save + 1, PARM_BOUNDARY);
+    emit_block_move (stack_area, validize_mem (save_area),
+                    GEN_INT (high_to_save - low_to_save + 1),
+                    BLOCK_OP_CALL_PARM);
 }
 #endif /* REG_PARM_STACK_SPACE */
 
@@ -1029,7 +1041,8 @@ store_unaligned_arguments_into_pseudos (args, num_actuals)
           significant byte (to the right).  On a BYTES_BIG_ENDIAN machine,
           this means we must skip the empty high order bytes when
           calculating the bit offset.  */
-       if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD)
+       if (BYTES_BIG_ENDIAN
+           && bytes < UNITS_PER_WORD)
          big_endian_correction = (BITS_PER_WORD  - (bytes * BITS_PER_UNIT));
 
        for (j = 0; j < args[i].n_aligned_regs; j++)
@@ -1207,6 +1220,16 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
                                           args[i].tree_value);
              type = build_pointer_type (type);
            }
+         else if (TREE_CODE (args[i].tree_value) == TARGET_EXPR)
+           {
+             /* In the V3 C++ ABI, parameters are destroyed in the caller.
+                We implement this by passing the address of the temporary
+                rather than expanding it into another allocated slot.  */
+             args[i].tree_value = build1 (ADDR_EXPR,
+                                          build_pointer_type (type),
+                                          args[i].tree_value);
+             type = build_pointer_type (type);
+           }
          else
            {
              /* We make a copy of the object and pass the address to the
@@ -1239,7 +1262,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
                copy = assign_temp (type, 0, 1, 0);
 
              store_expr (args[i].tree_value, copy, 0);
-             *ecf_flags &= ~(ECF_CONST | ECF_PURE);
+             *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
 
              args[i].tree_value = build1 (ADDR_EXPR,
                                           build_pointer_type (type),
@@ -1298,7 +1321,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
       /* If this is an addressable type, we cannot pre-evaluate it.  Thus,
         we cannot consider this function call constant.  */
       if (TREE_ADDRESSABLE (type))
-       *ecf_flags &= ~(ECF_CONST | ECF_PURE);
+       *ecf_flags &= ~ECF_LIBCALL_BLOCK;
 
       /* Compute the stack-size of this argument.  */
       if (args[i].reg == 0 || args[i].partial != 0
@@ -1469,7 +1492,7 @@ precompute_arguments (flags, num_actuals, args)
      worse code)  */
 
   for (i = 0; i < num_actuals; i++)
-    if ((flags & (ECF_CONST | ECF_PURE))
+    if ((flags & ECF_LIBCALL_BLOCK)
        || calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS))
       {
        enum machine_mode mode;
@@ -1478,14 +1501,9 @@ precompute_arguments (flags, num_actuals, args)
        if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
          abort ();
 
-       push_temp_slots ();
-
        args[i].value
          = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
 
-       preserve_temp_slots (args[i].value);
-       pop_temp_slots ();
-
        /* ANSI doesn't require a sequence point here,
           but PCC has one, so this will avoid some problems.  */
        emit_queue ();
@@ -1509,8 +1527,8 @@ precompute_arguments (flags, num_actuals, args)
                args[i].initial_value
                  = gen_lowpart_SUBREG (mode, args[i].value);
                SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1;
-               SUBREG_PROMOTED_UNSIGNED_P (args[i].initial_value)
-                 = args[i].unsignedp;
+               SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
+                 args[i].unsignedp);
              }
 #endif
          }
@@ -1670,22 +1688,9 @@ rtx_for_function_call (fndecl, exp)
   else
     /* Generate an rtx (probably a pseudo-register) for the address.  */
     {
-      rtx funaddr;
       push_temp_slots ();
-      funaddr = funexp
-       = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      funexp = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
       pop_temp_slots ();       /* FUNEXP can't be BLKmode.  */
-
-      /* Check the function is executable.  */
-      if (current_function_check_memory_usage)
-       {
-#ifdef POINTERS_EXTEND_UNSIGNED
-         if (GET_MODE (funexp) != ptr_mode)
-           funaddr = convert_memory_address (ptr_mode, funexp);
-#endif
-         emit_library_call (chkr_check_exec_libfunc, LCT_CONST_MAKE_BLOCK,
-                            VOIDmode, 1, funaddr, ptr_mode);
-       }
       emit_queue ();
     }
   return funexp;
@@ -1696,14 +1701,20 @@ rtx_for_function_call (fndecl, exp)
    expressions were already evaluated.
 
    Mark all register-parms as living through the call, putting these USE
-   insns in the CALL_INSN_FUNCTION_USAGE field.  */
+   insns in the CALL_INSN_FUNCTION_USAGE field.  
+   When IS_SIBCALL, perform the check_sibcall_overlap_argument_overlap
+   checking, setting *SIBCALL_FAILURE if appropriate.  */
 
 static void
-load_register_parameters (args, num_actuals, call_fusage, flags)
+load_register_parameters (args, num_actuals, call_fusage, flags, 
+                           is_sibcall, sibcall_failure)
      struct arg_data *args;
      int num_actuals;
      rtx *call_fusage;
      int flags;
+     int is_sibcall;
+     int *sibcall_failure;
 {
   int i, j;
 
@@ -1720,6 +1731,7 @@ load_register_parameters (args, num_actuals, call_fusage, flags)
 
       if (reg)
        {
+         rtx before_arg = get_last_insn ();
          /* Set to non-negative if must move a word at a time, even if just
             one word (e.g, partial == 1 && mode == DFmode).  Set to -1 if
             we just use a normal move insn.  This value can be zero if the
@@ -1757,6 +1769,13 @@ load_register_parameters (args, num_actuals, call_fusage, flags)
                               validize_mem (args[i].value), nregs,
                               args[i].mode);
 
+         /* When a parameter is a block, and perhaps in other cases, it is
+            possible that it did a load from an argument slot that was
+            already clobbered.  */
+         if (is_sibcall
+             && check_sibcall_argument_overlap (before_arg, &args[i], 0))
+           *sibcall_failure = 1;
+
          /* Handle calls that pass values in multiple non-contiguous
             locations.  The Irix 6 ABI has examples of this.  */
          if (GET_CODE (reg) == PARALLEL)
@@ -1806,7 +1825,7 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr)
   timevar_pop (TV_INTEGRATION);
 
   /* If inlining succeeded, return.  */
-  if (temp != (rtx) (HOST_WIDE_INT) - 1)
+  if (temp != (rtx) (size_t) - 1)
     {
       if (ACCUMULATE_OUTGOING_ARGS)
        {
@@ -1862,7 +1881,7 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr)
                                                NULL_RTX, BITS_PER_UNIT);
                  seq = get_insns ();
                  end_sequence ();
-                 emit_insns_before (seq, first_insn);
+                 emit_insn_before (seq, first_insn);
                  emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
                }
            }
@@ -1885,8 +1904,8 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr)
       warning_with_decl (fndecl, "inlining failed in call to `%s'");
       warning ("called from here");
     }
-  mark_addressable (fndecl);
-  return (rtx) (HOST_WIDE_INT) - 1;
+  (*lang_hooks.mark_addressable) (fndecl);
+  return (rtx) (size_t) - 1;
 }
 
 /* We need to pop PENDING_STACK_ADJUST bytes.  But, if the arguments
@@ -1951,7 +1970,7 @@ combine_pending_stack_adjustment_and_call (unadjusted_args_size,
 /* Scan X expression if it does not dereference any argument slots
    we already clobbered by tail call arguments (as noted in stored_args_map
    bitmap).
-   Return non-zero if X expression dereferences such argument slots,
+   Return nonzero if X expression dereferences such argument slots,
    zero otherwise.  */
 
 static int
@@ -2013,14 +2032,16 @@ check_sibcall_argument_overlap_1 (x)
 
 /* Scan sequence after INSN if it does not dereference any argument slots
    we already clobbered by tail call arguments (as noted in stored_args_map
-   bitmap).  Add stack slots for ARG to stored_args_map bitmap afterwards.
-   Return non-zero if sequence after INSN dereferences such argument slots,
-   zero otherwise.  */
+   bitmap).  If MARK_STORED_ARGS_MAP, add stack slots for ARG to
+   stored_args_map bitmap afterwards (when ARG is a register MARK_STORED_ARGS_MAP
+   should be 0).  Return nonzero if sequence after INSN dereferences such argument
+   slots, zero otherwise.  */
 
 static int
-check_sibcall_argument_overlap (insn, arg)
+check_sibcall_argument_overlap (insn, arg, mark_stored_args_map)
      rtx insn;
      struct arg_data *arg;
+     int mark_stored_args_map;
 {
   int low, high;
 
@@ -2034,17 +2055,49 @@ check_sibcall_argument_overlap (insn, arg)
        && check_sibcall_argument_overlap_1 (PATTERN (insn)))
       break;
 
+  if (mark_stored_args_map)
+    {
 #ifdef ARGS_GROW_DOWNWARD
-  low = -arg->offset.constant - arg->size.constant;
+      low = -arg->slot_offset.constant - arg->size.constant;
 #else
-  low = arg->offset.constant;
+      low = arg->slot_offset.constant;
 #endif
 
-  for (high = low + arg->size.constant; low < high; low++)
-    SET_BIT (stored_args_map, low);
+      for (high = low + arg->size.constant; low < high; low++)
+       SET_BIT (stored_args_map, low);
+    }
   return insn != NULL_RTX;
 }
 
+static tree
+fix_unsafe_tree (t)
+     tree t;
+{
+  switch (unsafe_for_reeval (t))
+    {
+    case 0: /* Safe.  */
+      break;
+
+    case 1: /* Mildly unsafe.  */
+      t = unsave_expr (t);
+      break;
+
+    case 2: /* Wildly unsafe.  */
+      {
+       tree var = build_decl (VAR_DECL, NULL_TREE,
+                              TREE_TYPE (t));
+       SET_DECL_RTL (var,
+                     expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL));
+       t = var;
+      }
+      break;
+
+    default:
+      abort ();
+    }
+  return t;
+}
+
 /* Generate all the code for a function call
    and return an rtx for its value.
    Store the value in TARGET (specified as an rtx) if convenient.
@@ -2162,13 +2215,6 @@ expand_call (exp, target, ignore)
   /* The alignment of the stack, in bytes.  */
   HOST_WIDE_INT preferred_unit_stack_boundary;
 
-  /* The value of the function call can be put in a hard register.  But
-     if -fcheck-memory-usage, code which invokes functions (and thus
-     damages some hard registers) can be inserted before using the value.
-     So, target is always a pseudo-register in that case.  */
-  if (current_function_check_memory_usage)
-    target = 0;
-
   /* See if this is "nothrow" function call.  */
   if (TREE_NOTHROW (exp))
     flags |= ECF_NOTHROW;
@@ -2198,7 +2244,7 @@ expand_call (exp, target, ignore)
              warning_with_decl (fndecl, "can't inline call to `%s'");
              warning ("called from here");
            }
-         mark_addressable (fndecl);
+         (*lang_hooks.mark_addressable) (fndecl);
        }
 
       flags |= flags_from_decl_or_type (fndecl);
@@ -2209,14 +2255,6 @@ expand_call (exp, target, ignore)
   else
     flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
 
-  /* Mark if the function returns with the stack pointer depressed.  */
-  if (TREE_CODE (TREE_TYPE (TREE_TYPE (p))) == FUNCTION_TYPE
-      && TYPE_RETURNS_STACK_DEPRESSED (TREE_TYPE (TREE_TYPE (p))))
-    {
-      flags |= ECF_SP_DEPRESSED;
-      flags &= ~(ECF_PURE | ECF_CONST);
-    }
-
 #ifdef REG_PARM_STACK_SPACE
 #ifdef MAYBE_REG_PARM_STACK_SPACE
   reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
@@ -2241,7 +2279,7 @@ expand_call (exp, target, ignore)
   if (aggregate_value_p (exp))
     {
       /* This call returns a big structure.  */
-      flags &= ~(ECF_CONST | ECF_PURE);
+      flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
 
 #ifdef PCC_STATIC_STRUCT_RETURN
       {
@@ -2252,7 +2290,7 @@ expand_call (exp, target, ignore)
            /* In case this is a static function, note that it has been
               used.  */
            if (! TREE_ADDRESSABLE (fndecl))
-             mark_addressable (fndecl);
+             (*lang_hooks.mark_addressable) (fndecl);
            is_integrable = 0;
          }
       }
@@ -2260,7 +2298,17 @@ expand_call (exp, target, ignore)
       {
        struct_value_size = int_size_in_bytes (TREE_TYPE (exp));
 
-       if (target && GET_CODE (target) == MEM)
+       if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (exp))
+         {
+           /* The structure value address arg is already in actparms.
+              Pull it out.  It might be nice to just leave it there, but
+              we need to set structure_value_addr.  */
+           tree return_arg = TREE_VALUE (actparms);
+           actparms = TREE_CHAIN (actparms);
+           structure_value_addr = expand_expr (return_arg, NULL_RTX,
+                                               VOIDmode, EXPAND_NORMAL);
+         }
+       else if (target && GET_CODE (target) == MEM)
          structure_value_addr = XEXP (target, 0);
        else
          {
@@ -2284,7 +2332,7 @@ expand_call (exp, target, ignore)
       rtx temp = try_to_integrate (fndecl, actparms, target,
                                   ignore, TREE_TYPE (exp),
                                   structure_value_addr);
-      if (temp != (rtx) (HOST_WIDE_INT) - 1)
+      if (temp != (rtx) (size_t) - 1)
        return temp;
     }
 
@@ -2388,7 +2436,7 @@ expand_call (exp, target, ignore)
         do this eventually, but it is too complicated to keep track of
         what insns go in the cse'able block and which don't.  */
 
-      flags &= ~(ECF_CONST | ECF_PURE);
+      flags &= ~ECF_LIBCALL_BLOCK;
       must_preallocate = 1;
     }
 
@@ -2446,17 +2494,13 @@ expand_call (exp, target, ignore)
         It does not seem worth the effort since few optimizable
         sibling calls will return a structure.  */
       || structure_value_addr != NULL_RTX
-      /* If the register holding the address is a callee saved
-        register, then we lose.  We have no way to prevent that,
-        so we only allow calls to named functions.  */
-      /* ??? This could be done by having the insn constraints
-        use a register class that is all call-clobbered.  Any
-        reload insns generated to fix things up would appear
-        before the sibcall_epilogue.  */
-      || fndecl == NULL_TREE
-      || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP))
-      || TREE_THIS_VOLATILE (fndecl)
-      || !FUNCTION_OK_FOR_SIBCALL (fndecl)
+      /* Check whether the target is able to optimize the call
+        into a sibcall.  */
+      || !(*targetm.function_ok_for_sibcall) (fndecl, exp)
+      /* Functions that do not return exactly once may not be sibcall
+         optimized.  */
+      || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP | ECF_NORETURN))
+      || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
       /* If this function requires more stack slots than the current
         function, we cannot change it into a sibling call.  */
       || args_size.constant > current_function_args_size
@@ -2466,7 +2510,7 @@ expand_call (exp, target, ignore)
         != RETURN_POPS_ARGS (current_function_decl,
                              TREE_TYPE (current_function_decl),
                              current_function_args_size))
-  try_tail_call = 0;
+    try_tail_call = 0;
 
   if (try_tail_call || try_tail_recursion)
     {
@@ -2502,35 +2546,16 @@ expand_call (exp, target, ignore)
 
       for (; i != end; i += inc)
        {
-         switch (unsafe_for_reeval (args[i].tree_value))
-           {
-           case 0: /* Safe.  */
-             break;
-
-           case 1: /* Mildly unsafe.  */
-             args[i].tree_value = unsave_expr (args[i].tree_value);
-             break;
-
-           case 2: /* Wildly unsafe.  */
-             {
-               tree var = build_decl (VAR_DECL, NULL_TREE,
-                                      TREE_TYPE (args[i].tree_value));
-               SET_DECL_RTL (var,
-                             expand_expr (args[i].tree_value, NULL_RTX,
-                                          VOIDmode, EXPAND_NORMAL));
-               args[i].tree_value = var;
-             }
-             break;
-
-           default:
-             abort ();
-           }
+          args[i].tree_value = fix_unsafe_tree (args[i].tree_value);
          /* We need to build actparms for optimize_tail_recursion.  We can
             safely trash away TREE_PURPOSE, since it is unused by this
             function.  */
          if (try_tail_recursion)
            actparms = tree_cons (NULL_TREE, args[i].tree_value, actparms);
        }
+      /* Do the same for the function address if it is an expression. */
+      if (!fndecl)
+        TREE_OPERAND (exp, 0) = fix_unsafe_tree (TREE_OPERAND (exp, 0));
       /* Expanding one of those dangerous arguments could have added
         cleanups, but otherwise give it a whirl.  */
       if (any_pending_cleanups (1))
@@ -2588,7 +2613,7 @@ expand_call (exp, target, ignore)
         is subject to race conditions, just as with multithreaded
         programs.  */
 
-      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__bb_fork_func"),
+      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__gcov_flush"),
                         LCT_ALWAYS_RETURN,
                         VOIDmode, 0);
     }
@@ -2661,21 +2686,19 @@ expand_call (exp, target, ignore)
       /* Don't let pending stack adjusts add up to too much.
         Also, do all pending adjustments now if there is any chance
         this might be a call to alloca or if we are expanding a sibling
-        call sequence.  */
+        call sequence or if we are calling a function that is to return
+        with stack pointer depressed.  */
       if (pending_stack_adjust >= 32
-         || (pending_stack_adjust > 0 && (flags & ECF_MAY_BE_ALLOCA))
+         || (pending_stack_adjust > 0
+             && (flags & (ECF_MAY_BE_ALLOCA | ECF_SP_DEPRESSED)))
          || pass == 0)
        do_pending_stack_adjust ();
 
       /* When calling a const function, we must pop the stack args right away,
         so that the pop is deleted or moved with the call.  */
-      if (flags & (ECF_CONST | ECF_PURE))
+      if (pass && (flags & ECF_LIBCALL_BLOCK))
        NO_DEFER_POP;
 
-      /* Push the temporary stack slot level so that we can free any
-        temporaries we make.  */
-      push_temp_slots ();
-
 #ifdef FINAL_REG_PARM_STACK_SPACE
       reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
                                                         args_size.var);
@@ -2686,7 +2709,7 @@ expand_call (exp, target, ignore)
 
       /* Now we are about to start emitting insns that can be deleted
         if a libcall is deleted.  */
-      if (flags & (ECF_CONST | ECF_PURE | ECF_MALLOC))
+      if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC)))
        start_sequence ();
 
       adjusted_args_size = args_size;
@@ -2708,6 +2731,12 @@ expand_call (exp, target, ignore)
       if (pass == 0)
        {
          argblock = virtual_incoming_args_rtx;
+         argblock
+#ifdef STACK_GROWS_DOWNWARD
+           = plus_constant (argblock, current_function_pretend_args_size);
+#else
+           = plus_constant (argblock, -current_function_pretend_args_size);
+#endif
          stored_args_map = sbitmap_alloc (args_size.constant);
          sbitmap_zero (stored_args_map);
        }
@@ -2902,7 +2931,7 @@ expand_call (exp, target, ignore)
          /* When the stack adjustment is pending, we get better code
             by combining the adjustments.  */
          if (pending_stack_adjust
-             && ! (flags & (ECF_CONST | ECF_PURE))
+             && ! (flags & ECF_LIBCALL_BLOCK)
              && ! inhibit_defer_pop)
            {
              pending_stack_adjust
@@ -2962,7 +2991,7 @@ expand_call (exp, target, ignore)
                               reg_parm_stack_space)
                || (pass == 0
                    && check_sibcall_argument_overlap (before_arg,
-                                                      &args[i])))
+                                                      &args[i], 1)))
              sibcall_failure = 1;
          }
 
@@ -2986,7 +3015,7 @@ expand_call (exp, target, ignore)
                                 reg_parm_stack_space)
                  || (pass == 0
                      && check_sibcall_argument_overlap (before_arg,
-                                                        &args[i])))
+                                                        &args[i], 1)))
                sibcall_failure = 1;
            }
 
@@ -3014,16 +3043,6 @@ expand_call (exp, target, ignore)
                                     force_operand (structure_value_addr,
                                                    NULL_RTX)));
 
-         /* Mark the memory for the aggregate as write-only.  */
-         if (current_function_check_memory_usage)
-           emit_library_call (chkr_set_right_libfunc, LCT_CONST_MAKE_BLOCK,
-                              VOIDmode, 3,
-                              structure_value_addr, ptr_mode,
-                              GEN_INT (struct_value_size),
-                              TYPE_MODE (sizetype),
-                              GEN_INT (MEMORY_USE_WO),
-                              TYPE_MODE (integer_type_node));
-
          if (GET_CODE (struct_value_rtx) == REG)
            use_reg (&call_fusage, struct_value_rtx);
        }
@@ -3031,7 +3050,8 @@ expand_call (exp, target, ignore)
       funexp = prepare_call_address (funexp, fndecl, &call_fusage,
                                     reg_parm_seen, pass == 0);
 
-      load_register_parameters (args, num_actuals, &call_fusage, flags);
+      load_register_parameters (args, num_actuals, &call_fusage, flags,
+                               pass == 0, &sibcall_failure);
 
       /* Perform postincrements before actually calling the function.  */
       emit_queue ();
@@ -3062,7 +3082,7 @@ expand_call (exp, target, ignore)
       emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
                   adjusted_args_size.constant, struct_value_size,
                   next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
-                  flags);
+                  flags, & args_so_far);
 
       /* Verify that we've deallocated all the stack we used.  */
       if (pass
@@ -3073,46 +3093,49 @@ expand_call (exp, target, ignore)
         Test valreg so we don't crash; may safely ignore `const'
         if return type is void.  Disable for PARALLEL return values, because
         we have no way to move such values into a pseudo register.  */
-      if (pass
-         && (flags & (ECF_CONST | ECF_PURE))
-         && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+      if (pass && (flags & ECF_LIBCALL_BLOCK))
        {
-         rtx note = 0;
-         rtx temp = gen_reg_rtx (GET_MODE (valreg));
          rtx insns;
 
-         /* Mark the return value as a pointer if needed.  */
-         if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
-           mark_reg_pointer (temp, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))));
-
-         /* Construct an "equal form" for the value which mentions all the
-            arguments in order as well as the function name.  */
-         for (i = 0; i < num_actuals; i++)
-           note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note);
-         note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note);
-
-         insns = get_insns ();
-         end_sequence ();
-
-         if (flags & ECF_PURE)
-           note = gen_rtx_EXPR_LIST (VOIDmode,
-              gen_rtx_USE (VOIDmode,
-                           gen_rtx_MEM (BLKmode,
-                                        gen_rtx_SCRATCH (VOIDmode))), note);
-
-         emit_libcall_block (insns, temp, valreg, note);
-
-         valreg = temp;
-       }
-      else if (flags & (ECF_CONST | ECF_PURE))
-       {
-         /* Otherwise, just write out the sequence without a note.  */
-         rtx insns = get_insns ();
-
-         end_sequence ();
-         emit_insns (insns);
+         if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
+           {
+             insns = get_insns ();
+             end_sequence ();
+             emit_insn (insns);
+           }
+         else
+           {
+             rtx note = 0;
+             rtx temp = gen_reg_rtx (GET_MODE (valreg));
+
+             /* Mark the return value as a pointer if needed.  */
+             if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
+               mark_reg_pointer (temp,
+                                 TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp))));
+
+             /* Construct an "equal form" for the value which mentions all the
+                arguments in order as well as the function name.  */
+             for (i = 0; i < num_actuals; i++)
+               note = gen_rtx_EXPR_LIST (VOIDmode,
+                                         args[i].initial_value, note);
+             note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note);
+
+             insns = get_insns ();
+             end_sequence ();
+
+             if (flags & ECF_PURE)
+               note = gen_rtx_EXPR_LIST (VOIDmode,
+                       gen_rtx_USE (VOIDmode,
+                                    gen_rtx_MEM (BLKmode,
+                                                 gen_rtx_SCRATCH (VOIDmode))),
+                       note);
+
+             emit_libcall_block (insns, temp, valreg, note);
+
+             valreg = temp;
+           }
        }
-      else if (flags & ECF_MALLOC)
+      else if (pass && (flags & ECF_MALLOC))
        {
          rtx temp = gen_reg_rtx (GET_MODE (valreg));
          rtx last, insns;
@@ -3132,7 +3155,7 @@ expand_call (exp, target, ignore)
          /* Write out the sequence.  */
          insns = get_insns ();
          end_sequence ();
-         emit_insns (insns);
+         emit_insn (insns);
          valreg = temp;
        }
 
@@ -3183,9 +3206,7 @@ expand_call (exp, target, ignore)
 
       if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
          || ignore)
-       {
-         target = const0_rtx;
-       }
+       target = const0_rtx;
       else if (structure_value_addr)
        {
          if (target == 0 || GET_CODE (target) != MEM)
@@ -3279,7 +3300,7 @@ expand_call (exp, target, ignore)
          }
          target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
          SUBREG_PROMOTED_VAR_P (target) = 1;
-         SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;
+         SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp);
        }
 #endif
 
@@ -3318,9 +3339,9 @@ expand_call (exp, target, ignore)
                if (save_mode != BLKmode)
                  emit_move_insn (stack_area, args[i].save_area);
                else
-                 emit_block_move (stack_area,
-                                  validize_mem (args[i].save_area),
-                                  GEN_INT (args[i].size.constant));
+                 emit_block_move (stack_area, args[i].save_area,
+                                  GEN_INT (args[i].size.constant),
+                                  BLOCK_OP_CALL_PARM);
              }
 
          highest_outgoing_arg_in_use = initial_highest_arg_in_use;
@@ -3334,8 +3355,6 @@ expand_call (exp, target, ignore)
       if ((flags & ECF_MAY_BE_ALLOCA) && nonlocal_goto_handler_slots != 0)
        emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
 
-      pop_temp_slots ();
-
       /* Free up storage we no longer need.  */
       for (i = 0; i < num_actuals; ++i)
        if (args[i].aligned_regs)
@@ -3423,7 +3442,7 @@ expand_call (exp, target, ignore)
                                                tail_recursion_label));
     }
   else
-    emit_insns (normal_call_insns);
+    emit_insn (normal_call_insns);
 
   currently_expanding_call--;
 
@@ -3487,6 +3506,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   int reg_parm_stack_space = 0;
   int needed;
   rtx before_call;
+  tree tfom;                   /* type_for_mode (outmode, 0) */
 
 #ifdef REG_PARM_STACK_SPACE
   /* Define the boundary of the register parm stack space that needs to be
@@ -3513,15 +3533,18 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   switch (fn_type)
     {
     case LCT_NORMAL:
+      break;
     case LCT_CONST:
+      flags |= ECF_CONST;
+      break;
     case LCT_PURE:
-      /* Nothing to do here.  */
+      flags |= ECF_PURE;
       break;
     case LCT_CONST_MAKE_BLOCK:
-      flags |= ECF_CONST;
+      flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
       break;
     case LCT_PURE_MAKE_BLOCK:
-      flags |= ECF_PURE;
+      flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
       break;
     case LCT_NORETURN:
       flags |= ECF_NORETURN;
@@ -3545,27 +3568,31 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 
   /* If this kind of value comes back in memory,
      decide where in memory it should come back.  */
-  if (outmode != VOIDmode && aggregate_value_p (type_for_mode (outmode, 0)))
+  if (outmode != VOIDmode)
     {
+      tfom = (*lang_hooks.types.type_for_mode) (outmode, 0);
+      if (aggregate_value_p (tfom))
+       {
 #ifdef PCC_STATIC_STRUCT_RETURN
-      rtx pointer_reg
-       = hard_function_value (build_pointer_type (type_for_mode (outmode, 0)),
-                              0, 0);
-      mem_value = gen_rtx_MEM (outmode, pointer_reg);
-      pcc_struct_value = 1;
-      if (value == 0)
-       value = gen_reg_rtx (outmode);
+         rtx pointer_reg
+           = hard_function_value (build_pointer_type (tfom), 0, 0);
+         mem_value = gen_rtx_MEM (outmode, pointer_reg);
+         pcc_struct_value = 1;
+         if (value == 0)
+           value = gen_reg_rtx (outmode);
 #else /* not PCC_STATIC_STRUCT_RETURN */
-      struct_value_size = GET_MODE_SIZE (outmode);
-      if (value != 0 && GET_CODE (value) == MEM)
-       mem_value = value;
-      else
-       mem_value = assign_temp (type_for_mode (outmode, 0), 0, 1, 1);
+         struct_value_size = GET_MODE_SIZE (outmode);
+         if (value != 0 && GET_CODE (value) == MEM)
+           mem_value = value;
+         else
+           mem_value = assign_temp (tfom, 0, 1, 1);
 #endif
-
-      /* This call returns a big structure.  */
-      flags &= ~(ECF_CONST | ECF_PURE);
+         /* This call returns a big structure.  */
+         flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+       }
     }
+  else
+    tfom = void_type_node;
 
   /* ??? Unfinished: must pass the memory address as an argument.  */
 
@@ -3592,7 +3619,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 
   /* Now we are about to start emitting insns that can be deleted
      if a libcall is deleted.  */
-  if (flags & (ECF_CONST | ECF_PURE))
+  if (flags & ECF_LIBCALL_BLOCK)
     start_sequence ();
 
   push_temp_slots ();
@@ -3674,16 +3701,35 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 #endif
            ;
 
+         /* loop.c won't look at CALL_INSN_FUNCTION_USAGE of const/pure
+            functions, so we have to pretend this isn't such a function.  */
+         if (flags & ECF_LIBCALL_BLOCK)
+           {
+             rtx insns = get_insns ();
+             end_sequence ();
+             emit_insn (insns);
+           }
+         flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK);
+
+         /* If this was a CONST function, it is now PURE since
+            it now reads memory.  */
+         if (flags & ECF_CONST)
+           {
+             flags &= ~ECF_CONST;
+             flags |= ECF_PURE;
+           }
+
          if (GET_MODE (val) == MEM && ! must_copy)
            slot = val;
          else if (must_copy)
            {
-             slot = assign_temp (type_for_mode (mode, 0), 0, 1, 1);
+             slot = assign_temp ((*lang_hooks.types.type_for_mode) (mode, 0),
+                                 0, 1, 1);
              emit_move_insn (slot, val);
            }
          else
            {
-             tree type = type_for_mode (mode, 0);
+             tree type = (*lang_hooks.types.type_for_mode) (mode, 0);
 
              slot = gen_rtx_MEM (mode,
                                  expand_expr (build1 (ADDR_EXPR,
@@ -3893,8 +3939,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
            {
              save_area = assign_stack_temp (BLKmode, num_to_save, 0);
              set_mem_align (save_area, PARM_BOUNDARY);
-             emit_block_move (validize_mem (save_area), stack_area,
-                              GEN_INT (num_to_save));
+             emit_block_move (save_area, stack_area, GEN_INT (num_to_save),
+                              BLOCK_OP_CALL_PARM);
            }
          else
            {
@@ -3962,8 +4008,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
                }
            }
 
-         emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
-                         argblock, GEN_INT (argvec[argnum].offset.constant),
+         emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY,
+                         partial, reg, 0, argblock,
+                         GEN_INT (argvec[argnum].offset.constant),
                          reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad));
 
          /* Now mark the segment we just used.  */
@@ -4050,13 +4097,12 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 
   emit_call_1 (fun,
               get_identifier (XSTR (orgfun, 0)),
-              build_function_type (outmode == VOIDmode ? void_type_node
-                                   : type_for_mode (outmode, 0), NULL_TREE),
+              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),
               valreg,
-              old_inhibit_defer_pop + 1, call_fusage, flags);
+              old_inhibit_defer_pop + 1, call_fusage, flags, & args_so_far);
 
   /* For calls to `setjmp', etc., inform flow.c it should complain
      if nonvolatile values are live.  For functions that cannot return,
@@ -4087,40 +4133,42 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      Test valreg so we don't crash; may safely ignore `const'
      if return type is void.  Disable for PARALLEL return values, because
      we have no way to move such values into a pseudo register.  */
-  if ((flags & (ECF_CONST | ECF_PURE))
-      && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+  if (flags & ECF_LIBCALL_BLOCK)
     {
-      rtx note = 0;
-      rtx temp = gen_reg_rtx (GET_MODE (valreg));
       rtx insns;
-      int i;
 
-      /* Construct an "equal form" for the value which mentions all the
-        arguments in order as well as the function name.  */
-      for (i = 0; i < nargs; i++)
-       note = gen_rtx_EXPR_LIST (VOIDmode, argvec[i].value, note);
-      note = gen_rtx_EXPR_LIST (VOIDmode, fun, note);
+      if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
+       {
+         insns = get_insns ();
+         end_sequence ();
+         emit_insn (insns);
+       }
+      else
+       {
+         rtx note = 0;
+         rtx temp = gen_reg_rtx (GET_MODE (valreg));
+         int i;
 
-      insns = get_insns ();
-      end_sequence ();
+         /* Construct an "equal form" for the value which mentions all the
+            arguments in order as well as the function name.  */
+         for (i = 0; i < nargs; i++)
+           note = gen_rtx_EXPR_LIST (VOIDmode, argvec[i].value, note);
+         note = gen_rtx_EXPR_LIST (VOIDmode, fun, note);
 
-      if (flags & ECF_PURE)
-       note = gen_rtx_EXPR_LIST (VOIDmode,
-          gen_rtx_USE (VOIDmode,
-                       gen_rtx_MEM (BLKmode,
-                                    gen_rtx_SCRATCH (VOIDmode))), note);
+         insns = get_insns ();
+         end_sequence ();
 
-      emit_libcall_block (insns, temp, valreg, note);
+         if (flags & ECF_PURE)
+           note = gen_rtx_EXPR_LIST (VOIDmode,
+                       gen_rtx_USE (VOIDmode,
+                                    gen_rtx_MEM (BLKmode,
+                                                 gen_rtx_SCRATCH (VOIDmode))),
+                       note);
 
-      valreg = temp;
-    }
-  else if (flags & (ECF_CONST | ECF_PURE))
-    {
-      /* Otherwise, just write out the sequence without a note.  */
-      rtx insns = get_insns ();
+         emit_libcall_block (insns, temp, valreg, note);
 
-      end_sequence ();
-      emit_insns (insns);
+         valreg = temp;
+       }
     }
   pop_temp_slots ();
 
@@ -4135,9 +4183,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
            emit_move_insn (value, mem_value);
        }
       else if (value != 0)
-       emit_move_insn (value, hard_libcall_value (outmode));
+       emit_move_insn (value, valreg);
       else
-       value = hard_libcall_value (outmode);
+       value = valreg;
     }
 
   if (ACCUMULATE_OUTGOING_ARGS)
@@ -4163,8 +4211,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
          if (save_mode != BLKmode)
            emit_move_insn (stack_area, save_area);
          else
-           emit_block_move (stack_area, validize_mem (save_area),
-                            GEN_INT (high_to_save - low_to_save + 1));
+           emit_block_move (stack_area, save_area,
+                            GEN_INT (high_to_save - low_to_save + 1),
+                            BLOCK_OP_CALL_PARM);
        }
 #endif
 
@@ -4198,10 +4247,12 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
    and machine_modes to convert them to.
    The rtx values should have been passed through protect_from_queue already.
 
-   FN_TYPE will be zero for `normal' calls, one for `const' calls,
-   which will be enclosed in REG_LIBCALL/REG_RETVAL notes, and two for
-   `pure' calls, that are handled like `const' calls with extra
-   (use (memory (scratch)).  */
+   FN_TYPE should be LCT_NORMAL for `normal' calls, LCT_CONST for `const'
+   calls, LCT_PURE for `pure' calls, LCT_CONST_MAKE_BLOCK for `const' calls
+   which should be enclosed in REG_LIBCALL/REG_RETVAL notes,
+   LCT_PURE_MAKE_BLOCK for `purep' calls which should be enclosed in
+   REG_LIBCALL/REG_RETVAL notes with extra (use (memory (scratch)),
+   or other LCT_ value for other types of library calls.  */
 
 void
 emit_library_call VPARAMS((rtx orgfun, enum libcall_type fn_type,
@@ -4264,7 +4315,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value,
 
    FNDECL is the declaration of the function we are calling.
 
-   Return non-zero if this arg should cause sibcall failure,
+   Return nonzero if this arg should cause sibcall failure,
    zero otherwise.  */
 
 static int
@@ -4339,7 +4390,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
                  arg->save_area = assign_temp (nt, 0, 1, 1);
                  preserve_temp_slots (arg->save_area);
                  emit_block_move (validize_mem (arg->save_area), stack_area,
-                                  expr_size (arg->tree_value));
+                                  expr_size (arg->tree_value),
+                                  BLOCK_OP_CALL_PARM);
                }
              else
                {
@@ -4360,7 +4412,13 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
   /* If this isn't going to be placed on both the stack and in registers,
      set up the register and number of words.  */
   if (! arg->pass_on_stack)
-    reg = arg->reg, partial = arg->partial;
+    {
+      if (flags & ECF_SIBCALL)
+       reg = arg->tail_call_reg;
+      else
+       reg = arg->reg;
+      partial = arg->partial;
+    }
 
   if (reg != 0 && partial == 0)
     /* Being passed entirely in a register.  We shouldn't be called in
@@ -4420,18 +4478,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
     do_pending_stack_adjust ();
 
   if (arg->value == arg->stack)
-    {
-      /* If the value is already in the stack slot, we are done.  */
-      if (current_function_check_memory_usage && GET_CODE (arg->stack) == MEM)
-       {
-         emit_library_call (chkr_set_right_libfunc, LCT_CONST_MAKE_BLOCK,
-                            VOIDmode, 3, XEXP (arg->stack, 0), Pmode,
-                            ARGS_SIZE_RTX (arg->size),
-                            TYPE_MODE (sizetype),
-                            GEN_INT (MEMORY_USE_RW),
-                            TYPE_MODE (integer_type_node));
-       }
-    }
+    /* If the value is already in the stack slot, we are done.  */
+    ;
   else if (arg->mode != BLKmode)
     {
       int size;
@@ -4464,15 +4512,21 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
 
       /* This isn't already where we want it on the stack, so put it there.
         This can either be done with push or copy insns.  */
-      emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, 0,
-                     partial, reg, used - size, argblock,
+      emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, 
+                     PARM_BOUNDARY, partial, reg, used - size, argblock,
                      ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->alignment_pad));
+
+      /* Unless this is a partially-in-register argument, the argument is now
+        in the stack.  */
+      if (partial == 0)
+       arg->value = arg->stack;
     }
   else
     {
       /* BLKmode, at least partly to be pushed.  */
 
+      unsigned int parm_align;
       int excess;
       rtx size_rtx;
 
@@ -4494,7 +4548,25 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
             emit_push_insn for BLKmode is careful to avoid it.  */
          excess = (arg->size.constant - int_size_in_bytes (TREE_TYPE (pval))
                    + partial * UNITS_PER_WORD);
-         size_rtx = expr_size (pval);
+         size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)),
+                                 NULL_RTX, TYPE_MODE (sizetype), 0);
+       }
+
+      /* Some types will require stricter alignment, which will be
+        provided for elsewhere in argument layout.  */
+      parm_align = MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval)));
+
+      /* When an argument is padded down, the block is aligned to
+        PARM_BOUNDARY, but the actual argument isn't.  */
+      if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward)
+       {
+         if (arg->size.var)
+           parm_align = BITS_PER_UNIT;
+         else if (excess)
+           {
+             unsigned int excess_align = (excess & -excess) * BITS_PER_UNIT;
+             parm_align = MIN (parm_align, excess_align);
+           }
        }
 
       if ((flags & ECF_SIBCALL) && GET_CODE (arg->value) == MEM)
@@ -4554,29 +4626,29 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
           {
            rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant);
            emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1,
-                           TYPE_ALIGN (TREE_TYPE (pval)), partial, reg,
-                           excess, argblock, ARGS_SIZE_RTX (arg->offset),
-                           reg_parm_stack_space,
+                           parm_align, partial, reg, excess, argblock,
+                           ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
                            ARGS_SIZE_RTX (arg->alignment_pad));
          }
        }
        
 
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
-                     TYPE_ALIGN (TREE_TYPE (pval)), partial, reg, excess,
-                     argblock, ARGS_SIZE_RTX (arg->offset),
-                     reg_parm_stack_space,
+                     parm_align, partial, reg, excess, argblock,
+                     ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->alignment_pad));
-    }
 
-  /* Unless this is a partially-in-register argument, the argument is now
-     in the stack.
+      /* Unless this is a partially-in-register argument, the argument is now
+        in the stack.
 
-     ??? Note that this can change arg->value from arg->stack to
-     arg->stack_slot and it matters when they are not the same.
-     It isn't totally clear that this is correct in all cases.  */
-  if (partial == 0)
-    arg->value = arg->stack_slot;
+        ??? Unlike the case above, in which we want the actual
+        address of the data, so that we can load it directly into a
+        register, here we want the address of the stack slot, so that
+        it's properly aligned for word-by-word copying or something
+        like that.  It's not clear that this is always correct.  */
+      if (partial == 0)
+       arg->value = arg->stack_slot;
+    }
 
   /* Once we have pushed something, pops can't safely
      be deferred during the rest of the arguments.  */
@@ -4595,3 +4667,48 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
 
   return sibcall_failure;
 }
+
+
+/* Nonzero if we do not know how to pass TYPE solely in registers.
+   We cannot do so in the following cases:
+
+   - if the type has variable size
+   - if the type is marked as addressable (it is required to be constructed
+     into the stack)
+   - if the padding and mode of the type is such that a copy into a register
+     would put it into the wrong part of the register.
+
+   Which padding can't be supported depends on the byte endianness.
+
+   A value in a register is implicitly padded at the most significant end.
+   On a big-endian machine, that is the lower end in memory.
+   So a value padded in memory at the upper end can't go in a register.
+   For a little-endian machine, the reverse is true.  */
+
+bool
+default_must_pass_in_stack (mode, type)
+     enum machine_mode mode;
+     tree type;
+{
+  if (!type)
+    return true;
+
+  /* If the type has variable size...  */
+  if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+    return true;
+
+  /* If the type is marked as addressable (it is required
+     to be constructed into the stack)...  */
+  if (TREE_ADDRESSABLE (type))
+    return true;
+
+  /* If the padding and mode of the type is such that a copy into
+     a register would put it into the wrong part of the register.  */
+  if (mode == BLKmode
+      && int_size_in_bytes (type) % (PARM_BOUNDARY / BITS_PER_UNIT)
+      && (FUNCTION_ARG_PADDING (mode, type)
+         == (BYTES_BIG_ENDIAN ? upward : downward)))
+    return true;
+
+  return false;
+}