re PR target/69706 (internal compiler error: in extract_constrain_insn, at recog...
authorEric Botcazou <ebotcazou@adacore.com>
Mon, 29 Feb 2016 10:20:31 +0000 (10:20 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 29 Feb 2016 10:20:31 +0000 (10:20 +0000)
PR target/69706
* config/sparc/sparc.c (ROUND_ADVANCE): Rename to...
(NWORDS_UP): ...this
(init_cumulative_args): Minor tweaks.
(sparc_promote_function_mode): Likewise.
(scan_record_type): Delete.
(traverse_record_type): New function template.
(classify_data_t): New structure type.
(classify_registers): New inline function.
(function_arg_slotno): In 64-bit mode, bail out early if FP slots are
exhausted.  Instantiate traverse_record_type on classify_registers and
deal with the case of a structure passed in slot #15 with no FP field
in the first word.
(assign_data_t): New structure type.
(compute_int_layout): New static function.
(compute_fp_layout): Likewise.
(count_registers): New inline function.
(assign_int_registers): New static function.
(assign_fp_registers): Likewise.
(assign_registers): New inline function.
(function_arg_record_value_1): Delete.
(function_arg_record_value_2): Likewise.
(function_arg_record_value_3): Likewise.
(function_arg_record_value): Adjust to above changes.  Instantiate
traverse_record_type on count_registers to first count the number of
registers to be used and then on assign_registers to assign them.
(function_arg_union_value): Adjust to above renaming.
(sparc_function_arg_1); Minor tweaks.  Remove commented out code.
(sparc_arg_partial_bytes): Adjust to above renaming.  Deal with the
case of a structure passed in slot #15
(sparc_function_arg_advance): Likewise.
(function_arg_padding): Minor tweak.

From-SVN: r233808

gcc/ChangeLog
gcc/config/sparc/sparc.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/sparc/20160229-1.c [new file with mode: 0644]

index 772fc3b7582c883224c81a40fc1565c52721e822..3edc42e47fffcc04f8ce3d4e57d3682c74a1c2dd 100644 (file)
@@ -1,3 +1,38 @@
+2016-02-29  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR target/69706
+       * config/sparc/sparc.c (ROUND_ADVANCE): Rename to...
+       (NWORDS_UP): ...this
+       (init_cumulative_args): Minor tweaks.
+       (sparc_promote_function_mode): Likewise.
+       (scan_record_type): Delete.
+       (traverse_record_type): New function template.
+       (classify_data_t): New structure type.
+       (classify_registers): New inline function.
+       (function_arg_slotno): In 64-bit mode, bail out early if FP slots are
+       exhausted.  Instantiate traverse_record_type on classify_registers and
+       deal with the case of a structure passed in slot #15 with no FP field
+       in the first word.
+       (assign_data_t): New structure type.
+       (compute_int_layout): New static function.
+       (compute_fp_layout): Likewise.
+       (count_registers): New inline function.
+       (assign_int_registers): New static function.
+       (assign_fp_registers): Likewise.
+       (assign_registers): New inline function.
+       (function_arg_record_value_1): Delete.
+       (function_arg_record_value_2): Likewise.
+       (function_arg_record_value_3): Likewise.
+       (function_arg_record_value): Adjust to above changes.  Instantiate
+       traverse_record_type on count_registers to first count the number of
+       registers to be used and then on assign_registers to assign them.
+       (function_arg_union_value): Adjust to above renaming.
+       (sparc_function_arg_1); Minor tweaks.  Remove commented out code.
+       (sparc_arg_partial_bytes): Adjust to above renaming.  Deal with the
+       case of a structure passed in slot #15
+       (sparc_function_arg_advance): Likewise.
+       (function_arg_padding): Minor tweak.
+
 2016-02-29  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/69720
index 71609f277010ba0ae476f0fbea8d64fdb2674a67..d077680048c6b78d297ecc9291c063efd7af971c 100644 (file)
@@ -518,7 +518,6 @@ int sparc_indent_opcode = 0;
 
 static void sparc_option_override (void);
 static void sparc_init_modes (void);
-static void scan_record_type (const_tree, int *, int *, int *);
 static int function_arg_slotno (const CUMULATIVE_ARGS *, machine_mode,
                                const_tree, bool, bool, int *, int *);
 
@@ -6086,8 +6085,8 @@ conventions.  */
 #define SPARC_INT_ARG_MAX 6
 /* Maximum number of fp regs for args.  */
 #define SPARC_FP_ARG_MAX 16
-
-#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+/* Number of words (partially) occupied for a given size in units.  */
+#define NWORDS_UP(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 
 /* Handle the INIT_CUMULATIVE_ARGS macro.
    Initialize a variable CUM of type CUMULATIVE_ARGS
@@ -6095,25 +6094,20 @@ conventions.  */
    For a library call, FNTYPE is 0.  */
 
 void
-init_cumulative_args (struct sparc_args *cum, tree fntype,
-                     rtx libname ATTRIBUTE_UNUSED,
-                     tree fndecl ATTRIBUTE_UNUSED)
+init_cumulative_args (struct sparc_args *cum, tree fntype, rtx, tree)
 {
   cum->words = 0;
   cum->prototype_p = fntype && prototype_p (fntype);
-  cum->libcall_p = fntype == 0;
+  cum->libcall_p = !fntype;
 }
 
 /* Handle promotion of pointer and integer arguments.  */
 
 static machine_mode
-sparc_promote_function_mode (const_tree type,
-                             machine_mode mode,
-                             int *punsignedp,
-                             const_tree fntype ATTRIBUTE_UNUSED,
-                             int for_return ATTRIBUTE_UNUSED)
+sparc_promote_function_mode (const_tree type, machine_mode mode,
+                            int *punsignedp, const_tree, int)
 {
-  if (type != NULL_TREE && POINTER_TYPE_P (type))
+  if (type && POINTER_TYPE_P (type))
     {
       *punsignedp = POINTERS_EXTEND_UNSIGNED;
       return Pmode;
@@ -6135,36 +6129,75 @@ sparc_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED)
   return TARGET_ARCH64 ? true : false;
 }
 
-/* Scan the record type TYPE and return the following predicates:
-    - INTREGS_P: the record contains at least one field or sub-field
-      that is eligible for promotion in integer registers.
-    - FP_REGS_P: the record contains at least one field or sub-field
-      that is eligible for promotion in floating-point registers.
-    - PACKED_P: the record contains at least one field that is packed.  */
+/* Traverse the record TYPE recursively and call FUNC on its fields.
+   NAMED is true if this is for a named parameter.  DATA is passed
+   to FUNC for each field.  OFFSET is the starting position and
+   PACKED is true if we are inside a packed record.  */
 
+template <typename T, void Func (const_tree, HOST_WIDE_INT, bool, T*)>
 static void
-scan_record_type (const_tree type, int *intregs_p, int *fpregs_p,
-                 int *packed_p)
+traverse_record_type (const_tree type, bool named, T *data,
+                     HOST_WIDE_INT offset = 0, bool packed = false)
 {
-  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
-    {
-      if (TREE_CODE (field) == FIELD_DECL)
+  /* The ABI obviously doesn't specify how packed structures are passed.
+     These are passed in integer regs if possible, otherwise memory.  */
+  if (!packed)
+    for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
        {
-         tree field_type = TREE_TYPE (field);
+         packed = true;
+         break;
+       }
 
-         if (TREE_CODE (field_type) == RECORD_TYPE)
-           scan_record_type (field_type, intregs_p, fpregs_p, packed_p);
-         else if ((FLOAT_TYPE_P (field_type)
-                  || TREE_CODE (field_type) == VECTOR_TYPE)
-                 && TARGET_FPU)
-           *fpregs_p = 1;
-         else
-           *intregs_p = 1;
+  /* Walk the real fields, but skip those with no size or a zero size.
+     ??? Fields with variable offset are handled as having zero offset.  */
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL)
+      {
+       if (!DECL_SIZE (field) || integer_zerop (DECL_SIZE (field)))
+         continue;
 
-         if (DECL_PACKED (field))
-           *packed_p = 1;
-       }
+       HOST_WIDE_INT bitpos = offset;
+       if (TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST)
+         bitpos += int_bit_position (field);
+
+       tree field_type = TREE_TYPE (field);
+       if (TREE_CODE (field_type) == RECORD_TYPE)
+         traverse_record_type<T, Func> (field_type, named, data, bitpos,
+                                        packed);
+       else
+         {
+           const bool fp_type
+             = FLOAT_TYPE_P (field_type) || VECTOR_TYPE_P (field_type);
+           Func (field, bitpos, fp_type && named && !packed && TARGET_FPU,
+                 data);
+         }
+      }
+}
+
+/* Handle recursive register classifying for structure layout.  */
+
+typedef struct
+{
+  bool int_regs;       /* true if field eligible to int registers.  */
+  bool fp_regs;                /* true if field eligible to FP registers.  */
+  bool fp_regs_in_first_word;  /* true if such field in first word.  */
+} classify_data_t;
+
+/* A subroutine of function_arg_slotno.  Classify the field.  */
+
+inline void
+classify_registers (const_tree, HOST_WIDE_INT bitpos, bool fp,
+                   classify_data_t *data)
+{
+  if (fp)
+    {
+      data->fp_regs = true;
+      if (bitpos < BITS_PER_WORD)
+       data->fp_regs_in_first_word = true;
     }
+  else
+    data->int_regs = true;
 }
 
 /* Compute the slot number to pass an argument in.
@@ -6178,16 +6211,16 @@ scan_record_type (const_tree type, int *intregs_p, int *fpregs_p,
     not be available.
    NAMED is nonzero if this argument is a named parameter
     (otherwise it is an extra parameter matching an ellipsis).
-   INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
+   INCOMING is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
    *PREGNO records the register number to use if scalar type.
    *PPADDING records the amount of padding needed in words.  */
 
 static int
 function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
-                    const_tree type, bool named, bool incoming_p,
+                    const_tree type, bool named, bool incoming,
                     int *pregno, int *ppadding)
 {
-  int regbase = (incoming_p
+  int regbase = (incoming
                 ? SPARC_INCOMING_INT_ARG_FIRST
                 : SPARC_OUTGOING_INT_ARG_FIRST);
   int slotno = cum->words;
@@ -6243,8 +6276,10 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
     case MODE_VECTOR_INT:
       if (TARGET_ARCH64 && TARGET_FPU && named)
        {
+         /* If all arg slots are filled, then must pass on stack.  */
          if (slotno >= SPARC_FP_ARG_MAX)
            return -1;
+
          regno = SPARC_FP_ARG_FIRST + slotno * 2;
          /* Arguments filling only one single FP register are
             right-justified in the outer double FP register.  */
@@ -6256,8 +6291,10 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
 
     case MODE_INT:
     case MODE_COMPLEX_INT:
+      /* If all arg slots are filled, then must pass on stack.  */
       if (slotno >= SPARC_INT_ARG_MAX)
        return -1;
+
       regno = regbase + slotno;
       break;
 
@@ -6270,42 +6307,43 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
 
       if (TARGET_ARCH32
          || !type
-         || (TREE_CODE (type) != VECTOR_TYPE
-             && TREE_CODE (type) != RECORD_TYPE))
+         || (TREE_CODE (type) != RECORD_TYPE
+             && TREE_CODE (type) != VECTOR_TYPE))
        {
+         /* If all arg slots are filled, then must pass on stack.  */
          if (slotno >= SPARC_INT_ARG_MAX)
            return -1;
+
          regno = regbase + slotno;
        }
       else  /* TARGET_ARCH64 && type */
        {
-         int intregs_p = 0, fpregs_p = 0, packed_p = 0;
-
-         /* First see what kinds of registers we would need.  */
-         if (TREE_CODE (type) == VECTOR_TYPE)
-           fpregs_p = 1;
-         else
-           scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
-
-         /* The ABI obviously doesn't specify how packed structures
-            are passed.  These are defined to be passed in int regs
-            if possible, otherwise memory.  */
-         if (packed_p || !named)
-           fpregs_p = 0, intregs_p = 1;
-
          /* If all arg slots are filled, then must pass on stack.  */
-         if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
+         if (slotno >= SPARC_FP_ARG_MAX)
            return -1;
 
-         /* If there are only int args and all int arg slots are filled,
-            then must pass on stack.  */
-         if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
-           return -1;
+         if (TREE_CODE (type) == RECORD_TYPE)
+           {
+             classify_data_t data = { false, false, false };
+             traverse_record_type<classify_data_t, classify_registers>
+               (type, named, &data);
+
+             /* If all slots are filled except for the last one, but there
+                is no FP field in the first word, then must pass on stack.  */
+             if (data.fp_regs
+                 && !data.fp_regs_in_first_word
+                 && slotno >= SPARC_FP_ARG_MAX - 1)
+               return -1;
+
+             /* If there are only int args and all int slots are filled,
+                then must pass on stack.  */
+             if (!data.fp_regs
+                 && data.int_regs
+                 && slotno >= SPARC_INT_ARG_MAX)
+               return -1;
+           }
 
-         /* Note that even if all int arg slots are filled, fp members may
-            still be passed in regs if such regs are available.
-            *PREGNO isn't set because there may be more than one, it's up
-            to the caller to compute them.  */
+         /* PREGNO isn't set since both int and FP regs can be used.  */
          return slotno;
        }
       break;
@@ -6318,277 +6356,211 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
   return slotno;
 }
 
-/* Handle recursive register counting for structure field layout.  */
+/* Handle recursive register counting/assigning for structure layout.  */
 
-struct function_arg_record_value_parms
+typedef struct
 {
-  rtx ret;             /* return expression being built.  */
   int slotno;          /* slot number of the argument.  */
-  int named;           /* whether the argument is named.  */
   int regbase;         /* regno of the base register.  */
-  int stack;           /* 1 if part of the argument is on the stack.  */
   int intoffset;       /* offset of the first pending integer field.  */
-  unsigned int nregs;  /* number of words passed in registers.  */
-};
-
-static void function_arg_record_value_3
- (HOST_WIDE_INT, struct function_arg_record_value_parms *);
-static void function_arg_record_value_2
- (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
-static void function_arg_record_value_1
- (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
-static rtx function_arg_record_value (const_tree, machine_mode, int, int, int);
-static rtx function_arg_union_value (int, machine_mode, int, int);
+  int nregs;           /* number of words passed in registers.  */
+  bool stack;          /* true if part of the argument is on the stack.  */
+  rtx ret;             /* return expression being built.  */
+} assign_data_t;
 
-/* A subroutine of function_arg_record_value.  Traverse the structure
-   recursively and determine how many registers will be required.  */
+/* A subroutine of function_arg_record_value.  Compute the number of integer
+   registers to be assigned between PARMS->intoffset and BITPOS.  Return
+   true if at least one integer register is assigned or false otherwise.  */
 
-static void
-function_arg_record_value_1 (const_tree type, HOST_WIDE_INT startbitpos,
-                            struct function_arg_record_value_parms *parms,
-                            bool packed_p)
+static bool
+compute_int_layout (HOST_WIDE_INT bitpos, assign_data_t *data, int *pnregs)
 {
-  tree field;
+  if (data->intoffset < 0)
+    return false;
 
-  /* We need to compute how many registers are needed so we can
-     allocate the PARALLEL but before we can do that we need to know
-     whether there are any packed fields.  The ABI obviously doesn't
-     specify how structures are passed in this case, so they are
-     defined to be passed in int regs if possible, otherwise memory,
-     regardless of whether there are fp values present.  */
+  const int intoffset = data->intoffset;
+  data->intoffset = -1;
 
-  if (! packed_p)
-    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-      {
-       if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
-         {
-           packed_p = true;
-           break;
-         }
-      }
+  const int this_slotno = data->slotno + intoffset / BITS_PER_WORD;
+  const unsigned int startbit = ROUND_DOWN (intoffset, BITS_PER_WORD);
+  const unsigned int endbit = ROUND_UP (bitpos, BITS_PER_WORD);
+  int nregs = (endbit - startbit) / BITS_PER_WORD;
 
-  /* Compute how many registers we need.  */
-  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+  if (nregs > 0 && nregs > SPARC_INT_ARG_MAX - this_slotno)
     {
-      if (TREE_CODE (field) == FIELD_DECL)
-       {
-         HOST_WIDE_INT bitpos = startbitpos;
+      nregs = SPARC_INT_ARG_MAX - this_slotno;
 
-         if (DECL_SIZE (field) != 0)
-           {
-             if (integer_zerop (DECL_SIZE (field)))
-               continue;
+      /* We need to pass this field (partly) on the stack.  */
+      data->stack = 1;
+    }
 
-             if (tree_fits_uhwi_p (bit_position (field)))
-               bitpos += int_bit_position (field);
-           }
+  if (nregs <= 0)
+    return false;
 
-         /* ??? FIXME: else assume zero offset.  */
-
-         if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
-           function_arg_record_value_1 (TREE_TYPE (field),
-                                        bitpos,
-                                        parms,
-                                        packed_p);
-         else if ((FLOAT_TYPE_P (TREE_TYPE (field))
-                   || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
-                  && TARGET_FPU
-                  && parms->named
-                  && ! packed_p)
-           {
-             if (parms->intoffset != -1)
-               {
-                 unsigned int startbit, endbit;
-                 int intslots, this_slotno;
+  *pnregs = nregs;
+  return true;
+}
 
-                 startbit = ROUND_DOWN (parms->intoffset, BITS_PER_WORD);
-                 endbit   = ROUND_UP (bitpos, BITS_PER_WORD);
+/* A subroutine of function_arg_record_value.  Compute the number and the mode
+   of the FP registers to be assigned for FIELD.  Return true if at least one
+   FP register is assigned or false otherwise.  */
 
-                 intslots = (endbit - startbit) / BITS_PER_WORD;
-                 this_slotno = parms->slotno + parms->intoffset
-                   / BITS_PER_WORD;
+static bool
+compute_fp_layout (const_tree field, HOST_WIDE_INT bitpos,
+                  assign_data_t *data,
+                  int *pnregs, machine_mode *pmode)
+{
+  const int this_slotno = data->slotno + bitpos / BITS_PER_WORD;
+  machine_mode mode = DECL_MODE (field);
+  int nregs, nslots;
 
-                 if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
-                   {
-                     intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
-                     /* We need to pass this field on the stack.  */
-                     parms->stack = 1;
-                   }
+  /* Slots are counted as words while regs are counted as having the size of
+     the (inner) mode.  */
+  if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE && mode == BLKmode)
+    {
+      mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+      nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
+    }
+  else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+    {
+      mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+      nregs = 2;
+    }
+  else
+    nregs = 1;
 
-                 parms->nregs += intslots;
-                 parms->intoffset = -1;
-               }
+  nslots = NWORDS_UP (nregs * GET_MODE_SIZE (mode));
 
-             /* There's no need to check this_slotno < SPARC_FP_ARG MAX.
-                If it wasn't true we wouldn't be here.  */
-             if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
-                 && DECL_MODE (field) == BLKmode)
-               parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
-             else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
-               parms->nregs += 2;
-             else
-               parms->nregs += 1;
-           }
-         else
-           {
-             if (parms->intoffset == -1)
-               parms->intoffset = bitpos;
-           }
-       }
+  if (nslots > SPARC_FP_ARG_MAX - this_slotno)
+    {
+      nslots = SPARC_FP_ARG_MAX - this_slotno;
+      nregs = (nslots * UNITS_PER_WORD) / GET_MODE_SIZE (mode);
+
+      /* We need to pass this field (partly) on the stack.  */
+      data->stack = 1;
+
+      if (nregs <= 0)
+       return false;
     }
+
+  *pnregs = nregs;
+  *pmode = mode;
+  return true;
 }
 
-/* A subroutine of function_arg_record_value.  Assign the bits of the
-   structure between parms->intoffset and bitpos to integer registers.  */
+/* A subroutine of function_arg_record_value.  Count the number of registers
+   to be assigned for FIELD and between PARMS->intoffset and BITPOS.  */
 
-static void
-function_arg_record_value_3 (HOST_WIDE_INT bitpos,
-                            struct function_arg_record_value_parms *parms)
+inline void
+count_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
+                assign_data_t *data)
 {
-  machine_mode mode;
-  unsigned int regno;
-  unsigned int startbit, endbit;
-  int this_slotno, intslots, intoffset;
-  rtx reg;
+  if (fp)
+    {
+      int nregs;
+      machine_mode mode;
 
-  if (parms->intoffset == -1)
-    return;
+      if (compute_int_layout (bitpos, data, &nregs))
+       data->nregs += nregs;
 
-  intoffset = parms->intoffset;
-  parms->intoffset = -1;
+      if (compute_fp_layout (field, bitpos, data, &nregs, &mode))
+       data->nregs += nregs;
+    }
+  else
+    {
+      if (data->intoffset < 0)
+       data->intoffset = bitpos;
+    }
+}
 
-  startbit = ROUND_DOWN (intoffset, BITS_PER_WORD);
-  endbit = ROUND_UP (bitpos, BITS_PER_WORD);
-  intslots = (endbit - startbit) / BITS_PER_WORD;
-  this_slotno = parms->slotno + intoffset / BITS_PER_WORD;
+/* A subroutine of function_arg_record_value.  Assign the bits of the
+   structure between PARMS->intoffset and BITPOS to integer registers.  */
+
+static void
+assign_int_registers (HOST_WIDE_INT bitpos, assign_data_t *data)
+{
+  int intoffset = data->intoffset;
+  machine_mode mode;
+  int nregs;
 
-  intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
-  if (intslots <= 0)
+  if (!compute_int_layout (bitpos, data, &nregs))
     return;
 
   /* If this is the trailing part of a word, only load that much into
      the register.  Otherwise load the whole register.  Note that in
      the latter case we may pick up unwanted bits.  It's not a problem
      at the moment but may wish to revisit.  */
-
   if (intoffset % BITS_PER_WORD != 0)
     mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
                                   MODE_INT);
   else
     mode = word_mode;
 
+  const int this_slotno = data->slotno + intoffset / BITS_PER_WORD;
+  unsigned int regno = data->regbase + this_slotno;
   intoffset /= BITS_PER_UNIT;
+
   do
     {
-      regno = parms->regbase + this_slotno;
-      reg = gen_rtx_REG (mode, regno);
-      XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
+      rtx reg = gen_rtx_REG (mode, regno);
+      XVECEXP (data->ret, 0, data->stack + data->nregs)
        = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
-
-      this_slotno += 1;
-      intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+      data->nregs += 1;
       mode = word_mode;
-      parms->nregs += 1;
-      intslots -= 1;
+      regno += 1;
+      intoffset = (intoffset | (UNITS_PER_WORD - 1)) + 1;
     }
-  while (intslots > 0);
+  while (--nregs > 0);
 }
 
-/* A subroutine of function_arg_record_value.  Traverse the structure
-   recursively and assign bits to floating point registers.  Track which
-   bits in between need integer registers; invoke function_arg_record_value_3
-   to make that happen.  */
+/* A subroutine of function_arg_record_value.  Assign FIELD at position
+   BITPOS to FP registers.  */
 
 static void
-function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
-                            struct function_arg_record_value_parms *parms,
-                            bool packed_p)
+assign_fp_registers (const_tree field, HOST_WIDE_INT bitpos,
+                            assign_data_t *data)
 {
-  tree field;
+  int nregs;
+  machine_mode mode;
 
-  if (! packed_p)
-    for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
-      {
-       if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
-         {
-           packed_p = true;
-           break;
-         }
-      }
+  if (!compute_fp_layout (field, bitpos, data, &nregs, &mode))
+    return;
+
+  const int this_slotno = data->slotno + bitpos / BITS_PER_WORD;
+  int regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
+  if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
+    regno++;
+  int pos = bitpos / BITS_PER_UNIT;
 
-  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+  do
     {
-      if (TREE_CODE (field) == FIELD_DECL)
-       {
-         HOST_WIDE_INT bitpos = startbitpos;
+      rtx reg = gen_rtx_REG (mode, regno);
+      XVECEXP (data->ret, 0, data->stack + data->nregs)
+       = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
+      data->nregs += 1;
+      regno += GET_MODE_SIZE (mode) / 4;
+      pos += GET_MODE_SIZE (mode);
+    }
+  while (--nregs > 0);
+}
 
-         if (DECL_SIZE (field) != 0)
-           {
-             if (integer_zerop (DECL_SIZE (field)))
-               continue;
+/* A subroutine of function_arg_record_value.  Assign FIELD and the bits of
+   the structure between PARMS->intoffset and BITPOS to registers.  */
 
-             if (tree_fits_uhwi_p (bit_position (field)))
-               bitpos += int_bit_position (field);
-           }
+inline void
+assign_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
+                 assign_data_t *data)
+{
+  if (fp)
+    {
+      assign_int_registers (bitpos, data);
 
-         /* ??? FIXME: else assume zero offset.  */
-
-         if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
-           function_arg_record_value_2 (TREE_TYPE (field),
-                                        bitpos,
-                                        parms,
-                                        packed_p);
-         else if ((FLOAT_TYPE_P (TREE_TYPE (field))
-                   || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
-                  && TARGET_FPU
-                  && parms->named
-                  && ! packed_p)
-           {
-             int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
-             int regno, nregs, pos;
-             machine_mode mode = DECL_MODE (field);
-             rtx reg;
-
-             function_arg_record_value_3 (bitpos, parms);
-
-             if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
-                 && mode == BLKmode)
-               {
-                 mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
-                 nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
-               }
-             else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
-               {
-                 mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
-                 nregs = 2;
-               }
-             else
-               nregs = 1;
-
-             regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
-             if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
-               regno++;
-             reg = gen_rtx_REG (mode, regno);
-             pos = bitpos / BITS_PER_UNIT;
-             XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
-               = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
-             parms->nregs += 1;
-             while (--nregs > 0)
-               {
-                 regno += GET_MODE_SIZE (mode) / 4;
-                 reg = gen_rtx_REG (mode, regno);
-                 pos += GET_MODE_SIZE (mode);
-                 XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
-                   = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
-                 parms->nregs += 1;
-               }
-           }
-         else
-           {
-             if (parms->intoffset == -1)
-               parms->intoffset = bitpos;
-           }
-       }
+      assign_fp_registers (field, bitpos, data);
+    }
+  else
+    {
+      if (data->intoffset < 0)
+       data->intoffset = bitpos;
     }
 }
 
@@ -6602,52 +6574,33 @@ function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
     not be available.
    MODE is the argument's machine mode.
    SLOTNO is the index number of the argument's slot in the parameter array.
-   NAMED is nonzero if this argument is a named parameter
+   NAMED is true if this argument is a named parameter
     (otherwise it is an extra parameter matching an ellipsis).
    REGBASE is the regno of the base register for the parameter array.  */
 
 static rtx
 function_arg_record_value (const_tree type, machine_mode mode,
-                          int slotno, int named, int regbase)
+                          int slotno, bool named, int regbase)
 {
   HOST_WIDE_INT typesize = int_size_in_bytes (type);
-  struct function_arg_record_value_parms parms;
-  unsigned int nregs;
+  assign_data_t data;
+  int nregs;
 
-  parms.ret = NULL_RTX;
-  parms.slotno = slotno;
-  parms.named = named;
-  parms.regbase = regbase;
-  parms.stack = 0;
+  data.slotno = slotno;
+  data.regbase = regbase;
 
-  /* Compute how many registers we need.  */
-  parms.nregs = 0;
-  parms.intoffset = 0;
-  function_arg_record_value_1 (type, 0, &parms, false);
+  /* Count how many registers we need.  */
+  data.nregs = 0;
+  data.intoffset = 0;
+  data.stack = false;
+  traverse_record_type<assign_data_t, count_registers> (type, named, &data);
 
   /* Take into account pending integer fields.  */
-  if (parms.intoffset != -1)
-    {
-      unsigned int startbit, endbit;
-      int intslots, this_slotno;
-
-      startbit = ROUND_DOWN (parms.intoffset, BITS_PER_WORD);
-      endbit = ROUND_UP (typesize*BITS_PER_UNIT, BITS_PER_WORD);
-      intslots = (endbit - startbit) / BITS_PER_WORD;
-      this_slotno = slotno + parms.intoffset / BITS_PER_WORD;
-
-      if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
-        {
-         intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
-         /* We need to pass this field on the stack.  */
-         parms.stack = 1;
-        }
-
-      parms.nregs += intslots;
-    }
+  if (compute_int_layout (typesize * BITS_PER_UNIT, &data, &nregs))
+    data.nregs += nregs;
 
   /* Allocate the vector and handle some annoying special cases.  */
-  nregs = parms.nregs;
+  nregs = data.nregs;
 
   if (nregs == 0)
     {
@@ -6670,7 +6623,7 @@ function_arg_record_value (const_tree type, machine_mode mode,
 
   gcc_assert (nregs > 0);
 
-  parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs));
+  data.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (data.stack + nregs));
 
   /* If at least one field must be passed on the stack, generate
      (parallel [(expr_list (nil) ...) ...]) so that all fields will
@@ -6678,19 +6631,21 @@ function_arg_record_value (const_tree type, machine_mode mode,
      semantics of TARGET_ARG_PARTIAL_BYTES doesn't handle the case
      of structures for which the fields passed exclusively in registers
      are not at the beginning of the structure.  */
-  if (parms.stack)
-    XVECEXP (parms.ret, 0, 0)
+  if (data.stack)
+    XVECEXP (data.ret, 0, 0)
       = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
 
-  /* Fill in the entries.  */
-  parms.nregs = 0;
-  parms.intoffset = 0;
-  function_arg_record_value_2 (type, 0, &parms, false);
-  function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
+  /* Assign the registers.  */
+  data.nregs = 0;
+  data.intoffset = 0;
+  traverse_record_type<assign_data_t, assign_registers> (type, named, &data);
 
-  gcc_assert (parms.nregs == nregs);
+  /* Assign pending integer fields.  */
+  assign_int_registers (typesize * BITS_PER_UNIT, &data);
 
-  return parms.ret;
+  gcc_assert (data.nregs == nregs);
+
+  return data.ret;
 }
 
 /* Used by function_arg and sparc_function_value_1 to implement the conventions
@@ -6706,7 +6661,7 @@ static rtx
 function_arg_union_value (int size, machine_mode mode, int slotno,
                          int regno)
 {
-  int nwords = ROUND_ADVANCE (size), i;
+  int nwords = NWORDS_UP (size), i;
   rtx regs;
 
   /* See comment in previous function for empty structures.  */
@@ -6777,17 +6732,17 @@ function_arg_vector_value (int size, int regno)
 
 static rtx
 sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
-                     const_tree type, bool named, bool incoming_p)
+                     const_tree type, bool named, bool incoming)
 {
   const CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
 
-  int regbase = (incoming_p
+  int regbase = (incoming
                 ? SPARC_INCOMING_INT_ARG_FIRST
                 : SPARC_OUTGOING_INT_ARG_FIRST);
   int slotno, regno, padding;
   enum mode_class mclass = GET_MODE_CLASS (mode);
 
-  slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
+  slotno = function_arg_slotno (cum, mode, type, named, incoming,
                                &regno, &padding);
   if (slotno == -1)
     return 0;
@@ -6837,35 +6792,7 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
     {
       rtx reg = gen_rtx_REG (mode, regno);
       if (cum->prototype_p || cum->libcall_p)
-       {
-         /* "* 2" because fp reg numbers are recorded in 4 byte
-            quantities.  */
-#if 0
-         /* ??? This will cause the value to be passed in the fp reg and
-            in the stack.  When a prototype exists we want to pass the
-            value in the reg but reserve space on the stack.  That's an
-            optimization, and is deferred [for a bit].  */
-         if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2)
-           return gen_rtx_PARALLEL (mode,
-                           gen_rtvec (2,
-                                      gen_rtx_EXPR_LIST (VOIDmode,
-                                               NULL_RTX, const0_rtx),
-                                      gen_rtx_EXPR_LIST (VOIDmode,
-                                               reg, const0_rtx)));
-         else
-#else
-         /* ??? It seems that passing back a register even when past
-            the area declared by REG_PARM_STACK_SPACE will allocate
-            space appropriately, and will not copy the data onto the
-            stack, exactly as we desire.
-
-            This is due to locate_and_pad_parm being called in
-            expand_call whenever reg_parm_stack_space > 0, which
-            while beneficial to our example here, would seem to be
-            in error from what had been intended.  Ho hum...  -- r~ */
-#endif
-           return reg;
-       }
+       return reg;
       else
        {
          rtx v0, v1;
@@ -6877,7 +6804,7 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
              /* On incoming, we don't need to know that the value
                 is passed in %f0 and %i0, and it confuses other parts
                 causing needless spillage even on the simplest cases.  */
-             if (incoming_p)
+             if (incoming)
                return reg;
 
              intreg = (SPARC_OUTGOING_INT_ARG_FIRST
@@ -6956,7 +6883,7 @@ sparc_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
 {
   int slotno, regno, padding;
 
-  /* We pass false for incoming_p here, it doesn't matter.  */
+  /* We pass false for incoming here, it doesn't matter.  */
   slotno = function_arg_slotno (get_cumulative_args (cum), mode, type, named,
                                false, &regno, &padding);
 
@@ -6966,8 +6893,8 @@ sparc_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
   if (TARGET_ARCH32)
     {
       if ((slotno + (mode == BLKmode
-                    ? ROUND_ADVANCE (int_size_in_bytes (type))
-                    : ROUND_ADVANCE (GET_MODE_SIZE (mode))))
+                    ? NWORDS_UP (int_size_in_bytes (type))
+                    : NWORDS_UP (GET_MODE_SIZE (mode))))
          > SPARC_INT_ARG_MAX)
        return (SPARC_INT_ARG_MAX - slotno) * UNITS_PER_WORD;
     }
@@ -6982,7 +6909,8 @@ sparc_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
          int size = int_size_in_bytes (type);
 
          if (size > UNITS_PER_WORD
-             && slotno == SPARC_INT_ARG_MAX - 1)
+             && (slotno == SPARC_INT_ARG_MAX - 1
+                 || slotno == SPARC_FP_ARG_MAX - 1))
            return UNITS_PER_WORD;
        }
       else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
@@ -7068,18 +6996,16 @@ sparc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
   int regno, padding;
 
-  /* We pass false for incoming_p here, it doesn't matter.  */
+  /* We pass false for incoming here, it doesn't matter.  */
   function_arg_slotno (cum, mode, type, named, false, &regno, &padding);
 
   /* If argument requires leading padding, add it.  */
   cum->words += padding;
 
   if (TARGET_ARCH32)
-    {
-      cum->words += (mode != BLKmode
-                    ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
-                    : ROUND_ADVANCE (int_size_in_bytes (type)));
-    }
+    cum->words += (mode == BLKmode
+                  ? NWORDS_UP (int_size_in_bytes (type))
+                  : NWORDS_UP (GET_MODE_SIZE (mode)));
   else
     {
       if (type && AGGREGATE_TYPE_P (type))
@@ -7094,11 +7020,9 @@ sparc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
            ++cum->words;
        }
       else
-       {
-         cum->words += (mode != BLKmode
-                        ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
-                        : ROUND_ADVANCE (int_size_in_bytes (type)));
-       }
+       cum->words += (mode == BLKmode
+                      ? NWORDS_UP (int_size_in_bytes (type))
+                      : NWORDS_UP (GET_MODE_SIZE (mode)));
     }
 }
 
@@ -7109,7 +7033,7 @@ sparc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
 enum direction
 function_arg_padding (machine_mode mode, const_tree type)
 {
-  if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
+  if (TARGET_ARCH64 && type && AGGREGATE_TYPE_P (type))
     return upward;
 
   /* Fall back to the default.  */
index 4e85314e00bcf1a61088a6d7d417f189e9a21c65..e5ec39c67f7b9d56c8c9c162d62f834062e263f3 100644 (file)
@@ -1,3 +1,7 @@
+2016-02-29  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc.target/sparc/20160229-1.c: New test.
+
 2016-02-29  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gnat.dg/stack_usage3.adb: New test.
diff --git a/gcc/testsuite/gcc.target/sparc/20160229-1.c b/gcc/testsuite/gcc.target/sparc/20160229-1.c
new file mode 100644 (file)
index 0000000..c64b7a8
--- /dev/null
@@ -0,0 +1,157 @@
+/* PR target/69706 */
+/* Reported by John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> */
+
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" }
+/* { dg-require-effective-target lp64 } */
+
+extern void abort (void);
+
+
+/* Pass a 12-byte structure partially in slot #15 and on the stack.  */
+
+struct t_rgb { float r, g, b; };
+
+void write_xpm (void *out, unsigned int flags, const char *title, 
+               const char *legend, const char *label_x, const char *label_y,
+               int n_x, int n_y, float axis_x[], float axis_y[], float *mat[],
+               float lo, float hi, struct t_rgb rlo, struct t_rgb rhi)
+{
+  register float f30 asm ("f30");
+  register float f31 asm ("f31");
+
+  if (f30 != 1.0f)
+    abort ();
+
+  if (f31 != 2.0f)
+    abort ();
+
+  if (rhi.r != 1.0f)
+    abort ();
+
+  if (rhi.g != 2.0f)
+    abort ();
+
+  if (rhi.b != 3.0f)
+    abort ();
+}
+
+
+/* Pass a 16-byte structure partially in slot #15 and on the stack.  */
+
+struct S1 { _Complex float f1; _Complex float f2; };
+
+void f1 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+        int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+        struct S1 s1)
+{
+  register float f30 asm ("f30");
+  register float f31 asm ("f31");
+
+  if (f30 != 4.0f)
+    abort ();
+
+  if (f31 != 5.0f)
+    abort ();
+
+  if (__real__ s1.f1 != 4.0f)
+    abort ();
+
+  if (__imag__ s1.f1 != 5.0f)
+    abort ();
+
+  if (__real__ s1.f2 != 6.0f)
+    abort ();
+
+  if (__imag__ s1.f2 != 7.0f)
+    abort ();
+}
+
+
+/* Pass a 16-byte structure partially in slot #15 and on the stack.  */
+
+struct S2 { double d1; double d2; };
+
+void f2 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+        int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+        struct S2 s2)
+{
+  register double d30 asm ("f30");
+
+  if (d30 != 1.0)
+    abort ();
+
+  if (s2.d1 != 1.0)
+    abort ();
+
+  if (s2.d2 != 2.0)
+    abort ();
+}
+
+
+/* Pass a 16-byte structure partially in slot #15 and on the stack.  */
+
+struct S3 { _Complex double d; };
+
+void f3 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+        int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+        struct S3 s3)
+{
+  register double d30 asm ("f30");
+
+  if (d30 != 3.0)
+    abort ();
+
+  if (__real__ s3.d != 3.0)
+    abort ();
+
+  if (__imag__ s3.d != 4.0)
+    abort ();
+}
+
+
+/* Pass a 16-byte structure entirely on the stack.  */
+
+struct S4 { long l; double d; };
+
+void f4 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+        int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+        struct S4 s4)
+{
+  if (s4.l != 5)
+    abort ();
+
+  if (s4.d != 6.0)
+    abort ();
+}
+
+
+#define PI 3.141592654
+
+int main (void)
+{
+  struct t_rgb lo = { -1.0f, -2.0f, -3.0f };
+  struct t_rgb hi = { 1.0f, 2.0f, 3.0f };
+  float arrf[1];
+  float *arrp[1];
+  struct S1 s1 = { 4.0f + 5.0fi, 6.0f + 7.0fi };
+  struct S2 s2 = { 1.0, 2.0 };
+  struct S3 s3 = { 3.0 + 4.0i };
+  struct S4 s4 = { 5, 6.0 };
+  register double d32 asm ("f32") = PI;
+
+  write_xpm (0, 0, "", "", "", "", 0, 0, arrf, arrf, arrp, 0.0f, 0.0f, lo, hi);
+
+  f1 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s1);
+
+  f2 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s2);
+
+  f3 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s3);
+
+  f4 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s4);
+
+  if (d32 != PI)
+    abort ();
+
+  return 0;
+}