OSDN Git Service

* gcc.c-torture/execute/ieee/ieee.exp: Change sh-*-* to sh*-*-*.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 95ff8b1..5b5657f 100644 (file)
@@ -1,23 +1,23 @@
 /* Convert function calls to rtl insns, for GNU C compiler.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -25,36 +25,19 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.h"
 #include "flags.h"
 #include "expr.h"
+#include "libfuncs.h"
 #include "function.h"
 #include "regs.h"
-#include "insn-flags.h"
 #include "toplev.h"
 #include "output.h"
 #include "tm_p.h"
 #include "timevar.h"
 #include "sbitmap.h"
 
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
-/* Supply a default definition for PUSH_ARGS.  */
-#ifndef PUSH_ARGS
-#ifdef PUSH_ROUNDING
-#define PUSH_ARGS      !ACCUMULATE_OUTGOING_ARGS
-#else
-#define PUSH_ARGS      0
-#endif
-#endif
-
 #if !defined FUNCTION_OK_FOR_SIBCALL
 #define FUNCTION_OK_FOR_SIBCALL(DECL) 1
 #endif
 
-#if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
-#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
-#endif
-
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
 
@@ -73,6 +56,10 @@ Boston, MA 02111-1307, USA.  */
 #define PUSH_ARGS_REVERSED 0
 #endif
 
+#ifndef STACK_POINTER_OFFSET
+#define STACK_POINTER_OFFSET    0
+#endif
+
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
 
@@ -187,6 +174,8 @@ static int calls_function_1 PARAMS ((tree, int));
 /* 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,
@@ -218,7 +207,6 @@ static void compute_argument_addresses              PARAMS ((struct arg_data *,
 static rtx rtx_for_function_call               PARAMS ((tree, tree));
 static void load_register_parameters           PARAMS ((struct arg_data *,
                                                         int, rtx *, int));
-static int libfunc_nothrow                     PARAMS ((rtx));
 static rtx emit_library_call_value_1           PARAMS ((int, rtx, rtx,
                                                         enum libcall_type,
                                                         enum machine_mode,
@@ -268,7 +256,7 @@ calls_function_1 (exp, which)
      tree exp;
      int which;
 {
-  register int i;
+  int i;
   enum tree_code code = TREE_CODE (exp);
   int class = TREE_CODE_CLASS (code);
   int length = first_rtl_op (code);
@@ -320,8 +308,8 @@ calls_function_1 (exp, which)
 
     case BLOCK:
       {
-       register tree local;
-       register tree subblock;
+       tree local;
+       tree subblock;
 
        for (local = BLOCK_VARS (exp); local; local = TREE_CHAIN (local))
          if (DECL_INITIAL (local) != 0
@@ -366,11 +354,12 @@ calls_function_1 (exp, which)
    CALL_INSN_FUNCTION_USAGE information.  */
 
 rtx
-prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
+prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen, sibcallp)
      rtx funexp;
      tree fndecl;
      rtx *call_fusage;
      int reg_parm_seen;
+     int sibcallp;
 {
   rtx static_chain_value = 0;
 
@@ -388,7 +377,7 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
     funexp = ((SMALL_REGISTER_CLASSES && reg_parm_seen)
              ? force_not_mem (memory_address (FUNCTION_MODE, funexp))
              : memory_address (FUNCTION_MODE, funexp));
-  else
+  else if (! sibcallp)
     {
 #ifndef NO_FUNCTION_CSE
       if (optimize && ! flag_no_function_cse)
@@ -448,7 +437,7 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
    We restore `inhibit_defer_pop' to that value.
 
    CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that
-   denote registers used by the called function.   */
+   denote registers used by the called function.  */
 
 static void
 emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
@@ -608,7 +597,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
 
   /* If this is a const call, then set the insn's unchanging bit.  */
   if (ecf_flags & (ECF_CONST | ECF_PURE))
-    CONST_CALL_P (call_insn) = 1;
+    CONST_OR_PURE_CALL_P (call_insn) = 1;
 
   /* If this call can't throw, attach a REG_EH_REGION reg note to that
      effect.  */
@@ -619,6 +608,16 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
   if (ecf_flags & ECF_NORETURN)
     REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_NORETURN, const0_rtx,
                                               REG_NOTES (call_insn));
+  if (ecf_flags & ECF_ALWAYS_RETURN)
+    REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_ALWAYS_RETURN, const0_rtx,
+                                              REG_NOTES (call_insn));
+
+  if (ecf_flags & ECF_RETURNS_TWICE)
+    {
+      REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_SETJMP, const0_rtx,
+                                                REG_NOTES (call_insn));
+      current_function_calls_setjmp = 1;
+    }
 
   SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
 
@@ -989,7 +988,7 @@ restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save)
     move_by_pieces (stack_area, validize_mem (save_area),
                    high_to_save - low_to_save + 1, PARM_BOUNDARY);
 }
-#endif
+#endif /* REG_PARM_STACK_SPACE */
 
 /* If any elements in ARGS refer to parameters that are to be passed in
    registers, but not in memory, and whose alignment does not permit a
@@ -1369,10 +1368,8 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
   /* For accumulate outgoing args mode we don't need to align, since the frame
      will be already aligned.  Align to STACK_BOUNDARY in order to prevent
      backends from generating missaligned frame sizes.  */
-#ifdef STACK_BOUNDARY
   if (ACCUMULATE_OUTGOING_ARGS && preferred_stack_boundary > STACK_BOUNDARY)
     preferred_stack_boundary = STACK_BOUNDARY;
-#endif
 
   /* Compute the actual size of the argument block required.  The variable
      and constant sizes must be combined, the size may have to be rounded,
@@ -1383,7 +1380,6 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
       args_size->var = ARGS_SIZE_TREE (*args_size);
       args_size->constant = 0;
 
-#ifdef PREFERRED_STACK_BOUNDARY
       preferred_stack_boundary /= BITS_PER_UNIT;
       if (preferred_stack_boundary > 1)
        {
@@ -1394,7 +1390,6 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
            abort ();
          args_size->var = round_up (args_size->var, preferred_stack_boundary);
        }
-#endif
 
       if (reg_parm_stack_space > 0)
        {
@@ -1413,7 +1408,6 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
     }
   else
     {
-#ifdef PREFERRED_STACK_BOUNDARY
       preferred_stack_boundary /= BITS_PER_UNIT;
       if (preferred_stack_boundary < 1)
        preferred_stack_boundary = 1;
@@ -1423,7 +1417,6 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
                              / preferred_stack_boundary
                              * preferred_stack_boundary)
                             - stack_pointer_delta);
-#endif
 
       args_size->constant = MAX (args_size->constant,
                                 reg_parm_stack_space);
@@ -1477,6 +1470,8 @@ precompute_arguments (flags, num_actuals, args)
     if ((flags & (ECF_CONST | ECF_PURE))
        || calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS))
       {
+       enum machine_mode mode;
+
        /* If this is an addressable type, we cannot pre-evaluate it.  */
        if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
          abort ();
@@ -1496,11 +1491,11 @@ precompute_arguments (flags, num_actuals, args)
        args[i].initial_value = args[i].value
          = protect_from_queue (args[i].value, 0);
 
-       if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode)
+       mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
+       if (mode != args[i].mode)
          {
            args[i].value
-             = convert_modes (args[i].mode,
-                              TYPE_MODE (TREE_TYPE (args[i].tree_value)),
+             = convert_modes (args[i].mode, mode,
                               args[i].value, args[i].unsignedp);
 #ifdef PROMOTE_FOR_CALL_ONLY
            /* CSE will replace this only if it contains args[i].value
@@ -1510,8 +1505,7 @@ precompute_arguments (flags, num_actuals, args)
                && GET_MODE_CLASS (args[i].mode) == MODE_INT)
              {
                args[i].initial_value
-                 = gen_rtx_SUBREG (TYPE_MODE (TREE_TYPE (args[i].tree_value)),
-                                   args[i].value, 0);
+                 = 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;
@@ -1636,8 +1630,8 @@ compute_argument_addresses (args, argblock, num_actuals)
             outgoing arguments and we cannot allow reordering of reads
             from function arguments with stores to outgoing arguments
             of sibling calls.  */
-         MEM_ALIAS_SET (args[i].stack) = 0;
-         MEM_ALIAS_SET (args[i].stack_slot) = 0;
+         set_mem_alias_set (args[i].stack, 0);
+         set_mem_alias_set (args[i].stack_slot, 0);
        }
     }
 }
@@ -2162,8 +2156,8 @@ expand_call (exp, target, ignore)
   int old_inhibit_defer_pop = inhibit_defer_pop;
   int old_stack_allocated;
   rtx call_fusage;
-  register tree p = TREE_OPERAND (exp, 0);
-  register int i;
+  tree p = TREE_OPERAND (exp, 0);
+  int i;
   /* The alignment of the stack, in bits.  */
   HOST_WIDE_INT preferred_stack_boundary;
   /* The alignment of the stack, in bytes.  */
@@ -2296,11 +2290,7 @@ expand_call (exp, target, ignore)
     }
 
   /* Figure out the amount to which the stack should be aligned.  */
-#ifdef PREFERRED_STACK_BOUNDARY
   preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
-#else
-  preferred_stack_boundary = STACK_BOUNDARY;
-#endif
 
   /* Operand 0 is a pointer-to-function; get the type of the function.  */
   funtype = TREE_TYPE (TREE_OPERAND (exp, 0));
@@ -2384,8 +2374,8 @@ expand_call (exp, target, ignore)
   args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));
   memset ((char *) args, 0, num_actuals * sizeof (struct arg_data));
 
-  /* Build up entries inthe ARGS array, compute the size of the arguments
-     into ARGS_SIZE, etc.  */
+  /* Build up entries in the ARGS array, compute the size of the
+     arguments into ARGS_SIZE, etc.  */
   initialize_argument_information (num_actuals, args, &args_size,
                                   n_named_args, actparms, fndecl,
                                   &args_so_far, reg_parm_stack_space,
@@ -2397,7 +2387,7 @@ expand_call (exp, target, ignore)
       /* If this function requires a variable-sized argument list, don't
         try to make a cse'able block for this call.  We may be able to
         do this eventually, but it is too complicated to keep track of
-        what insns go in the cse'able block and which don't.   */
+        what insns go in the cse'able block and which don't.  */
 
       flags &= ~(ECF_CONST | ECF_PURE);
       must_preallocate = 1;
@@ -2526,8 +2516,9 @@ expand_call (exp, target, ignore)
              {
                tree var = build_decl (VAR_DECL, NULL_TREE,
                                       TREE_TYPE (args[i].tree_value));
-               DECL_RTL (var) = expand_expr (args[i].tree_value, NULL_RTX,
-                                             VOIDmode, EXPAND_NORMAL);
+               SET_DECL_RTL (var,
+                             expand_expr (args[i].tree_value, NULL_RTX,
+                                          VOIDmode, EXPAND_NORMAL));
                args[i].tree_value = var;
              }
              break;
@@ -2598,7 +2589,8 @@ 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"), 0,
+      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__bb_fork_func"),
+                        LCT_ALWAYS_RETURN,
                         VOIDmode, 0);
     }
 
@@ -2903,7 +2895,6 @@ expand_call (exp, target, ignore)
 
       compute_argument_addresses (args, argblock, num_actuals);
 
-#ifdef PREFERRED_STACK_BOUNDARY
       /* If we push args individually in reverse order, perform stack alignment
         before the first push (the last arg).  */
       if (PUSH_ARGS_REVERSED && argblock == 0
@@ -2929,12 +2920,6 @@ expand_call (exp, target, ignore)
       /* Now that the stack is properly aligned, pops can't safely
         be deferred during the evaluation of the arguments.  */
       NO_DEFER_POP;
-#endif
-
-      /* Don't try to defer pops if preallocating, not even from the first arg,
-        since ARGBLOCK probably refers to the SP.  */
-      if (argblock)
-       NO_DEFER_POP;
 
       funexp = rtx_for_function_call (fndecl, exp);
 
@@ -3006,13 +2991,11 @@ expand_call (exp, target, ignore)
                sibcall_failure = 1;
            }
 
-#ifdef PREFERRED_STACK_BOUNDARY
       /* If we pushed args in forward order, perform stack alignment
         after pushing the last arg.  */
       if (!PUSH_ARGS_REVERSED && argblock == 0)
        anti_adjust_stack (GEN_INT (adjusted_args_size.constant
                                    - unadjusted_args_size));
-#endif
 
       /* If register arguments require space on the stack and stack space
         was not preallocated, allocate stack space here for arguments
@@ -3047,7 +3030,7 @@ expand_call (exp, target, ignore)
        }
 
       funexp = prepare_call_address (funexp, fndecl, &call_fusage,
-                                    reg_parm_seen);
+                                    reg_parm_seen, pass == 0);
 
       load_register_parameters (args, num_actuals, &call_fusage, flags);
 
@@ -3072,11 +3055,9 @@ expand_call (exp, target, ignore)
       /* All arguments and registers used for the call must be set up by
         now!  */
 
-#ifdef PREFERRED_STACK_BOUNDARY
       /* Stack must be properly aligned now.  */
       if (pass && stack_pointer_delta % preferred_unit_stack_boundary)
        abort ();
-#endif
 
       /* Generate the actual call instruction.  */
       emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
@@ -3160,9 +3141,9 @@ expand_call (exp, target, ignore)
         if nonvolatile values are live.  For functions that cannot return,
         inform flow that control does not fall through.  */
 
-      if ((flags & (ECF_RETURNS_TWICE | ECF_NORETURN | ECF_LONGJMP)) || pass == 0)
+      if ((flags & (ECF_NORETURN | ECF_LONGJMP)) || pass == 0)
        {
-         /* The barrier or NOTE_INSN_SETJMP note must be emitted
+         /* The barrier must be emitted
             immediately after the CALL_INSN.  Some ports emit more
             than just a CALL_INSN above, so we must search for it here.  */
 
@@ -3175,13 +3156,7 @@ expand_call (exp, target, ignore)
                abort ();
            }
 
-         if (flags & ECF_RETURNS_TWICE)
-           {
-             emit_note_after (NOTE_INSN_SETJMP, last);
-             current_function_calls_setjmp = 1;
-           }
-         else
-           emit_barrier_after (last);
+         emit_barrier_after (last);
        }
 
       if (flags & ECF_LONGJMP)
@@ -3286,13 +3261,25 @@ expand_call (exp, target, ignore)
        {
          tree type = TREE_TYPE (exp);
          int unsignedp = TREE_UNSIGNED (type);
+         int offset = 0;
 
          /* If we don't promote as expected, something is wrong.  */
          if (GET_MODE (target)
              != promote_mode (type, TYPE_MODE (type), &unsignedp, 1))
            abort ();
 
-         target = gen_rtx_SUBREG (TYPE_MODE (type), target, 0);
+       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_P (target) = unsignedp;
        }
@@ -3457,25 +3444,9 @@ expand_call (exp, target, ignore)
   return target;
 }
 \f
-/* Returns nonzero if FUN is the symbol for a library function which can
-   not throw.  */
-
-static int
-libfunc_nothrow (fun)
-     rtx fun;
-{
-  if (fun == throw_libfunc
-      || fun == rethrow_libfunc
-      || fun == sjthrow_libfunc
-      || fun == sjpopnthrow_libfunc)
-    return 0;
-
-  return 1;
-}
-\f
 /* Output a library call to function FUN (a SYMBOL_REF rtx).
    The RETVAL parameter specifies whether return value needs to be saved, other
-   parameters are documented in the emit_library_call function bellow.  */
+   parameters are documented in the emit_library_call function below.  */
 static rtx
 emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      int retval;
@@ -3490,7 +3461,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   struct args_size args_size;
   /* Size of arguments before any adjustments (such as rounding).  */
   struct args_size original_args_size;
-  register int argnum;
+  int argnum;
   rtx fun;
   int inc;
   int count;
@@ -3514,9 +3485,10 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   rtx valreg;
   int pcc_struct_value = 0;
   int struct_value_size = 0;
-  int flags = 0;
+  int flags;
   int reg_parm_stack_space = 0;
   int needed;
+  rtx before_call;
 
 #ifdef REG_PARM_STACK_SPACE
   /* Define the boundary of the register parm stack space that needs to be
@@ -3537,21 +3509,41 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 #endif
 #endif
 
-  if (fn_type == LCT_CONST_MAKE_BLOCK)
-    flags |= ECF_CONST;
-  else if (fn_type == LCT_PURE_MAKE_BLOCK)
-    flags |= ECF_PURE;
-  fun = orgfun;
+  /* By default, library functions can not throw.  */
+  flags = ECF_NOTHROW;
 
-  if (libfunc_nothrow (fun))
-    flags |= ECF_NOTHROW;
+  switch (fn_type)
+    {
+    case LCT_NORMAL:
+    case LCT_CONST:
+    case LCT_PURE:
+      /* Nothing to do here.  */
+      break;
+    case LCT_CONST_MAKE_BLOCK:
+      flags |= ECF_CONST;
+      break;
+    case LCT_PURE_MAKE_BLOCK:
+      flags |= ECF_PURE;
+      break;
+    case LCT_NORETURN:
+      flags |= ECF_NORETURN;
+      break;
+    case LCT_THROW:
+      flags = ECF_NORETURN;
+      break;
+    case LCT_ALWAYS_RETURN:
+      flags = ECF_ALWAYS_RETURN;
+      break;
+    case LCT_RETURNS_TWICE:
+      flags = ECF_RETURNS_TWICE;
+      break;
+    }
+  fun = orgfun;
 
-#ifdef PREFERRED_STACK_BOUNDARY
   /* Ensure current function's preferred stack boundary is at least
      what we need.  */
   if (cfun->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
     cfun->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
-#endif
 
   /* If this kind of value comes back in memory,
      decide where in memory it should come back.  */
@@ -3589,7 +3581,11 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg));
   memset ((char *) argvec, 0, (nargs + 1) * sizeof (struct arg));
 
+#ifdef INIT_CUMULATIVE_LIBCALL_ARGS
+  INIT_CUMULATIVE_LIBCALL_ARGS (args_so_far, outmode, fun);
+#else
   INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0);
+#endif
 
   args_size.constant = 0;
   args_size.var = 0;
@@ -3672,16 +3668,44 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
       if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1))
        {
-         /* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can
-            be viewed as just an efficiency improvement.  */
-         rtx slot = assign_temp (type_for_mode (mode, 0), 0, 1, 1);
+         rtx slot;
+         int must_copy = 1
+#ifdef FUNCTION_ARG_CALLEE_COPIES        
+           && ! FUNCTION_ARG_CALLEE_COPIES (args_so_far, mode,
+                                            NULL_TREE, 1)
+#endif
+           ;
+
+         if (GET_MODE (val) == MEM && ! must_copy)
+           slot = val;
+         else if (must_copy)
+           {
+             slot = assign_temp (type_for_mode (mode, 0), 0, 1, 1);
+             emit_move_insn (slot, val);
+           }
+         else
+           {
+             tree type = type_for_mode (mode, 0);
+
+             slot = gen_rtx_MEM (mode,
+                                 expand_expr (build1 (ADDR_EXPR,
+                                                      build_pointer_type
+                                                      (type),
+                                                      make_tree (type, val)),
+                                              NULL_RTX, VOIDmode, 0));
+           }
 
          call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
                                           gen_rtx_USE (VOIDmode, slot),
                                           call_fusage);
-         emit_move_insn (slot, val);
-         val = force_operand (XEXP (slot, 0), NULL_RTX);
+         if (must_copy)
+           call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
+                                            gen_rtx_CLOBBER (VOIDmode,
+                                                             slot),
+                                            call_fusage);
+
          mode = Pmode;
+         val = force_operand (XEXP (slot, 0), NULL_RTX);
        }
 #endif
 
@@ -3728,14 +3752,12 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   assemble_external_libcall (fun);
 
   original_args_size = args_size;
-#ifdef PREFERRED_STACK_BOUNDARY
   args_size.constant = (((args_size.constant
                          + stack_pointer_delta
                          + STACK_BYTES - 1)
                          / STACK_BYTES
                          * STACK_BYTES)
                         - stack_pointer_delta);
-#endif
 
   args_size.constant = MAX (args_size.constant,
                            reg_parm_stack_space);
@@ -3788,11 +3810,15 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
               highest_outgoing_arg_in_use - initial_highest_arg_in_use);
       needed = 0;
 
-      /* The address of the outgoing argument list must not be copied to a
-        register here, because argblock would be left pointing to the
-        wrong place after the call to allocate_dynamic_stack_space below.  */
+      /* We must be careful to use virtual regs before they're instantiated,
+         and real regs afterwards.  Loop optimization, for example, can create
+        new libcalls after we've instantiated the virtual regs, and if we
+        use virtuals anyway, they won't match the rtl patterns.  */
 
-      argblock = virtual_outgoing_args_rtx;
+      if (virtuals_instantiated)
+       argblock = plus_constant (stack_pointer_rtx, STACK_POINTER_OFFSET);
+      else
+       argblock = virtual_outgoing_args_rtx;
     }
   else
     {
@@ -3800,13 +3826,11 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
        argblock = push_block (GEN_INT (args_size.constant), 0, 0);
     }
 
-#ifdef PREFERRED_STACK_BOUNDARY
   /* If we push args individually in reverse order, perform stack alignment
      before the first push (the last arg).  */
   if (argblock == 0 && PUSH_ARGS_REVERSED)
     anti_adjust_stack (GEN_INT (args_size.constant
                                - original_args_size.constant));
-#endif
 
   if (PUSH_ARGS_REVERSED)
     {
@@ -3888,8 +3912,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      are to be pushed.  */
   for (count = 0; count < nargs; count++, argnum += inc)
     {
-      register enum machine_mode mode = argvec[argnum].mode;
-      register rtx val = argvec[argnum].value;
+      enum machine_mode mode = argvec[argnum].mode;
+      rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
       int lower_bound = 0, upper_bound = 0, i;
@@ -3952,20 +3976,18 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
        }
     }
 
-#ifdef PREFERRED_STACK_BOUNDARY
   /* If we pushed args in forward order, perform stack alignment
      after pushing the last arg.  */
   if (argblock == 0 && !PUSH_ARGS_REVERSED)
     anti_adjust_stack (GEN_INT (args_size.constant
                                - original_args_size.constant));
-#endif
 
   if (PUSH_ARGS_REVERSED)
     argnum = nargs - 1;
   else
     argnum = 0;
 
-  fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0);
+  fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0, 0);
 
   /* Now load any reg parms into their regs.  */
 
@@ -3973,7 +3995,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      are to be pushed.  */
   for (count = 0; count < nargs; count++, argnum += inc)
     {
-      register rtx val = argvec[argnum].value;
+      rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
 
@@ -4016,11 +4038,11 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   valreg = (mem_value == 0 && outmode != VOIDmode
            ? hard_libcall_value (outmode) : NULL_RTX);
 
-#ifdef PREFERRED_STACK_BOUNDARY
   /* Stack must be properly aligned now.  */
   if (stack_pointer_delta & (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1))
     abort ();
-#endif
+
+  before_call = get_last_insn ();
 
   /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
      will set inhibit_defer_pop to that value.  */
@@ -4039,6 +4061,28 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
               valreg,
               old_inhibit_defer_pop + 1, call_fusage, flags);
 
+  /* For calls to `setjmp', etc., inform flow.c it should complain
+     if nonvolatile values are live.  For functions that cannot return,
+     inform flow that control does not fall through.  */
+
+  if (flags & (ECF_NORETURN | ECF_LONGJMP))
+    {
+      /* The barrier note must be emitted
+        immediately after the CALL_INSN.  Some ports emit more than
+        just a CALL_INSN above, so we must search for it here.  */
+
+      rtx last = get_last_insn ();
+      while (GET_CODE (last) != CALL_INSN)
+       {
+         last = PREV_INSN (last);
+         /* There was no CALL_INSN?  */
+         if (last == before_call)
+           abort ();
+       }
+
+      emit_barrier_after (last);
+    }
+
   /* Now restore inhibit_defer_pop to its actual original value.  */
   OK_DEFER_POP;
 
@@ -4156,35 +4200,24 @@ 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 is zero for `normal' calls, one for `const' calls, wich
-   which will be enclosed in REG_LIBCALL/REG_RETVAL notes and two for `pure'
-   calls, that are handled like `const' calls with extra
+   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)).  */
 
 void
 emit_library_call VPARAMS((rtx orgfun, enum libcall_type fn_type,
                           enum machine_mode outmode, int nargs, ...))
 {
-#ifndef ANSI_PROTOTYPES
-  rtx orgfun;
-  int fn_type;
-  enum machine_mode outmode;
-  int nargs;
-#endif
-  va_list p;
-
-  VA_START (p, nargs);
-
-#ifndef ANSI_PROTOTYPES
-  orgfun = va_arg (p, rtx);
-  fn_type = va_arg (p, int);
-  outmode = va_arg (p, enum machine_mode);
-  nargs = va_arg (p, int);
-#endif
+  VA_OPEN (p, nargs);
+  VA_FIXEDARG (p, rtx, orgfun);
+  VA_FIXEDARG (p, int, fn_type);
+  VA_FIXEDARG (p, enum machine_mode, outmode);
+  VA_FIXEDARG (p, int, nargs);
 
   emit_library_call_value_1 (0, orgfun, NULL_RTX, fn_type, outmode, nargs, p);
 
-  va_end (p);
+  VA_CLOSE (p);
 }
 \f
 /* Like emit_library_call except that an extra argument, VALUE,
@@ -4200,30 +4233,21 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value,
                                 enum libcall_type fn_type,
                                 enum machine_mode outmode, int nargs, ...))
 {
-#ifndef ANSI_PROTOTYPES
-  rtx orgfun;
-  rtx value;
-  int fn_type;
-  enum machine_mode outmode;
-  int nargs;
-#endif
-  va_list p;
-
-  VA_START (p, nargs);
-
-#ifndef ANSI_PROTOTYPES
-  orgfun = va_arg (p, rtx);
-  value = va_arg (p, rtx);
-  fn_type = va_arg (p, int);
-  outmode = va_arg (p, enum machine_mode);
-  nargs = va_arg (p, int);
-#endif
+  rtx result;
+  
+  VA_OPEN (p, nargs);
+  VA_FIXEDARG (p, rtx, orgfun);
+  VA_FIXEDARG (p, rtx, value);
+  VA_FIXEDARG (p, int, fn_type);
+  VA_FIXEDARG (p, enum machine_mode, outmode);
+  VA_FIXEDARG (p, int, nargs);
 
-  value = emit_library_call_value_1 (1, orgfun, value, fn_type, outmode, nargs, p);
+  result = emit_library_call_value_1 (1, orgfun, value, fn_type, outmode,
+                                     nargs, p);
 
-  va_end (p);
+  VA_CLOSE (p);
 
-  return value;
+  return result;
 }
 \f
 #if 0
@@ -4291,7 +4315,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
      int variable_size ATTRIBUTE_UNUSED;
      int reg_parm_stack_space;
 {
-  register tree pval = arg->tree_value;
+  tree pval = arg->tree_value;
   rtx reg = 0;
   int partial = 0;
   int used = 0;
@@ -4381,7 +4405,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
 
   if (reg != 0 && partial == 0)
     /* Being passed entirely in a register.  We shouldn't be called in
-       this case.   */
+       this case.  */
     abort ();
 
   /* If this arg needs special alignment, don't load the registers
@@ -4451,7 +4475,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
     }
   else if (arg->mode != BLKmode)
     {
-      register int size;
+      int size;
 
       /* Argument is a scalar, not entirely passed in registers.
         (If part is passed in registers, arg->partial says how much
@@ -4490,7 +4514,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
     {
       /* BLKmode, at least partly to be pushed.  */
 
-      register int excess;
+      int excess;
       rtx size_rtx;
 
       /* Pushing a nonscalar.
@@ -4547,9 +4571,19 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
            }
        }
 
-      /*  If parm is passed both in stack and in register and offset is 
-         greater than reg_parm_stack_space, split the offset. */
+      /* Special handling is required if part of the parameter lies in the
+        register parameter area.  The argument may be copied into the stack
+        slot using memcpy(), but the original contents of the register
+        parameter area will be restored after the memcpy() call.
+
+        To ensure that the part that lies in the register parameter area
+        is copied correctly, we emit a separate push for that part.  This
+        push should be small enough to avoid a call to memcpy().  */
+#ifndef STACK_PARMS_IN_REG_PARM_AREA
       if (arg->reg && arg->pass_on_stack)
+#else
+      if (1)
+#endif
        {
          if (arg->offset.constant < reg_parm_stack_space && arg->offset.var)
            error ("variable offset is passed paritially in stack and in reg");
@@ -4561,12 +4595,10 @@ 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)) / BITS_PER_UNIT, 
-                           partial, reg, excess, argblock, 
-                           ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
+                           TYPE_ALIGN (TREE_TYPE (pval)), partial, reg,
+                           excess, argblock, ARGS_SIZE_RTX (arg->offset),
+                           reg_parm_stack_space,
                            ARGS_SIZE_RTX (arg->alignment_pad));
-
-           size_rtx = GEN_INT (INTVAL(size_rtx) - reg_parm_stack_space);
          }
        }