calls.c (stored_args_map): New variable.
authorJakub Jelinek <jakub@redhat.com>
Thu, 13 Jul 2000 18:19:27 +0000 (20:19 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 13 Jul 2000 18:19:27 +0000 (20:19 +0200)
* calls.c (stored_args_map): New variable.
(check_sibcall_argument_overlap_1): New.
(check_sibcall_argument_overlap): New.
(expand_call): Initialize stored_args_map.
Call check_sibcall_argument_overlap.

* gcc.c-torture/execute/20000707-1.c: New test.

From-SVN: r35017

gcc/ChangeLog
gcc/calls.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/20000707-1.c [new file with mode: 0644]

index 86f6e952d34278b551d4988d58992e40a9738cf2..355eb2ec0e2011c067cf7e4c282d12b33df1ddb0 100644 (file)
@@ -1,3 +1,11 @@
+2000-07-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * calls.c (stored_args_map): New variable.
+       (check_sibcall_argument_overlap_1): New.
+       (check_sibcall_argument_overlap): New.
+       (expand_call): Initialize stored_args_map.
+       Call check_sibcall_argument_overlap.
+
 2000-07-13  Bruce Korb  <bkorb@gnu.org>
 
        * fixinc/fixfixes.c: move EXIT_BROKEN to header, add sub-expr max count
index 3561f5987f40d62ade43527b51b62dee9d01353c..784b3b165f8919253736f1e08e9d482a95884e2d 100644 (file)
@@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "tm_p.h"
 #include "timevar.h"
+#include "sbitmap.h"
 
 #ifndef ACCUMULATE_OUTGOING_ARGS
 #define ACCUMULATE_OUTGOING_ARGS 0
@@ -145,6 +146,13 @@ static char *stack_usage_map;
 /* Size of STACK_USAGE_MAP.  */
 static int highest_outgoing_arg_in_use;
 
+/* A bitmap of virtual-incoming stack space.  Bit is set if the corresponding
+   stack location's tail call argument has been already stored into the stack.
+   This bitmap is used to prevent sibling call optimization if function tries
+   to use parent's incoming argument slots when they have been already
+   overwritten with tail call arguments.  */
+static sbitmap stored_args_map;
+
 /* stack_arg_under_construction is nonzero when an argument may be
    initialized with a constructor call (including a C function that
    returns a BLKmode struct) and expand_call must take special action
@@ -215,6 +223,9 @@ 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 check_sibcall_argument_overlap_1    PARAMS ((rtx));
+static int check_sibcall_argument_overlap      PARAMS ((rtx, struct arg_data *));
+
 static int combine_pending_stack_adjustment_and_call
                                                 PARAMS ((int, struct args_size *, int));
 
@@ -1917,6 +1928,95 @@ combine_pending_stack_adjustment_and_call (unadjusted_args_size,
   return adjustment;
 }
 
+/* Scan X expression if it does not dereference any argument slots
+   we already clobbered by tail call arguments (as noted in stored_args_map
+   bitmap).
+   Return non-zero if X expression dereferences such argument slots,
+   zero otherwise.  */
+
+static int
+check_sibcall_argument_overlap_1 (x)
+     rtx x;
+{
+  RTX_CODE code;
+  int i, j;
+  unsigned int k;
+  const char *fmt;
+
+  if (x == NULL_RTX)
+    return 0;
+
+  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;
+
+      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;
+    }
+
+  /* Scan all subexpressions. */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+    {
+      if (*fmt == 'e')
+        {
+          if (check_sibcall_argument_overlap_1 (XEXP (x, i)))
+            return 1;
+        }
+      else if (*fmt == 'E')
+        {
+          for (j = 0; j < XVECLEN (x, i); j++)
+            if (check_sibcall_argument_overlap_1 (XVECEXP (x, i, j)))
+              return 1;
+        }
+    }
+  return 0;
+
+}
+
+/* Scan sequence after INSN if it does not dereference any argument slots
+   we already clobbered by tail call arguments (as noted in stored_args_map
+   bitmap).  Add stack slots for ARG to stored_args_map bitmap afterwards.
+   Return non-zero if sequence after INSN dereferences such argument slots,
+   zero otherwise.  */
+
+static int
+check_sibcall_argument_overlap (insn, arg)
+     rtx insn;
+     struct arg_data *arg;
+{     
+  int low, high;
+
+  if (insn == NULL_RTX)
+    insn = get_insns ();
+  else
+    insn = NEXT_INSN (insn);
+
+  for (; insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn) &&
+       check_sibcall_argument_overlap_1 (PATTERN (insn)))
+      break;
+
+  low = arg->offset.constant;
+  for (high = low + arg->size.constant; low < high; low++)
+    SET_BIT (stored_args_map, low);
+  return insn != NULL_RTX;
+}
+
 /* 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.
@@ -2589,7 +2689,11 @@ expand_call (exp, target, ignore)
       /* The argument block when performing a sibling call is the
          incoming argument block.  */
       if (pass == 0)
-       argblock = virtual_incoming_args_rtx;
+       {
+         argblock = virtual_incoming_args_rtx;
+         stored_args_map = sbitmap_alloc (args_size.constant);
+         sbitmap_zero (stored_args_map);
+       }
 
       /* If we have no actual push instructions, or shouldn't use them,
         make space for all args right now.  */
@@ -2840,8 +2944,15 @@ 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,
-                        adjusted_args_size.var != 0, reg_parm_stack_space);
+         {
+           rtx before_arg = get_last_insn ();
+
+           store_one_arg (&args[i], argblock, flags,
+                          adjusted_args_size.var != 0, reg_parm_stack_space);
+           if (pass == 0 &&
+               check_sibcall_argument_overlap (before_arg, &args[i]))
+             sibcall_failure = 1;
+         }
 
       /* If we have a parm that is passed in registers but not in memory
         and whose alignment does not permit a direct copy into registers,
@@ -2855,8 +2966,15 @@ 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,
-                          adjusted_args_size.var != 0, reg_parm_stack_space);
+           {
+             rtx before_arg = get_last_insn ();
+
+             store_one_arg (&args[i], argblock, flags,
+                            adjusted_args_size.var != 0, reg_parm_stack_space);
+             if (pass == 0 &&
+                 check_sibcall_argument_overlap (before_arg, &args[i]))
+               sibcall_failure = 1;
+           }
 
 #ifdef PREFERRED_STACK_BOUNDARY
       /* If we pushed args in forward order, perform stack alignment
@@ -3234,6 +3352,8 @@ expand_call (exp, target, ignore)
              args[i].aligned_regs = 0;
              args[i].stack = 0;
            }
+
+         sbitmap_free (stored_args_map);
        }
       else
        normal_call_insns = insns;
index 05211a85729c94f7fc9892cb30be4dde7018cd26..1f94bdbdaeb2bbfab3613d9ae56324fc5f293f3c 100644 (file)
@@ -1,3 +1,7 @@
+2000-07-13  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.c-torture/execute/20000707-1.c: New test.
+
 2000-07-13  Neil Booth  <NeilB@earthling.net>
 
        * testsuite/gcc.dg/cpp/digraph1.c,
diff --git a/gcc/testsuite/gcc.c-torture/execute/20000707-1.c b/gcc/testsuite/gcc.c-torture/execute/20000707-1.c
new file mode 100644 (file)
index 0000000..f1c50a9
--- /dev/null
@@ -0,0 +1,27 @@
+extern void abort(void);
+extern void exit(int);
+
+struct baz {
+  int a, b, c;
+};
+
+void
+foo (int a, int b, int c)
+{
+  if (a != 4)
+    abort ();
+}
+
+void
+bar (struct baz x, int b, int c)
+{
+  foo (x.b, b, c);
+}
+
+int
+main ()
+{
+  struct baz x = { 3, 4, 5 };
+  bar (x, 1, 2);
+  exit (0);
+}