public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [SPARC] Fix PR target/69706
@ 2016-02-29 10:21 Eric Botcazou
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Botcazou @ 2016-02-29 10:21 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2805 bytes --]

This is both an ICE and an ABI bug dating back to the implementation of the 
64-bit calling conventions in 1998: for structures larger than 8 bytes and not 
larger than 16 bytes containing a FP field in the second half and passed in 
slot #15 of the parameter array, the compiler passes the FP field in the %f32 
register instead of on the stack; this results in an ICE for a 'float' and an 
ABI bug for a 'double'.

The attached fix implements the detection and the handling of this case and 
shouldn't change anything in the other cases; however, since the existing code 
was suffering from excessive duplication (structure traversal was implemented 
3 times, handling of FP fields twice and handling of integer fields 3 times), 
the code refactors the whole thing and in particular uses a function template 
for the traversal, which is then instantiated 3 times.

Bootstrapped/regtested on SPARC64/Solaris and also compat-regtested (both bugs 
are rare enough as to go unnoticed by the compat testsuite).  I also verified 
manually that GCC is now compatible with Sun CC in this case too.

I'll document the ABI change in changes.html separately.


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  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc.target/sparc/20160229-1.c: New test.

-- 
Eric Botcazou

[-- Attachment #2: 20160229-1.c --]
[-- Type: text/x-csrc, Size: 3301 bytes --]

/* 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;
}

[-- Attachment #3: pr69706-3.diff --]
[-- Type: text/x-patch, Size: 32462 bytes --]

Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 233556)
+++ config/sparc/sparc.c	(working copy)
@@ -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,9 +6085,9 @@ conventions.  */
 #define SPARC_INT_ARG_MAX 6
 /* Maximum number of fp regs for args.  */
 #define SPARC_FP_ARG_MAX 16
+/* Number of words (partially) occupied for a given size in units.  */
+#define NWORDS_UP(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
 
-#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
-
 /* Handle the INIT_CUMULATIVE_ARGS macro.
    Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
@@ -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
   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 @@ static void
     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,
     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,
 
     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,
 
       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;
+	  /* If all arg slots are filled, then must pass on stack.  */
+	  if (slotno >= SPARC_FP_ARG_MAX)
+	    return -1;
 
-	  /* 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);
+	  if (TREE_CODE (type) == RECORD_TYPE)
+	    {
+	      classify_data_t data = { false, false, false };
+	      traverse_record_type<classify_data_t, classify_registers>
+		(type, named, &data);
 
-	  /* 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 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 all arg slots are filled, then must pass on stack.  */
-	  if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
-	    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;
+	    }
 
-	  /* 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;
-
-	  /* 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,159 +6356,140 @@ function_arg_slotno (const struct sparc_args *cum,
   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.  */
-};
+  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;
 
-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);
+/* 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.  */
 
-/* A subroutine of function_arg_record_value.  Traverse the structure
-   recursively and determine how many registers will be required.  */
-
-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.  */
+  *pnregs = nregs;
+  return true;
+}
 
-	  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;
+/* 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.  */
 
-		  startbit = ROUND_DOWN (parms->intoffset, BITS_PER_WORD);
-		  endbit   = ROUND_UP (bitpos, 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;
 
-		  intslots = (endbit - startbit) / BITS_PER_WORD;
-		  this_slotno = parms->slotno + parms->intoffset
-		    / BITS_PER_WORD;
+  /* 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;
 
-		  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;
-		    }
+  nslots = NWORDS_UP (nregs * GET_MODE_SIZE (mode));
 
-		  parms->nregs += intslots;
-		  parms->intoffset = -1;
-		}
+  if (nslots > SPARC_FP_ARG_MAX - this_slotno)
+    {
+      nslots = SPARC_FP_ARG_MAX - this_slotno;
+      nregs = (nslots * UNITS_PER_WORD) / 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;
-	    }
-	}
+      /* 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.  Count the number of registers
+   to be assigned for FIELD and between PARMS->intoffset and BITPOS.  */
+
+inline void
+count_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
+		 assign_data_t *data)
+{
+  if (fp)
+    {
+      int nregs;
+      machine_mode mode;
+
+      if (compute_int_layout (bitpos, data, &nregs))
+	data->nregs += nregs;
+
+      if (compute_fp_layout (field, bitpos, data, &nregs, &mode))
+	data->nregs += nregs;
+    }
+  else
+    {
+      if (data->intoffset < 0)
+	data->intoffset = bitpos;
+    }
+}
+
 /* A subroutine of function_arg_record_value.  Assign the bits of the
-   structure between parms->intoffset and bitpos to integer registers.  */
+   structure between PARMS->intoffset and BITPOS to integer registers.  */
 
 static void
-function_arg_record_value_3 (HOST_WIDE_INT bitpos,
-			     struct function_arg_record_value_parms *parms)
+assign_int_registers (HOST_WIDE_INT bitpos, assign_data_t *data)
 {
+  int intoffset = data->intoffset;
   machine_mode mode;
-  unsigned int regno;
-  unsigned int startbit, endbit;
-  int this_slotno, intslots, intoffset;
-  rtx reg;
+  int nregs;
 
-  if (parms->intoffset == -1)
+  if (!compute_int_layout (bitpos, data, &nregs))
     return;
 
-  intoffset = parms->intoffset;
-  parms->intoffset = -1;
-
-  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;
-
-  intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
-  if (intslots <= 0)
-    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);
@@ -6477,119 +6496,72 @@ static void
   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;
 
-  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+  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;
+
+  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;
+    }
 }
 
 /* Used by function_arg and sparc_function_value_1 to implement the complex
@@ -6602,52 +6574,33 @@ static void
     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;
+  if (compute_int_layout (typesize * BITS_PER_UNIT, &data, &nregs))
+    data.nregs += nregs;
 
-      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;
-    }
-
   /* 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, machin
 
   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, machin
      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, mac
     {
       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, mac
 	      /* 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, ma
 {
   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, ma
   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, ma
 	  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,7 +6996,7 @@ sparc_function_arg_advance (cumulative_args_t cum_
   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.  */
@@ -7075,11 +7003,9 @@ sparc_function_arg_advance (cumulative_args_t cum_
   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_
 	    ++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_
 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.  */

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [SPARC] Fix PR target/69706
  2016-02-29 11:17 Uros Bizjak
@ 2016-03-01  0:22 ` Eric Botcazou
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Botcazou @ 2016-03-01  0:22 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 623 bytes --]

> +/* Number of words (partially) occupied for a given size in units.  */
> +#define NWORDS_UP(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
> 
> -#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) /
> UNITS_PER_WORD)
> 
> You can use CEIL macro from system.h here.

Good idea, thanks, applied on the mainline.


	PR target/69706
	* config/sparc/sparc.c (NWORDS_UP): Rename to...
	(CEIL_NWORDS): ...this.  Use CEIL macro.
	(compute_fp_layout): Adjust to above renaming.
	(function_arg_union_value): Likewise.
	(sparc_arg_partial_bytes): Likewise.
	(sparc_function_arg_advance): Likewise.

-- 
Eric Botcazou

[-- Attachment #2: p.diff --]
[-- Type: text/x-patch, Size: 2213 bytes --]

Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 233808)
+++ config/sparc/sparc.c	(working copy)
@@ -6086,7 +6086,7 @@ conventions.  */
 /* Maximum number of fp regs for args.  */
 #define SPARC_FP_ARG_MAX 16
 /* Number of words (partially) occupied for a given size in units.  */
-#define NWORDS_UP(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+#define CEIL_NWORDS(SIZE) CEIL((SIZE), UNITS_PER_WORD)
 
 /* Handle the INIT_CUMULATIVE_ARGS macro.
    Initialize a variable CUM of type CUMULATIVE_ARGS
@@ -6429,7 +6429,7 @@ compute_fp_layout (const_tree field, HOS
   else
     nregs = 1;
 
-  nslots = NWORDS_UP (nregs * GET_MODE_SIZE (mode));
+  nslots = CEIL_NWORDS (nregs * GET_MODE_SIZE (mode));
 
   if (nslots > SPARC_FP_ARG_MAX - this_slotno)
     {
@@ -6661,7 +6661,7 @@ static rtx
 function_arg_union_value (int size, machine_mode mode, int slotno,
 			  int regno)
 {
-  int nwords = NWORDS_UP (size), i;
+  int nwords = CEIL_NWORDS (size), i;
   rtx regs;
 
   /* See comment in previous function for empty structures.  */
@@ -6893,8 +6893,8 @@ sparc_arg_partial_bytes (cumulative_args
   if (TARGET_ARCH32)
     {
       if ((slotno + (mode == BLKmode
-		     ? NWORDS_UP (int_size_in_bytes (type))
-		     : NWORDS_UP (GET_MODE_SIZE (mode))))
+		     ? CEIL_NWORDS (int_size_in_bytes (type))
+		     : CEIL_NWORDS (GET_MODE_SIZE (mode))))
 	  > SPARC_INT_ARG_MAX)
 	return (SPARC_INT_ARG_MAX - slotno) * UNITS_PER_WORD;
     }
@@ -7004,8 +7004,8 @@ sparc_function_arg_advance (cumulative_a
 
   if (TARGET_ARCH32)
     cum->words += (mode == BLKmode
-		   ? NWORDS_UP (int_size_in_bytes (type))
-		   : NWORDS_UP (GET_MODE_SIZE (mode)));
+		   ? CEIL_NWORDS (int_size_in_bytes (type))
+		   : CEIL_NWORDS (GET_MODE_SIZE (mode)));
   else
     {
       if (type && AGGREGATE_TYPE_P (type))
@@ -7021,8 +7021,8 @@ sparc_function_arg_advance (cumulative_a
 	}
       else
 	cum->words += (mode == BLKmode
-		       ? NWORDS_UP (int_size_in_bytes (type))
-		       : NWORDS_UP (GET_MODE_SIZE (mode)));
+		       ? CEIL_NWORDS (int_size_in_bytes (type))
+		       : CEIL_NWORDS (GET_MODE_SIZE (mode)));
     }
 }
 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [SPARC] Fix PR target/69706
@ 2016-02-29 11:17 Uros Bizjak
  2016-03-01  0:22 ` Eric Botcazou
  0 siblings, 1 reply; 3+ messages in thread
From: Uros Bizjak @ 2016-02-29 11:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Eric Botcazou

Hello!

> This is both an ICE and an ABI bug dating back to the implementation of the
> 64-bit calling conventions in 1998: for structures larger than 8 bytes and not
> larger than 16 bytes containing a FP field in the second half and passed in
> slot #15 of the parameter array, the compiler passes the FP field in the %f32
> register instead of on the stack; this results in an ICE for a 'float' and an
> ABI bug for a 'double'.

...

+/* Number of words (partially) occupied for a given size in units.  */
+#define NWORDS_UP(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)

-#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)

You can use CEIL macro from system.h here.

Uros.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-03-01  0:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-29 10:21 [SPARC] Fix PR target/69706 Eric Botcazou
2016-02-29 11:17 Uros Bizjak
2016-03-01  0:22 ` Eric Botcazou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).