Subject: SLOW_UNALIGNED_ACCESS granularity
To: None <gcc-patches@gcc.gnu.org>
From: David Edelsohn <dje@watson.ibm.com>
List: port-powerpc
Date: 12/29/1999 13:22:41
	The SLOW_UNALIGNED_ACCESS macro currently does not utilize any
parameters to differentiate between the various types of access.  This
limitation does not allow the PowerPC port enough flexibility to describe
which unaligned accesses have an unacceptable cost and which do not.  I
would like to change the macro to utilize a MODE parameter to allow
machine description files to differentiate and provide better feedback to
the backend.  Currently I am not adding an ALIGN parameter as well,
although that might be useful for some architectures.

	The following patch only shows the changes to the backend, but I
would modify each machine description currently using
SLOW_UNALIGNED_ACCESS to ignore the parameter and let each port maintainer
tune the revised macro as necessary.


	* expmed.c (SLOW_UNALIGNED_ACCESS): Add parameter to default
	definition.
	(store_bit_field): Call SLOW_UNALIGNED_ACCESS with relevant mode.
	(store_fixed_bit_field): Call macro with word_mode.
	(extract_bit_field): Call macro with relevant mode.
	* (SLOW_UNALIGNED_ACCESS): Add parameter to default
	definition.
	(move_by_pieces): Call SLOW_UNALIGNED_ACCESS with word_mode.
	(move_by_pieces_ninsns): Likewise.
	(clear_by_pieces): Likewise.
	(emit_push_insn): Likewise.
	(store_field): Call macro with relevant mode.
	(expand_expr): Likewise.
	(expand_expr_unaligned): Likewise.

Index: expmed.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expmed.c,v
retrieving revision 1.41
diff -c -p -r1.41 expmed.c
*** expmed.c	1999/10/26 06:48:38	1.41
--- expmed.c	1999/12/29 17:54:30
*************** static void do_cmp_and_jump		PROTO((rtx,
*** 56,62 ****
  static int sdiv_pow2_cheap, smod_pow2_cheap;
  
  #ifndef SLOW_UNALIGNED_ACCESS
! #define SLOW_UNALIGNED_ACCESS STRICT_ALIGNMENT
  #endif
  
  /* For compilers that support multiple targets with different word sizes,
--- 56,62 ----
  static int sdiv_pow2_cheap, smod_pow2_cheap;
  
  #ifndef SLOW_UNALIGNED_ACCESS
! #define SLOW_UNALIGNED_ACCESS(MODE) STRICT_ALIGNMENT
  #endif
  
  /* For compilers that support multiple targets with different word sizes,
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 297,303 ****
       BITPOS is 0 in a REG bigger than a word.  */
    if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
        && (GET_CODE (op0) != MEM
! 	  || ! SLOW_UNALIGNED_ACCESS
  	  || (offset * BITS_PER_UNIT % bitsize == 0
  	      && align % GET_MODE_SIZE (fieldmode) == 0))
        && bitpos == 0 && bitsize == GET_MODE_BITSIZE (fieldmode))
--- 297,303 ----
       BITPOS is 0 in a REG bigger than a word.  */
    if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
        && (GET_CODE (op0) != MEM
! 	  || ! SLOW_UNALIGNED_ACCESS (fieldmode)
  	  || (offset * BITS_PER_UNIT % bitsize == 0
  	      && align % GET_MODE_SIZE (fieldmode) == 0))
        && bitpos == 0 && bitsize == GET_MODE_BITSIZE (fieldmode))
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 511,517 ****
  	    bestmode = GET_MODE (op0);
  
  	  if (bestmode == VOIDmode
! 	      || (SLOW_UNALIGNED_ACCESS && GET_MODE_SIZE (bestmode) > align))
  	    goto insv_loses;
  
  	  /* Adjust address to point to the containing unit of that mode.  */
--- 511,518 ----
  	    bestmode = GET_MODE (op0);
  
  	  if (bestmode == VOIDmode
! 	      || (SLOW_UNALIGNED_ACCESS (bestmode)
! 		  && GET_MODE_SIZE (bestmode) > align))
  	    goto insv_loses;
  
  	  /* Adjust address to point to the containing unit of that mode.  */
*************** store_fixed_bit_field (op0, offset, bits
*** 634,640 ****
    int all_zero = 0;
    int all_one = 0;
  
!   if (! SLOW_UNALIGNED_ACCESS)
      struct_align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
      
    /* There is a case not handled here:
--- 635,641 ----
    int all_zero = 0;
    int all_one = 0;
  
!   if (! SLOW_UNALIGNED_ACCESS (word_mode))
      struct_align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
      
    /* There is a case not handled here:
*************** extract_bit_field (str_rtx, bitsize, bit
*** 1054,1060 ****
  	&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
  				  GET_MODE_BITSIZE (GET_MODE (op0))))
         || (GET_CODE (op0) == MEM
! 	   && (! SLOW_UNALIGNED_ACCESS
  	       || (offset * BITS_PER_UNIT % bitsize == 0
  		   && align * BITS_PER_UNIT % bitsize == 0))))
        && ((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode)
--- 1055,1061 ----
  	&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
  				  GET_MODE_BITSIZE (GET_MODE (op0))))
         || (GET_CODE (op0) == MEM
! 	   && (! SLOW_UNALIGNED_ACCESS (mode)
  	       || (offset * BITS_PER_UNIT % bitsize == 0
  		   && align * BITS_PER_UNIT % bitsize == 0))))
        && ((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode)
*************** extract_bit_field (str_rtx, bitsize, bit
*** 1255,1261 ****
  		    bestmode = GET_MODE (xop0);
  
  		  if (bestmode == VOIDmode
! 		      || (SLOW_UNALIGNED_ACCESS && GET_MODE_SIZE (bestmode) > align))
  		    goto extzv_loses;
  
  		  /* Compute offset as multiple of this unit,
--- 1256,1263 ----
  		    bestmode = GET_MODE (xop0);
  
  		  if (bestmode == VOIDmode
! 		      || (SLOW_UNALIGNED_ACCESS (bestmode)
! 			  && GET_MODE_SIZE (bestmode) > align))
  		    goto extzv_loses;
  
  		  /* Compute offset as multiple of this unit,
*************** extract_bit_field (str_rtx, bitsize, bit
*** 1392,1398 ****
  		    bestmode = GET_MODE (xop0);
  
  		  if (bestmode == VOIDmode
! 		      || (SLOW_UNALIGNED_ACCESS && GET_MODE_SIZE (bestmode) > align))
  		    goto extv_loses;
  
  		  /* Compute offset as multiple of this unit,
--- 1394,1401 ----
  		    bestmode = GET_MODE (xop0);
  
  		  if (bestmode == VOIDmode
! 		      || (SLOW_UNALIGNED_ACCESS (bestmode)
! 			  && GET_MODE_SIZE (bestmode) > align))
  		    goto extv_loses;
  
  		  /* Compute offset as multiple of this unit,
Index: expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expr.c,v
retrieving revision 1.190
diff -c -p -r1.190 expr.c
*** expr.c	1999/12/24 17:27:36	1.190
--- expr.c	1999/12/29 17:54:31
*************** enum insn_code clrstr_optab[NUM_MACHINE_
*** 200,206 ****
  /* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow.  */
  
  #ifndef SLOW_UNALIGNED_ACCESS
! #define SLOW_UNALIGNED_ACCESS STRICT_ALIGNMENT
  #endif
  
  /* This is run once per compilation to set up which modes can be used
--- 200,206 ----
  /* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow.  */
  
  #ifndef SLOW_UNALIGNED_ACCESS
! #define SLOW_UNALIGNED_ACCESS(MODE) STRICT_ALIGNMENT
  #endif
  
  /* This is run once per compilation to set up which modes can be used
*************** move_by_pieces (to, from, len, align)
*** 1437,1443 ****
  	data.to_addr = copy_addr_to_reg (to_addr);
      }
  
!   if (! SLOW_UNALIGNED_ACCESS
        || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
      align = MOVE_MAX;
  
--- 1437,1443 ----
  	data.to_addr = copy_addr_to_reg (to_addr);
      }
  
!   if (! SLOW_UNALIGNED_ACCESS (word_mode)
        || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
      align = MOVE_MAX;
  
*************** move_by_pieces_ninsns (l, align)
*** 1479,1485 ****
    register int n_insns = 0;
    int max_size = MOVE_MAX + 1;
  
!   if (! SLOW_UNALIGNED_ACCESS
        || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
      align = MOVE_MAX;
  
--- 1479,1485 ----
    register int n_insns = 0;
    int max_size = MOVE_MAX + 1;
  
!   if (! SLOW_UNALIGNED_ACCESS (word_mode)
        || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
      align = MOVE_MAX;
  
*************** clear_by_pieces (to, len, align)
*** 2285,2291 ****
  	data.to_addr = copy_addr_to_reg (to_addr);
      }
  
!   if (! SLOW_UNALIGNED_ACCESS
        || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
      align = MOVE_MAX;
  
--- 2285,2291 ----
  	data.to_addr = copy_addr_to_reg (to_addr);
      }
  
!   if (! SLOW_UNALIGNED_ACCESS (word_mode)
        || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
      align = MOVE_MAX;
  
*************** emit_push_insn (x, mode, type, size, ali
*** 2974,2980 ****
  	  /* Here we avoid the case of a structure whose weak alignment
  	     forces many pushes of a small amount of data,
  	     and such small pushes do rounding that causes trouble.  */
! 	  && ((! SLOW_UNALIGNED_ACCESS)
  	      || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT
  	      || PUSH_ROUNDING (align) == align)
  	  && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
--- 2974,2980 ----
  	  /* Here we avoid the case of a structure whose weak alignment
  	     forces many pushes of a small amount of data,
  	     and such small pushes do rounding that causes trouble.  */
! 	  && ((! SLOW_UNALIGNED_ACCESS (word_mode))
  	      || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT
  	      || PUSH_ROUNDING (align) == align)
  	  && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
*************** store_field (target, bitsize, bitpos, mo
*** 4772,4781 ****
        || GET_CODE (target) == SUBREG
        /* If the field isn't aligned enough to store as an ordinary memref,
  	 store it as a bit field.  */
!       || (mode != BLKmode && SLOW_UNALIGNED_ACCESS
  	  && (align * BITS_PER_UNIT < GET_MODE_ALIGNMENT (mode)
  	      || bitpos % GET_MODE_ALIGNMENT (mode)))
!       || (mode == BLKmode && SLOW_UNALIGNED_ACCESS
  	  && (TYPE_ALIGN (TREE_TYPE (exp)) > align * BITS_PER_UNIT
  	      || bitpos % TYPE_ALIGN (TREE_TYPE (exp)) != 0))
        /* If the RHS and field are a constant size and the size of the
--- 4772,4781 ----
        || GET_CODE (target) == SUBREG
        /* If the field isn't aligned enough to store as an ordinary memref,
  	 store it as a bit field.  */
!       || (mode != BLKmode && SLOW_UNALIGNED_ACCESS (mode)
  	  && (align * BITS_PER_UNIT < GET_MODE_ALIGNMENT (mode)
  	      || bitpos % GET_MODE_ALIGNMENT (mode)))
!       || (mode == BLKmode && SLOW_UNALIGNED_ACCESS (mode)
  	  && (TYPE_ALIGN (TREE_TYPE (exp)) > align * BITS_PER_UNIT
  	      || bitpos % TYPE_ALIGN (TREE_TYPE (exp)) != 0))
        /* If the RHS and field are a constant size and the size of the
*************** expand_expr (exp, target, tmode, modifie
*** 6751,6764 ****
  		     && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
  		    /* If the field isn't aligned enough to fetch as a memref,
  		       fetch it as a bit field.  */
! 		    || (mode1 != BLKmode && SLOW_UNALIGNED_ACCESS
  			&& ((TYPE_ALIGN (TREE_TYPE (tem))
  			     < (unsigned int) GET_MODE_ALIGNMENT (mode))
  			    || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))))
  	    || (modifier != EXPAND_CONST_ADDRESS
  		&& modifier != EXPAND_INITIALIZER
  		&& mode == BLKmode
! 			&& SLOW_UNALIGNED_ACCESS
  		&& (TYPE_ALIGN (type) > alignment * BITS_PER_UNIT
  		    || bitpos % TYPE_ALIGN (type) != 0)))
  	  {
--- 6751,6764 ----
  		     && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
  		    /* If the field isn't aligned enough to fetch as a memref,
  		       fetch it as a bit field.  */
! 		    || (mode1 != BLKmode && SLOW_UNALIGNED_ACCESS (mode1)
  			&& ((TYPE_ALIGN (TREE_TYPE (tem))
  			     < (unsigned int) GET_MODE_ALIGNMENT (mode))
  			    || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))))
  	    || (modifier != EXPAND_CONST_ADDRESS
  		&& modifier != EXPAND_INITIALIZER
  		&& mode == BLKmode
! 		&& SLOW_UNALIGNED_ACCESS (mode)
  		&& (TYPE_ALIGN (type) > alignment * BITS_PER_UNIT
  		    || bitpos % TYPE_ALIGN (type) != 0)))
  	  {
*************** expand_expr_unaligned (exp, palign)
*** 8691,8697 ****
  	   EXPAND_INITIALIZER), then we must not copy to a temporary.  */
  	if (mode1 == VOIDmode
  	    || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
! 	    || (SLOW_UNALIGNED_ACCESS
  		&& (TYPE_ALIGN (type) > alignment * BITS_PER_UNIT
  		    || bitpos % TYPE_ALIGN (type) != 0)))
  	  {
--- 8691,8697 ----
  	   EXPAND_INITIALIZER), then we must not copy to a temporary.  */
  	if (mode1 == VOIDmode
  	    || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
! 	    || (SLOW_UNALIGNED_ACCESS (mode1)
  		&& (TYPE_ALIGN (type) > alignment * BITS_PER_UNIT
  		    || bitpos % TYPE_ALIGN (type) != 0)))
  	  {