OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 07898c3..eff0042 100644 (file)
@@ -32,6 +32,19 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "tm_p.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
@@ -49,11 +62,15 @@ Boston, MA 02111-1307, USA.  */
 #ifdef PUSH_ROUNDING
 
 #if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
-#define PUSH_ARGS_REVERSED     /* If it's last to first */
+#define PUSH_ARGS_REVERSED  PUSH_ARGS
 #endif
 
 #endif
 
+#ifndef PUSH_ARGS_REVERSED
+#define PUSH_ARGS_REVERSED 0
+#endif
+
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
 
@@ -101,10 +118,8 @@ struct arg_data
      differ from STACK if this arg pads downward.  This location is known
      to be aligned to FUNCTION_ARG_BOUNDARY.  */
   rtx stack_slot;
-#ifdef ACCUMULATE_OUTGOING_ARGS
   /* Place that this stack area has been saved, if needed.  */
   rtx save_area;
-#endif
   /* If an argument's alignment does not permit direct copying into registers,
      copy in smaller-sized pieces into pseudos.  These are stored in a
      block pointed to by this field.  The next field says how many
@@ -116,7 +131,6 @@ struct arg_data
   struct args_size alignment_pad;
 };
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
 /* A vector of one char per byte of stack space.  A byte if non-zero if
    the corresponding stack location has been used.
    This vector is used to prevent a function call within an argument from
@@ -132,14 +146,32 @@ static int highest_outgoing_arg_in_use;
    to make sure the object being constructed does not overlap the
    argument list for the constructor call.  */
 int stack_arg_under_construction;
-#endif
 
 static int calls_function      PARAMS ((tree, int));
 static int calls_function_1    PARAMS ((tree, int));
 
-#define ECF_IS_CONST           1
-#define ECF_NOTHROW            2
-#define ECF_SIBCALL            4
+/* Nonzero if this is a call to a `const' function. */
+#define ECF_CONST              1
+/* Nonzero if this is a call to a `volatile' function.  */
+#define ECF_NORETURN           2
+/* Nonzero if this is a call to malloc or a related function. */
+#define ECF_MALLOC             4
+/* Nonzero if it is plausible that this is a call to alloca.  */
+#define ECF_MAY_BE_ALLOCA      8
+/* Nonzero if this is a call to a function that won't throw an exception.  */
+#define ECF_NOTHROW            16
+/* Nonzero if this is a call to setjmp or a related function.  */
+#define ECF_RETURNS_TWICE      32
+/* Nonzero if this is a call to `longjmp'.  */
+#define ECF_LONGJMP            64
+/* Nonzero if this is a syscall that makes a new process in the image of
+   the current one.  */
+#define ECF_FORK_OR_EXEC       128
+#define ECF_SIBCALL            256
+/* Nonzero if this is a call to "pure" function (like const function,
+   but may read memory.  */
+#define ECF_PURE               512
+
 static void emit_call_1                PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
                                         HOST_WIDE_INT, HOST_WIDE_INT, rtx,
                                         rtx, int, rtx, int));
@@ -153,9 +185,8 @@ static void store_unaligned_arguments_into_pseudos PARAMS ((struct arg_data *,
 static int finalize_must_preallocate           PARAMS ((int, int,
                                                         struct arg_data *,
                                                         struct args_size *));
-static void precompute_arguments               PARAMS ((int, int, int,
-                                                        struct arg_data *,
-                                                        struct args_size *));
+static void precompute_arguments               PARAMS ((int, int,
+                                                        struct arg_data *));
 static int compute_argument_block_size         PARAMS ((int, 
                                                         struct args_size *,
                                                         int));
@@ -165,7 +196,7 @@ static void initialize_argument_information PARAMS ((int,
                                                         int, tree, tree,
                                                         CUMULATIVE_ARGS *,
                                                         int, rtx *, int *,
-                                                        int *, int *, int));
+                                                        int *, int *));
 static void compute_argument_addresses         PARAMS ((struct arg_data *,
                                                         rtx, int));
 static rtx rtx_for_function_call               PARAMS ((tree, tree));
@@ -175,8 +206,14 @@ static int libfunc_nothrow                 PARAMS ((rtx));
 static rtx emit_library_call_value_1           PARAMS ((int, rtx, rtx, int,
                                                         enum machine_mode,
                                                         int, va_list));
+static int special_function_p                  PARAMS ((tree, int));
+static int flags_from_decl_or_type             PARAMS ((tree));
+static rtx try_to_integrate                    PARAMS ((tree, tree, rtx,
+                                                        int, tree, rtx));
+static int combine_pending_stack_adjustment_and_call
+                                                PARAMS ((int, struct args_size *, int));
 
-#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+#ifdef REG_PARM_STACK_SPACE
 static rtx save_fixed_argument_area    PARAMS ((int, rtx, int *, int *));
 static void restore_fixed_argument_area        PARAMS ((rtx, rtx, int, int));
 #endif
@@ -388,9 +425,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.
-
-   IS_CONST is true if this is a `const' call.  */
+   denote registers used by the called function.  */
 
 static void
 emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
@@ -413,10 +448,8 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
   rtx struct_value_size_rtx = GEN_INT (struct_value_size);
 #endif
   rtx call_insn;
-#ifndef ACCUMULATE_OUTGOING_ARGS
   int already_popped = 0;
   HOST_WIDE_INT n_popped = RETURN_POPS_ARGS (fndecl, funtype, stack_size);
-#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,
@@ -424,7 +457,6 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
   if (GET_CODE (funexp) != SYMBOL_REF)
     funexp = memory_address (FUNCTION_MODE, funexp);
 
-#ifndef ACCUMULATE_OUTGOING_ARGS
 #if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop)
   if ((ecf_flags & ECF_SIBCALL)
       && HAVE_sibcall_pop && HAVE_sibcall_value_pop
@@ -459,7 +491,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
    even if the call has no arguments to pop.  */
 #if defined (HAVE_call) && defined (HAVE_call_value)
   if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop
-       && n_popped > 0)
+      && n_popped > 0)
 #else
   if (HAVE_call_pop && HAVE_call_value_pop)
 #endif
@@ -483,7 +515,6 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
     }
   else
 #endif
-#endif
 
 #if defined (HAVE_sibcall) && defined (HAVE_sibcall_value)
   if ((ecf_flags & ECF_SIBCALL)
@@ -528,6 +559,15 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
   if (! call_insn)
     abort ();
 
+  /* Mark memory as used for "pure" function call.  */
+  if (ecf_flags & ECF_PURE)
+    {
+      call_fusage =  gen_rtx_EXPR_LIST (VOIDmode,
+       gen_rtx_USE (VOIDmode,
+                    gen_rtx_MEM (BLKmode,
+                                 gen_rtx_SCRATCH (VOIDmode))), call_fusage);
+    }
+
   /* Put the register usage information on the CALL.  If there is already
      some usage information, put ours at the end.  */
   if (CALL_INSN_FUNCTION_USAGE (call_insn))
@@ -544,7 +584,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
     CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
 
   /* If this is a const call, then set the insn's unchanging bit.  */
-  if (ecf_flags & ECF_IS_CONST)
+  if (ecf_flags & (ECF_CONST | ECF_PURE))
     CONST_CALL_P (call_insn) = 1;
 
   /* If this call can't throw, attach a REG_EH_REGION reg note to that
@@ -559,18 +599,6 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
      if the context of the call as a whole permits.  */
   inhibit_defer_pop = old_inhibit_defer_pop;
 
-#ifndef ACCUMULATE_OUTGOING_ARGS
-  /* If returning from the subroutine does not automatically pop the args,
-     we need an instruction to pop them sooner or later.
-     Perhaps do it now; perhaps just record how much space to pop later.
-
-     If returning from the subroutine does pop the args, indicate that the
-     stack pointer will be changed.  */
-
-  /* The space for the args is no longer waiting for the call; either it
-     was popped by the call, or it'll be popped below.  */
-  arg_space_so_far -= rounded_stack_size;
-
   if (n_popped > 0)
     {
       if (!already_popped)
@@ -580,17 +608,40 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
                               CALL_INSN_FUNCTION_USAGE (call_insn));
       rounded_stack_size -= n_popped;
       rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
+      stack_pointer_delta -= n_popped;
     }
 
-  if (rounded_stack_size != 0)
+  if (!ACCUMULATE_OUTGOING_ARGS)
     {
-      if (flag_defer_pop && inhibit_defer_pop == 0
-         && !(ecf_flags & ECF_IS_CONST))
-       pending_stack_adjust += rounded_stack_size;
-      else
-       adjust_stack (rounded_stack_size_rtx);
+      /* If returning from the subroutine does not automatically pop the args,
+        we need an instruction to pop them sooner or later.
+        Perhaps do it now; perhaps just record how much space to pop later.
+
+        If returning from the subroutine does pop the args, indicate that the
+        stack pointer will be changed.  */
+
+      if (rounded_stack_size != 0)
+       {
+         if (flag_defer_pop && inhibit_defer_pop == 0
+             && !(ecf_flags & (ECF_CONST | ECF_PURE)))
+           pending_stack_adjust += rounded_stack_size;
+         else
+           adjust_stack (rounded_stack_size_rtx);
+       }
     }
-#endif
+  /* When we accumulate outgoing args, we must avoid any stack manipulations.
+     Restore the stack pointer to its original value now.  Usually
+     ACCUMULATE_OUTGOING_ARGS targets don't get here, but there are exceptions.
+     On  i386 ACCUMULATE_OUTGOING_ARGS can be enabled on demand, and
+     popping variants of functions exist as well.
+
+     ??? We may optimize similar to defer_pop above, but it is
+     probably not worthwhile.
+   
+     ??? It will be worthwhile to enable combine_stack_adjustments even for
+     such machines.  */
+  else if (n_popped)
+    anti_adjust_stack (GEN_INT (n_popped));
 }
 
 /* Determine if the function identified by NAME and FNDECL is one with
@@ -599,33 +650,20 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
    For example, if the function might return more than one time (setjmp), then
    set RETURNS_TWICE to a nonzero value.
 
-   Similarly set IS_LONGJMP for if the function is in the longjmp family.
+   Similarly set LONGJMP for if the function is in the longjmp family.
 
-   Set IS_MALLOC for any of the standard memory allocation functions which
+   Set MALLOC for any of the standard memory allocation functions which
    allocate from the heap.
 
    Set MAY_BE_ALLOCA for any memory allocation function that might allocate
    space from the stack such as alloca.  */
 
-void
-special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
-                   is_malloc, may_be_alloca)
+static int
+special_function_p (fndecl, flags)
      tree fndecl;
-     int *returns_twice;
-     int *is_longjmp;
-     int *fork_or_exec;
-     int *is_malloc;
-     int *may_be_alloca;
+     int flags;
 {
-  *returns_twice = 0;
-  *is_longjmp = 0;
-  *fork_or_exec = 0;
-  *may_be_alloca = 0;
-
-  /* The function decl may have the `malloc' attribute.  */
-  *is_malloc = fndecl && DECL_IS_MALLOC (fndecl);
-
-  if (! *is_malloc 
+  if (! (flags & ECF_MALLOC)
       && fndecl && DECL_NAME (fndecl)
       && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
       /* Exclude functions not at the file scope, or not `extern',
@@ -639,13 +677,13 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
       /* We assume that alloca will always be called by name.  It
         makes no sense to pass it as a pointer-to-function to
         anything that does not understand its behavior.  */
-      *may_be_alloca
-       = (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
-            && name[0] == 'a'
-            && ! strcmp (name, "alloca"))
-           || (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
-               && name[0] == '_'
-               && ! strcmp (name, "__builtin_alloca"))));
+      if (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
+           && name[0] == 'a'
+           && ! strcmp (name, "alloca"))
+          || (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
+              && name[0] == '_'
+              && ! strcmp (name, "__builtin_alloca"))))
+       flags |= ECF_MAY_BE_ALLOCA;
 
       /* Disregard prefix _, __ or __x.  */
       if (name[0] == '_')
@@ -660,27 +698,28 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
 
       if (tname[0] == 's')
        {
-         *returns_twice
-            = ((tname[1] == 'e'
-                && (! strcmp (tname, "setjmp")
-                    || ! strcmp (tname, "setjmp_syscall")))
-               || (tname[1] == 'i'
-                   && ! strcmp (tname, "sigsetjmp"))
-               || (tname[1] == 'a'
-                   && ! strcmp (tname, "savectx")));
+         if ((tname[1] == 'e'
+              && (! strcmp (tname, "setjmp")
+                  || ! strcmp (tname, "setjmp_syscall")))
+             || (tname[1] == 'i'
+                 && ! strcmp (tname, "sigsetjmp"))
+             || (tname[1] == 'a'
+                 && ! strcmp (tname, "savectx")))
+           flags |= ECF_RETURNS_TWICE;
+
          if (tname[1] == 'i'
              && ! strcmp (tname, "siglongjmp"))
-           *is_longjmp = 1;
+           flags |= ECF_LONGJMP;
        }
       else if ((tname[0] == 'q' && tname[1] == 's'
                && ! strcmp (tname, "qsetjmp"))
               || (tname[0] == 'v' && tname[1] == 'f'
                   && ! strcmp (tname, "vfork")))
-       *returns_twice = 1;
+       flags |= ECF_RETURNS_TWICE;
 
       else if (tname[0] == 'l' && tname[1] == 'o'
               && ! strcmp (tname, "longjmp"))
-       *is_longjmp = 1;
+       flags |= ECF_LONGJMP;
 
       else if ((tname[0] == 'f' && tname[1] == 'o'
                && ! strcmp (tname, "fork"))
@@ -694,7 +733,7 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
                   && (tname[5] == '\0'
                       || ((tname[5] == 'p' || tname[5] == 'e')
                           && tname[6] == '\0'))))
-       *fork_or_exec = 1;
+       flags |= ECF_FORK_OR_EXEC;
 
       /* Do not add any more malloc-like functions to this list,
          instead mark them as malloc functions using the malloc attribute.
@@ -707,10 +746,50 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
               && (! strcmp (tname, "malloc")
                   || ! strcmp (tname, "calloc")
                   || ! strcmp (tname, "strdup")))
-       *is_malloc = 1;
+       flags |= ECF_MALLOC;
+    }
+  return flags;
+}
+
+/* Return nonzero when tree represent call to longjmp.  */
+int
+setjmp_call_p (fndecl)
+     tree fndecl;
+{
+  return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
+}
+
+/* Detect flags (function attributes) from the function type node.  */
+static int
+flags_from_decl_or_type (exp)
+     tree exp;
+{
+  int flags = 0;
+  /* ??? We can't set IS_MALLOC for function types?  */
+  if (DECL_P (exp))
+    {
+      /* The function exp may have the `malloc' attribute.  */
+      if (DECL_P (exp) && DECL_IS_MALLOC (exp))
+       flags |= ECF_MALLOC;
+
+      /* The function exp may have the `pure' attribute.  */
+      if (DECL_P (exp) && DECL_IS_PURE (exp))
+       flags |= ECF_PURE;
+
+      if (TREE_NOTHROW (exp))
+       flags |= ECF_NOTHROW;
     }
+
+  if (TREE_READONLY (exp) && !TREE_THIS_VOLATILE (exp))
+    flags |= ECF_CONST;
+
+  if (TREE_THIS_VOLATILE (exp))
+    flags |= ECF_NORETURN;
+
+  return flags;
 }
 
+
 /* Precompute all register parameters as described by ARGS, storing values
    into fields within the ARGS array.
 
@@ -774,7 +853,7 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen)
       }
 }
 
-#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+#ifdef 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
@@ -833,11 +912,11 @@ 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.  */
+         /* 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 / BITS_PER_UNIT);
+                         PARM_BOUNDARY);
        }
       else
        {
@@ -877,8 +956,7 @@ restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save)
        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 / BITS_PER_UNIT);
+                   high_to_save - low_to_save + 1, PARM_BOUNDARY);
 }
 #endif
          
@@ -945,12 +1023,10 @@ store_unaligned_arguments_into_pseudos (args, num_actuals)
 
            bytes -= bitsize / BITS_PER_UNIT;
            store_bit_field (reg, bitsize, big_endian_correction, word_mode,
-                            extract_bit_field (word, bitsize, 0, 1,
-                                               NULL_RTX, word_mode,
-                                               word_mode,
-                                               bitalign / BITS_PER_UNIT,
+                            extract_bit_field (word, bitsize, 0, 1, NULL_RTX,
+                                               word_mode, word_mode, bitalign,
                                                BITS_PER_WORD),
-                            bitalign / BITS_PER_UNIT, BITS_PER_WORD);
+                            bitalign, BITS_PER_WORD);
          }
       }
 }
@@ -973,14 +1049,14 @@ store_unaligned_arguments_into_pseudos (args, num_actuals)
    OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level
    and may be modified by this routine.
 
-   OLD_PENDING_ADJ, MUST_PREALLOCATE and IS_CONST are pointers to integer
+   OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer
    flags which may may be modified by this routine.  */
 
 static void
 initialize_argument_information (num_actuals, args, args_size, n_named_args,
                                 actparms, fndecl, args_so_far,
                                 reg_parm_stack_space, old_stack_level,
-                                old_pending_adj, must_preallocate, is_const,
+                                old_pending_adj, must_preallocate,
                                 ecf_flags)
      int num_actuals ATTRIBUTE_UNUSED;
      struct arg_data *args;
@@ -993,8 +1069,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
      rtx *old_stack_level;
      int *old_pending_adj;
      int *must_preallocate;
-     int *is_const;
-     int ecf_flags;
+     int *ecf_flags;
 {
   /* 1 if scanning parms front to back, -1 if scanning back to front.  */
   int inc;
@@ -1013,13 +1088,16 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
      We fill up ARGS from the front or from the back if necessary
      so that in any case the first arg to be pushed ends up at the front.  */
 
-#ifdef PUSH_ARGS_REVERSED
-  i = num_actuals - 1, inc = -1;
-  /* In this case, must reverse order of args
-     so that we compute and push the last arg first.  */
-#else
-  i = 0, inc = 1;
-#endif
+  if (PUSH_ARGS_REVERSED)
+    {
+      i = num_actuals - 1, inc = -1;
+      /* In this case, must reverse order of args
+        so that we compute and push the last arg first.  */
+    }
+  else
+    {
+      i = 0, inc = 1;
+    }
 
   /* I counts args in order (to be) pushed; ARGPOS counts in order written.  */
   for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)
@@ -1134,7 +1212,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
              MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
 
              store_expr (args[i].tree_value, copy, 0);
-             *is_const = 0;
+             *ecf_flags &= ~(ECF_CONST | ECF_PURE);
 
              args[i].tree_value = build1 (ADDR_EXPR,
                                           build_pointer_type (type),
@@ -1157,7 +1235,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
       /* If this is a sibling call and the machine has register windows, the
         register window has to be unwinded before calling the routine, so
         arguments have to go into the incoming registers.  */
-      if (ecf_flags & ECF_SIBCALL)
+      if (*ecf_flags & ECF_SIBCALL)
        args[i].reg = FUNCTION_INCOMING_ARG (*args_so_far, mode, type,
                                             argpos < n_named_args);
       else
@@ -1193,7 +1271,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
       /* If this is an addressable type, we cannot pre-evaluate it.  Thus,
         we cannot consider this function call constant.  */
       if (TREE_ADDRESSABLE (type))
-       *is_const = 0;
+       *ecf_flags &= ~(ECF_CONST | ECF_PURE);
 
       /* Compute the stack-size of this argument.  */
       if (args[i].reg == 0 || args[i].partial != 0
@@ -1262,6 +1340,14 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
 {
   int unadjusted_args_size = args_size->constant;
 
+  /* 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,
      and there may be a minimum required size.  */
@@ -1274,7 +1360,14 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
 #ifdef PREFERRED_STACK_BOUNDARY
       preferred_stack_boundary /= BITS_PER_UNIT;
       if (preferred_stack_boundary > 1)
-       args_size->var = round_up (args_size->var, preferred_stack_boundary);
+       {
+         /* We don't handle this case yet.  To handle it correctly we have
+            to add the delta, round and substract the delta.  
+            Currently no machine description requires this support.  */
+         if (stack_pointer_delta & (preferred_stack_boundary - 1))
+           abort();
+         args_size->var = round_up (args_size->var, preferred_stack_boundary);
+       }
 #endif
 
       if (reg_parm_stack_space > 0)
@@ -1299,13 +1392,11 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
       if (preferred_stack_boundary < 1)
        preferred_stack_boundary = 1;
       args_size->constant = (((args_size->constant
-                              + arg_space_so_far
-                              + pending_stack_adjust
+                              + stack_pointer_delta
                               + preferred_stack_boundary - 1)
                              / preferred_stack_boundary
                              * preferred_stack_boundary)
-                            - arg_space_so_far
-                            - pending_stack_adjust);
+                            - stack_pointer_delta);
 #endif
 
       args_size->constant = MAX (args_size->constant,
@@ -1325,25 +1416,19 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
 
 /* Precompute parameters as needed for a function call.
 
-   IS_CONST indicates the target function is a pure function.
-
-   MUST_PREALLOCATE indicates that we must preallocate stack space for
-   any stack arguments.
+   FLAGS is mask of ECF_* constants.
 
    NUM_ACTUALS is the number of arguments.
 
    ARGS is an array containing information for each argument; this routine
-   fills in the INITIAL_VALUE and VALUE fields for each precomputed argument.
-
-   ARGS_SIZE contains information about the size of the arg list.  */
+   fills in the INITIAL_VALUE and VALUE fields for each precomputed argument.  
+   */
 
 static void
-precompute_arguments (is_const, must_preallocate, num_actuals, args, args_size)
-     int is_const;
-     int must_preallocate;
+precompute_arguments (flags, num_actuals, args)
+     int flags;
      int num_actuals;
      struct arg_data *args;
-     struct args_size *args_size;
 {
   int i;
 
@@ -1358,15 +1443,13 @@ precompute_arguments (is_const, must_preallocate, num_actuals, args, args_size)
      on the stack, then we must precompute any parameter which contains a
      function call which will store arguments on the stack.
      Otherwise, evaluating the parameter may clobber previous parameters
-     which have already been stored into the stack.  */
+     which have already been stored into the stack.  (we have code to avoid
+     such case by saving the ougoing stack arguments, but it results in
+     worse code)  */
 
   for (i = 0; i < num_actuals; i++)
-    if (is_const
-       || ((args_size->var != 0 || args_size->constant != 0)
-           && calls_function (args[i].tree_value, 1))
-       || (must_preallocate
-           && (args_size->var != 0 || args_size->constant != 0)
-           && calls_function (args[i].tree_value, 0)))
+    if ((flags & (ECF_CONST | ECF_PURE))
+       || calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS))
       {
        /* If this is an addressable type, we cannot pre-evaluate it.  */
        if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
@@ -1622,12 +1705,9 @@ load_register_parameters (args, num_actuals, call_fusage)
             locations.  The Irix 6 ABI has examples of this.  */
 
          if (GET_CODE (reg) == PARALLEL)
-           {
-             emit_group_load (reg, args[i].value,
-                              int_size_in_bytes (TREE_TYPE (args[i].tree_value)),
-                              (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
-                               / BITS_PER_UNIT));
-           }
+           emit_group_load (reg, args[i].value,
+                            int_size_in_bytes (TREE_TYPE (args[i].tree_value)),
+                            TYPE_ALIGN (TREE_TYPE (args[i].tree_value)));
 
          /* If simple case, just do move.  If normal partial, store_one_arg
             has already loaded the register for us.  In all other cases,
@@ -1661,6 +1741,178 @@ load_register_parameters (args, num_actuals, call_fusage)
     }
 }
 
+/* Try to integreate function.  See expand_inline_function for documentation
+   about the parameters.  */
+
+static rtx
+try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr)
+     tree fndecl;
+     tree actparms;
+     rtx target;
+     int ignore;
+     tree type;
+     rtx structure_value_addr;
+{
+  rtx temp;
+  rtx before_call;
+  int i;
+  rtx old_stack_level = 0;
+  int reg_parm_stack_space = 0;
+
+#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
+
+  before_call = get_last_insn ();
+
+  temp = expand_inline_function (fndecl, actparms, target,
+                                ignore, type,
+                                structure_value_addr);
+
+  /* If inlining succeeded, return.  */
+  if (temp != (rtx) (HOST_WIDE_INT) - 1)
+    {
+      if (ACCUMULATE_OUTGOING_ARGS)
+       {
+         /* If the outgoing argument list must be preserved, push
+            the stack before executing the inlined function if it
+            makes any calls.  */
+
+         for (i = reg_parm_stack_space - 1; i >= 0; i--)
+           if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)
+             break;
+
+         if (stack_arg_under_construction || i >= 0)
+           {
+             rtx first_insn
+               = before_call ? NEXT_INSN (before_call) : get_insns ();
+             rtx insn = NULL_RTX, seq;
+
+             /* Look for a call in the inline function code.
+                If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is
+                nonzero then there is a call and it is not necessary
+                to scan the insns.  */
+
+             if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0)
+               for (insn = first_insn; insn; insn = NEXT_INSN (insn))
+                 if (GET_CODE (insn) == CALL_INSN)
+                   break;
+
+             if (insn)
+               {
+                 /* Reserve enough stack space so that the largest
+                    argument list of any function call in the inline
+                    function does not overlap the argument list being
+                    evaluated.  This is usually an overestimate because
+                    allocate_dynamic_stack_space reserves space for an
+                    outgoing argument list in addition to the requested
+                    space, but there is no way to ask for stack space such
+                    that an argument list of a certain length can be
+                    safely constructed. 
+
+                    Add the stack space reserved for register arguments, if
+                    any, in the inline function.  What is really needed is the
+                    largest value of reg_parm_stack_space in the inline
+                    function, but that is not available.  Using the current
+                    value of reg_parm_stack_space is wrong, but gives
+                    correct results on all supported machines.  */
+
+                 int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size
+                               + reg_parm_stack_space);
+
+                 start_sequence ();
+                 emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+                 allocate_dynamic_stack_space (GEN_INT (adjust),
+                                               NULL_RTX, BITS_PER_UNIT);
+                 seq = get_insns ();
+                 end_sequence ();
+                 emit_insns_before (seq, first_insn);
+                 emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
+               }
+           }
+       }
+
+      /* If the result is equivalent to TARGET, return TARGET to simplify
+         checks in store_expr.  They can be equivalent but not equal in the
+         case of a function that returns BLKmode.  */
+      if (temp != target && rtx_equal_p (temp, target))
+       return target;
+      return temp;
+    }
+
+  /* If inlining failed, mark FNDECL as needing to be compiled
+     separately after all.  If function was declared inline,
+     give a warning.  */
+  if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
+      && optimize > 0 && !TREE_ADDRESSABLE (fndecl))
+    {
+      warning_with_decl (fndecl, "inlining failed in call to `%s'");
+      warning ("called from here");
+    }
+  mark_addressable (fndecl);
+  return (rtx) (HOST_WIDE_INT) - 1;
+}
+
+/* We need to pop PENDING_STACK_ADJUST bytes.  But, if the arguments
+   wouldn't fill up an even multiple of PREFERRED_UNIT_STACK_BOUNDARY
+   bytes, then we would need to push some additional bytes to pad the
+   arguments.  So, we compute an adjust to the stack pointer for an
+   amount that will leave the stack under-aligned by UNADJUSTED_ARGS_SIZE
+   bytes.  Then, when the arguments are pushed the stack will be perfectly
+   aligned.  ARGS_SIZE->CONSTANT is set to the number of bytes that should
+   be popped after the call.  Returns the adjustment.  */
+
+static int
+combine_pending_stack_adjustment_and_call (unadjusted_args_size,
+                                          args_size,
+                                          preferred_unit_stack_boundary)
+     int unadjusted_args_size;
+     struct args_size *args_size;
+     int preferred_unit_stack_boundary;
+{
+  /* The number of bytes to pop so that the stack will be
+     under-aligned by UNADJUSTED_ARGS_SIZE bytes.  */
+  HOST_WIDE_INT adjustment;
+  /* The alignment of the stack after the arguments are pushed, if we
+     just pushed the arguments without adjust the stack here.  */
+  HOST_WIDE_INT unadjusted_alignment;
+
+  unadjusted_alignment 
+    = ((stack_pointer_delta + unadjusted_args_size)
+       % preferred_unit_stack_boundary);
+
+  /* We want to get rid of as many of the PENDING_STACK_ADJUST bytes
+     as possible -- leaving just enough left to cancel out the
+     UNADJUSTED_ALIGNMENT.  In other words, we want to ensure that the
+     PENDING_STACK_ADJUST is non-negative, and congruent to
+     -UNADJUSTED_ALIGNMENT modulo the PREFERRED_UNIT_STACK_BOUNDARY.  */
+
+  /* Begin by trying to pop all the bytes.  */
+  unadjusted_alignment 
+    = (unadjusted_alignment 
+       - (pending_stack_adjust % preferred_unit_stack_boundary));
+  adjustment = pending_stack_adjust;
+  /* Push enough additional bytes that the stack will be aligned
+     after the arguments are pushed.  */
+  if (unadjusted_alignment >= 0)
+    adjustment -= preferred_unit_stack_boundary - unadjusted_alignment;
+  else
+    adjustment += unadjusted_alignment;
+  
+  /* Now, sets ARGS_SIZE->CONSTANT so that we pop the right number of
+     bytes after the call.  The right number is the entire
+     PENDING_STACK_ADJUST less our ADJUSTMENT plus the amount required
+     by the arguments in the first place.  */
+  args_size->constant 
+    = pending_stack_adjust - adjustment + unadjusted_args_size;
+
+  return adjustment;
+}
+
 /* Generate all the code for a function call
    and return an rtx for its value.
    Store the value in TARGET (specified as an rtx) if convenient.
@@ -1692,9 +1944,6 @@ expand_call (exp, target, ignore)
      or 0 if the function is computed (not known by name).  */
   tree fndecl = 0;
   char *name = 0;
-#ifdef ACCUMULATE_OUTGOING_ARGS
-  rtx before_call;
-#endif
   rtx insn;
   int try_tail_call;
   int pass;
@@ -1744,11 +1993,7 @@ expand_call (exp, target, ignore)
      So the entire argument block must then be preallocated (i.e., we
      ignore PUSH_ROUNDING in that case).  */
 
-#ifdef PUSH_ROUNDING
-  int must_preallocate = 0;
-#else
-  int must_preallocate = 1;
-#endif
+  int must_preallocate = !PUSH_ARGS;
 
   /* Size of the stack reserved for parameter registers.  */
   int reg_parm_stack_space = 0;
@@ -1757,46 +2002,32 @@ expand_call (exp, target, ignore)
      (on machines that lack push insns), or 0 if space not preallocated.  */
   rtx argblock = 0;
 
-  /* Nonzero if it is plausible that this is a call to alloca.  */
-  int may_be_alloca;
-  /* Nonzero if this is a call to malloc or a related function. */
-  int is_malloc;
-  /* Nonzero if this is a call to setjmp or a related function.  */
-  int returns_twice;
-  /* Nonzero if this is a call to `longjmp'.  */
-  int is_longjmp;
-  /* Nonzero if this is a syscall that makes a new process in the image of
-     the current one.  */
-  int fork_or_exec;
+  /* Mask of ECF_ flags.  */
+  int flags = 0;
   /* Nonzero if this is a call to an inline function.  */
   int is_integrable = 0;
-  /* Nonzero if this is a call to a `const' function.
-     Note that only explicitly named functions are handled as `const' here.  */
-  int is_const = 0;
-  /* Nonzero if this is a call to a `volatile' function.  */
-  int is_volatile = 0;
-  /* Nonzero if this is a call to a function that won't throw an exception.  */
-  int nothrow = TREE_NOTHROW (exp);
-#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+#ifdef 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 old_stack_arg_under_construction = 0;
-#endif
 
   rtx old_stack_level = 0;
   int old_pending_adj = 0;
   int old_inhibit_defer_pop = inhibit_defer_pop;
+  int old_stack_allocated;
   rtx call_fusage;
   register tree p;
   register int i;
-  int preferred_stack_boundary;
+  /* The alignment of the stack, in bits.  */
+  HOST_WIDE_INT preferred_stack_boundary;
+  /* The alignment of the stack, in bytes.  */
+  HOST_WIDE_INT preferred_unit_stack_boundary;
 
   /* The value of the function call can be put in a hard register.  But
      if -fcheck-memory-usage, code which invokes functions (and thus
@@ -1805,57 +2036,47 @@ expand_call (exp, target, ignore)
   if (current_function_check_memory_usage)
     target = 0;
 
+  /* See if this is "nothrow" function call.  */
+  if (TREE_NOTHROW (exp))
+    flags |= ECF_NOTHROW;
+
   /* See if we can find a DECL-node for the actual function.
      As a result, decide whether this is a call to an integrable function.  */
 
-  p = TREE_OPERAND (exp, 0);
-  if (TREE_CODE (p) == ADDR_EXPR)
+  fndecl = get_callee_fndecl (exp);
+  if (fndecl)
     {
-      fndecl = TREE_OPERAND (p, 0);
-      if (TREE_CODE (fndecl) != FUNCTION_DECL)
-       fndecl = 0;
-      else
+      if (!flag_no_inline
+         && fndecl != current_function_decl
+         && DECL_INLINE (fndecl)
+         && DECL_SAVED_INSNS (fndecl)
+         && DECL_SAVED_INSNS (fndecl)->inlinable)
+       is_integrable = 1;
+      else if (! TREE_ADDRESSABLE (fndecl))
        {
-         if (!flag_no_inline
-             && fndecl != current_function_decl
-             && DECL_INLINE (fndecl)
-             && DECL_SAVED_INSNS (fndecl)
-             && DECL_SAVED_INSNS (fndecl)->inlinable)
-           is_integrable = 1;
-         else if (! TREE_ADDRESSABLE (fndecl))
-           {
-             /* In case this function later becomes inlinable,
-                record that there was already a non-inline call to it.
+         /* In case this function later becomes inlinable,
+            record that there was already a non-inline call to it.
 
-                Use abstraction instead of setting TREE_ADDRESSABLE
-                directly.  */
-             if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
-                 && optimize > 0)
-               {
-                 warning_with_decl (fndecl, "can't inline call to `%s'");
-                 warning ("called from here");
-               }
-             mark_addressable (fndecl);
+            Use abstraction instead of setting TREE_ADDRESSABLE
+            directly.  */
+         if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
+             && optimize > 0)
+           {
+             warning_with_decl (fndecl, "can't inline call to `%s'");
+             warning ("called from here");
            }
-
-         if (TREE_READONLY (fndecl) && ! TREE_THIS_VOLATILE (fndecl)
-             && TYPE_MODE (TREE_TYPE (exp)) != VOIDmode)
-           is_const = 1;
-
-         if (TREE_THIS_VOLATILE (fndecl))
-           is_volatile = 1;
-
-         if (TREE_NOTHROW (fndecl))
-           nothrow = 1;
+         mark_addressable (fndecl);
        }
+
+      flags |= flags_from_decl_or_type (fndecl);
     }
 
   /* If we don't have specific function to call, see if we have a 
-     constant or `noreturn' function from the type.  */
-  if (fndecl == 0)
+     attributes set in the type.  */
+  else
     {
-      is_const = TREE_READONLY (TREE_TYPE (TREE_TYPE (p)));
-      is_volatile = TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (p)));
+      p = TREE_OPERAND (exp, 0);
+      flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
     }
 
 #ifdef REG_PARM_STACK_SPACE
@@ -1866,8 +2087,8 @@ expand_call (exp, target, ignore)
 #endif
 #endif
 
-#if defined(PUSH_ROUNDING) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
-  if (reg_parm_stack_space > 0)
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+  if (reg_parm_stack_space > 0 && PUSH_ARGS)
     must_preallocate = 1;
 #endif
 
@@ -1882,7 +2103,7 @@ expand_call (exp, target, ignore)
   if (aggregate_value_p (exp))
     {
       /* This call returns a big structure.  */
-      is_const = 0;
+      flags &= ~(ECF_CONST | ECF_PURE);
 
 #ifdef PCC_STATIC_STRUCT_RETURN
       {
@@ -1933,138 +2154,60 @@ expand_call (exp, target, ignore)
 
   if (is_integrable)
     {
-      rtx temp;
+      rtx temp = try_to_integrate (fndecl, actparms, target,
+                                  ignore, TREE_TYPE (exp),
+                                  structure_value_addr);
+      if (temp != (rtx) (HOST_WIDE_INT) - 1)
+       return temp;
+    }
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
-      before_call = get_last_insn ();
-#endif
+  currently_expanding_call++;
 
-      temp = expand_inline_function (fndecl, actparms, target,
-                                    ignore, TREE_TYPE (exp),
-                                    structure_value_addr);
+  /* 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.
 
-      /* If inlining succeeded, return.  */
-      if (temp != (rtx) (HOST_WIDE_INT) -1)
-       {
-#ifdef ACCUMULATE_OUTGOING_ARGS
-         /* If the outgoing argument list must be preserved, push
-            the stack before executing the inlined function if it
-            makes any calls.  */
+     If rtx_equal_function_value_matters is false, that means we've 
+     finished with regular parsing.  Which means that some of the
+     machinery we use to generate tail-calls is no longer in place.
+     This is most often true of sjlj-exceptions, which we couldn't
+     tail-call to anyway.  */
 
-         for (i = reg_parm_stack_space - 1; i >= 0; i--)
-           if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)
-             break;
+  try_tail_call = 0;
+  if (flag_optimize_sibling_calls
+      && currently_expanding_call == 1
+      && rtx_equal_function_value_matters
+      && stmt_loop_nest_empty ()
+      && ! any_pending_cleanups (1))
+    {
+      tree new_actparms = NULL_TREE;
 
-         if (stack_arg_under_construction || i >= 0)
-           {
-             rtx first_insn
-               = before_call ? NEXT_INSN (before_call) : get_insns ();
-             rtx insn = NULL_RTX, seq;
+      /* Ok, we're going to give the tail call the old college try.
+        This means we're going to evaluate the function arguments
+        up to three times.  There are two degrees of badness we can
+        encounter, those that can be unsaved and those that can't.
+        (See unsafe_for_reeval commentary for details.)
 
-             /* Look for a call in the inline function code.
-                If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is
-                nonzero then there is a call and it is not necessary
-                to scan the insns.  */
+        Generate a new argument list.  Pass safe arguments through
+        unchanged.  For the easy badness wrap them in UNSAVE_EXPRs.  
+        For hard badness, evaluate them now and put their resulting
+        rtx in a temporary VAR_DECL.  */
 
-             if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0)
-               for (insn = first_insn; insn; insn = NEXT_INSN (insn))
-                 if (GET_CODE (insn) == CALL_INSN)
-                   break;
+      for (p = actparms; p; p = TREE_CHAIN (p))
+       switch (unsafe_for_reeval (TREE_VALUE (p)))
+         {
+         case 0: /* Safe.  */
+           new_actparms = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p),
+                                     new_actparms);
+           break;
 
-             if (insn)
-               {
-                 /* Reserve enough stack space so that the largest
-                    argument list of any function call in the inline
-                    function does not overlap the argument list being
-                    evaluated.  This is usually an overestimate because
-                    allocate_dynamic_stack_space reserves space for an
-                    outgoing argument list in addition to the requested
-                    space, but there is no way to ask for stack space such
-                    that an argument list of a certain length can be
-                    safely constructed. 
-
-                    Add the stack space reserved for register arguments, if
-                    any, in the inline function.  What is really needed is the
-                    largest value of reg_parm_stack_space in the inline
-                    function, but that is not available.  Using the current
-                    value of reg_parm_stack_space is wrong, but gives
-                    correct results on all supported machines.  */
-
-                 int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size
-                               + reg_parm_stack_space);
-
-                 start_sequence ();
-                 emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
-                 allocate_dynamic_stack_space (GEN_INT (adjust),
-                                               NULL_RTX, BITS_PER_UNIT);
-                 seq = get_insns ();
-                 end_sequence ();
-                 emit_insns_before (seq, first_insn);
-                 emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
-               }
-           }
-#endif
-
-         /* If the result is equivalent to TARGET, return TARGET to simplify
-            checks in store_expr.  They can be equivalent but not equal in the
-            case of a function that returns BLKmode.  */
-         if (temp != target && rtx_equal_p (temp, target))
-           return target;
-         return temp;
-       }
-
-      /* If inlining failed, mark FNDECL as needing to be compiled
-        separately after all.  If function was declared inline,
-        give a warning.  */
-      if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
-         && optimize > 0 && ! TREE_ADDRESSABLE (fndecl))
-       {
-         warning_with_decl (fndecl, "inlining failed in call to `%s'");
-         warning ("called from here");
-       }
-      mark_addressable (fndecl);
-    }
-
-  currently_expanding_call++;
-
-  /* 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.  */
-
-  try_tail_call = 0;
-  if (optimize >= 2
-      && currently_expanding_call == 1
-      && stmt_loop_nest_empty ()
-      && ! any_pending_cleanups (1))
-    {
-      tree new_actparms = NULL_TREE;
-
-      /* Ok, we're going to give the tail call the old college try.
-        This means we're going to evaluate the function arguments
-        up to three times.  There are two degrees of badness we can
-        encounter, those that can be unsaved and those that can't.
-        (See unsafe_for_reeval commentary for details.)
-
-        Generate a new argument list.  Pass safe arguments through
-        unchanged.  For the easy badness wrap them in UNSAVE_EXPRs.  
-        For hard badness, evaluate them now and put their resulting
-        rtx in a temporary VAR_DECL.  */
-
-      for (p = actparms; p; p = TREE_CHAIN (p))
-       switch (unsafe_for_reeval (TREE_VALUE (p)))
-         {
-         case 0: /* Safe.  */
-           new_actparms = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p),
-                                     new_actparms);
-           break;
-
-         case 1: /* Mildly unsafe.  */
-           new_actparms = tree_cons (TREE_PURPOSE (p),
-                                     unsave_expr (TREE_VALUE (p)),
-                                     new_actparms);
-           break;
+         case 1: /* Mildly unsafe.  */
+           new_actparms = tree_cons (TREE_PURPOSE (p),
+                                     unsave_expr (TREE_VALUE (p)),
+                                     new_actparms);
+           break;
 
          case 2: /* Wildly unsafe.  */
            {
@@ -2099,6 +2242,7 @@ expand_call (exp, target, ignore)
         recursion call can be ignored if we indeed use the tail recursion
         call expansion.  */
       int save_pending_stack_adjust = pending_stack_adjust;
+      int save_stack_pointer_delta = stack_pointer_delta;
 
       /* 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
@@ -2116,6 +2260,7 @@ expand_call (exp, target, ignore)
       /* Restore the original pending stack adjustment for the sibling and
         normal call cases below.  */
       pending_stack_adjust = save_pending_stack_adjust;
+      stack_pointer_delta = save_stack_pointer_delta;
     }
 
   function_call_count++;
@@ -2123,11 +2268,13 @@ expand_call (exp, target, ignore)
   if (fndecl && DECL_NAME (fndecl))
     name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
 
+  /* 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
+  preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
 
   /* Ensure current function's preferred stack boundary is at least
      what we need.  We don't have to increase alignment for recursive
@@ -2138,10 +2285,9 @@ expand_call (exp, target, ignore)
 
   /* See if this is a call to a function that can return more than once
      or a call to longjmp or malloc.  */
-  special_function_p (fndecl, &returns_twice, &is_longjmp, &fork_or_exec,
-                     &is_malloc, &may_be_alloca);
+  flags |= special_function_p (fndecl, flags);
 
-  if (may_be_alloca)
+  if (flags & ECF_MAY_BE_ALLOCA)
     current_function_calls_alloca = 1;
 
   /* Operand 0 is a pointer-to-function; get the type of the function.  */
@@ -2161,6 +2307,7 @@ expand_call (exp, target, ignore)
         recursion call can be ignored if we indeed use the tail recursion
         call expansion.  */
       int save_pending_stack_adjust;
+      int save_stack_pointer_delta;
       rtx insns;
       rtx before_call, next_arg_reg;
 
@@ -2189,6 +2336,10 @@ expand_call (exp, target, ignore)
              || ! FUNCTION_OK_FOR_SIBCALL (fndecl))
            continue;
 
+         /* Emit any queued insns now; otherwise they would end up in
+             only one of the alternates.  */
+         emit_queue ();
+
          /* We know at this point that there are not currently any
             pending cleanups.  If, however, in the process of evaluating
             the arguments we were to create some, we'll need to be
@@ -2198,10 +2349,15 @@ expand_call (exp, target, ignore)
          /* State variables we need to save and restore between
             iterations.  */
          save_pending_stack_adjust = pending_stack_adjust;
+         save_stack_pointer_delta = stack_pointer_delta;
        }
+      if (pass)
+       flags &= ~ECF_SIBCALL;
+      else
+       flags |= ECF_SIBCALL;
 
       /* Other state variables that we must reinitialize each time
-        through the loop (that are not initialized by the loop itself.  */
+        through the loop (that are not initialized by the loop itself).  */
       argblock = 0;
       call_fusage = 0;
 
@@ -2213,7 +2369,7 @@ expand_call (exp, target, ignore)
 
       /* 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 (is_const)
+      if (flags & (ECF_CONST | ECF_PURE))
        NO_DEFER_POP;
 
       /* Don't let pending stack adjusts add up to too much.
@@ -2221,11 +2377,11 @@ expand_call (exp, target, ignore)
         this might be a call to alloca or if we are expanding a sibling
         call sequence.  */
       if (pending_stack_adjust >= 32
-         || (pending_stack_adjust > 0 && may_be_alloca)
+         || (pending_stack_adjust > 0 && (flags & ECF_MAY_BE_ALLOCA))
          || pass == 0)
        do_pending_stack_adjust ();
 
-      if (profile_arc_flag && fork_or_exec)
+      if (profile_arc_flag && (flags & ECF_FORK_OR_EXEC))
        {
          /* A fork duplicates the profile information, and an exec discards
             it.  We can't rely on fork/exec to be paired.  So write out the
@@ -2260,10 +2416,9 @@ expand_call (exp, target, ignore)
             If it is virtual_outgoing_args_rtx, we must copy it to another
             register in some cases.  */
          rtx temp = (GET_CODE (structure_value_addr) != REG
-#ifdef ACCUMULATE_OUTGOING_ARGS
-                     || (stack_arg_under_construction
+                     || (ACCUMULATE_OUTGOING_ARGS
+                         && stack_arg_under_construction
                          && structure_value_addr == virtual_outgoing_args_rtx)
-#endif
                      ? copy_addr_to_reg (structure_value_addr)
                      : structure_value_addr);
 
@@ -2319,8 +2474,7 @@ expand_call (exp, target, ignore)
                                       n_named_args, actparms, fndecl,
                                       &args_so_far, reg_parm_stack_space,
                                       &old_stack_level, &old_pending_adj,
-                                      &must_preallocate, &is_const,
-                                      (pass == 0) ? ECF_SIBCALL : 0);
+                                      &must_preallocate, &flags);
 
 #ifdef FINAL_REG_PARM_STACK_SPACE
       reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
@@ -2336,7 +2490,7 @@ expand_call (exp, target, ignore)
 
             Also do not make a sibling call.  */
 
-         is_const = 0;
+         flags &= ~(ECF_CONST | ECF_PURE);
          must_preallocate = 1;
          sibcall_failure = 1;
        }
@@ -2348,19 +2502,9 @@ expand_call (exp, target, ignore)
          sibcall_failure = 1;
        }
 
-      /* Compute the actual size of the argument block required.  The variable
-        and constant sizes must be combined, the size may have to be rounded,
-        and there may be a minimum required size.  When generating a sibcall
-        pattern, do not round up, since we'll be re-using whatever space our
-        caller provided.  */
-      unadjusted_args_size
-       = compute_argument_block_size (reg_parm_stack_space, &args_size,
-                                      (pass == 0 ? 0
-                                       : preferred_stack_boundary));
-
       /* If the callee pops its own arguments, then it must pop exactly
         the same number of arguments as the current function.  */
-      if (RETURN_POPS_ARGS (fndecl, funtype, unadjusted_args_size)
+      if (RETURN_POPS_ARGS (fndecl, funtype, args_size.constant)
          != RETURN_POPS_ARGS (current_function_decl,
                               TREE_TYPE (current_function_decl),
                               current_function_args_size))
@@ -2380,38 +2524,49 @@ expand_call (exp, target, ignore)
              || reg_mentioned_p (virtual_outgoing_args_rtx,
                                  structure_value_addr))
          && (args_size.var
-#ifndef ACCUMULATE_OUTGOING_ARGS
-             || args_size.constant
-#endif
-             ))
+             || (!ACCUMULATE_OUTGOING_ARGS && args_size.constant)))
        structure_value_addr = copy_to_reg (structure_value_addr);
 
       /* Precompute any arguments as needed.  */
-      precompute_arguments (is_const, must_preallocate, num_actuals,
-                           args, &args_size);
+      if (pass)
+       precompute_arguments (flags, num_actuals, args);
 
       /* Now we are about to start emitting insns that can be deleted
         if a libcall is deleted.  */
-      if (is_const || is_malloc)
+      if (flags & (ECF_CONST | ECF_PURE | ECF_MALLOC))
        start_sequence ();
 
+      /* Compute the actual size of the argument block required.  The variable
+        and constant sizes must be combined, the size may have to be rounded,
+        and there may be a minimum required size.  When generating a sibcall
+        pattern, do not round up, since we'll be re-using whatever space our
+        caller provided.  */
+      unadjusted_args_size
+       = compute_argument_block_size (reg_parm_stack_space, &args_size,
+                                      (pass == 0 ? 0
+                                       : preferred_stack_boundary));
+
+      old_stack_allocated =  stack_pointer_delta - pending_stack_adjust;
+
+      /* The argument block when performing a sibling call is the
+         incoming argument block.  */
+      if (pass == 0)
+       argblock = virtual_incoming_args_rtx;
+
       /* If we have no actual push instructions, or shouldn't use them,
         make space for all args right now.  */
-
-      if (args_size.var != 0)
+      else if (args_size.var != 0)
        {
          if (old_stack_level == 0)
            {
              emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
              old_pending_adj = pending_stack_adjust;
              pending_stack_adjust = 0;
-#ifdef ACCUMULATE_OUTGOING_ARGS
              /* stack_arg_under_construction says whether a stack arg is
                 being constructed at the old stack level.  Pushing the stack
                 gets a clean outgoing argument block.  */
              old_stack_arg_under_construction = stack_arg_under_construction;
              stack_arg_under_construction = 0;
-#endif
            }
          argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0);
        }
@@ -2433,169 +2588,179 @@ expand_call (exp, target, ignore)
 
          if (must_preallocate)
            {
-#ifdef ACCUMULATE_OUTGOING_ARGS
-             /* 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.
+             if (ACCUMULATE_OUTGOING_ARGS)
+               {
+                 /* 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.  The actual
-                save will be done by store_one_arg. 
+                    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.  The
+                    actual save will be done by store_one_arg. 
 
-                Another approach might be to try to reorder the argument
-                evaluations to avoid this conflicting stack usage.  */
+                    Another approach might be to try to reorder the argument
+                    evaluations to avoid this conflicting stack usage.  */
 
 #ifndef 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;
+                 /* 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);
+                 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);
+                 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 */
-             if (inhibit_defer_pop == 0)
+                 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
                {
-                 /* Try to reuse some or all of the pending_stack_adjust
-                    to get this space.  Maybe we can avoid any pushing.  */
-                 if (needed > pending_stack_adjust)
+                 if (inhibit_defer_pop == 0)
                    {
-                     needed -= pending_stack_adjust;
-                     pending_stack_adjust = 0;
+                     /* Try to reuse some or all of the pending_stack_adjust
+                        to get this space.  */
+                     needed
+                       = (combine_pending_stack_adjustment_and_call 
+                          (unadjusted_args_size,
+                           &args_size,
+                           preferred_unit_stack_boundary));
+
+                     /* combine_pending_stack_adjustment_and_call computes
+                        an adjustment before the arguments are allocated.
+                        Account for them and see whether or not the stack
+                        needs to go up or down.  */
+                     needed = unadjusted_args_size - needed;
+
+                     if (needed < 0)
+                       {
+                         /* We're releasing stack space.  */
+                         /* ??? We can avoid any adjustment at all if we're
+                            already aligned.  FIXME.  */
+                         pending_stack_adjust = -needed;
+                         do_pending_stack_adjust ();
+                         needed = 0;
+                       }
+                     else 
+                       /* We need to allocate space.  We'll do that in
+                          push_block below.  */
+                       pending_stack_adjust = 0;
                    }
+
+                 /* Special case this because overhead of `push_block' in
+                    this case is non-trivial.  */
+                 if (needed == 0)
+                   argblock = virtual_outgoing_args_rtx;
                  else
+                   argblock = push_block (GEN_INT (needed), 0, 0);
+
+                 /* We only really need to call `copy_to_reg' in the case
+                    where push insns are going to be used to pass ARGBLOCK
+                    to a function call in ARGS.  In that case, the stack
+                    pointer changes value from the allocation point to the
+                    call point, and hence the value of
+                    VIRTUAL_OUTGOING_ARGS_RTX changes as well.  But might
+                    as well always do it.  */
+                 argblock = copy_to_reg (argblock);
+
+                 /* The save/restore code in store_one_arg handles all
+                    cases except one: a constructor call (including a C
+                    function returning a BLKmode struct) to initialize
+                    an argument.  */
+                 if (stack_arg_under_construction)
                    {
-                     pending_stack_adjust -= needed;
-                     needed = 0;
-                   }
-               }
-             /* Special case this because overhead of `push_block' in this
-                case is non-trivial.  */
-             if (needed == 0)
-               argblock = virtual_outgoing_args_rtx;
-             else
-               argblock = push_block (GEN_INT (needed), 0, 0);
-
-             /* We only really need to call `copy_to_reg' in the case where
-                push insns are going to be used to pass ARGBLOCK to a function
-                call in ARGS.  In that case, the stack pointer changes value
-                from the allocation point to the call point, and hence
-                the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.
-                But might as well always do it.  */
-             argblock = copy_to_reg (argblock);
-#endif /* not ACCUMULATE_OUTGOING_ARGS */
-           }
-       }
-
-      /* The argument block when performing a sibling call is the
-        incoming argument block.  */
-      if (pass == 0)
-       {
-         rtx temp = plus_constant (arg_pointer_rtx,
-                                   FIRST_PARM_OFFSET (current_function_decl));
-         argblock = force_reg (Pmode, force_operand (temp, NULL_RTX));
-       }
-
-#ifdef ACCUMULATE_OUTGOING_ARGS
-      /* The save/restore code in store_one_arg handles all cases except one:
-        a constructor call (including a C function returning a BLKmode struct)
-        to initialize an argument.  */
-      if (stack_arg_under_construction)
-       {
 #ifndef OUTGOING_REG_PARM_STACK_SPACE
-         rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant);
+                     rtx push_size = GEN_INT (reg_parm_stack_space
+                                              + args_size.constant);
 #else
-         rtx push_size = GEN_INT (args_size.constant);
+                     rtx push_size = GEN_INT (args_size.constant);
 #endif
-         if (old_stack_level == 0)
-           {
-             emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
-             old_pending_adj = pending_stack_adjust;
-             pending_stack_adjust = 0;
-             /* stack_arg_under_construction says whether a stack arg is
-                being constructed at the old stack level.  Pushing the stack
-                gets a clean outgoing argument block.  */
-             old_stack_arg_under_construction = stack_arg_under_construction;
-             stack_arg_under_construction = 0;
-             /* 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);
-             highest_outgoing_arg_in_use = 0;
+                     if (old_stack_level == 0)
+                       {
+                         emit_stack_save (SAVE_BLOCK, &old_stack_level,
+                                          NULL_RTX);
+                         old_pending_adj = pending_stack_adjust;
+                         pending_stack_adjust = 0;
+                         /* stack_arg_under_construction says whether a stack
+                            arg is being constructed at the old stack level.
+                            Pushing the stack gets a clean outgoing argument
+                            block.  */
+                         old_stack_arg_under_construction
+                           = stack_arg_under_construction;
+                         stack_arg_under_construction = 0;
+                         /* 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);
+                         highest_outgoing_arg_in_use = 0;
+                       }
+                     allocate_dynamic_stack_space (push_size, NULL_RTX,
+                                                   BITS_PER_UNIT);
+                   }
+                 /* If argument evaluation might modify the stack pointer,
+                    copy the address of the argument list to a register.  */
+                 for (i = 0; i < num_actuals; i++)
+                   if (args[i].pass_on_stack)
+                     {
+                       argblock = copy_addr_to_reg (argblock);
+                       break;
+                     }
+               }
            }
-         allocate_dynamic_stack_space (push_size, NULL_RTX, BITS_PER_UNIT);
        }
-      /* If argument evaluation might modify the stack pointer, copy the
-        address of the argument list to a register.  */
-      for (i = 0; i < num_actuals; i++)
-       if (args[i].pass_on_stack)
-         {
-           argblock = copy_addr_to_reg (argblock);
-           break;
-         }
-#endif
 
       compute_argument_addresses (args, argblock, num_actuals);
 
-#ifdef PUSH_ARGS_REVERSED
 #ifdef PREFERRED_STACK_BOUNDARY
       /* If we push args individually in reverse order, perform stack alignment
         before the first push (the last arg).  */
-      if (args_size.constant != unadjusted_args_size)
+      if (PUSH_ARGS_REVERSED && argblock == 0
+         && args_size.constant != unadjusted_args_size)
        {
          /* When the stack adjustment is pending, we get better code
             by combining the adjustments.  */
-         if (pending_stack_adjust && ! is_const
+         if (pending_stack_adjust 
+             && ! (flags & (ECF_CONST | ECF_PURE))
              && ! inhibit_defer_pop)
            {
-             args_size.constant = (unadjusted_args_size
-                                   + ((pending_stack_adjust
-                                       + args_size.constant
-                                       + arg_space_so_far
-                                       - unadjusted_args_size)
-                                      % (preferred_stack_boundary
-                                         / BITS_PER_UNIT)));
-             pending_stack_adjust -= (args_size.constant
-                                      - unadjusted_args_size);
+             pending_stack_adjust
+               = (combine_pending_stack_adjustment_and_call 
+                  (unadjusted_args_size,
+                   &args_size,
+                   preferred_unit_stack_boundary));
              do_pending_stack_adjust ();
            }
          else if (argblock == 0)
            anti_adjust_stack (GEN_INT (args_size.constant
                                        - unadjusted_args_size));
-         arg_space_so_far += args_size.constant - unadjusted_args_size;
-
-         /* Now that the stack is properly aligned, pops can't safely
-            be deferred during the evaluation of the arguments.  */
-         NO_DEFER_POP;
        }
-#endif
+      /* 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,
@@ -2621,11 +2786,12 @@ expand_call (exp, target, ignore)
         once we have started filling any specific hard regs.  */
       precompute_register_parameters (num_actuals, args, &reg_parm_seen);
 
-#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+#ifdef REG_PARM_STACK_SPACE
       /* Save the fixed argument area if it's part of the caller's frame and
         is clobbered by argument setup for this call.  */
-      save_area = save_fixed_argument_area (reg_parm_stack_space, argblock,
-                                           &low_to_save, &high_to_save);
+      if (ACCUMULATE_OUTGOING_ARGS && pass)
+       save_area = save_fixed_argument_area (reg_parm_stack_space, argblock,
+                                             &low_to_save, &high_to_save);
 #endif
 
       /* Now store (and compute if necessary) all non-register parms.
@@ -2636,7 +2802,7 @@ expand_call (exp, target, ignore)
 
       for (i = 0; i < num_actuals; i++)
        if (args[i].reg == 0 || args[i].pass_on_stack)
-         store_one_arg (&args[i], argblock, may_be_alloca,
+         store_one_arg (&args[i], argblock, flags,
                         args_size.var != 0, reg_parm_stack_space);
 
       /* If we have a parm that is passed in registers but not in memory
@@ -2651,25 +2817,23 @@ expand_call (exp, target, ignore)
       if (reg_parm_seen)
        for (i = 0; i < num_actuals; i++)
          if (args[i].partial != 0 && ! args[i].pass_on_stack)
-           store_one_arg (&args[i], argblock, may_be_alloca,
+           store_one_arg (&args[i], argblock, flags,
                           args_size.var != 0, reg_parm_stack_space);
 
-#ifndef PUSH_ARGS_REVERSED
 #ifdef PREFERRED_STACK_BOUNDARY
       /* If we pushed args in forward order, perform stack alignment
         after pushing the last arg.  */
-      /* ??? Fix for arg_space_so_far.  */
-      if (argblock == 0)
+      if (!PUSH_ARGS_REVERSED && argblock == 0)
        anti_adjust_stack (GEN_INT (args_size.constant
                                    - unadjusted_args_size));
 #endif
-#endif
 
       /* If register arguments require space on the stack and stack space
         was not preallocated, allocate stack space here for arguments
         passed in registers.  */
-#if ! defined(ACCUMULATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE)
-      if (must_preallocate == 0 && reg_parm_stack_space > 0)
+#ifdef OUTGOING_REG_PARM_STACK_SPACE
+      if (!ACCUMULATE_OUTGOING_ARGS
+          && must_preallocate == 0 && reg_parm_stack_space > 0)
        anti_adjust_stack (GEN_INT (reg_parm_stack_space));
 #endif
 
@@ -2722,19 +2886,29 @@ 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,
                   args_size.constant, struct_value_size,
                   next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
-                  ((is_const ? ECF_IS_CONST : 0)
-                   | (nothrow ? ECF_NOTHROW : 0)
-                   | (pass == 0 ? ECF_SIBCALL : 0)));
+                  flags);
+
+      /* Verify that we've deallocated all the stack we used.  */
+      if (pass
+          && old_stack_allocated != stack_pointer_delta - pending_stack_adjust)
+       abort();
 
       /* If call is cse'able, make appropriate pair of reg-notes around it.
         Test valreg so we don't crash; may safely ignore `const'
         if return type is void.  Disable for PARALLEL return values, because
         we have no way to move such values into a pseudo register.  */
-      if (is_const && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+      if ((flags & (ECF_CONST | ECF_PURE))
+         && valreg != 0 && GET_CODE (valreg) != PARALLEL)
        {
          rtx note = 0;
          rtx temp = gen_reg_rtx (GET_MODE (valreg));
@@ -2742,30 +2916,28 @@ expand_call (exp, target, ignore)
 
          /* Mark the return value as a pointer if needed.  */
          if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
-           {
-             tree pointed_to = TREE_TYPE (TREE_TYPE (exp));
-             mark_reg_pointer (temp, TYPE_ALIGN (pointed_to) / BITS_PER_UNIT);
-           }
+           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.  */
-#ifdef PUSH_ARGS_REVERSED
          for (i = 0; i < num_actuals; i++)
            note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note);
-#else
-         for (i = num_actuals - 1; i >= 0; i--)
-           note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note);
-#endif
          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 (is_const)
+      else if (flags & (ECF_CONST | ECF_PURE))
        {
          /* Otherwise, just write out the sequence without a note.  */
          rtx insns = get_insns ();
@@ -2773,14 +2945,14 @@ expand_call (exp, target, ignore)
          end_sequence ();
          emit_insns (insns);
        }
-      else if (is_malloc)
+      else if (flags & ECF_MALLOC)
        {
          rtx temp = gen_reg_rtx (GET_MODE (valreg));
          rtx last, insns;
 
          /* The return value from a malloc-like function is a pointer. */
          if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
-           mark_reg_pointer (temp, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+           mark_reg_pointer (temp, BIGGEST_ALIGNMENT);
 
          emit_move_insn (temp, valreg);
 
@@ -2801,7 +2973,7 @@ expand_call (exp, target, ignore)
         if nonvolatile values are live.  For functions that cannot return,
         inform flow that control does not fall through.  */
 
-      if (returns_twice || is_volatile || is_longjmp || pass == 0)
+      if ((flags & (ECF_RETURNS_TWICE | ECF_NORETURN | ECF_LONGJMP)) || pass == 0)
        {
          /* The barrier or NOTE_INSN_SETJMP note must be emitted
             immediately after the CALL_INSN.  Some ports emit more
@@ -2816,7 +2988,7 @@ expand_call (exp, target, ignore)
                abort ();
            }
 
-         if (returns_twice)
+         if (flags & ECF_RETURNS_TWICE)
            {
              emit_note_after (NOTE_INSN_SETJMP, last);
              current_function_calls_setjmp = 1;
@@ -2826,7 +2998,7 @@ expand_call (exp, target, ignore)
            emit_barrier_after (last);
        }
 
-      if (is_longjmp)
+      if (flags & ECF_LONGJMP)
        current_function_calls_longjmp = 1, sibcall_failure = 1;
 
       /* If this function is returning into a memory location marked as
@@ -2890,7 +3062,8 @@ expand_call (exp, target, ignore)
 
          if (! rtx_equal_p (target, valreg))
            emit_group_store (target, valreg, bytes,
-                             TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
+                             TYPE_ALIGN (TREE_TYPE (exp)));
+
          /* We can not support sibling calls for this case.  */
          sibcall_failure = 1;
        }
@@ -2939,22 +3112,18 @@ expand_call (exp, target, ignore)
        {
          emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
          pending_stack_adjust = old_pending_adj;
-#ifdef ACCUMULATE_OUTGOING_ARGS
          stack_arg_under_construction = old_stack_arg_under_construction;
          highest_outgoing_arg_in_use = initial_highest_arg_in_use;
          stack_usage_map = initial_stack_usage_map;
-#endif
          sibcall_failure = 1;
        }
-#ifdef ACCUMULATE_OUTGOING_ARGS
-      else
+      else if (ACCUMULATE_OUTGOING_ARGS && pass)
        {
 #ifdef REG_PARM_STACK_SPACE
          if (save_area)
            {
              restore_fixed_argument_area (save_area, argblock,
                                           high_to_save, low_to_save);
-             sibcall_failure = 1;
            }
 #endif
 
@@ -2974,20 +3143,18 @@ expand_call (exp, target, ignore)
                  emit_block_move (stack_area,
                                   validize_mem (args[i].save_area),
                                   GEN_INT (args[i].size.constant),
-                                  PARM_BOUNDARY / BITS_PER_UNIT);
-               sibcall_failure = 1;
+                                  PARM_BOUNDARY);
              }
 
          highest_outgoing_arg_in_use = initial_highest_arg_in_use;
          stack_usage_map = initial_stack_usage_map;
        }
-#endif
 
       /* If this was alloca, record the new stack level for nonlocal gotos.  
         Check for the handler slots since we might not have a save area
         for non-local gotos.  */
 
-      if (may_be_alloca && nonlocal_goto_handler_slots != 0)
+      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 ();
@@ -3016,10 +3183,11 @@ expand_call (exp, target, ignore)
             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.  */
+
          pending_stack_adjust = save_pending_stack_adjust;
+         stack_pointer_delta = save_stack_pointer_delta;
        }
       else
        normal_call_insns = insns;
@@ -3094,11 +3262,11 @@ libfunc_nothrow (fun)
    The RETVAL parameter specifies whether return value needs to be saved, other 
    parameters are documented in the emit_library_call function bellow.  */
 static rtx
-emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
+emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
      int retval;
      rtx orgfun;
      rtx value;
-     int no_queue;
+     int fn_type;
      enum machine_mode outmode;
      int nargs;
      va_list p;
@@ -3120,27 +3288,23 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
   int old_inhibit_defer_pop = inhibit_defer_pop;
   rtx call_fusage = 0;
   rtx mem_value = 0;
+  rtx valreg;
   int pcc_struct_value = 0;
   int struct_value_size = 0;
-  int is_const;
+  int flags = 0;
   int reg_parm_stack_space = 0;
-  int nothrow;
-#ifdef ACCUMULATE_OUTGOING_ARGS
   int needed;
-#endif
 
-#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+#ifdef 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 = 0;
   rtx save_area = 0;            /* Place that it is saved */
 #endif
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
   /* Size of the stack reserved for parameter registers.  */
   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
@@ -3150,10 +3314,14 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 #endif
 
-  is_const = no_queue;
+  if (fn_type == 1)
+    flags |= ECF_CONST;
+  else if (fn_type == 2)
+    flags |= ECF_PURE;
   fun = orgfun;
 
-  nothrow = libfunc_nothrow (fun);
+  if (libfunc_nothrow (fun))
+    flags |= ECF_NOTHROW;
 
 #ifdef PREFERRED_STACK_BOUNDARY
   /* Ensure current function's preferred stack boundary is at least
@@ -3183,7 +3351,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 
       /* This call returns a big structure.  */
-      is_const = 0;
+      flags &= ~(ECF_CONST | ECF_PURE);
     }
 
   /* ??? Unfinished: must pass the memory address as an argument.  */
@@ -3205,6 +3373,11 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 
   count = 0;
 
+  /* Now we are about to start emitting insns that can be deleted
+     if a libcall is deleted.  */
+  if (flags & (ECF_CONST | ECF_PURE))
+    start_sequence ();
+
   push_temp_slots ();
 
   /* If there's a structure value address to be passed,
@@ -3230,7 +3403,11 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 
       locate_and_pad_parm (Pmode, NULL_TREE,
-                          argvec[count].reg && argvec[count].partial == 0,
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+                           1,
+#else
+                          argvec[count].reg != 0,
+#endif
                           NULL_TREE, &args_size, &argvec[count].offset,
                           &argvec[count].size, &alignment_pad);
 
@@ -3295,7 +3472,11 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 
       locate_and_pad_parm (mode, NULL_TREE,
-                          argvec[count].reg && argvec[count].partial == 0,
+#ifdef STACK_PARMS_IN_REG_PARM_AREA
+                           1,
+#else
+                          argvec[count].reg != 0,
+#endif
                           NULL_TREE, &args_size, &argvec[count].offset,
                           &argvec[count].size, &alignment_pad);
 
@@ -3322,8 +3503,12 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 
   original_args_size = args_size;
 #ifdef PREFERRED_STACK_BOUNDARY
-  args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
-                        / STACK_BYTES) * STACK_BYTES);
+  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,
@@ -3336,133 +3521,138 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
   if (args_size.constant > current_function_outgoing_args_size)
     current_function_outgoing_args_size = args_size.constant;
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
-  /* 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.
+  if (ACCUMULATE_OUTGOING_ARGS)
+    {
+      /* 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.
+        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.  */
+        Another approach might be to try to reorder the argument
+        evaluations to avoid this conflicting stack usage.  */
 
-  needed = args_size.constant;
+      needed = args_size.constant;
 
 #ifndef 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;
+      /* 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);
+      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
+      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
+    {
+      if (!PUSH_ARGS)
+       argblock = push_block (GEN_INT (args_size.constant), 0, 0);
+    }
 
-#ifdef PUSH_ARGS_REVERSED
 #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)
+  if (argblock == 0 && PUSH_ARGS_REVERSED)
     anti_adjust_stack (GEN_INT (args_size.constant
                                - original_args_size.constant));
 #endif
-#endif
 
-#ifdef PUSH_ARGS_REVERSED
-  inc = -1;
-  argnum = nargs - 1;
-#else
-  inc = 1;
-  argnum = 0;
-#endif
+  if (PUSH_ARGS_REVERSED)
+    {
+      inc = -1;
+      argnum = nargs - 1;
+    }
+  else
+    {
+      inc = 1;
+      argnum = 0;
+    }
 
-#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.
+#ifdef REG_PARM_STACK_SPACE
+  if (ACCUMULATE_OUTGOING_ARGS)
+    {
+      /* 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.  */
+        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++)
+      for (count = 0; count < reg_parm_stack_space + 1; count++)
 #else
-  for (count = 0; count < reg_parm_stack_space; count++)
+      for (count = 0; count < reg_parm_stack_space; count++)
 #endif
-    {
-      if (count >=  highest_outgoing_arg_in_use
-         || stack_usage_map[count] == 0)
-       continue;
+       {
+         if (count >=  highest_outgoing_arg_in_use
+             || stack_usage_map[count] == 0)
+           continue;
 
-      if (low_to_save == -1)
-       low_to_save = count;
+         if (low_to_save == -1)
+           low_to_save = count;
 
-      high_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 (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;
+         /* 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;
 
 #ifdef ARGS_GROW_DOWNWARD
-      stack_area = gen_rtx_MEM (save_mode,
-                               memory_address (save_mode,
-                                               plus_constant (argblock,
-                                                              - high_to_save)));
+         stack_area = gen_rtx_MEM (save_mode,
+                                   memory_address (save_mode,
+                                                   plus_constant (argblock,
+                                                                  - high_to_save)));
 #else
-      stack_area = gen_rtx_MEM (save_mode,
-                               memory_address (save_mode,
-                                               plus_constant (argblock,
-                                                              low_to_save)));
+         stack_area = gen_rtx_MEM (save_mode,
+                                   memory_address (save_mode,
+                                                   plus_constant (argblock,
+                                                                  low_to_save)));
 #endif
-      if (save_mode == BLKmode)
-       {
-         save_area = assign_stack_temp (BLKmode, num_to_save, 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);
+         if (save_mode == BLKmode)
+           {
+             save_area = assign_stack_temp (BLKmode, num_to_save, 0);
+             emit_block_move (validize_mem (save_area), stack_area,
+                              GEN_INT (num_to_save), PARM_BOUNDARY);
+           }
+         else
+           {
+             save_area = gen_reg_rtx (save_mode);
+             emit_move_insn (save_area, stack_area);
+           }
        }
     }
 #endif
@@ -3477,80 +3667,78 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
       register rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
-#ifdef ACCUMULATE_OUTGOING_ARGS
-      int lower_bound, upper_bound, i;
-#endif
+      int lower_bound = 0, upper_bound = 0, i;
 
       if (! (reg != 0 && partial == 0))
        {
-#ifdef ACCUMULATE_OUTGOING_ARGS
-         /* If this is being stored into a pre-allocated, fixed-size, stack
-            area, save any previous data at that location.  */
+         if (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[argnum].offset.constant + 1;
-         lower_bound = upper_bound - argvec[argnum].size.constant;
+             /* stack_slot is negative, but we want to index stack_usage_map
+                with positive values.  */
+             upper_bound = -argvec[argnum].offset.constant + 1;
+             lower_bound = upper_bound - argvec[argnum].size.constant;
 #else
-         lower_bound = argvec[argnum].offset.constant;
-         upper_bound = lower_bound + argvec[argnum].size.constant;
+             lower_bound = argvec[argnum].offset.constant;
+             upper_bound = lower_bound + argvec[argnum].size.constant;
 #endif
 
-         for (i = lower_bound; i < upper_bound; i++)
-           if (stack_usage_map[i]
-               /* Don't store things in the fixed argument area at this point;
-                  it has already been saved.  */
-               && i > reg_parm_stack_space)
-             break;
+             for (i = lower_bound; i < upper_bound; i++)
+               if (stack_usage_map[i]
+                   /* Don't store things in the fixed argument area at this
+                      point; it has already been saved.  */
+                   && i > reg_parm_stack_space)
+                 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[argnum].size.constant * BITS_PER_UNIT,
-                                MODE_INT, 1);
-             rtx stack_area
-               = gen_rtx_MEM
-                 (save_mode,
-                  memory_address
-                  (save_mode,
-                   plus_constant (argblock,
-                                  argvec[argnum].offset.constant)));
-             argvec[argnum].save_area = gen_reg_rtx (save_mode);
-
-             emit_move_insn (argvec[argnum].save_area, stack_area);
+             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[argnum].size.constant
+                                    * BITS_PER_UNIT,
+                                    MODE_INT, 1);
+                 rtx stack_area
+                   = gen_rtx_MEM
+                     (save_mode,
+                      memory_address
+                      (save_mode,
+                       plus_constant (argblock,
+                                      argvec[argnum].offset.constant)));
+                 argvec[argnum].save_area = gen_reg_rtx (save_mode);
+
+                 emit_move_insn (argvec[argnum].save_area, stack_area);
+               }
            }
-#endif
+
          emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
                          argblock, GEN_INT (argvec[argnum].offset.constant),
                          reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad));
 
-#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
+         if (ACCUMULATE_OUTGOING_ARGS)
+           for (i = lower_bound; i < upper_bound; i++)
+             stack_usage_map[i] = 1;
 
          NO_DEFER_POP;
        }
     }
 
-#ifndef PUSH_ARGS_REVERSED
 #ifdef PREFERRED_STACK_BOUNDARY
   /* If we pushed args in forward order, perform stack alignment
      after pushing the last arg.  */
-  if (argblock == 0)
+  if (argblock == 0 && !PUSH_ARGS_REVERSED)
     anti_adjust_stack (GEN_INT (args_size.constant
                                - original_args_size.constant));
 #endif
-#endif
 
-#ifdef PUSH_ARGS_REVERSED
-  argnum = nargs - 1;
-#else
-  argnum = 0;
-#endif
+  if (PUSH_ARGS_REVERSED)
+    argnum = nargs - 1;
+  else
+    argnum = 0;
 
   fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0);
 
@@ -3576,12 +3764,6 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
       NO_DEFER_POP;
     }
 
-#if 0
-  /* For version 1.37, try deleting this entirely.  */
-  if (! no_queue)
-    emit_queue ();
-#endif
-
   /* Any regs containing parms remain in use through the call.  */
   for (count = 0; count < nargs; count++)
     {
@@ -3606,6 +3788,14 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
   /* Don't allow popping to be deferred, since then
      cse'ing of library calls could delete a call and leave the pop.  */
   NO_DEFER_POP;
+  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
 
   /* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
      will set inhibit_defer_pop to that value.  */
@@ -3621,14 +3811,51 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
                original_args_size.constant, args_size.constant,
               struct_value_size,
               FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
-              mem_value == 0 && outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
-              old_inhibit_defer_pop + 1, call_fusage,
-              ((is_const ? ECF_IS_CONST : 0)
-               | (nothrow ? ECF_NOTHROW : 0)));
+              valreg,
+              old_inhibit_defer_pop + 1, call_fusage, flags);
 
   /* Now restore inhibit_defer_pop to its actual original value.  */
   OK_DEFER_POP;
 
+  /* If call is cse'able, make appropriate pair of reg-notes around it.
+     Test valreg so we don't crash; may safely ignore `const'
+     if return type is void.  Disable for PARALLEL return values, because
+     we have no way to move such values into a pseudo register.  */
+  if ((flags & (ECF_CONST | ECF_PURE))
+      && valreg != 0 && GET_CODE (valreg) != PARALLEL)
+    {
+      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);
+
+      insns = get_insns ();
+      end_sequence ();
+
+      if (flags & ECF_PURE)
+       note = gen_rtx_EXPR_LIST (VOIDmode,
+          gen_rtx_USE (VOIDmode,
+                       gen_rtx_MEM (BLKmode,
+                                    gen_rtx_SCRATCH (VOIDmode))), note);
+
+      emit_libcall_block (insns, temp, valreg, note);
+
+      valreg = temp;
+    }
+  else if (flags & (ECF_CONST | ECF_PURE))
+    {
+      /* Otherwise, just write out the sequence without a note.  */
+      rtx insns = get_insns ();
+
+      end_sequence ();
+      emit_insns (insns);
+    }
   pop_temp_slots ();
 
   /* Copy the value to the right place.  */
@@ -3647,50 +3874,51 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
        value = hard_libcall_value (outmode);
     }
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
-#ifdef REG_PARM_STACK_SPACE
-  if (save_area)
+  if (ACCUMULATE_OUTGOING_ARGS)
     {
-      enum machine_mode save_mode = GET_MODE (save_area);
+#ifdef REG_PARM_STACK_SPACE
+      if (save_area)
+       {
+         enum machine_mode save_mode = GET_MODE (save_area);
 #ifdef ARGS_GROW_DOWNWARD
-      rtx stack_area
-       = gen_rtx_MEM (save_mode,
-                      memory_address (save_mode,
-                                      plus_constant (argblock,
-                                                     - high_to_save)));
+         rtx stack_area
+           = gen_rtx_MEM (save_mode,
+                          memory_address (save_mode,
+                                          plus_constant (argblock,
+                                                         - high_to_save)));
 #else
-      rtx stack_area
-       = gen_rtx_MEM (save_mode,
-                      memory_address (save_mode,
-                                      plus_constant (argblock, low_to_save)));
+         rtx stack_area
+           = gen_rtx_MEM (save_mode,
+                          memory_address (save_mode,
+                                          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);
-    }
+         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);
+       }
 #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);
-      }
+             
+      /* 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
+      highest_outgoing_arg_in_use = initial_highest_arg_in_use;
+      stack_usage_map = initial_stack_usage_map;
+    }
 
   return value;
 
@@ -3703,26 +3931,18 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
    and machine_modes to convert them to.
    The rtx values should have been passed through protect_from_queue already.
 
-   NO_QUEUE will be true if and only if the library call is a `const' call
-   which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
-   to the variable is_const in expand_call.
-
-   NO_QUEUE must be true for const calls, because if it isn't, then
-   any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes,
-   and will be lost if the libcall sequence is optimized away.
-
-   NO_QUEUE must be false for non-const calls, because if it isn't, the
-   call insn will have its CONST_CALL_P bit set, and it will be incorrectly
-   optimized.  For instance, the instruction scheduler may incorrectly
-   move memory references across the non-const call.  */
+   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
+   (use (memory (scratch)).  */
 
 void
-emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
+emit_library_call VPARAMS((rtx orgfun, int fn_type, enum machine_mode outmode,
                           int nargs, ...))
 {
 #ifndef ANSI_PROTOTYPES
   rtx orgfun;
-  int no_queue;
+  int fn_type;
   enum machine_mode outmode;
   int nargs;
 #endif
@@ -3732,12 +3952,12 @@ emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
 
 #ifndef ANSI_PROTOTYPES
   orgfun = va_arg (p, rtx);
-  no_queue = va_arg (p, int);
+  fn_type = va_arg (p, int);
   outmode = va_arg (p, enum machine_mode);
   nargs = va_arg (p, int);
 #endif
 
-  emit_library_call_value_1 (0, orgfun, NULL_RTX, no_queue, outmode, nargs, p);
+  emit_library_call_value_1 (0, orgfun, NULL_RTX, fn_type, outmode, nargs, p);
 
   va_end (p);
 }
@@ -3751,13 +3971,13 @@ emit_library_call VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
    If VALUE is nonzero, VALUE is returned.  */
 
 rtx
-emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
+emit_library_call_value VPARAMS((rtx orgfun, rtx value, int fn_type,
                                 enum machine_mode outmode, int nargs, ...))
 {
 #ifndef ANSI_PROTOTYPES
   rtx orgfun;
   rtx value;
-  int no_queue;
+  int fn_type;
   enum machine_mode outmode;
   int nargs;
 #endif
@@ -3768,12 +3988,12 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
 #ifndef ANSI_PROTOTYPES
   orgfun = va_arg (p, rtx);
   value = va_arg (p, rtx);
-  no_queue = va_arg (p, int);
+  fn_type = va_arg (p, int);
   outmode = va_arg (p, enum machine_mode);
   nargs = va_arg (p, int);
 #endif
 
-  value = emit_library_call_value_1 (1, orgfun, value, no_queue, outmode, nargs, p);
+  value = emit_library_call_value_1 (1, orgfun, value, fn_type, outmode, nargs, p);
 
   va_end (p);
 
@@ -3835,11 +4055,11 @@ target_for_arg (type, size, args_addr, offset)
    FNDECL is the declaration of the function we are calling.  */
 
 static void
-store_one_arg (arg, argblock, may_be_alloca, variable_size,
+store_one_arg (arg, argblock, flags, variable_size,
               reg_parm_stack_space)
      struct arg_data *arg;
      rtx argblock;
-     int may_be_alloca;
+     int flags;
      int variable_size ATTRIBUTE_UNUSED;
      int reg_parm_stack_space;
 {
@@ -3847,9 +4067,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
   rtx reg = 0;
   int partial = 0;
   int used = 0;
-#ifdef ACCUMULATE_OUTGOING_ARGS
   int i, lower_bound = 0, upper_bound = 0;
-#endif
 
   if (TREE_CODE (pval) == ERROR_MARK)
     return;
@@ -3858,75 +4076,75 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
      this argument.  */
   push_temp_slots ();
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
-  /* If this is being stored into a pre-allocated, fixed-size, stack area,
-     save any previous data at that location.  */
-  if (argblock && ! variable_size && arg->stack)
+  if (ACCUMULATE_OUTGOING_ARGS && !(flags & ECF_SIBCALL))
     {
+      /* If this is being stored into a pre-allocated, fixed-size, stack area,
+        save any previous data at that location.  */
+      if (argblock && ! variable_size && arg->stack)
+       {
 #ifdef ARGS_GROW_DOWNWARD
-      /* stack_slot is negative, but we want to index stack_usage_map
-         with positive values.  */
-      if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
-       upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1;
-      else
-       upper_bound = 0;
+         /* stack_slot is negative, but we want to index stack_usage_map
+            with positive values.  */
+         if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
+           upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1;
+         else
+           upper_bound = 0;
 
-      lower_bound = upper_bound - arg->size.constant;
+         lower_bound = upper_bound - arg->size.constant;
 #else
-      if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
-       lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1));
-      else
-       lower_bound = 0;
+         if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
+           lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1));
+         else
+           lower_bound = 0;
 
-      upper_bound = lower_bound + arg->size.constant;
+         upper_bound = lower_bound + arg->size.constant;
 #endif
 
-      for (i = lower_bound; i < upper_bound; i++)
-       if (stack_usage_map[i]
-           /* Don't store things in the fixed argument area at this point;
-              it has already been saved.  */
-           && i > reg_parm_stack_space)
-         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 (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1);
-         rtx stack_area
-           = gen_rtx_MEM (save_mode,
-                          memory_address (save_mode,
-                                          XEXP (arg->stack_slot, 0)));
+         for (i = lower_bound; i < upper_bound; i++)
+           if (stack_usage_map[i]
+               /* Don't store things in the fixed argument area at this point;
+                  it has already been saved.  */
+               && i > reg_parm_stack_space)
+             break;
 
-         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))); 
-             preserve_temp_slots (arg->save_area);
-             emit_block_move (validize_mem (arg->save_area), stack_area,
-                              GEN_INT (arg->size.constant),
-                              PARM_BOUNDARY / BITS_PER_UNIT);
-           }
-         else
+         if (i != upper_bound)
            {
-             arg->save_area = gen_reg_rtx (save_mode);
-             emit_move_insn (arg->save_area, stack_area);
+             /* We need to make a save area.  See what mode we can make it.  */
+             enum machine_mode save_mode
+               = mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1);
+             rtx stack_area
+               = gen_rtx_MEM (save_mode,
+                              memory_address (save_mode,
+                                              XEXP (arg->stack_slot, 0)));
+
+             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))); 
+                 preserve_temp_slots (arg->save_area);
+                 emit_block_move (validize_mem (arg->save_area), stack_area,
+                                  GEN_INT (arg->size.constant),
+                                  PARM_BOUNDARY);
+               }
+             else
+               {
+                 arg->save_area = gen_reg_rtx (save_mode);
+                 emit_move_insn (arg->save_area, stack_area);
+               }
            }
        }
+      /* Now that we have saved any slots that will be overwritten by this
+        store, mark all slots this store will use.  We must do this before
+        we actually expand the argument since the expansion itself may
+        trigger library calls which might need to use the same stack slot.  */
+      if (argblock && ! variable_size && arg->stack)
+       for (i = lower_bound; i < upper_bound; i++)
+         stack_usage_map[i] = 1;
     }
 
-  /* Now that we have saved any slots that will be overwritten by this
-     store, mark all slots this store will use.  We must do this before
-     we actually expand the argument since the expansion itself may
-     trigger library calls which might need to use the same stack slot.  */
-  if (argblock && ! variable_size && arg->stack)
-    for (i = lower_bound; i < upper_bound; i++)
-      stack_usage_map[i] = 1;
-#endif
-
   /* 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)
@@ -3946,7 +4164,6 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
      it directly into its stack slot.  Otherwise, we can.  */
   if (arg->value == 0)
     {
-#ifdef ACCUMULATE_OUTGOING_ARGS
       /* stack_arg_under_construction is nonzero if a function argument is
         being evaluated directly into the outgoing argument list and
         expand_call must take special action to preserve the argument list
@@ -3967,7 +4184,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
 
       if (arg->pass_on_stack)
        stack_arg_under_construction++;
-#endif
+
       arg->value = expand_expr (pval,
                                (partial
                                 || TYPE_MODE (TREE_TYPE (pval)) != arg->mode)
@@ -3981,15 +4198,13 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
        arg->value = convert_modes (arg->mode, TYPE_MODE (TREE_TYPE (pval)),
                                    arg->value, arg->unsignedp);
 
-#ifdef ACCUMULATE_OUTGOING_ARGS
       if (arg->pass_on_stack)
        stack_arg_under_construction--;
-#endif
     }
 
   /* Don't allow anything left on stack from computation
      of argument to alloca.  */
-  if (may_be_alloca)
+  if (flags & ECF_MAY_BE_ALLOCA)
     do_pending_stack_adjust ();
 
   if (arg->value == arg->stack)
@@ -4041,8 +4256,6 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
                      partial, reg, used - size, argblock,
                      ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->alignment_pad));
-
-      arg_space_so_far += used;
     }
   else
     {
@@ -4070,12 +4283,11 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
          excess = (arg->size.constant - int_size_in_bytes (TREE_TYPE (pval))
                    + partial * UNITS_PER_WORD);
          size_rtx = expr_size (pval);
-         arg_space_so_far += excess + INTVAL (size_rtx);
        }
 
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
-                     TYPE_ALIGN (TREE_TYPE (pval)) / BITS_PER_UNIT, partial,
-                     reg, excess, argblock, ARGS_SIZE_RTX (arg->offset),
+                     TYPE_ALIGN (TREE_TYPE (pval)), partial, reg, excess,
+                     argblock, ARGS_SIZE_RTX (arg->offset),
                      reg_parm_stack_space,
                      ARGS_SIZE_RTX (arg->alignment_pad));
     }