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 corner cases


Hello,

this fixes an ABI problem with recently introduced data types:
vector types and integer types > 8 bytes.  These were erroneously
treated as being passed in registers (requiring more than two
consecutive registers in some cases!).

The patch fixes this by making all vector types and all types of
size > 8 bytes to be passed and returned in memory always.  It
also adds sanity checks to make sure newly added types not yet
handled by the backend will always abort instead of silently falling 
through to some default case.

This patch does cause an incompatible ABI change, strictly
speaking, but only for data types that nobody should be using
up to now (and if they did, it would most likely fail anyway).

Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux,
committed to CVS head.  I'll be committing a stripped-down
version of the patch to 3.3 shortly.

Bye,
Ulrich

ChangeLog:

	* config/s390/s390-protos.h (s390_function_value): Declare.
	* config/s390/s390.c (TARGET_RETURN_IN_MEMORY): Define.
	(s390_return_in_memory): New function.
	(s390_function_value): New function.
	(s390_function_arg_float): Return false for all arguments larger
	than 8 bytes.
	(s390_function_arg_pass_by_reference): Likewise.  Return true for
	all vector arguments.
	(s390_function_arg_integer): New function.
	(s390_function_arg_advance): Call it.  Add sanity checks.
	(s390_function_arg): Likewise.
	* config/s390/s390.h (FUNCTION_VALUE): Call s390_function_value.
	(LIBCALL_VALUE): Likewise.
	(RET_REG): Remove.
	(RETURN_IN_MEMORY): Remove.



Index: gcc/config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.39
diff -c -p -r1.39 s390-protos.h
*** gcc/config/s390/s390-protos.h	30 Oct 2003 02:02:46 -0000	1.39
--- gcc/config/s390/s390-protos.h	6 Nov 2003 21:20:18 -0000
*************** extern void s390_function_arg_advance (C
*** 99,104 ****
--- 99,105 ----
  				       tree, int);
  #ifdef RTX_CODE
  extern rtx s390_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+ extern rtx s390_function_value (tree, enum machine_mode);
  extern void s390_va_start (tree, rtx);
  extern rtx s390_va_arg (tree, tree);
  #endif /* RTX_CODE */
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.121
diff -c -p -r1.121 s390.c
*** gcc/config/s390/s390.c	2 Nov 2003 09:34:54 -0000	1.121
--- gcc/config/s390/s390.c	6 Nov 2003 21:20:23 -0000
*************** static void s390_select_rtx_section (enu
*** 60,65 ****
--- 60,66 ----
  static void s390_encode_section_info (tree, rtx, int);
  static bool s390_cannot_force_const_mem (rtx);
  static rtx s390_delegitimize_address (rtx);
+ static bool s390_return_in_memory (tree, tree);
  static void s390_init_builtins (void);
  static rtx s390_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
  static void s390_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
*************** static tree s390_build_builtin_va_list (
*** 107,112 ****
--- 108,116 ----
  #undef TARGET_DELEGITIMIZE_ADDRESS
  #define TARGET_DELEGITIMIZE_ADDRESS s390_delegitimize_address
  
+ #undef TARGET_RETURN_IN_MEMORY
+ #define TARGET_RETURN_IN_MEMORY s390_return_in_memory
+ 
  #undef  TARGET_INIT_BUILTINS
  #define TARGET_INIT_BUILTINS s390_init_builtins
  #undef  TARGET_EXPAND_BUILTIN
*************** s390_function_arg_size (enum machine_mod
*** 6009,6014 ****
--- 6013,6022 ----
  static bool
  s390_function_arg_float (enum machine_mode mode, tree type)
  {
+   int size = s390_function_arg_size (mode, type);
+   if (size > 8)
+     return false;
+ 
    /* Soft-float changes the ABI: no floating-point registers are used.  */
    if (TARGET_SOFT_FLOAT)
      return false;
*************** s390_function_arg_float (enum machine_mo
*** 6043,6048 ****
--- 6051,6089 ----
    return TREE_CODE (type) == REAL_TYPE;
  }
  
+ /* Return true if a function argument of type TYPE and mode MODE
+    is to be passed in an integer register, or a pair of integer
+    registers, if available.  */
+ 
+ static bool
+ s390_function_arg_integer (enum machine_mode mode, tree type)
+ {
+   int size = s390_function_arg_size (mode, type);
+   if (size > 8)
+     return false;
+ 
+   /* No type info available for some library calls ...  */
+   if (!type)
+     return GET_MODE_CLASS (mode) == MODE_INT
+ 	   || (TARGET_SOFT_FLOAT &&  GET_MODE_CLASS (mode) == MODE_FLOAT);
+ 
+   /* We accept small integral (and similar) types.  */
+   if (INTEGRAL_TYPE_P (type)
+       || POINTER_TYPE_P (type) 
+       || TREE_CODE (type) == OFFSET_TYPE
+       || (TARGET_SOFT_FLOAT && TREE_CODE (type) == REAL_TYPE))
+     return true;
+ 
+   /* We also accept structs of size 1, 2, 4, 8 that are not
+      passed in floating-point registers.  */  
+   if (AGGREGATE_TYPE_P (type)
+       && exact_log2 (size) >= 0
+       && !s390_function_arg_float (mode, type))
+     return true;
+ 
+   return false;
+ }
+ 
  /* 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,
*************** int
*** 6053,6067 ****
  s390_function_arg_pass_by_reference (enum machine_mode mode, tree type)
  {
    int size = s390_function_arg_size (mode, type);
  
    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;
      }
  
--- 6094,6109 ----
  s390_function_arg_pass_by_reference (enum machine_mode mode, tree type)
  {
    int size = s390_function_arg_size (mode, type);
+   if (size > 8)
+     return true;
  
    if (type)
      {
!       if (AGGREGATE_TYPE_P (type) && exact_log2 (size) < 0)
          return 1;
  
!       if (TREE_CODE (type) == COMPLEX_TYPE
! 	  || TREE_CODE (type) == VECTOR_TYPE)
          return 1;
      }
  
*************** s390_function_arg_advance (CUMULATIVE_AR
*** 6086,6096 ****
      {
        cum->fprs += 1;
      }
!   else
      {
        int size = s390_function_arg_size (mode, type);
        cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
      }
  }
  
  /* Define where to put the arguments to a function.
--- 6128,6140 ----
      {
        cum->fprs += 1;
      }
!   else if (s390_function_arg_integer (mode, type))
      {
        int size = s390_function_arg_size (mode, type);
        cum->gprs += ((size + UNITS_PER_WORD-1) / UNITS_PER_WORD);
      }
+   else
+     abort ();
  }
  
  /* Define where to put the arguments to a function.
*************** s390_function_arg (CUMULATIVE_ARGS *cum,
*** 6126,6132 ****
        else
  	return gen_rtx (REG, mode, cum->fprs + 16);
      }
!   else
      {
        int size = s390_function_arg_size (mode, type);
        int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD;
--- 6170,6176 ----
        else
  	return gen_rtx (REG, mode, cum->fprs + 16);
      }
!   else if (s390_function_arg_integer (mode, type))
      {
        int size = s390_function_arg_size (mode, type);
        int n_gprs = (size + UNITS_PER_WORD-1) / UNITS_PER_WORD;
*************** s390_function_arg (CUMULATIVE_ARGS *cum,
*** 6136,6141 ****
--- 6180,6247 ----
        else
  	return gen_rtx (REG, mode, cum->gprs + 2);
      }
+ 
+   /* After the real arguments, expand_call calls us once again
+      with a void_type_node type.  Whatever we return here is
+      passed as operand 2 to the call expanders.
+ 
+      We don't need this feature ...  */
+   else if (type == void_type_node)
+     return const0_rtx;
+ 
+   abort ();
+ }
+ 
+ /* Return true if return values of type TYPE should be returned
+    in a memory buffer whose address is passed by the caller as
+    hidden first argument.  */
+ 
+ static bool
+ s390_return_in_memory (tree type, tree fundecl ATTRIBUTE_UNUSED)
+ {
+   /* We accept small integral (and similar) types.  */
+   if (INTEGRAL_TYPE_P (type)
+       || POINTER_TYPE_P (type) 
+       || TREE_CODE (type) == OFFSET_TYPE
+       || TREE_CODE (type) == REAL_TYPE)
+     return int_size_in_bytes (type) > 8;
+ 
+   /* Aggregates and similar constructs are always returned
+      in memory.  */
+   if (AGGREGATE_TYPE_P (type)
+       || TREE_CODE (type) == COMPLEX_TYPE
+       || TREE_CODE (type) == VECTOR_TYPE)
+     return true;
+ 
+   /* ??? We get called on all sorts of random stuff from
+      aggregate_value_p.  We can't abort, but it's not clear
+      what's safe to return.  Pretend it's a struct I guess.  */
+   return true;
+ }
+ 
+ /* Define where to return a (scalar) value of type TYPE.
+    If TYPE is null, define where to return a (scalar)
+    value of mode MODE from a libcall.  */
+ 
+ rtx
+ s390_function_value (tree type, enum machine_mode mode)
+ {
+   if (type)
+     {
+       int unsignedp = TREE_UNSIGNED (type);
+       mode = promote_mode (type, TYPE_MODE (type), &unsignedp, 1);
+     }
+ 
+   if (GET_MODE_CLASS (mode) != MODE_INT 
+       && GET_MODE_CLASS (mode) != MODE_FLOAT)
+     abort ();
+   if (GET_MODE_SIZE (mode) > 8)
+     abort ();
+ 
+   if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+     return gen_rtx_REG (mode, 16);
+   else
+     return gen_rtx_REG (mode, 2);
  }
  
  
Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.90
diff -c -p -r1.90 s390.h
*** gcc/config/s390/s390.h	30 Oct 2003 14:11:34 -0000	1.90
--- gcc/config/s390/s390.h	6 Nov 2003 21:20:24 -0000
*************** CUMULATIVE_ARGS;
*** 707,739 ****
  
  /* Scalar return values.  */
  
! /* We return scalars in general purpose register 2 for integral values,
!    and floating point register 0 for fp values.  */
! #define FUNCTION_VALUE(VALTYPE, FUNC)				\
!   gen_rtx_REG ((INTEGRAL_TYPE_P (VALTYPE)			\
! 		&& TYPE_PRECISION (VALTYPE) < BITS_PER_WORD)	\
! 	       || POINTER_TYPE_P (VALTYPE)			\
! 	       ? word_mode : TYPE_MODE (VALTYPE),		\
! 	       TREE_CODE (VALTYPE) == REAL_TYPE && TARGET_HARD_FLOAT ? 16 : 2)
  
! /* Define how to find the value returned by a library function assuming
!    the value has mode MODE.  */
! #define RET_REG(MODE) ((GET_MODE_CLASS (MODE) == MODE_INT       \
!                        || TARGET_SOFT_FLOAT ) ? 2 : 16)
! #define LIBCALL_VALUE(MODE)  gen_rtx (REG, MODE, RET_REG (MODE))
  
  /* Only gpr 2 and fpr 0 are ever used as return registers.  */
  #define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16)
- 
- 
- /* Aggregate return values.  */
- 
- /* The definition of this macro implies that there are cases where
-    a scalar value cannot be returned in registers.  */
- #define RETURN_IN_MEMORY(type)       				\
-   (TYPE_MODE (type) == BLKmode || 				\
-    GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_INT  ||	\
-    GET_MODE_CLASS (TYPE_MODE (type)) == MODE_COMPLEX_FLOAT)
  
  /* Structure value address is passed as invisible first argument (gpr 2).  */
  #define STRUCT_VALUE 0
--- 707,720 ----
  
  /* Scalar return values.  */
  
! #define FUNCTION_VALUE(VALTYPE, FUNC) \
!   s390_function_value ((VALTYPE), VOIDmode)
  
! #define LIBCALL_VALUE(MODE) \
!   s390_function_value (NULL, (MODE))
  
  /* Only gpr 2 and fpr 0 are ever used as return registers.  */
  #define FUNCTION_VALUE_REGNO_P(N) ((N) == 2 || (N) == 16)
  
  /* Structure value address is passed as invisible first argument (gpr 2).  */
  #define STRUCT_VALUE 0
-- 
  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]