OSDN Git Service

2005-10-17 Paul Thomas <pault@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / calls.c
index 89f747f..7dbc21f 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;
@@ -591,7 +582,7 @@ flags_from_decl_or_type (tree exp)
 
       /* The function exp may have the `pure' attribute.  */
       if (DECL_IS_PURE (exp))
-       flags |= ECF_PURE | ECF_LIBCALL_BLOCK;
+       flags |= ECF_PURE;
 
       if (DECL_IS_NOVOPS (exp))
        flags |= ECF_NOVOPS;
@@ -600,7 +591,7 @@ flags_from_decl_or_type (tree exp)
        flags |= ECF_NOTHROW;
 
       if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp))
-       flags |= ECF_LIBCALL_BLOCK | ECF_CONST;
+       flags |= ECF_CONST;
 
       flags = special_function_p (exp, flags);
     }
@@ -615,7 +606,7 @@ flags_from_decl_or_type (tree exp)
   if (TREE_CODE (type) == FUNCTION_TYPE && TYPE_RETURNS_STACK_DEPRESSED (type))
     {
       flags |= ECF_SP_DEPRESSED;
-      flags &= ~(ECF_PURE | ECF_CONST | ECF_LIBCALL_BLOCK);
+      flags &= ~(ECF_PURE | ECF_CONST);
     }
 
   return flags;
@@ -1446,6 +1437,42 @@ rtx_for_function_call (tree fndecl, tree addr)
   return funexp;
 }
 
+/* Return true if and only if SIZE storage units (usually bytes)
+   starting from address ADDR overlap with already clobbered argument
+   area.  This function is used to determine if we should give up a
+   sibcall.  */
+
+static bool
+mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size)
+{
+  HOST_WIDE_INT i;
+
+  if (addr == current_function_internal_arg_pointer)
+    i = 0;
+  else if (GET_CODE (addr) == PLUS
+          && (XEXP (addr, 0)
+              == current_function_internal_arg_pointer)
+          && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+    i = INTVAL (XEXP (addr, 1));
+  else
+    return false;
+
+#ifdef ARGS_GROW_DOWNWARD
+  i = -i - size;
+#endif
+  if (size > 0)
+    {
+      unsigned HOST_WIDE_INT k;
+
+      for (k = 0; k < size; k++)
+       if (i + k < stored_args_map->n_bits
+           && TEST_BIT (stored_args_map, i + k))
+         return true;
+    }
+
+  return false;
+}
+
 /* Do the register loads required for any wholly-register parms or any
    parms which are passed both on the stack and in a register.  Their
    expressions were already evaluated.
@@ -1453,7 +1480,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
@@ -1543,6 +1570,12 @@ load_register_parameters (struct arg_data *args, int num_actuals,
            {
              rtx mem = validize_mem (args[i].value);
 
+             /* Check for overlap with already clobbered argument area.  */
+             if (is_sibcall
+                 && mem_overlaps_already_clobbered_arg_p (XEXP (args[i].value, 0),
+                                                          size))
+               *sibcall_failure = 1;
+
              /* Handle a BLKmode that needs shifting.  */
              if (nregs == 1 && size < UNITS_PER_WORD
 #ifdef BLOCK_REG_PADDING
@@ -1656,7 +1689,6 @@ check_sibcall_argument_overlap_1 (rtx x)
 {
   RTX_CODE code;
   int i, j;
-  unsigned int k;
   const char *fmt;
 
   if (x == NULL_RTX)
@@ -1665,28 +1697,8 @@ check_sibcall_argument_overlap_1 (rtx x)
   code = GET_CODE (x);
 
   if (code == MEM)
-    {
-      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
-       return 0;
-
-#ifdef ARGS_GROW_DOWNWARD
-      i = -i - GET_MODE_SIZE (GET_MODE (x));
-#endif
-
-      for (k = 0; k < GET_MODE_SIZE (GET_MODE (x)); k++)
-       if (i + k < stored_args_map->n_bits
-           && TEST_BIT (stored_args_map, i + k))
-         return 1;
-
-      return 0;
-    }
+    return mem_overlaps_already_clobbered_arg_p (XEXP (x, 0),
+                                                GET_MODE_SIZE (GET_MODE (x)));
 
   /* Scan all subexpressions.  */
   fmt = GET_RTX_FORMAT (code);
@@ -2256,6 +2268,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,
@@ -3632,6 +3647,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);
+           }
        }
     }
 
@@ -4063,6 +4100,13 @@ 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)
+      && mem_overlaps_already_clobbered_arg_p (XEXP (arg->value, 0),
+                                              arg->locate.size.constant))
+    sibcall_failure = 1;
+
   /* Don't allow anything left on stack from computation
      of argument to alloca.  */
   if (flags & ECF_MAY_BE_ALLOCA)