OSDN Git Service

gcc/
authorcarlos <carlos@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 4 Apr 2006 16:19:59 +0000 (16:19 +0000)
committercarlos <carlos@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 4 Apr 2006 16:19:59 +0000 (16:19 +0000)
2006-04-04  Carlos O'Donell  <carlos@codesourcery.com>

* doc/tm.texi (TARGET_STRUCT_VALUE_RTX): Document
new value 2 for incoming.
* function.c (expand_function_start): Call struct_value_rtx
with incoming as 2.
* config/sparc/sparc.md: Comment updated_return.
* config/sparc/sparc.opt: Add -mstd-struct-return option.
* config/sparc/sparc.c (sparc_struct_value_rtx): Use standard
struct return if sparc_std_struct_return and incoming is 2.
(print_operand): Do not adjust return if
sparc_std_struct_return.

gcc/testsuite/

2006-04-04  Carlos O'Donell  <carlos@codesourcery.com>

* gcc.target/sparc/struct-ret-check.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@112672 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/sparc/sparc.c
gcc/config/sparc/sparc.md
gcc/config/sparc/sparc.opt
gcc/doc/tm.texi
gcc/function.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sparc/struct-ret-check.c [new file with mode: 0644]

index 192d6f7..a9ad12d 100644 (file)
@@ -1,3 +1,16 @@
+2006-04-04  Carlos O'Donell  <carlos@codesourcery.com>
+
+       * doc/tm.texi (TARGET_STRUCT_VALUE_RTX): Document
+       new value 2 for incoming.
+       * function.c (expand_function_start): Call struct_value_rtx
+       with incoming as 2.
+       * config/sparc/sparc.md: Comment updated_return.
+       * config/sparc/sparc.opt: Add -mstd-struct-return option.
+       * config/sparc/sparc.c (sparc_struct_value_rtx): Use standard
+       struct return if sparc_std_struct_return and incoming is 2.
+       (print_operand): Do not adjust return if
+       sparc_std_struct_return.
+
 2006-04-04  Roger Sayle  <roger@eyesopen.com>
 
        * builtins.c (fold_builtin_sprintf): Use fold_convert instead of
index 709a92b..e880226 100644 (file)
@@ -5425,7 +5425,7 @@ sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
    Return where to find the structure return value address.  */
 
 static rtx
-sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
+sparc_struct_value_rtx (tree fndecl, int incoming)
 {
   if (TARGET_ARCH64)
     return 0;
@@ -5440,6 +5440,46 @@ sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
        mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
                                                 STRUCT_VALUE_OFFSET));
 
+      /* Only follow the SPARC ABI for fixed-size structure returns. 
+         Variable size structure returns are handled per the normal 
+         procedures in GCC. This is enabled by -mstd-struct-return */
+      if (incoming == 2 
+         && sparc_std_struct_return
+         && TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
+         && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
+       {
+         /* We must check and adjust the return address, as it is
+            optional as to whether the return object is really
+            provided.  */
+         rtx ret_rtx = gen_rtx_REG (Pmode, 31);
+         rtx scratch = gen_reg_rtx (SImode);
+         rtx endlab = gen_label_rtx (); 
+
+         /* Calculate the return object size */
+         tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl));
+         rtx size_rtx = GEN_INT (TREE_INT_CST_LOW (size) & 0xfff);
+         /* Construct a temporary return value */
+         rtx temp_val = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
+
+         /* Implement SPARC 32-bit psABI callee returns struck checking
+            requirements: 
+           
+             Fetch the instruction where we will return to and see if
+            it's an unimp instruction (the most significant 10 bits
+            will be zero).  */
+         emit_move_insn (scratch, gen_rtx_MEM (SImode,
+                                               plus_constant (ret_rtx, 8)));
+         /* Assume the size is valid and pre-adjust */
+         emit_insn (gen_add3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode, 0, endlab);
+         emit_insn (gen_sub3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         /* Assign stack temp: 
+            Write the address of the memory pointed to by temp_val into
+            the memory pointed to by mem */
+         emit_move_insn (mem, XEXP (temp_val, 0));
+         emit_label (endlab);
+       }
+
       set_mem_alias_set (mem, struct_value_alias_set);
       return mem;
     }
@@ -6639,9 +6679,14 @@ print_operand (FILE *file, rtx x, int code)
         so we have to account for it.  This insn is used in the 32-bit ABI
         when calling a function that returns a non zero-sized structure. The
         64-bit ABI doesn't have it.  Be careful to have this test be the same
-        as that used on the call.  */
+        as that used on the call. The exception here is that when 
+        sparc_std_struct_return is enabled, the psABI is followed exactly
+        and the adjustment is made by the code in sparc_struct_value_rtx. 
+        The call emitted is the same when sparc_std_struct_return is 
+        present. */
      if (! TARGET_ARCH64
         && current_function_returns_struct
+        && ! sparc_std_struct_return
         && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
             == INTEGER_CST)
         && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
index b6ebb82..ed68f1e 100644 (file)
   DONE;
 })
 
-;; This is a bit of a hack.  We're incrementing a fixed register (%i7),
-;; and parts of the compiler don't want to believe that the add is needed.
+;; Adjust the return address conditionally. If the value of op1 is equal
+;; to all zero then adjust the return address i.e. op0 = op0 + 4.
+;; This is technically *half* the check required by the 32-bit SPARC
+;; psABI. This check only ensures that an "unimp" insn was written by
+;; the caller, but doesn't check to see if the expected size matches
+;; (this is encoded in the 12 lower bits). This check is obsolete and
+;; only used by the above code "untyped_return".
 
 (define_insn "update_return"
   [(unspec:SI [(match_operand:SI 0 "register_operand" "r")
index da50e1a..8cdf11c 100644 (file)
@@ -99,6 +99,9 @@ mcmodel=
 Target RejectNegative Joined Var(sparc_cmodel_string)
 Use given SPARC-V9 code model
 
+mstd-struct-return
+Target Report RejectNegative Var(sparc_std_struct_return)
+Enable strict 32-bit psABI struct return checking.
 
 Mask(LITTLE_ENDIAN)
 ;; Generate code for little-endian
index 2e7632e..69514e2 100644 (file)
@@ -4187,12 +4187,15 @@ On some architectures the place where the structure value address
 is found by the called function is not the same place that the
 caller put it.  This can be due to register windows, or it could
 be because the function prologue moves it to a different place.
-@var{incoming} is @code{true} when the location is needed in
-the context of the called function, and @code{false} in the context of
+@var{incoming} is @code{1} or @code{2} when the location is needed in
+the context of the called function, and @code{0} in the context of
 the caller.
 
-If @var{incoming} is @code{true} and the address is to be found on the
-stack, return a @code{mem} which refers to the frame pointer.
+If @var{incoming} is non-zero and the address is to be found on the
+stack, return a @code{mem} which refers to the frame pointer. If
+@var{incoming} is @code{2}, the result is being used to fetch the
+structure value address at the beginning of a function.  If you need 
+to emit adjusting code, you should do it at this point.
 @end deftypefn
 
 @defmac PCC_STATIC_STRUCT_RETURN
index 2e9aec0..3becef3 100644 (file)
@@ -4120,7 +4120,7 @@ expand_function_start (tree subr)
       else
 #endif
        {
-         rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 1);
+         rtx sv = targetm.calls.struct_value_rtx (TREE_TYPE (subr), 2);
          /* Expect to be passed the address of a place to store the value.
             If it is passed as an argument, assign_parms will take care of
             it.  */
index f626bd7..1872b3d 100644 (file)
@@ -1,3 +1,7 @@
+2006-04-04  Carlos O'Donell  <carlos@codesourcery.com>
+
+       * gcc.target/sparc/struct-ret-check.c: New test.
+
 2006-04-03  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
 
        * gfortran.dg/fmt_zero_digits.f90: New test for no error when
diff --git a/gcc/testsuite/gcc.target/sparc/struct-ret-check.c b/gcc/testsuite/gcc.target/sparc/struct-ret-check.c
new file mode 100644 (file)
index 0000000..350224e
--- /dev/null
@@ -0,0 +1,126 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc. */
+/* Contributed by Carlos O'Donell on 2006-03-14 */
+
+/* Test that GCC follows the SPARC 32-bit psABI with regards to
+   structure return checking in a callee. When -mstd-struct-return 
+   is specificed then gcc will emit code to skip the unimp insn. */ 
+
+/* Origin: Carlos O'Donell <carlos@codesourcery.com> */
+/* { dg-do run { target sparc*-*-solaris* sparc*-*-linux* sparc*-*-*bsd* } } */
+/* { dg-options "-mstd-struct-return" } */
+/* { dg-require-effective-target ilp32 } */
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+/* Local declaration of div_t structure */
+struct mydiv_t {
+  int rem;
+  int quot;
+};
+
+/* Global check variable used by signal handler */
+int check = 1;
+struct mydiv_t dcheck;
+
+struct mydiv_t foo (void)
+{
+  struct mydiv_t bar;
+  bar.rem = 3;
+  bar.quot = 4;
+  return bar;
+}
+
+void handle_sigill (int signum)
+{
+  if (signum == SIGILL && check == 2)
+    {
+      /* We expected a SIGILL due to a mismatch in unimp size
+        and struct mydiv_t size */
+      exit (0);
+    }
+  else
+    abort ();
+}
+
+/* Implement 3 checks to validate SPARC 32-bit psABI callee 
+   returns struct
+   
+   Test1: Save area is valid. unimp size is valid.
+   Success: Save area modified correctly.
+   Failure: Save area unmodified.
+
+   Test2: Save area is valid. unimp size is invalid (invalid insn).
+   Success: Save area unmodified. check == 2.
+   Failure: Save area modified or check == 1.
+
+   Test3: Save area is invalid. unimp size is invalid (invalid size).
+   Success: Will raise a SIGILL. 
+   Failure: SIGSEGV caused by write to invalid save area. */
+
+int main (void)
+{
+  dcheck.rem = 1;
+  dcheck.quot = 2;
+
+  /*** Test1 ***/
+  /* Insert a call, insert unimp by hand */
+  __asm__ ("st %1, [ %%sp + 0x40 ]\n\t"
+          "call foo\n\t"
+          " nop\n\t"
+          "unimp %2\n\t" 
+          : "=m" (dcheck)
+          : "r" (&dcheck), "i" (sizeof(struct mydiv_t)) 
+          : "memory");
+
+  /* If the caller doesn't adjust the return, then it crashes.
+     Check the result too. */
+
+  if ((dcheck.rem != 3) || (dcheck.quot !=4))
+    abort ();
+  
+
+  /*** Test 2 ***/
+  dcheck.rem = 1;
+  dcheck.quot = 2;
+
+  /* Ignore the return of the function */
+  __asm__ ("st %3, [ %%sp + 0x40 ]\n\t"
+          "call foo\n\t"
+          " nop\n\t"
+          "mov %2, %0\n\t"
+          : "+r" (check), "=m" (dcheck) 
+          : "i" (0x2), "r" (&dcheck)
+          : "memory");
+
+  /* If the caller does an unconditional adjustment it will skip
+     the mov, and then we can fail the test based on check's value 
+     We pass a valid pointer to a save area in order to check if 
+     caller incorrectly wrote to the save area aswell. There may
+     be a case where the unimp check and skip is correct, but the
+     write to the save area still occurs. */
+
+  if (check != 2)
+    abort ();
+
+  if ((dcheck.rem != 1) || (dcheck.quot != 2))
+    abort ();
+
+  /*** Test 3 ***/
+  /* Prepare a test that must SIGILL. According to the spec
+     if the sizes of the save area and return don't match then
+     the copy is ignored and we return to the unimp. */
+
+  signal (SIGILL, handle_sigill);
+
+  __asm__ ("st %%g0, [ %%sp + 0x40 ]\n\t"
+          "call foo\n\t"
+          " nop\n\t"
+          "unimp %0\n\t"
+          : /* No outputs */ 
+          : "i" (sizeof(struct mydiv_t)-1) 
+          : "memory");
+
+  /* NEVER REACHED */
+  exit (0);
+}