OSDN Git Service

2001-07-10 Jan van Male <jan.vanmale@fenk.wau.nl>
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 885817d..c5a5cb6 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert function calls to rtl insns, for GNU C compiler.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -27,26 +27,12 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.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
@@ -73,6 +59,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)
 
@@ -218,8 +208,8 @@ 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, 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));
@@ -296,6 +286,17 @@ calls_function_1 (exp, which)
 
       break;
 
+    case CONSTRUCTOR:
+      {
+       tree tem;
+
+       for (tem = CONSTRUCTOR_ELTS (exp); tem != 0; tem = TREE_CHAIN (tem))
+         if (calls_function_1 (TREE_VALUE (tem), which))
+           return 1;
+      }
+
+      return 0;
+
     case SAVE_EXPR:
       if (SAVE_EXPR_RTL (exp) != 0)
        return 0;
@@ -472,10 +473,9 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
 #if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop)
   if ((ecf_flags & ECF_SIBCALL)
       && HAVE_sibcall_pop && HAVE_sibcall_value_pop
-      && (RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0
-         || stack_size == 0))
+      && (n_popped > 0 || stack_size == 0))
     {
-      rtx n_pop = GEN_INT (RETURN_POPS_ARGS (fndecl, funtype, stack_size));
+      rtx n_pop = GEN_INT (n_popped));
       rtx pat;
 
       /* If this subroutine pops its own args, record that in the call insn
@@ -864,7 +864,7 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen)
                || (GET_CODE (args[i].value) == SUBREG
                    && GET_CODE (SUBREG_REG (args[i].value)) == REG)))
            && args[i].mode != BLKmode
-           && rtx_cost (args[i].value, SET) > 2
+           && rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1)
            && ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
                || preserve_subexpressions_p ()))
          args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
@@ -1466,6 +1466,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 ();
@@ -1485,11 +1487,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
@@ -1499,8 +1501,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;
@@ -1678,9 +1679,8 @@ rtx_for_function_call (fndecl, exp)
             that this seems safer.  */
          funaddr = convert_memory_address (Pmode, funexp);
 #endif
-         emit_library_call (chkr_check_exec_libfunc, 1,
-                            VOIDmode, 1,
-                            funaddr, Pmode);
+         emit_library_call (chkr_check_exec_libfunc, LCT_CONST_MAKE_BLOCK,
+                            VOIDmode, 1, funaddr, Pmode);
        }
       emit_queue ();
     }
@@ -1929,7 +1929,7 @@ combine_pending_stack_adjustment_and_call (unadjusted_args_size,
      after the arguments are pushed.  */
   if (preferred_unit_stack_boundary > 1)
     {
-      if (unadjusted_alignment >= 0)
+      if (unadjusted_alignment > 0)
        adjustment -= preferred_unit_stack_boundary - unadjusted_alignment;
       else
        adjustment += unadjusted_alignment;
@@ -2261,16 +2261,11 @@ expand_call (exp, target, ignore)
          structure_value_addr = XEXP (target, 0);
        else
          {
-           rtx d;
-
            /* For variable-sized objects, we must be called with a target
               specified.  If we were to allocate space on the stack here,
               we would have no way of knowing when to free it.  */
+           rtx d = assign_temp (TREE_TYPE (exp), 1, 1, 1);
 
-           if (struct_value_size < 0)
-             abort ();
-
-           d = assign_temp (TREE_TYPE (exp), 1, 1, 1);
            mark_temp_addr_taken (d);
            structure_value_addr = XEXP (d, 0);
            target = 0;
@@ -2377,10 +2372,10 @@ expand_call (exp, target, ignore)
 
   /* Make a vector to hold all the information about each arg.  */
   args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));
-  bzero ((char *) args, 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,
@@ -2417,9 +2412,8 @@ expand_call (exp, target, ignore)
 
   /* Tail calls can make things harder to debug, and we're traditionally
      pushed these optimizations into -O2.  Don't try if we're already
-     expanding a call, as that means we're an argument.  Similarly, if
-     there's pending loops or cleanups we know there's code to follow
-     the call.
+     expanding a call, as that means we're an argument.  Don't try if
+     there's cleanups, as we know there's code to follow the call.
 
      If rtx_equal_function_value_matters is false, that means we've
      finished with regular parsing.  Which means that some of the
@@ -2430,7 +2424,6 @@ expand_call (exp, target, ignore)
   if (currently_expanding_call++ != 0
       || !flag_optimize_sibling_calls
       || !rtx_equal_function_value_matters
-      || !stmt_loop_nest_empty ()
       || any_pending_cleanups (1)
       || args_size.var)
     try_tail_call = try_tail_recursion = 0;
@@ -2463,6 +2456,7 @@ expand_call (exp, target, ignore)
         before the sibcall_epilogue.  */
       || fndecl == NULL_TREE
       || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP))
+      || TREE_THIS_VOLATILE (fndecl)
       || !FUNCTION_OK_FOR_SIBCALL (fndecl)
       /* If this function requires more stack slots than the current
         function, we cannot change it into a sibling call.  */
@@ -2522,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;
@@ -2554,6 +2549,10 @@ expand_call (exp, target, ignore)
       int save_pending_stack_adjust = pending_stack_adjust;
       int save_stack_pointer_delta = stack_pointer_delta;
 
+      /* Emit any queued insns now; otherwise they would end up in
+        only one of the alternates.  */
+      emit_queue ();
+
       /* Use a new sequence to hold any RTL we generate.  We do not even
         know if we will use this RTL yet.  The final decision can not be
         made until after RTL generation for the entire function is
@@ -2659,11 +2658,6 @@ expand_call (exp, target, ignore)
          expand_start_target_temps ();
        }
 
-      /* 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))
-       NO_DEFER_POP;
-
       /* 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
@@ -2673,6 +2667,11 @@ expand_call (exp, target, ignore)
          || 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))
+       NO_DEFER_POP;
+
       /* Push the temporary stack slot level so that we can free any
         temporaries we make.  */
       push_temp_slots ();
@@ -2782,11 +2781,11 @@ expand_call (exp, target, ignore)
                    = (char *) alloca (highest_outgoing_arg_in_use);
 
                  if (initial_highest_arg_in_use)
-                   bcopy (initial_stack_usage_map, stack_usage_map,
-                          initial_highest_arg_in_use);
+                   memcpy (stack_usage_map, initial_stack_usage_map,
+                           initial_highest_arg_in_use);
 
                  if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
-                   bzero (&stack_usage_map[initial_highest_arg_in_use],
+                   memset (&stack_usage_map[initial_highest_arg_in_use], 0,
                           (highest_outgoing_arg_in_use
                            - initial_highest_arg_in_use));
                  needed = 0;
@@ -2875,7 +2874,7 @@ expand_call (exp, target, ignore)
                          /* Make a new map for the new argument list.  */
                          stack_usage_map = (char *)
                            alloca (highest_outgoing_arg_in_use);
-                         bzero (stack_usage_map, highest_outgoing_arg_in_use);
+                         memset (stack_usage_map, 0, highest_outgoing_arg_in_use);
                          highest_outgoing_arg_in_use = 0;
                        }
                      allocate_dynamic_stack_space (push_size, NULL_RTX,
@@ -3026,7 +3025,7 @@ expand_call (exp, target, ignore)
 
          /* Mark the memory for the aggregate as write-only.  */
          if (current_function_check_memory_usage)
-           emit_library_call (chkr_set_right_libfunc, 1,
+           emit_library_call (chkr_set_right_libfunc, LCT_CONST_MAKE_BLOCK,
                               VOIDmode, 3,
                               structure_value_addr, ptr_mode,
                               GEN_INT (struct_value_size),
@@ -3228,18 +3227,20 @@ expand_call (exp, target, ignore)
         The Irix 6 ABI has examples of this.  */
       else if (GET_CODE (valreg) == PARALLEL)
        {
-         int bytes = int_size_in_bytes (TREE_TYPE (exp));
-
          if (target == 0)
            {
-             target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)),
-                                         bytes, 0);
-             MEM_SET_IN_STRUCT_P (target, AGGREGATE_TYPE_P (TREE_TYPE (exp)));
+             /* This will only be assigned once, so it can be readonly.  */
+             tree nt = build_qualified_type (TREE_TYPE (exp),
+                                             (TYPE_QUALS (TREE_TYPE (exp))
+                                              | TYPE_QUAL_CONST));
+
+             target = assign_temp (nt, 0, 1, 1);
              preserve_temp_slots (target);
            }
 
          if (! rtx_equal_p (target, valreg))
-           emit_group_store (target, valreg, bytes,
+           emit_group_store (target, valreg,
+                             int_size_in_bytes (TREE_TYPE (exp)),
                              TYPE_ALIGN (TREE_TYPE (exp)));
 
          /* We can not support sibling calls for this case.  */
@@ -3258,7 +3259,12 @@ expand_call (exp, target, ignore)
          emit_move_insn (target, valreg);
        }
       else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
-       target = copy_blkmode_from_reg (target, valreg, TREE_TYPE (exp));
+       {
+         target = copy_blkmode_from_reg (target, valreg, TREE_TYPE (exp));
+
+         /* We can not support sibling calls for this case.  */
+         sibcall_failure = 1;
+       }
       else
        target = copy_to_reg (valreg);
 
@@ -3271,13 +3277,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;
        }
@@ -3357,10 +3375,6 @@ expand_call (exp, target, ignore)
        {
          tail_call_insns = insns;
 
-         /* If something prevents making this a sibling call,
-            zero out the sequence.  */
-         if (sibcall_failure)
-           tail_call_insns = NULL_RTX;
          /* Restore the pending stack adjustment now that we have
             finished generating the sibling call sequence.  */
 
@@ -3379,6 +3393,11 @@ expand_call (exp, target, ignore)
        }
       else
        normal_call_insns = insns;
+
+      /* If something prevents making this a sibling call,
+        zero out the sequence.  */
+      if (sibcall_failure)
+       tail_call_insns = NULL_RTX;
     }
 
   /* The function optimize_sibling_and_tail_recursive_calls doesn't
@@ -3441,22 +3460,6 @@ 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.  */
@@ -3465,7 +3468,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      int retval;
      rtx orgfun;
      rtx value;
-     int fn_type;
+     enum libcall_type fn_type;
      enum machine_mode outmode;
      int nargs;
      va_list p;
@@ -3498,9 +3501,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
@@ -3521,14 +3525,30 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
 #endif
 #endif
 
-  if (fn_type == 1)
-    flags |= ECF_CONST;
-  else if (fn_type == 2)
-    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;
+    }
+  fun = orgfun;
 
 #ifdef PREFERRED_STACK_BOUNDARY
   /* Ensure current function's preferred stack boundary is at least
@@ -3554,7 +3574,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
       if (value != 0 && GET_CODE (value) == MEM)
        mem_value = value;
       else
-       mem_value = assign_stack_temp (outmode, GET_MODE_SIZE (outmode), 0);
+       mem_value = assign_temp (type_for_mode (outmode, 0), 0, 1, 1);
 #endif
 
       /* This call returns a big structure.  */
@@ -3571,9 +3591,13 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      library functions shouldn't have many args.  */
 
   argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg));
-  bzero ((char *) argvec, (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;
@@ -3656,12 +3680,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_stack_temp (mode, GET_MODE_SIZE (mode), 0);
-         emit_move_insn (slot, val);
-         val = force_operand (XEXP (slot, 0), NULL_RTX);
+         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);
+         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
 
@@ -3760,19 +3816,23 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
       stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
 
       if (initial_highest_arg_in_use)
-       bcopy (initial_stack_usage_map, stack_usage_map,
-              initial_highest_arg_in_use);
+       memcpy (stack_usage_map, initial_stack_usage_map,
+               initial_highest_arg_in_use);
 
       if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
-       bzero (&stack_usage_map[initial_highest_arg_in_use],
+       memset (&stack_usage_map[initial_highest_arg_in_use], 0,
               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
     {
@@ -4002,6 +4062,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
     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.  */
   /* The return type is needed to decide how many bytes the function pops.
@@ -4019,6 +4081,34 @@ 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_RETURNS_TWICE | ECF_NORETURN | ECF_LONGJMP))
+    {
+      /* The barrier or NOTE_INSN_SETJMP 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 ();
+       }
+
+      if (flags & ECF_RETURNS_TWICE)
+       {
+         emit_note_after (NOTE_INSN_SETJMP, last);
+         current_function_calls_setjmp = 1;
+       }
+      else
+       emit_barrier_after (last);
+    }
+
   /* Now restore inhibit_defer_pop to its actual original value.  */
   OK_DEFER_POP;
 
@@ -4142,8 +4232,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
    (use (memory (scratch)).  */
 
 void
-emit_library_call VPARAMS((rtx orgfun, int fn_type, enum machine_mode outmode,
-                          int nargs, ...))
+emit_library_call VPARAMS((rtx orgfun, enum libcall_type fn_type,
+                          enum machine_mode outmode, int nargs, ...))
 {
 #ifndef ANSI_PROTOTYPES
   rtx orgfun;
@@ -4176,7 +4266,8 @@ emit_library_call VPARAMS((rtx orgfun, int fn_type, enum machine_mode outmode,
    If VALUE is nonzero, VALUE is returned.  */
 
 rtx
-emit_library_call_value VPARAMS((rtx orgfun, rtx value, int fn_type,
+emit_library_call_value VPARAMS((rtx orgfun, rtx value,
+                                enum libcall_type fn_type,
                                 enum machine_mode outmode, int nargs, ...))
 {
 #ifndef ANSI_PROTOTYPES
@@ -4327,15 +4418,15 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
 
              if (save_mode == BLKmode)
                {
-                 arg->save_area = assign_stack_temp (BLKmode,
-                                                     arg->size.constant, 0);
-                 MEM_SET_IN_STRUCT_P (arg->save_area,
-                                      AGGREGATE_TYPE_P (TREE_TYPE
-                                                        (arg->tree_value)));
+                 tree ot = TREE_TYPE (arg->tree_value);
+                 tree nt = build_qualified_type (ot, (TYPE_QUALS (ot)
+                                                      | TYPE_QUAL_CONST));
+
+                 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,
-                                  GEN_INT (arg->size.constant),
-                                  PARM_BOUNDARY);
+                                  expr_size (arg->tree_value),
+                                  MIN (PARM_BOUNDARY, TYPE_ALIGN (nt)));
                }
              else
                {
@@ -4420,8 +4511,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
       /* 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, 1, VOIDmode, 3,
-                            XEXP (arg->stack, 0), Pmode,
+         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),
@@ -4526,6 +4617,30 @@ 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. */
+      if (arg->reg && arg->pass_on_stack)
+       {
+         if (arg->offset.constant < reg_parm_stack_space && arg->offset.var)
+           error ("variable offset is passed paritially in stack and in reg");
+         else if (arg->offset.constant < reg_parm_stack_space && arg->size.var)
+           error ("variable size is passed partially in stack and in reg");
+         else if (arg->offset.constant < reg_parm_stack_space 
+             && ((arg->offset.constant + arg->size.constant) 
+                  > 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,
+                           ARGS_SIZE_RTX (arg->alignment_pad));
+
+           size_rtx = GEN_INT (INTVAL(size_rtx) - reg_parm_stack_space);
+         }
+       }
+       
+
       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),