OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 37fc928..eff0042 100644 (file)
@@ -150,9 +150,28 @@ int stack_arg_under_construction;
 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));
@@ -166,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));
@@ -178,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));
@@ -188,6 +206,12 @@ 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));
 
 #ifdef REG_PARM_STACK_SPACE
 static rtx save_fixed_argument_area    PARAMS ((int, rtx, int *, int *));
@@ -401,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,
@@ -537,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))
@@ -553,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
@@ -577,6 +608,7 @@ 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 (!ACCUMULATE_OUTGOING_ARGS)
@@ -588,14 +620,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
         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 - n_popped;
-
       if (rounded_stack_size != 0)
        {
          if (flag_defer_pop && inhibit_defer_pop == 0
-             && !(ecf_flags & ECF_IS_CONST))
+             && !(ecf_flags & (ECF_CONST | ECF_PURE)))
            pending_stack_adjust += rounded_stack_size;
          else
            adjust_stack (rounded_stack_size_rtx);
@@ -622,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',
@@ -662,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] == '_')
@@ -683,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"))
@@ -717,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.
@@ -730,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.
 
@@ -856,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
        {
@@ -900,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
          
@@ -968,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);
          }
       }
 }
@@ -996,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;
@@ -1016,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 ATTRIBUTE_UNUSED;
+     int *ecf_flags;
 {
   /* 1 if scanning parms front to back, -1 if scanning back to front.  */
   int inc;
@@ -1160,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),
@@ -1183,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
@@ -1219,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
@@ -1308,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)
@@ -1333,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,
@@ -1359,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;
 
@@ -1392,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)))
@@ -1656,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,
@@ -1695,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.
@@ -1726,7 +1944,6 @@ expand_call (exp, target, ignore)
      or 0 if the function is computed (not known by name).  */
   tree fndecl = 0;
   char *name = 0;
-  rtx before_call;
   rtx insn;
   int try_tail_call;
   int pass;
@@ -1785,26 +2002,10 @@ 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);
 #ifdef REG_PARM_STACK_SPACE
   /* Define the boundary of the register parm stack space that needs to be
      save, if any.  */
@@ -1819,10 +2020,14 @@ expand_call (exp, target, ignore)
   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
@@ -1831,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
@@ -1908,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
       {
@@ -1959,95 +2154,11 @@ expand_call (exp, target, ignore)
 
   if (is_integrable)
     {
-      rtx temp;
-
-      before_call = get_last_insn ();
-
-      temp = expand_inline_function (fndecl, actparms, target,
-                                    ignore, TREE_TYPE (exp),
-                                    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);
+      rtx temp = try_to_integrate (fndecl, actparms, target,
+                                  ignore, TREE_TYPE (exp),
+                                  structure_value_addr);
+      if (temp != (rtx) (HOST_WIDE_INT) - 1)
+       return temp;
     }
 
   currently_expanding_call++;
@@ -2056,11 +2167,18 @@ expand_call (exp, target, ignore)
      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.  */
+     the call.
+
+     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.  */
 
   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))
     {
@@ -2124,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
@@ -2141,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++;
@@ -2148,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
@@ -2163,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.  */
@@ -2186,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;
 
@@ -2214,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
@@ -2223,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;
 
@@ -2238,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.
@@ -2246,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
@@ -2343,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,
@@ -2360,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;
        }
@@ -2372,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))
@@ -2404,23 +2524,38 @@ expand_call (exp, target, ignore)
              || reg_mentioned_p (virtual_outgoing_args_rtx,
                                  structure_value_addr))
          && (args_size.var
-             || (!ACCUMULATE_OUTGOING_ARGS && args_size.constant)
-             ))
+             || (!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)
            {
@@ -2455,24 +2590,24 @@ expand_call (exp, target, ignore)
            {
              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.
+                 /* 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. 
+                    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.  */
 
 #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.  */
+                 /* 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
 
@@ -2483,7 +2618,8 @@ expand_call (exp, target, ignore)
                  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
                                                     needed);
 #endif
-                 stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
+                 stack_usage_map
+                   = (char *) alloca (highest_outgoing_arg_in_use);
 
                  if (initial_highest_arg_in_use)
                    bcopy (initial_stack_usage_map, stack_usage_map,
@@ -2495,9 +2631,9 @@ expand_call (exp, target, ignore)
                            - 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
+                 /* 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;
@@ -2507,82 +2643,94 @@ expand_call (exp, target, ignore)
                  if (inhibit_defer_pop == 0)
                    {
                      /* 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)
+                        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)
                        {
-                         needed -= pending_stack_adjust;
-                         pending_stack_adjust = 0;
-                       }
-                     else
-                       {
-                         pending_stack_adjust -= needed;
+                         /* 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.  */
+
+                 /* 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.  */
+                 /* 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 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));
-       }
 
-      if (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)
-           {
+                 /* 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;
-             }
        }
 
       compute_argument_addresses (args, argblock, num_actuals);
@@ -2595,29 +2743,24 @@ expand_call (exp, target, ignore)
        {
          /* 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;
        }
+      /* 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,
@@ -2646,7 +2789,7 @@ expand_call (exp, target, ignore)
 #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.  */
-      if (ACCUMULATE_OUTGOING_ARGS)
+      if (ACCUMULATE_OUTGOING_ARGS && pass)
        save_area = save_fixed_argument_area (reg_parm_stack_space, argblock,
                                              &low_to_save, &high_to_save);
 #endif
@@ -2659,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
@@ -2674,13 +2817,12 @@ 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);
 
 #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 (!PUSH_ARGS_REVERSED && argblock == 0)
        anti_adjust_stack (GEN_INT (args_size.constant
                                    - unadjusted_args_size));
@@ -2744,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));
@@ -2764,29 +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.  */
-         if (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);
+         for (i = 0; i < num_actuals; i++)
+           note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note);
          note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note);
 
          insns = get_insns ();
          end_sequence ();
 
+         if (flags & ECF_PURE)
+           note = gen_rtx_EXPR_LIST (VOIDmode,
+              gen_rtx_USE (VOIDmode,
+                           gen_rtx_MEM (BLKmode,
+                                        gen_rtx_SCRATCH (VOIDmode))), note);
+
          emit_libcall_block (insns, temp, valreg, note);
   
          valreg = temp;
        }
-      else if (is_const)
+      else if (flags & (ECF_CONST | ECF_PURE))
        {
          /* Otherwise, just write out the sequence without a note.  */
          rtx insns = get_insns ();
@@ -2794,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);
 
@@ -2822,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
@@ -2837,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;
@@ -2847,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
@@ -2911,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;
        }
@@ -2965,14 +3117,13 @@ expand_call (exp, target, ignore)
          stack_usage_map = initial_stack_usage_map;
          sibcall_failure = 1;
        }
-      else if (ACCUMULATE_OUTGOING_ARGS)
+      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
 
@@ -2992,8 +3143,7 @@ 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;
@@ -3004,7 +3154,7 @@ expand_call (exp, target, ignore)
         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 ();
@@ -3033,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;
@@ -3111,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;
@@ -3137,11 +3288,11 @@ 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;
   int needed;
 
 #ifdef REG_PARM_STACK_SPACE
@@ -3163,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
@@ -3196,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.  */
@@ -3218,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,
@@ -3243,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);
 
@@ -3308,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);
 
@@ -3335,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,
@@ -3474,8 +3646,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
            {
              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);
+                              GEN_INT (num_to_save), PARM_BOUNDARY);
            }
          else
            {
@@ -3502,8 +3673,8 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
        {
          if (ACCUMULATE_OUTGOING_ARGS)
            {
-             /* If this is being stored into a pre-allocated, fixed-size, stack
-                area, save any previous data at that location.  */
+             /* 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
@@ -3517,16 +3688,18 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 
              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.  */
+                   /* 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. */
+                 /* 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_for_size (argvec[argnum].size.constant
+                                    * BITS_PER_UNIT,
                                     MODE_INT, 1);
                  rtx stack_area
                    = gen_rtx_MEM
@@ -3540,6 +3713,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
                  emit_move_insn (argvec[argnum].save_area, stack_area);
                }
            }
+
          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));
@@ -3590,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++)
     {
@@ -3620,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.  */
@@ -3635,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.  */
@@ -3684,7 +3897,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
          else
            emit_block_move (stack_area, validize_mem (save_area),
                             GEN_INT (high_to_save - low_to_save + 1),
-                                PARM_BOUNDARY / BITS_PER_UNIT);
+                            PARM_BOUNDARY);
        }
 #endif
              
@@ -3718,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
@@ -3747,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);
 }
@@ -3766,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
@@ -3783,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);
 
@@ -3850,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;
 {
@@ -3871,7 +4076,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
      this argument.  */
   push_temp_slots ();
 
-  if (ACCUMULATE_OUTGOING_ARGS)
+  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.  */
@@ -3922,7 +4127,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
                  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);
+                                  PARM_BOUNDARY);
                }
              else
                {
@@ -3999,7 +4204,7 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
 
   /* 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)
@@ -4051,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
     {
@@ -4080,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));
     }