OSDN Git Service

* ChangeLog: Follow spelling conventions.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 2049bd2..d4e3f00 100644 (file)
@@ -33,6 +33,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "timevar.h"
 #include "sbitmap.h"
+#include "langhooks.h"
+#include "target.h"
 
 #if !defined FUNCTION_OK_FOR_SIBCALL
 #define FUNCTION_OK_FOR_SIBCALL(DECL) 1
@@ -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.  */
@@ -181,7 +183,8 @@ static int calls_function_1 PARAMS ((tree, int));
 
 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 *));
@@ -444,7 +447,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;
@@ -456,6 +459,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;
@@ -466,6 +470,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.  */
@@ -959,11 +967,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
        {
@@ -1000,11 +1005,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 */
 
@@ -1505,14 +1508,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 ();
@@ -1536,8 +1534,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
          }
@@ -1822,7 +1820,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)
        {
@@ -1878,7 +1876,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);
                }
            }
@@ -1901,8 +1899,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
@@ -1967,7 +1965,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
@@ -2030,7 +2028,7 @@ 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,
+   Return nonzero if sequence after INSN dereferences such argument slots,
    zero otherwise.  */
 
 static int
@@ -2207,7 +2205,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);
@@ -2253,7 +2251,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;
          }
       }
@@ -2285,7 +2283,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;
     }
 
@@ -2467,7 +2465,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)
     {
@@ -2675,10 +2673,6 @@ expand_call (exp, target, ignore)
       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);
@@ -2711,6 +2705,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);
        }
@@ -2937,9 +2937,6 @@ expand_call (exp, target, ignore)
            valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0));
        }
 
-      if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
-        flags &= ~ECF_LIBCALL_BLOCK;
-
       /* Precompute all register parameters.  It isn't safe to compute anything
         once we have started filling any specific hard regs.  */
       precompute_register_parameters (num_actuals, args, &reg_parm_seen);
@@ -3058,7 +3055,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
@@ -3071,32 +3068,45 @@ expand_call (exp, target, ignore)
         we have no way to move such values into a pseudo register.  */
       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;
+         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 (pass && (flags & ECF_MALLOC))
        {
@@ -3118,7 +3128,7 @@ expand_call (exp, target, ignore)
          /* Write out the sequence.  */
          insns = get_insns ();
          end_sequence ();
-         emit_insns (insns);
+         emit_insn (insns);
          valreg = temp;
        }
 
@@ -3263,7 +3273,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
 
@@ -3302,9 +3312,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;
@@ -3318,8 +3328,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)
@@ -3407,7 +3415,7 @@ expand_call (exp, target, ignore)
                                                tail_recursion_label));
     }
   else
-    emit_insns (normal_call_insns);
+    emit_insn (normal_call_insns);
 
   currently_expanding_call--;
 
@@ -3471,6 +3479,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
@@ -3532,27 +3541,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 | ECF_LIBCALL_BLOCK);
+         /* 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.  */
 
@@ -3661,16 +3674,27 @@ 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 (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,
@@ -3880,8 +3904,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
            {
@@ -3949,8 +3973,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.  */
@@ -4021,8 +4046,6 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
   NO_DEFER_POP;
   valreg = (mem_value == 0 && outmode != VOIDmode
            ? hard_libcall_value (outmode) : NULL_RTX);
-  if (valreg == 0 || GET_CODE (valreg) == PARALLEL)
-    flags &= ~ECF_LIBCALL_BLOCK;
 
   /* Stack must be properly aligned now.  */
   if (stack_pointer_delta & (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT - 1))
@@ -4039,13 +4062,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,
@@ -4078,29 +4100,40 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      we have no way to move such values into a pseudo register.  */
   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;
+
+         /* 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);
 
-      insns = get_insns ();
-      end_sequence ();
+         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);
+         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);
+         emit_libcall_block (insns, temp, valreg, note);
 
-      valreg = temp;
+         valreg = temp;
+       }
     }
   pop_temp_slots ();
 
@@ -4115,9 +4148,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)
@@ -4143,8 +4176,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
 
@@ -4246,7 +4280,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
@@ -4321,7 +4355,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
                {
@@ -4342,7 +4377,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
@@ -4436,15 +4477,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;
 
@@ -4466,7 +4513,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)
+           {
+             int excess_align = (excess & -excess) * BITS_PER_UNIT;
+             parm_align = MIN (parm_align, excess_align);
+           }
        }
 
       if ((flags & ECF_SIBCALL) && GET_CODE (arg->value) == MEM)
@@ -4526,29 +4591,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.  */