re PR target/13666 (deviation from the psABI for small unions)
authorEric Botcazou <ebotcazou@libertysurf.fr>
Mon, 26 Jan 2004 11:11:11 +0000 (12:11 +0100)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 26 Jan 2004 11:11:11 +0000 (11:11 +0000)
PR target/13666
* config/sparc/sparc.c (function_arg_union_value): New function.
(function_arg): Use it to deal with unions.
(function_value): Likewise.  Define 'regbase' only for ARCH64.
Replace a conditional statement by a simpler one.

From-SVN: r76628

gcc/ChangeLog
gcc/config/sparc/sparc.c

index bbeb017aea476010306e0e6c63b2a85a804a3008..af75fc13ef374c8a5e2463eedb8d4facb5fb9a17 100644 (file)
@@ -1,3 +1,11 @@
+2004-01-26  Eric Botcazou  <ebotcazou@libertysurf.fr>
+
+       PR target/13666
+       * config/sparc/sparc.c (function_arg_union_value): New function.
+       (function_arg): Use it to deal with unions.
+       (function_value): Likewise.  Define 'regbase' only for ARCH64.
+       Replace a conditional statement by a simpler one.
+
 2004-01-26  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.c (mips16_optimize_gp): Delete.
index b5247b8e91df81260cc8d3b21b6ca9d8345fcc5a..b732e7ae7069935f4c60504aa5b1a012fb064775 100644 (file)
@@ -4827,7 +4827,7 @@ init_cumulative_args (struct sparc_args *cum, tree fntype,
    Sub-fields are not taken into account for the PACKED_P predicate.  */
 
 static void
-scan_record_type(tree type, int *intregs_p, int *fpregs_p, int *packed_p)
+scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
 {
   tree field;
 
@@ -5002,6 +5002,7 @@ static void function_arg_record_value_2
 static void function_arg_record_value_1
  (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
 static rtx function_arg_record_value (tree, enum machine_mode, int, int, int);
+static rtx function_arg_union_value (int, int);
 
 /* A subroutine of function_arg_record_value.  Traverse the structure
    recursively and determine how many registers will be required.  */
@@ -5335,6 +5336,34 @@ function_arg_record_value (tree type, enum machine_mode mode,
   return parms.ret;
 }
 
+/* Used by function_arg and function_value to implement the conventions
+   of the 64-bit ABI for passing and returning unions.
+   Return an expression valid as a return value for the two macros
+   FUNCTION_ARG and FUNCTION_VALUE.
+
+   SIZE is the size in bytes of the union.
+   REGNO is the hard register the union will be passed in.  */
+
+static rtx
+function_arg_union_value (int size, int regno)
+{
+  enum machine_mode mode;
+  rtx reg;
+
+  if (size <= UNITS_PER_WORD)
+    mode = word_mode;
+  else
+    mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+
+  reg = gen_rtx_REG (mode, regno);
+
+  /* Unions are passed left-justified.  */
+  return gen_rtx_PARALLEL (mode,
+                          gen_rtvec (1, gen_rtx_EXPR_LIST (VOIDmode,
+                                                           reg,
+                                                           const0_rtx)));
+}
+
 /* Handle the FUNCTION_ARG macro.
    Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
@@ -5384,14 +5413,12 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
     }
   else if (type && TREE_CODE (type) == UNION_TYPE)
     {
-      enum machine_mode mode;
-      int bytes = int_size_in_bytes (type);
+      HOST_WIDE_INT size = int_size_in_bytes (type);
 
-      if (bytes > 16)
-       abort ();
+      if (size > 16)
+       abort (); /* shouldn't get here */
 
-      mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
-      reg = gen_rtx_REG (mode, regno);
+      return function_arg_union_value (size, regno);
     }
   /* v9 fp args in reg slots beyond the int reg slots get passed in regs
      but also have the slot allocated for them.
@@ -5646,12 +5673,13 @@ rtx
 function_value (tree type, enum machine_mode mode, int incoming_p)
 {
   int regno;
-  int regbase = (incoming_p
-                ? SPARC_OUTGOING_INT_ARG_FIRST
-                : SPARC_INCOMING_INT_ARG_FIRST);
 
   if (TARGET_ARCH64 && type)
     {
+      int regbase = (incoming_p
+                    ? SPARC_OUTGOING_INT_ARG_FIRST
+                    : SPARC_INCOMING_INT_ARG_FIRST);
+
       if (TREE_CODE (type) == RECORD_TYPE)
        {
          /* Structures up to 32 bytes in size are passed in registers,
@@ -5662,6 +5690,15 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
 
          return function_arg_record_value (type, mode, 0, 1, regbase);
        }
+      else if (TREE_CODE (type) == UNION_TYPE)
+       {
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+
+         if (size > 32)
+           abort (); /* shouldn't get here */
+
+         return function_arg_union_value (size, regbase);
+       }
       else if (AGGREGATE_TYPE_P (type))
        {
          /* All other aggregate types are passed in an integer register
@@ -5673,13 +5710,10 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
 
          mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
        }
+      else if (GET_MODE_CLASS (mode) == MODE_INT
+              && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+       mode = word_mode;
     }
-    
-  if (TARGET_ARCH64
-      && GET_MODE_CLASS (mode) == MODE_INT 
-      && GET_MODE_SIZE (mode) < UNITS_PER_WORD
-      && type && ! AGGREGATE_TYPE_P (type))
-    mode = DImode;
 
   if (incoming_p)
     regno = BASE_RETURN_VALUE_REG (mode);