OSDN Git Service

2005-09-08 Andrew Pinski <pinskia@physics.uc.edu>
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index b06830d..4074dbd 100644 (file)
@@ -570,17 +570,8 @@ flags_from_decl_or_type (tree exp)
 
   if (DECL_P (exp))
     {
-      struct cgraph_rtl_info *i = cgraph_rtl_info (exp);
       type = TREE_TYPE (exp);
 
-      if (i)
-       {
-         if (i->pure_function)
-           flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
-         if (i->const_function)
-           flags |= ECF_CONST | ECF_LIBCALL_BLOCK;
-       }
-
       /* The function exp may have the `malloc' attribute.  */
       if (DECL_IS_MALLOC (exp))
        flags |= ECF_MALLOC;
@@ -1453,7 +1444,7 @@ rtx_for_function_call (tree fndecl, tree addr)
    Mark all register-parms as living through the call, putting these USE
    insns in the CALL_INSN_FUNCTION_USAGE field.
 
-   When IS_SIBCALL, perform the check_sibcall_overlap_argument_overlap
+   When IS_SIBCALL, perform the check_sibcall_argument_overlap
    checking, setting *SIBCALL_FAILURE if appropriate.  */
 
 static void
@@ -1864,6 +1855,7 @@ expand_call (tree exp, rtx target, int ignore)
 
   int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
   char *initial_stack_usage_map = stack_usage_map;
+  char *stack_usage_map_buf = NULL;
 
   int old_stack_allocated;
 
@@ -2255,6 +2247,9 @@ expand_call (tree exp, rtx target, int ignore)
       if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC)))
        start_sequence ();
 
+      if (pass == 0 && cfun->stack_protect_guard)
+       stack_protect_epilogue ();
+
       adjusted_args_size = args_size;
       /* Compute the actual size of the argument block required.  The variable
         and constant sizes must be combined, the size may have to be rounded,
@@ -2350,7 +2345,10 @@ expand_call (tree exp, rtx target, int ignore)
                  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
                                                     needed);
 #endif
-                 stack_usage_map = alloca (highest_outgoing_arg_in_use);
+                 if (stack_usage_map_buf)
+                   free (stack_usage_map_buf);
+                 stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use);
+                 stack_usage_map = stack_usage_map_buf;
 
                  if (initial_highest_arg_in_use)
                    memcpy (stack_usage_map, initial_stack_usage_map,
@@ -2455,7 +2453,10 @@ expand_call (tree exp, rtx target, int ignore)
                    = stack_arg_under_construction;
                  stack_arg_under_construction = 0;
                  /* Make a new map for the new argument list.  */
-                 stack_usage_map = alloca (highest_outgoing_arg_in_use);
+                 if (stack_usage_map_buf)
+                   free (stack_usage_map_buf);
+                 stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use);
+                 stack_usage_map = stack_usage_map_buf;
                  memset (stack_usage_map, 0, highest_outgoing_arg_in_use);
                  highest_outgoing_arg_in_use = 0;
                }
@@ -2510,9 +2511,10 @@ expand_call (tree exp, rtx target, int ignore)
        {
          if (pcc_struct_value)
            valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
-                                         fndecl, (pass == 0));
+                                         fndecl, NULL, (pass == 0));
          else
-           valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0));
+           valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype,
+                                         (pass == 0));
        }
 
       /* Precompute all register parameters.  It isn't safe to compute anything
@@ -3009,6 +3011,9 @@ expand_call (tree exp, rtx target, int ignore)
       emit_move_insn (virtual_stack_dynamic_rtx, stack_pointer_rtx);
     }
 
+  if (stack_usage_map_buf)
+    free (stack_usage_map_buf);
+
   return target;
 }
 
@@ -3203,6 +3208,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   /* Size of the stack reserved for parameter registers.  */
   int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
   char *initial_stack_usage_map = stack_usage_map;
+  char *stack_usage_map_buf = NULL;
 
   rtx struct_value = targetm.calls.struct_value_rtx (0, 0);
 
@@ -3255,7 +3261,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
        {
 #ifdef PCC_STATIC_STRUCT_RETURN
          rtx pointer_reg
-           = hard_function_value (build_pointer_type (tfom), 0, 0);
+           = hard_function_value (build_pointer_type (tfom), 0, 0, 0);
          mem_value = gen_rtx_MEM (outmode, pointer_reg);
          pcc_struct_value = 1;
          if (value == 0)
@@ -3481,7 +3487,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
                                         needed);
 #endif
-      stack_usage_map = alloca (highest_outgoing_arg_in_use);
+      stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use);
+      stack_usage_map = stack_usage_map_buf;
 
       if (initial_highest_arg_in_use)
        memcpy (stack_usage_map, initial_stack_usage_map,
@@ -3619,6 +3626,28 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
              stack_usage_map[i] = 1;
 
          NO_DEFER_POP;
+
+         if (flags & ECF_CONST)
+           {
+             rtx use;
+
+             /* Indicate argument access so that alias.c knows that these
+                values are live.  */
+             if (argblock)
+               use = plus_constant (argblock,
+                                    argvec[argnum].locate.offset.constant);
+             else
+               /* When arguments are pushed, trying to tell alias.c where
+                  exactly this argument is won't work, because the
+                  auto-increment causes confusion.  So we merely indicate
+                  that we access something with a known mode somewhere on
+                  the stack.  */
+               use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
+                                   gen_rtx_SCRATCH (Pmode));
+             use = gen_rtx_MEM (argvec[argnum].mode, use);
+             use = gen_rtx_USE (VOIDmode, use);
+             call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
+           }
        }
     }
 
@@ -3835,6 +3864,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       stack_usage_map = initial_stack_usage_map;
     }
 
+  if (stack_usage_map_buf)
+    free (stack_usage_map_buf);
+
   return value;
 
 }
@@ -4047,6 +4079,43 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
        stack_arg_under_construction--;
     }
 
+  /* Check for overlap with already clobbered argument area.  */
+  if ((flags & ECF_SIBCALL) && MEM_P (arg->value))
+    {
+      int i = -1;
+      unsigned HOST_WIDE_INT k;
+      rtx x = arg->value;
+
+      if (XEXP (x, 0) == current_function_internal_arg_pointer)
+       i = 0;
+      else if (GET_CODE (XEXP (x, 0)) == PLUS
+              && XEXP (XEXP (x, 0), 0) ==
+                 current_function_internal_arg_pointer
+              && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+       i = INTVAL (XEXP (XEXP (x, 0), 1));
+      else
+       i = -1;
+
+      if (i >= 0)
+       {
+#ifdef ARGS_GROW_DOWNWARD
+         i = -i - arg->locate.size.constant;
+#endif
+         if (arg->locate.size.constant > 0)
+           {
+             unsigned HOST_WIDE_INT sc = arg->locate.size.constant;
+
+             for (k = 0; k < sc; k++)
+               if (i + k < stored_args_map->n_bits
+                   && TEST_BIT (stored_args_map, i + k))
+                 {
+                   sibcall_failure = 1;
+                   break;
+                 }
+           }
+       }
+    }
+
   /* Don't allow anything left on stack from computation
      of argument to alloca.  */
   if (flags & ECF_MAY_BE_ALLOCA)