x86-64 abi, regarding vector types

Richard Henderson rth@redhat.com
Sun Dec 19 08:23:00 GMT 2004


This is the patch that I'm thinking about using for 4.0.

Notice that, between type_mode_for_classify and classify_argument,
all ABI selection for vectors is done by looking at the type node,
and not the mode.

It is my considered opinion that every gcc port that attempts to
handle vectors by looking at the mode is broken.  I think this is
a serious problem and we should not make the release until this
is addressed.


r~


        * config/i386/i386.c (type_mode_for_classify): Rename from
        type_natural_mode.  Forward length 1 vectors to the subtype.
        Assert vectors of size < 8 have the correct scalar integral mode.
        (classify_argument): Test for 16 byte upper bound eariler.
        Use type_mode_for_classify.  Handle vectors explcitly, rather
        than falling back on mode.

Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.756
diff -c -p -d -r1.756 i386.c
*** config/i386/i386.c	17 Dec 2004 21:40:37 -0000	1.756
--- config/i386/i386.c	19 Dec 2004 07:54:14 -0000
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2035,2042 ****
    return;
  }
  
! /* Return the "natural" mode for TYPE.  In most cases, this is just TYPE_MODE.
!    But in the case of vector types, it is some vector mode.
  
     When we have only some of our vector isa extensions enabled, then there
     are some modes for which vector_mode_supported_p is false.  For these
--- 2035,2043 ----
    return;
  }
  
! /* Return the mode for TYPE to use for purposes of the ABI.  In most cases,
!    this is just TYPE_MODE.  But in the case of vector types, it may be some
!    vector mode.
  
     When we have only some of our vector isa extensions enabled, then there
     are some modes for which vector_mode_supported_p is false.  For these
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2046,2061 ****
     the middle-end decides to do with these vector types.  */
  
  static enum machine_mode
! type_natural_mode (tree type)
  {
    enum machine_mode mode = TYPE_MODE (type);
  
    if (TREE_CODE (type) == VECTOR_TYPE && !VECTOR_MODE_P (mode))
      {
        HOST_WIDE_INT size = int_size_in_bytes (type);
!       if ((size == 8 || size == 16)
! 	  /* ??? Generic code allows us to create width 1 vectors.  Ignore.  */
! 	  && TYPE_VECTOR_SUBPARTS (type) > 1)
  	{
  	  enum machine_mode innermode = TYPE_MODE (TREE_TYPE (type));
  
--- 2047,2066 ----
     the middle-end decides to do with these vector types.  */
  
  static enum machine_mode
! type_mode_for_classify (tree type)
  {
    enum machine_mode mode = TYPE_MODE (type);
  
    if (TREE_CODE (type) == VECTOR_TYPE && !VECTOR_MODE_P (mode))
      {
        HOST_WIDE_INT size = int_size_in_bytes (type);
! 
!       /* A pox on Motorola and its SPE ABI that requires that gcc allow
!          degenerate width 1 vector types.  Treat them just like scalars.  */
!       if (TYPE_VECTOR_SUBPARTS (type) == 1)
! 	return TYPE_MODE (TREE_TYPE (type));
! 
!       if (size == 8 || size == 16)
  	{
  	  enum machine_mode innermode = TYPE_MODE (TREE_TYPE (type));
  
*************** type_natural_mode (tree type)
*** 2072,2077 ****
--- 2077,2093 ----
  
  	  abort ();
  	}
+       /* Validate that generic code is acting as we want.  Non-degenerate
+ 	 vector types smaller than 8 bytes are all integral, and we've 
+ 	 chosen the appropriate integral mode for them.  Large vector types
+ 	 are passed in memory and have BLKmode.  */
+       else if (size < 8)
+ 	{
+ 	  gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (type)));
+ 	  gcc_assert (SCALAR_INT_MODE_P (mode));
+ 	}
+       else
+ 	gcc_assert (mode == BLKmode);
      }
  
    return mode;
*************** classify_argument (enum machine_mode mod
*** 2175,2190 ****
        && targetm.calls.must_pass_in_stack (mode, type))
      return 0;
  
    if (type && AGGREGATE_TYPE_P (type))
      {
        int i;
        tree field;
        enum x86_64_reg_class subclasses[MAX_CLASSES];
  
-       /* On x86-64 we pass structures larger than 16 bytes on the stack.  */
-       if (bytes > 16)
- 	return 0;
- 
        for (i = 0; i < words; i++)
  	classes[i] = X86_64_NO_CLASS;
  
--- 2191,2206 ----
        && targetm.calls.must_pass_in_stack (mode, type))
      return 0;
  
+   /* On x86-64 we pass everything larger than 16 bytes on the stack.  */
+   if (bytes > 16)
+     return 0;
+ 
    if (type && AGGREGATE_TYPE_P (type))
      {
        int i;
        tree field;
        enum x86_64_reg_class subclasses[MAX_CLASSES];
  
        for (i = 0; i < words; i++)
  	classes[i] = X86_64_NO_CLASS;
  
*************** classify_argument (enum machine_mode mod
*** 2212,2218 ****
  		   int offset = tree_low_cst (BINFO_OFFSET (base_binfo), 0) * 8;
  		   tree type = BINFO_TYPE (base_binfo);
  
! 		   num = classify_argument (TYPE_MODE (type),
  					    type, subclasses,
  					    (offset + bit_offset) % 256);
  		   if (!num)
--- 2228,2234 ----
  		   int offset = tree_low_cst (BINFO_OFFSET (base_binfo), 0) * 8;
  		   tree type = BINFO_TYPE (base_binfo);
  
! 		   num = classify_argument (type_mode_for_classify (type),
  					    type, subclasses,
  					    (offset + bit_offset) % 256);
  		   if (!num)
*************** classify_argument (enum machine_mode mod
*** 2351,2356 ****
--- 2367,2407 ----
  	}
        return words;
      }
+   else if (type && TREE_CODE (type) == VECTOR_TYPE)
+     {
+       if (TYPE_VECTOR_SUBPARTS (type) == 1)
+ 	{
+ 	  tree subtype = TREE_TYPE (type);
+ 	  return classify_argument (type_mode_for_classify (subtype),
+ 				    subtype, classes, bit_offset);
+ 	}
+ 
+       switch (bytes)
+ 	{
+ 	case 16:
+ 	  classes[0] = X86_64_SSE_CLASS;
+ 	  classes[1] = X86_64_SSEUP_CLASS;
+ 	  return 2;
+ 
+ 	case 8:
+ 	  classes[0] = X86_64_SSE_CLASS;
+ 	  return 1;
+ 
+ 	case 4:
+ 	case 2:
+ 	  gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (type)));
+ 	  gcc_assert (SCALAR_INT_MODE_P (mode));
+ 
+ 	  if (bit_offset + GET_MODE_BITSIZE (mode) <= 32)
+ 	    classes[0] = X86_64_INTEGERSI_CLASS;
+ 	  else
+ 	    classes[0] = X86_64_INTEGER_CLASS;
+ 	  return 1;
+ 
+ 	default:
+ 	  gcc_unreachable ();
+ 	}
+     }
  
    /* Compute alignment needed.  We align all types to natural boundaries with
       exception of XFmode that is aligned to 64bits.  */
*************** classify_argument (enum machine_mode mod
*** 2425,2463 ****
      case TCmode:
        /* This modes is larger than 16 bytes.  */
        return 0;
-     case V4SFmode:
-     case V4SImode:
-     case V16QImode:
-     case V8HImode:
-     case V2DFmode:
-     case V2DImode:
-       classes[0] = X86_64_SSE_CLASS;
-       classes[1] = X86_64_SSEUP_CLASS;
-       return 2;
-     case V2SFmode:
-     case V2SImode:
-     case V4HImode:
-     case V8QImode:
-       classes[0] = X86_64_SSE_CLASS;
-       return 1;
      case BLKmode:
      case VOIDmode:
        return 0;
      default:
-       if (VECTOR_MODE_P (mode))
- 	{
- 	  if (bytes > 16)
- 	    return 0;
- 	  if (GET_MODE_CLASS (GET_MODE_INNER (mode)) == MODE_INT)
- 	    {
- 	      if (bit_offset + GET_MODE_BITSIZE (mode) <= 32)
- 		classes[0] = X86_64_INTEGERSI_CLASS;
- 	      else
- 		classes[0] = X86_64_INTEGER_CLASS;
- 	      classes[1] = X86_64_INTEGER_CLASS;
- 	      return 1 + (bytes > 8);
- 	    }
- 	}
        abort ();
      }
  }
--- 2476,2485 ----
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 2740,2746 ****
    /* To simplify the code below, represent vector types with a vector mode
       even if MMX/SSE are not active.  */
    if (type && TREE_CODE (type) == VECTOR_TYPE)
!     mode = type_natural_mode (type);
  
    /* Handle a hidden AL argument containing number of registers for varargs
       x86-64 functions.  For i386 ABI just return constm1_rtx to avoid
--- 2762,2768 ----
    /* To simplify the code below, represent vector types with a vector mode
       even if MMX/SSE are not active.  */
    if (type && TREE_CODE (type) == VECTOR_TYPE)
!     mode = type_mode_for_classify (type);
  
    /* Handle a hidden AL argument containing number of registers for varargs
       x86-64 functions.  For i386 ABI just return constm1_rtx to avoid
*************** ix86_function_value (tree valtype)
*** 2989,2995 ****
  {
    if (TARGET_64BIT)
      {
!       rtx ret = construct_container (type_natural_mode (valtype),
  				     TYPE_MODE (valtype), valtype,
  				     1, REGPARM_MAX, SSE_REGPARM_MAX,
  				     x86_64_int_return_registers, 0);
--- 3011,3017 ----
  {
    if (TARGET_64BIT)
      {
!       rtx ret = construct_container (type_mode_for_classify (valtype),
  				     TYPE_MODE (valtype), valtype,
  				     1, REGPARM_MAX, SSE_REGPARM_MAX,
  				     x86_64_int_return_registers, 0);
*************** ix86_gimplify_va_arg (tree valist, tree 
*** 3360,3368 ****
    size = int_size_in_bytes (type);
    rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
  
!   container = construct_container (type_natural_mode (type), TYPE_MODE (type),
! 				   type, 0, REGPARM_MAX, SSE_REGPARM_MAX,
! 				   intreg, 0);
  
    /* Pull the value out of the saved registers.  */
  
--- 3382,3390 ----
    size = int_size_in_bytes (type);
    rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
  
!   container = construct_container (type_mode_for_classify (type),
! 				   TYPE_MODE (type), type, 0, REGPARM_MAX,
! 				   SSE_REGPARM_MAX, intreg, 0);
  
    /* Pull the value out of the saved registers.  */
  



More information about the Gcc mailing list