calls.c (emit_library_call): Handle saving of stack slots when ACCUMULATE_OUTGOING_AR...
authorJeff Law <law@gcc.gnu.org>
Mon, 14 Apr 1997 20:45:20 +0000 (14:45 -0600)
committerJeff Law <law@gcc.gnu.org>
Mon, 14 Apr 1997 20:45:20 +0000 (14:45 -0600)
        * calls.c (emit_library_call): Handle saving of stack slots when
        ACCUMULATE_OUTGOING_ARGS is defined.
        (emit_library_call_value): Likewise.

From-SVN: r13902

gcc/calls.c

index 91ebe63c6f9c57188d0aebb807439390a19ab686..25fc40e8fc4f916f1736af97af451c1f36654c02 100644 (file)
@@ -2276,10 +2276,32 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
   rtx argblock = 0;
   CUMULATIVE_ARGS args_so_far;
   struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
-              struct args_size offset; struct args_size size; };
+              struct args_size offset; struct args_size size; rtx save_area; };
   struct arg *argvec;
   int old_inhibit_defer_pop = inhibit_defer_pop;
   rtx call_fusage = 0;
+  /* Size of the stack reserved for parameter registers.  */
+  int reg_parm_stack_space = 0;
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+  /* Define the boundary of the register parm stack space that needs to be
+     save, if any.  */
+  int low_to_save = -1, high_to_save;
+  rtx save_area = 0;            /* Place that it is saved */
+#endif
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+  int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
+  char *initial_stack_usage_map = stack_usage_map;
+  int needed;
+#endif
+
+#ifdef REG_PARM_STACK_SPACE
+#ifdef MAYBE_REG_PARM_STACK_SPACE
+  reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
+#else
+  reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+#endif
+#endif
 
   VA_START (p, nargs);
 
@@ -2300,6 +2322,8 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
      library functions shouldn't have many args.  */
 
   argvec = (struct arg *) alloca (nargs * sizeof (struct arg));
+  bzero ((char *) argvec, nargs * sizeof (struct arg));
+
 
   INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0);
 
@@ -2379,23 +2403,15 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
          )
        args_size.constant += argvec[count].size.constant;
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
-      /* If this arg is actually passed on the stack, it might be
-        clobbering something we already put there (this library call might
-        be inside the evaluation of an argument to a function whose call
-        requires the stack).  This will only occur when the library call
-        has sufficient args to run out of argument registers.  Abort in
-        this case; if this ever occurs, code must be added to save and
-        restore the arg slot.  */
-
-      if (argvec[count].reg == 0 || argvec[count].partial != 0)
-       abort ();
-#endif
-
       FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
     }
   va_end (p);
 
+#ifdef FINAL_REG_PARM_STACK_SPACE
+  reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
+                                                    args_size.var);
+#endif
+      
   /* If this machine requires an external definition for library
      functions, write one out.  */
   assemble_external_libcall (fun);
@@ -2408,9 +2424,9 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
 
 #ifdef REG_PARM_STACK_SPACE
   args_size.constant = MAX (args_size.constant,
-                           REG_PARM_STACK_SPACE (NULL_TREE));
+                           reg_parm_stack_space);
 #ifndef OUTGOING_REG_PARM_STACK_SPACE
-  args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
+  args_size.constant -= reg_parm_stack_space;
 #endif
 #endif
 
@@ -2418,12 +2434,55 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
     current_function_outgoing_args_size = args_size.constant;
 
 #ifdef ACCUMULATE_OUTGOING_ARGS
-  args_size.constant = 0;
+  /* Since the stack pointer will never be pushed, it is possible for
+     the evaluation of a parm to clobber something we have already
+     written to the stack.  Since most function calls on RISC machines
+     do not use the stack, this is uncommon, but must work correctly.
+
+     Therefore, we save any area of the stack that was already written
+     and that we are using.  Here we set up to do this by making a new
+     stack usage map from the old one.
+
+     Another approach might be to try to reorder the argument
+     evaluations to avoid this conflicting stack usage.  */
+
+  needed = args_size.constant;
+#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+  /* Since we will be writing into the entire argument area, the
+     map must be allocated for its entire size, not just the part that
+     is the responsibility of the caller.  */
+  needed += reg_parm_stack_space;
+#endif
+
+#ifdef ARGS_GROW_DOWNWARD
+  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+                                    needed + 1);
+#else
+  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+                                    needed);
 #endif
+  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);
+
+  if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
+    bzero (&stack_usage_map[initial_highest_arg_in_use],
+          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.
+     */
+
+  argblock = virtual_outgoing_args_rtx;
+#else /* not ACCUMULATE_OUTGOING_ARGS */
 #ifndef PUSH_ROUNDING
   argblock = push_block (GEN_INT (args_size.constant), 0, 0);
 #endif
+#endif
 
 #ifdef PUSH_ARGS_REVERSED
 #ifdef STACK_BOUNDARY
@@ -2443,6 +2502,68 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
   argnum = 0;
 #endif
 
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+  /* The argument list is the property of the called routine and it
+     may clobber it.  If the fixed area has been used for previous
+     parameters, we must save and restore it.
+
+     Here we compute the boundary of the that needs to be saved, if any.  */
+
+#ifdef ARGS_GROW_DOWNWARD
+  for (count = 0; count < reg_parm_stack_space + 1; count++)
+#else
+  for (count = 0; count < reg_parm_stack_space; count++)
+#endif
+    {
+      if (count >=  highest_outgoing_arg_in_use
+         || stack_usage_map[count] == 0)
+       continue;
+
+      if (low_to_save == -1)
+       low_to_save = count;
+
+      high_to_save = count;
+    }
+
+  if (low_to_save >= 0)
+    {
+      int num_to_save = high_to_save - low_to_save + 1;
+      enum machine_mode save_mode
+       = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1);
+      rtx stack_area;
+
+      /* If we don't have the required alignment, must do this in BLKmode.  */
+      if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode),
+                              BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))
+       save_mode = BLKmode;
+
+      stack_area = gen_rtx (MEM, save_mode,
+                           memory_address (save_mode,
+                                           
+#ifdef ARGS_GROW_DOWNWARD
+                                           plus_constant (argblock,
+                                                          - high_to_save)
+#else
+                                           plus_constant (argblock,
+                                                          low_to_save)
+#endif
+                                           ));
+      if (save_mode == BLKmode)
+       {
+         save_area = assign_stack_temp (BLKmode, num_to_save, 0);
+         MEM_IN_STRUCT_P (save_area) = 0;
+         emit_block_move (validize_mem (save_area), stack_area,
+                          GEN_INT (num_to_save),
+                          PARM_BOUNDARY / BITS_PER_UNIT);
+       }
+      else
+       {
+         save_area = gen_reg_rtx (save_mode);
+         emit_move_insn (save_area, stack_area);
+       }
+    }
+#endif
+         
   /* Push the args that need to be pushed.  */
 
   for (count = 0; count < nargs; count++, argnum += inc)
@@ -2451,11 +2572,59 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
       register rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
+      int lower_bound, upper_bound, i;
 
       if (! (reg != 0 && partial == 0))
-       emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
-                       argblock, GEN_INT (argvec[count].offset.constant));
-      NO_DEFER_POP;
+       {
+#ifdef ACCUMULATE_OUTGOING_ARGS
+         /* If this is being stored into a pre-allocated, fixed-size, stack
+            area, save any previous data at that location.  */
+
+#ifdef ARGS_GROW_DOWNWARD
+         /* stack_slot is negative, but we want to index stack_usage_map
+            with positive values.  */
+         upper_bound = -argvec[count].offset.constant + 1;
+         lower_bound = upper_bound - argvec[count].size.constant;
+#else
+         lower_bound = argvec[count].offset.constant;
+         upper_bound = lower_bound + argvec[count].size.constant;
+#endif
+
+         for (i = lower_bound; i < upper_bound; i++)
+           if (stack_usage_map[i]
+#ifdef REG_PARM_STACK_SPACE
+               /* Don't store things in the fixed argument area at this point;
+                  it has already been saved.  */
+               && i > reg_parm_stack_space
+#endif
+               )
+             break;
+
+         if (i != upper_bound)
+           {
+             /* We need to make a save area.  See what mode we can make it.  */
+             enum machine_mode save_mode
+               = mode_for_size (argvec[count].size.constant * BITS_PER_UNIT,
+                                MODE_INT, 1);
+             rtx stack_area
+               = gen_rtx (MEM, save_mode,
+                          memory_address (save_mode, plus_constant (argblock,
+                                          argvec[count].offset.constant)));
+             argvec[count].save_area = gen_reg_rtx (save_mode);
+             emit_move_insn (argvec[count].save_area, stack_area);
+           }
+#endif
+         emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
+                         argblock, GEN_INT (argvec[count].offset.constant));
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+         /* Now mark the segment we just used.  */
+         for (i = lower_bound; i < upper_bound; i++)
+           stack_usage_map[i] = 1;
+#endif
+
+         NO_DEFER_POP;
+       }
     }
 
 #ifndef PUSH_ARGS_REVERSED
@@ -2524,6 +2693,48 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
 
   /* Now restore inhibit_defer_pop to its actual original value.  */
   OK_DEFER_POP;
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+#ifdef REG_PARM_STACK_SPACE
+      if (save_area)
+       {
+         enum machine_mode save_mode = GET_MODE (save_area);
+         rtx stack_area
+           = gen_rtx (MEM, save_mode,
+                      memory_address (save_mode,
+#ifdef ARGS_GROW_DOWNWARD
+                                      plus_constant (argblock, - high_to_save)
+#else
+                                      plus_constant (argblock, low_to_save)
+#endif
+                                      ));
+
+         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),
+                            PARM_BOUNDARY / BITS_PER_UNIT);
+       }
+#endif
+         
+  /* If we saved any argument areas, restore them.  */
+  for (count = 0; count < nargs; count++)
+    if (argvec[count].save_area)
+      {
+       enum machine_mode save_mode = GET_MODE (argvec[count].save_area);
+       rtx stack_area
+         = gen_rtx (MEM, save_mode,
+                    memory_address (save_mode, plus_constant (argblock,
+                                    argvec[count].offset.constant)));
+
+       emit_move_insn (stack_area, argvec[count].save_area);
+      }
+
+  highest_outgoing_arg_in_use = initial_highest_arg_in_use;
+  stack_usage_map = initial_stack_usage_map;
+#endif
+
 }
 \f
 /* Like emit_library_call except that an extra argument, VALUE,
@@ -2557,14 +2768,37 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
   rtx argblock = 0;
   CUMULATIVE_ARGS args_so_far;
   struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
-              struct args_size offset; struct args_size size; };
+              struct args_size offset; struct args_size size; rtx save_area; };
   struct arg *argvec;
   int old_inhibit_defer_pop = inhibit_defer_pop;
   rtx call_fusage = 0;
+  /* Size of the stack reserved for parameter registers.  */
+  int reg_parm_stack_space = 0;
   rtx mem_value = 0;
   int pcc_struct_value = 0;
   int struct_value_size = 0;
   int is_const;
+  int needed;
+
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+  /* Define the boundary of the register parm stack space that needs to be
+     save, if any.  */
+  int low_to_save = -1, high_to_save;
+  rtx save_area = 0;            /* Place that it is saved */
+#endif
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+  int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
+  char *initial_stack_usage_map = stack_usage_map;
+#endif
+
+#ifdef REG_PARM_STACK_SPACE
+#ifdef MAYBE_REG_PARM_STACK_SPACE
+  reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
+#else
+  reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+#endif
+#endif
 
   VA_START (p, nargs);
 
@@ -2613,6 +2847,7 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
      library functions shouldn't have many args.  */
 
   argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg));
+  bzero ((char *) argvec, nargs * sizeof (struct arg));
 
   INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0);
 
@@ -2734,23 +2969,14 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
          )
        args_size.constant += argvec[count].size.constant;
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
-      /* If this arg is actually passed on the stack, it might be
-        clobbering something we already put there (this library call might
-        be inside the evaluation of an argument to a function whose call
-        requires the stack).  This will only occur when the library call
-        has sufficient args to run out of argument registers.  Abort in
-        this case; if this ever occurs, code must be added to save and
-        restore the arg slot.  */
-
-      if (argvec[count].reg == 0 || argvec[count].partial != 0)
-       abort ();
-#endif
-
       FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
     }
   va_end (p);
 
+#ifdef FINAL_REG_PARM_STACK_SPACE
+  reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
+                                                    args_size.var);
+#endif
   /* If this machine requires an external definition for library
      functions, write one out.  */
   assemble_external_libcall (fun);
@@ -2763,9 +2989,9 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
 
 #ifdef REG_PARM_STACK_SPACE
   args_size.constant = MAX (args_size.constant,
-                           REG_PARM_STACK_SPACE (NULL_TREE));
+                           reg_parm_stack_space);
 #ifndef OUTGOING_REG_PARM_STACK_SPACE
-  args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
+  args_size.constant -= reg_parm_stack_space);
 #endif
 #endif
 
@@ -2773,12 +2999,55 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
     current_function_outgoing_args_size = args_size.constant;
 
 #ifdef ACCUMULATE_OUTGOING_ARGS
-  args_size.constant = 0;
+  /* Since the stack pointer will never be pushed, it is possible for
+     the evaluation of a parm to clobber something we have already
+     written to the stack.  Since most function calls on RISC machines
+     do not use the stack, this is uncommon, but must work correctly.
+
+     Therefore, we save any area of the stack that was already written
+     and that we are using.  Here we set up to do this by making a new
+     stack usage map from the old one.
+
+     Another approach might be to try to reorder the argument
+     evaluations to avoid this conflicting stack usage.  */
+
+  needed = args_size.constant;
+#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+  /* Since we will be writing into the entire argument area, the
+     map must be allocated for its entire size, not just the part that
+     is the responsibility of the caller.  */
+  needed += reg_parm_stack_space;
+#endif
+
+#ifdef ARGS_GROW_DOWNWARD
+  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+                                    needed + 1);
+#else
+  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+                                    needed);
 #endif
+  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);
+
+  if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
+    bzero (&stack_usage_map[initial_highest_arg_in_use],
+          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.
+     */
+
+  argblock = virtual_outgoing_args_rtx;
+#else /* not ACCUMULATE_OUTGOING_ARGS */
 #ifndef PUSH_ROUNDING
   argblock = push_block (GEN_INT (args_size.constant), 0, 0);
 #endif
+#endif
 
 #ifdef PUSH_ARGS_REVERSED
 #ifdef STACK_BOUNDARY
@@ -2798,6 +3067,68 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
   argnum = 0;
 #endif
 
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+  /* The argument list is the property of the called routine and it
+     may clobber it.  If the fixed area has been used for previous
+     parameters, we must save and restore it.
+
+     Here we compute the boundary of the that needs to be saved, if any.  */
+
+#ifdef ARGS_GROW_DOWNWARD
+  for (count = 0; count < reg_parm_stack_space + 1; count++)
+#else
+  for (count = 0; count < reg_parm_stack_space; count++)
+#endif
+    {
+      if (count >=  highest_outgoing_arg_in_use
+         || stack_usage_map[count] == 0)
+       continue;
+
+      if (low_to_save == -1)
+       low_to_save = count;
+
+      high_to_save = count;
+    }
+
+  if (low_to_save >= 0)
+    {
+      int num_to_save = high_to_save - low_to_save + 1;
+      enum machine_mode save_mode
+       = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1);
+      rtx stack_area;
+
+      /* If we don't have the required alignment, must do this in BLKmode.  */
+      if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode),
+                              BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))
+       save_mode = BLKmode;
+
+      stack_area = gen_rtx (MEM, save_mode,
+                           memory_address (save_mode,
+                                           
+#ifdef ARGS_GROW_DOWNWARD
+                                           plus_constant (argblock,
+                                                          - high_to_save)
+#else
+                                           plus_constant (argblock,
+                                                          low_to_save)
+#endif
+                                           ));
+      if (save_mode == BLKmode)
+       {
+         save_area = assign_stack_temp (BLKmode, num_to_save, 0);
+         MEM_IN_STRUCT_P (save_area) = 0;
+         emit_block_move (validize_mem (save_area), stack_area,
+                          GEN_INT (num_to_save),
+                          PARM_BOUNDARY / BITS_PER_UNIT);
+       }
+      else
+       {
+         save_area = gen_reg_rtx (save_mode);
+         emit_move_insn (save_area, stack_area);
+       }
+    }
+#endif
+         
   /* Push the args that need to be pushed.  */
 
   for (count = 0; count < nargs; count++, argnum += inc)
@@ -2806,11 +3137,59 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
       register rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
+      int lower_bound, upper_bound, i;
 
       if (! (reg != 0 && partial == 0))
-       emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
-                       argblock, GEN_INT (argvec[count].offset.constant));
-      NO_DEFER_POP;
+       {
+#ifdef ACCUMULATE_OUTGOING_ARGS
+         /* If this is being stored into a pre-allocated, fixed-size, stack
+            area, save any previous data at that location.  */
+
+#ifdef ARGS_GROW_DOWNWARD
+         /* stack_slot is negative, but we want to index stack_usage_map
+            with positive values.  */
+         upper_bound = -argvec[count].offset.constant + 1;
+         lower_bound = upper_bound - argvec[count].size.constant;
+#else
+         lower_bound = argvec[count].offset.constant;
+         upper_bound = lower_bound + argvec[count].size.constant;
+#endif
+
+         for (i = lower_bound; i < upper_bound; i++)
+           if (stack_usage_map[i]
+#ifdef REG_PARM_STACK_SPACE
+               /* Don't store things in the fixed argument area at this point;
+                  it has already been saved.  */
+               && i > reg_parm_stack_space
+#endif
+               )
+             break;
+
+         if (i != upper_bound)
+           {
+             /* We need to make a save area.  See what mode we can make it.  */
+             enum machine_mode save_mode
+               = mode_for_size (argvec[count].size.constant * BITS_PER_UNIT,
+                                MODE_INT, 1);
+             rtx stack_area
+               = gen_rtx (MEM, save_mode,
+                          memory_address (save_mode, plus_constant (argblock,
+                                          argvec[count].offset.constant)));
+             argvec[count].save_area = gen_reg_rtx (save_mode);
+             emit_move_insn (argvec[count].save_area, stack_area);
+           }
+#endif
+         emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
+                         argblock, GEN_INT (argvec[count].offset.constant));
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+         /* Now mark the segment we just used.  */
+         for (i = lower_bound; i < upper_bound; i++)
+           stack_usage_map[i] = 1;
+#endif
+
+         NO_DEFER_POP;
+       }
     }
 
 #ifndef PUSH_ARGS_REVERSED
@@ -2905,6 +3284,47 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
        value = hard_libcall_value (outmode);
     }
 
+#ifdef ACCUMULATE_OUTGOING_ARGS
+#ifdef REG_PARM_STACK_SPACE
+      if (save_area)
+       {
+         enum machine_mode save_mode = GET_MODE (save_area);
+         rtx stack_area
+           = gen_rtx (MEM, save_mode,
+                      memory_address (save_mode,
+#ifdef ARGS_GROW_DOWNWARD
+                                      plus_constant (argblock, - high_to_save)
+#else
+                                      plus_constant (argblock, low_to_save)
+#endif
+                                      ));
+
+         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),
+                            PARM_BOUNDARY / BITS_PER_UNIT);
+       }
+#endif
+         
+  /* If we saved any argument areas, restore them.  */
+  for (count = 0; count < nargs; count++)
+    if (argvec[count].save_area)
+      {
+       enum machine_mode save_mode = GET_MODE (argvec[count].save_area);
+       rtx stack_area
+         = gen_rtx (MEM, save_mode,
+                    memory_address (save_mode, plus_constant (argblock,
+                                    argvec[count].offset.constant)));
+
+       emit_move_insn (stack_area, argvec[count].save_area);
+      }
+
+  highest_outgoing_arg_in_use = initial_highest_arg_in_use;
+  stack_usage_map = initial_stack_usage_map;
+#endif
+
   return value;
 }
 \f