OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index f7cf503..eff0042 100644 (file)
@@ -168,6 +168,9 @@ static int calls_function_1 PARAMS ((tree, int));
    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,
@@ -182,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));
@@ -208,6 +210,8 @@ 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 *));
@@ -555,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))
@@ -571,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_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
@@ -610,7 +623,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
       if (rounded_stack_size != 0)
        {
          if (flag_defer_pop && inhibit_defer_pop == 0
-             && !(ecf_flags & ECF_CONST))
+             && !(ecf_flags & (ECF_CONST | ECF_PURE)))
            pending_stack_adjust += rounded_stack_size;
          else
            adjust_stack (rounded_stack_size_rtx);
@@ -759,6 +772,10 @@ flags_from_decl_or_type (exp)
       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;
     }
@@ -1195,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);
-             *ecf_flags &= ~ECF_CONST;
+             *ecf_flags &= ~(ECF_CONST | ECF_PURE);
 
              args[i].tree_value = build1 (ADDR_EXPR,
                                           build_pointer_type (type),
@@ -1254,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))
-       *ecf_flags &= ~ECF_CONST;
+       *ecf_flags &= ~(ECF_CONST | ECF_PURE);
 
       /* Compute the stack-size of this argument.  */
       if (args[i].reg == 0 || args[i].partial != 0
@@ -1401,23 +1418,17 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
 
    FLAGS is mask of ECF_* constants.
 
-   MUST_PREALLOCATE indicates that we must preallocate stack space for
-   any stack arguments.
-
    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 (flags, must_preallocate, num_actuals, args, args_size)
+precompute_arguments (flags, num_actuals, args)
      int flags;
-     int must_preallocate;
      int num_actuals;
      struct arg_data *args;
-     struct args_size *args_size;
 {
   int i;
 
@@ -1432,15 +1443,13 @@ precompute_arguments (flags, 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 ((flags & ECF_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)))
@@ -1848,6 +1857,62 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr)
   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.
@@ -1959,7 +2024,10 @@ expand_call (exp, target, ignore)
   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
@@ -1975,44 +2043,41 @@ expand_call (exp, target, ignore)
   /* 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");
            }
-
-         flags |= flags_from_decl_or_type (fndecl);
+         mark_addressable (fndecl);
        }
+
+      flags |= flags_from_decl_or_type (fndecl);
     }
 
   /* If we don't have specific function to call, see if we have a 
      attributes set in the type.  */
-  if (fndecl == 0)
-    flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
+  else
+    {
+      p = TREE_OPERAND (exp, 0);
+      flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
+    }
 
 #ifdef REG_PARM_STACK_SPACE
 #ifdef MAYBE_REG_PARM_STACK_SPACE
@@ -2038,7 +2103,7 @@ expand_call (exp, target, ignore)
   if (aggregate_value_p (exp))
     {
       /* This call returns a big structure.  */
-      flags &= ~ECF_CONST;
+      flags &= ~(ECF_CONST | ECF_PURE);
 
 #ifdef PCC_STATIC_STRUCT_RETURN
       {
@@ -2102,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))
     {
@@ -2196,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
@@ -2295,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 (flags & ECF_CONST)
+      if (flags & (ECF_CONST | ECF_PURE))
        NO_DEFER_POP;
 
       /* Don't let pending stack adjusts add up to too much.
@@ -2416,7 +2490,7 @@ expand_call (exp, target, ignore)
 
             Also do not make a sibling call.  */
 
-         flags &= ~ECF_CONST;
+         flags &= ~(ECF_CONST | ECF_PURE);
          must_preallocate = 1;
          sibcall_failure = 1;
        }
@@ -2428,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))
@@ -2460,25 +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 (flags, 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 (flags & (ECF_CONST | ECF_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)
            {
@@ -2513,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
 
@@ -2541,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,
@@ -2553,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;
@@ -2565,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);
@@ -2653,28 +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 && ! (flags & ECF_CONST)
+         if (pending_stack_adjust 
+             && ! (flags & (ECF_CONST | ECF_PURE))
              && ! inhibit_defer_pop)
            {
-             int adjust;
-             args_size.constant = (unadjusted_args_size
-                                   + ((pending_stack_adjust
-                                       + args_size.constant
-                                       - unadjusted_args_size)
-                                      % (preferred_stack_boundary
-                                         / BITS_PER_UNIT)));
-             adjust = (pending_stack_adjust - args_size.constant
-                       + unadjusted_args_size);
-             adjust_stack (GEN_INT (adjust));
-             pending_stack_adjust = 0;
+             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));
-         /* 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,
@@ -2703,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
@@ -2716,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, flags & ECF_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
@@ -2731,7 +2817,7 @@ 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, flags & ECF_MAY_BE_ALLOCA,
+           store_one_arg (&args[i], argblock, flags,
                           args_size.var != 0, reg_parm_stack_space);
 
 #ifdef PREFERRED_STACK_BOUNDARY
@@ -2800,6 +2886,12 @@ 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,
@@ -2815,7 +2907,8 @@ expand_call (exp, target, ignore)
         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) && 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));
@@ -2827,22 +2920,24 @@ expand_call (exp, target, ignore)
 
          /* 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 (flags & ECF_CONST)
+      else if (flags & (ECF_CONST | ECF_PURE))
        {
          /* Otherwise, just write out the sequence without a note.  */
          rtx insns = get_insns ();
@@ -3022,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
 
@@ -3050,7 +3144,6 @@ expand_call (exp, target, ignore)
                                   validize_mem (args[i].save_area),
                                   GEN_INT (args[i].size.constant),
                                   PARM_BOUNDARY);
-               sibcall_failure = 1;
              }
 
          highest_outgoing_arg_in_use = initial_highest_arg_in_use;
@@ -3169,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;
@@ -3195,6 +3288,7 @@ 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 flags = 0;
@@ -3220,8 +3314,10 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 #endif
 
-  if (no_queue)
+  if (fn_type == 1)
     flags |= ECF_CONST;
+  else if (fn_type == 2)
+    flags |= ECF_PURE;
   fun = orgfun;
 
   if (libfunc_nothrow (fun))
@@ -3255,7 +3351,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
 #endif
 
       /* This call returns a big structure.  */
-      flags &= ~ECF_CONST;
+      flags &= ~(ECF_CONST | ECF_PURE);
     }
 
   /* ??? Unfinished: must pass the memory address as an argument.  */
@@ -3277,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,
@@ -3302,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);
 
@@ -3367,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);
 
@@ -3564,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
@@ -3579,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
@@ -3653,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++)
     {
@@ -3683,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.  */
@@ -3698,12 +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,
+              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.  */
@@ -3779,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 flag ECF_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
@@ -3808,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);
 }
@@ -3827,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
@@ -3844,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);
 
@@ -3911,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;
 {
@@ -3932,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.  */
@@ -4060,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)