This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

S/390: Fix ABI problem


Hello,

this fixes a long-standing ABI problem detected by the new compat tests.
The problem is caused by a special case in the s390 ABI: a struct that
holds exactly one floating point member is supposed to be passed in a
floating-point register.  This worked fine for regular functions, but
was not implemented correctly for variable-argument lists.

Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux.
Fixes the gcc.dg/compat/struct-by-value-5 test case.
Committed to CVS head.

Bye,
Ulrich

ChangeLog:

	* config/s390/s390.c (s390_function_arg_float): New function.
	(s390_function_arg_pass_by_reference): Use it.
	(s390_function_arg_advance): Likewise.
	(s390_function_arg): Likewise.
	(s390_va_arg): Likewise


Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.90
diff -c -p -r1.90 s390.c
*** gcc/config/s390/s390.c	23 Apr 2003 17:13:11 -0000	1.90
--- gcc/config/s390/s390.c	11 May 2003 15:06:58 -0000
*************** static rtx restore_fpr PARAMS ((rtx, int
*** 211,216 ****
--- 211,217 ----
  static rtx save_gprs PARAMS ((rtx, int, int, int));
  static rtx restore_gprs PARAMS ((rtx, int, int, int));
  static int s390_function_arg_size PARAMS ((enum machine_mode, tree));
+ static bool s390_function_arg_float PARAMS ((enum machine_mode, tree));
  static struct machine_function * s390_init_machine_status PARAMS ((void));
   
  /* Return true if SET either doesn't set the CC register, or else
*************** s390_function_arg_size (mode, type)
*** 5699,5704 ****
--- 5700,5747 ----
    abort ();
  }
  
+ /* Return true if a function argument of type TYPE and mode MODE
+    is to be passed in a floating-point register, if available.  */
+ 
+ static bool
+ s390_function_arg_float (mode, type)
+      enum machine_mode mode;
+      tree type;
+ {
+   /* Soft-float changes the ABI: no floating-point registers are used.  */
+   if (TARGET_SOFT_FLOAT)
+     return false;
+ 
+   /* No type info available for some library calls ...  */
+   if (!type)
+     return mode == SFmode || mode == DFmode;
+ 
+   /* The ABI says that record types with a single member are treated
+      just like that member would be.  */
+   while (TREE_CODE (type) == RECORD_TYPE)
+     {
+       tree field, single = NULL_TREE;
+ 
+       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ 	{
+ 	  if (TREE_CODE (field) != FIELD_DECL)
+ 	    continue;
+ 
+ 	  if (single == NULL_TREE)
+ 	    single = TREE_TYPE (field);
+ 	  else
+ 	    return false;
+ 	}
+ 
+       if (single == NULL_TREE)
+ 	return false;
+       else
+ 	type = single;
+     }
+ 
+   return TREE_CODE (type) == REAL_TYPE;
+ }
+ 
  /* Return 1 if a function argument of type TYPE and mode MODE
     is to be passed by reference.  The ABI specifies that only
     structures of size 1, 2, 4, or 8 bytes are passed by value,
*************** s390_function_arg_pass_by_reference (mod
*** 5715,5728 ****
    if (type)
      {
        if (AGGREGATE_TYPE_P (type) &&
!           size != 1 && size != 2 && size != 4 && size != 8)
          return 1;
  
        if (TREE_CODE (type) == COMPLEX_TYPE)
          return 1;
      }
    return 0;
- 
  }
  
  /* Update the data in CUM to advance over an argument of mode MODE and
--- 5758,5772 ----
    if (type)
      {
        if (AGGREGATE_TYPE_P (type) &&
!           size != 1 && size != 2 && size != 4 && size != 8
! 	  && !s390_function_arg_float (mode, type))
          return 1;
  
        if (TREE_CODE (type) == COMPLEX_TYPE)
          return 1;
      }
+     
    return 0;
  }
  
  /* Update the data in CUM to advance over an argument of mode MODE and
*************** s390_function_arg_advance (cum, mode, ty
*** 5738,5750 ****
       tree type;
       int named ATTRIBUTE_UNUSED;
  {
!   if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode))
      {
!       cum->fprs++;
      }
!   else if (s390_function_arg_pass_by_reference (mode, type))
      {
!       cum->gprs += 1;
      }
    else
      {
--- 5782,5794 ----
       tree type;
       int named ATTRIBUTE_UNUSED;
  {
!   if (s390_function_arg_pass_by_reference (mode, type))
      {
!       cum->gprs += 1;
      }
!   else if (s390_function_arg_float (mode, type))
      {
!       cum->fprs += 1;
      }
    else
      {
*************** s390_function_arg (cum, mode, type, name
*** 5782,5788 ****
    if (s390_function_arg_pass_by_reference (mode, type))
        return 0;
  
!   if (! TARGET_SOFT_FLOAT && (mode == DFmode || mode == SFmode))
      {
        if (cum->fprs + 1 > (TARGET_64BIT? 4 : 2))
  	return 0;
--- 5826,5832 ----
    if (s390_function_arg_pass_by_reference (mode, type))
        return 0;
  
!   if (s390_function_arg_float (mode, type))
      {
        if (cum->fprs + 1 > (TARGET_64BIT? 4 : 2))
  	return 0;
*************** s390_va_arg (valist, type)
*** 5996,6002 ****
        size = UNITS_PER_WORD;
        max_reg = 4;
      }
!   else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT)
      {
        if (TARGET_DEBUG_ARG)
  	{
--- 6040,6046 ----
        size = UNITS_PER_WORD;
        max_reg = 4;
      }
!   else if (s390_function_arg_float (TYPE_MODE (type), type))
      {
        if (TARGET_DEBUG_ARG)
  	{
-- 
  Dr. Ulrich Weigand
  weigand@informatik.uni-erlangen.de


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]