OSDN Git Service

2003-03-10 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index d6f68cd..cab6571 100644 (file)
@@ -37,6 +37,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "sbitmap.h"
 #include "langhooks.h"
 #include "target.h"
+#include "cgraph.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -798,8 +799,14 @@ flags_from_decl_or_type (exp)
   /* ??? We can't set IS_MALLOC for function types?  */
   if (DECL_P (exp))
     {
+      struct cgraph_rtl_info *i = cgraph_rtl_info (exp);
       type = TREE_TYPE (exp);
 
+      if (i && i->pure_function)
+       flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
+      if (i && i->const_function)
+       flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
+
       /* The function exp may have the `malloc' attribute.  */
       if (DECL_P (exp) && DECL_IS_MALLOC (exp))
        flags |= ECF_MALLOC;
@@ -1634,6 +1641,7 @@ compute_argument_addresses (args, argblock, num_actuals)
 
          addr = plus_constant (addr, arg_offset);
          args[i].stack = gen_rtx_MEM (args[i].mode, addr);
+         set_mem_align (args[i].stack, PARM_BOUNDARY);
          set_mem_attributes (args[i].stack,
                              TREE_TYPE (args[i].tree_value), 1);
 
@@ -1644,6 +1652,7 @@ compute_argument_addresses (args, argblock, num_actuals)
 
          addr = plus_constant (addr, arg_offset);
          args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr);
+         set_mem_align (args[i].stack_slot, PARM_BOUNDARY);
          set_mem_attributes (args[i].stack_slot,
                              TREE_TYPE (args[i].tree_value), 1);
 
@@ -1663,12 +1672,12 @@ compute_argument_addresses (args, argblock, num_actuals)
    FNDECL is the tree node for the target function.  For an indirect call
    FNDECL will be NULL_TREE.
 
-   EXP is the CALL_EXPR for this call.  */
+   ADDR is the operand 0 of CALL_EXPR for this call.  */
 
 static rtx
-rtx_for_function_call (fndecl, exp)
+rtx_for_function_call (fndecl, addr)
      tree fndecl;
-     tree exp;
+     tree addr;
 {
   rtx funexp;
 
@@ -1690,7 +1699,7 @@ rtx_for_function_call (fndecl, exp)
     /* Generate an rtx (probably a pseudo-register) for the address.  */
     {
       push_temp_slots ();
-      funexp = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+      funexp = expand_expr (addr, NULL_RTX, VOIDmode, 0);
       pop_temp_slots ();       /* FUNEXP can't be BLKmode.  */
       emit_queue ();
     }
@@ -1834,9 +1843,11 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr)
             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;
+         i = reg_parm_stack_space;
+         if (i > highest_outgoing_arg_in_use)
+           i = highest_outgoing_arg_in_use;
+         while (--i >= 0 && stack_usage_map[i] == 0)
+           ;
 
          if (stack_arg_under_construction || i >= 0)
            {
@@ -2210,6 +2221,7 @@ expand_call (exp, target, ignore)
   int old_stack_allocated;
   rtx call_fusage;
   tree p = TREE_OPERAND (exp, 0);
+  tree addr = TREE_OPERAND (exp, 0);
   int i;
   /* The alignment of the stack, in bits.  */
   HOST_WIDE_INT preferred_stack_boundary;
@@ -2339,9 +2351,15 @@ expand_call (exp, target, ignore)
 
   /* Figure out the amount to which the stack should be aligned.  */
   preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+  if (fndecl)
+    {
+      struct cgraph_rtl_info *i = cgraph_rtl_info (fndecl);
+      if (i && i->preferred_incoming_stack_boundary)
+       preferred_stack_boundary = i->preferred_incoming_stack_boundary;
+    }
 
   /* Operand 0 is a pointer-to-function; get the type of the function.  */
-  funtype = TREE_TYPE (TREE_OPERAND (exp, 0));
+  funtype = TREE_TYPE (addr);
   if (! POINTER_TYPE_P (funtype))
     abort ();
   funtype = TREE_TYPE (funtype);
@@ -2416,7 +2434,7 @@ expand_call (exp, target, ignore)
      calling convention than normal calls.  The last argument in
      INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call
      or not.  */
-  INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, (fndecl == 0));
+  INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, fndecl);
 
   /* Make a vector to hold all the information about each arg.  */
   args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));
@@ -2478,8 +2496,8 @@ expand_call (exp, target, ignore)
 
   /* Tail recursion fails, when we are not dealing with recursive calls.  */
   if (!try_tail_recursion
-      || TREE_CODE (TREE_OPERAND (exp, 0)) != ADDR_EXPR
-      || TREE_OPERAND (TREE_OPERAND (exp, 0), 0) != current_function_decl)
+      || TREE_CODE (addr) != ADDR_EXPR
+      || TREE_OPERAND (addr, 0) != current_function_decl)
     try_tail_recursion = 0;
 
   /*  Rest of purposes for tail call optimizations to fail.  */
@@ -2501,7 +2519,7 @@ expand_call (exp, target, ignore)
       /* Functions that do not return exactly once may not be sibcall
          optimized.  */
       || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP | ECF_NORETURN))
-      || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
+      || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (addr)))
       /* If this function requires more stack slots than the current
         function, we cannot change it into a sibling call.  */
       || args_size.constant > current_function_args_size
@@ -2554,9 +2572,9 @@ expand_call (exp, target, ignore)
          if (try_tail_recursion)
            actparms = tree_cons (NULL_TREE, args[i].tree_value, actparms);
        }
-      /* Do the same for the function address if it is an expression. */
+      /* Do the same for the function address if it is an expression.  */
       if (!fndecl)
-        TREE_OPERAND (exp, 0) = fix_unsafe_tree (TREE_OPERAND (exp, 0));
+        addr = fix_unsafe_tree (addr);
       /* Expanding one of those dangerous arguments could have added
         cleanups, but otherwise give it a whirl.  */
       if (any_pending_cleanups (1))
@@ -2625,6 +2643,8 @@ expand_call (exp, target, ignore)
   if (cfun->preferred_stack_boundary < preferred_stack_boundary
       && fndecl != current_function_decl)
     cfun->preferred_stack_boundary = preferred_stack_boundary;
+  if (fndecl == current_function_decl)
+    cfun->recursive_call_emit = true;
 
   preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
 
@@ -2947,7 +2967,7 @@ expand_call (exp, target, ignore)
         be deferred during the evaluation of the arguments.  */
       NO_DEFER_POP;
 
-      funexp = rtx_for_function_call (fndecl, exp);
+      funexp = rtx_for_function_call (fndecl, addr);
 
       /* Figure out the register where the value, if any, will come back.  */
       valreg = 0;
@@ -3727,12 +3747,12 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
            {
              tree type = (*lang_hooks.types.type_for_mode) (mode, 0);
 
-             slot = gen_rtx_MEM (mode,
-                                 expand_expr (build1 (ADDR_EXPR,
-                                                      build_pointer_type
-                                                      (type),
-                                                      make_tree (type, val)),
-                                              NULL_RTX, VOIDmode, 0));
+             slot
+               = gen_rtx_MEM (mode,
+                              expand_expr (build1 (ADDR_EXPR,
+                                                   build_pointer_type (type),
+                                                   make_tree (type, val)),
+                                           NULL_RTX, VOIDmode, 0));
            }
 
          call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
@@ -3923,14 +3943,15 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p)
              upper_bound = lower_bound + argvec[argnum].size.constant;
 #endif
 
-             for (i = lower_bound; i < upper_bound; i++)
-               if (stack_usage_map[i]
-                   /* Don't store things in the fixed argument area at this
-                      point; it has already been saved.  */
-                   && i > reg_parm_stack_space)
-                 break;
+             i = lower_bound;
+             /* Don't worry about things in the fixed argument area;
+                it has already been saved.  */
+             if (i < reg_parm_stack_space)
+               i = reg_parm_stack_space;
+             while (i < upper_bound && stack_usage_map[i] == 0)
+               i++;
 
-             if (i != upper_bound)
+             if (i < upper_bound)
                {
                  /* We need to make a save area.  See what mode we can make
                     it.  */
@@ -4301,14 +4322,15 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
          upper_bound = lower_bound + arg->size.constant;
 #endif
 
-         for (i = lower_bound; i < upper_bound; i++)
-           if (stack_usage_map[i]
-               /* Don't store things in the fixed argument area at this point;
-                  it has already been saved.  */
-               && i > reg_parm_stack_space)
-             break;
+         i = lower_bound;
+         /* Don't worry about things in the fixed argument area;
+            it has already been saved.  */
+         if (i < reg_parm_stack_space)
+           i = reg_parm_stack_space;
+         while (i < upper_bound && stack_usage_map[i] == 0)
+           i++;
 
-         if (i != upper_bound)
+         if (i < upper_bound)
            {
              /* We need to make a save area.  See what mode we can make it.  */
              enum machine_mode save_mode
@@ -4337,13 +4359,6 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
                }
            }
        }
-      /* Now that we have saved any slots that will be overwritten by this
-        store, mark all slots this store will use.  We must do this before
-        we actually expand the argument since the expansion itself may
-        trigger library calls which might need to use the same stack slot.  */
-      if (argblock && ! variable_size && arg->stack)
-       for (i = lower_bound; i < upper_bound; i++)
-         stack_usage_map[i] = 1;
     }
 
   /* If this isn't going to be placed on both the stack and in registers,
@@ -4396,7 +4411,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
                                (partial
                                 || TYPE_MODE (TREE_TYPE (pval)) != arg->mode)
                                ? NULL_RTX : arg->stack,
-                               VOIDmode, 0);
+                               VOIDmode, EXPAND_STACK_PARM);
 
       /* If we are promoting object (or for any other reason) the mode
         doesn't agree, convert the mode.  */
@@ -4539,37 +4554,6 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
            }
        }
 
-      /* Special handling is required if part of the parameter lies in the
-        register parameter area.  The argument may be copied into the stack
-        slot using memcpy(), but the original contents of the register
-        parameter area will be restored after the memcpy() call.
-
-        To ensure that the part that lies in the register parameter area
-        is copied correctly, we emit a separate push for that part.  This
-        push should be small enough to avoid a call to memcpy().  */
-#ifndef STACK_PARMS_IN_REG_PARM_AREA
-      if (arg->reg && arg->pass_on_stack)
-#else
-      if (1)
-#endif
-       {
-         if (arg->offset.constant < reg_parm_stack_space && arg->offset.var)
-           error ("variable offset is passed partially in stack and in reg");
-         else if (arg->offset.constant < reg_parm_stack_space && arg->size.var)
-           error ("variable size is passed partially in stack and in reg");
-         else if (arg->offset.constant < reg_parm_stack_space 
-             && ((arg->offset.constant + arg->size.constant) 
-                  > reg_parm_stack_space))
-          {
-           rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant);
-           emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1,
-                           parm_align, partial, reg, excess, argblock,
-                           ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
-                           ARGS_SIZE_RTX (arg->alignment_pad));
-         }
-       }
-       
-
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
                      parm_align, partial, reg, excess, argblock,
                      ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
@@ -4587,6 +4571,12 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
        arg->value = arg->stack_slot;
     }
 
+  /* Mark all slots this store used.  */
+  if (ACCUMULATE_OUTGOING_ARGS && !(flags & ECF_SIBCALL)
+      && argblock && ! variable_size && arg->stack)
+    for (i = lower_bound; i < upper_bound; i++)
+      stack_usage_map[i] = 1;
+
   /* Once we have pushed something, pops can't safely
      be deferred during the rest of the arguments.  */
   NO_DEFER_POP;
@@ -4605,7 +4595,6 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
   return sibcall_failure;
 }
 
-
 /* Nonzero if we do not know how to pass TYPE solely in registers.
    We cannot do so in the following cases:
 
@@ -4628,7 +4617,7 @@ default_must_pass_in_stack (mode, type)
      tree type;
 {
   if (!type)
-    return true;
+    return false;
 
   /* If the type has variable size...  */
   if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)