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]

Use anti-ranges in memcpy/memset expansion


Hi,
this patch adds support to anti-ranges to determine_block_size.
This makes it possible to bound size of block from bellow that is
useful to avoid need for small size code path and it also allows
us to inline the following:
void *a;
void *b;
t(int c)
{
  if (c<10)
    memcpy (a,b,c);
}

Because C is signed, we do not really know that the block is smaller
than 10, but it is most likely the case.

Bootstrapped/regtested x86_64-linux OK?

Honza

	* md.texi (setmem): Document new parameter.
	* optabs.c (maybe_gen_insn): Support 9 operands.
	* builtins.c (determine_block_size): Add probable_max_size;
	support anti-ranges.
	(expand_builtin_memcpy. expand_builtin_memset_args): Pass around
	probable_max_size.
	* expr.c (emit_block_move_via_movmem, emit_block_move_hints,
	emit_block_move, clear_storage_hints, set_storage_via_setmem):
	Likewise.
	* expr.h (emit_block_move_hints, clear_storage_hints,
	set_storage_via_setmem): Update prototype.
	* i386.md (setmem, movmem patterns): Add 9th operand.
	* i386-protos.h (ix86_expand_set_or_movmem): Update prototype.
	* i386.c (ix86_expand_set_or_movmem): Take probable_max_size_exp
	argument; pass it to decide_alg.

	* gcc.target/i386/memcpy-3.c: New testcase.
Index: doc/md.texi
===================================================================
*** doc/md.texi	(revision 204945)
--- doc/md.texi	(working copy)
*************** all cases. This expected alignment is al
*** 5352,5357 ****
--- 5352,5359 ----
  Expected size, when unknown, is set to @code{(const_int -1)}.
  Operand 7 is the minimal size of the block and operand 8 is the
  maximal size of the block (NULL if it can not be represented as CONST_INT).
+ Operand 9 is the probable maximal size (i.e. we can not rely on it for correctness,
+ but it can be used for choosing proper code sequence for a given size).
  
  The use for multiple @code{setmem@var{m}} is as for @code{movmem@var{m}}.
  
Index: optabs.c
===================================================================
*** optabs.c	(revision 204945)
--- optabs.c	(working copy)
*************** maybe_gen_insn (enum insn_code icode, un
*** 8229,8234 ****
--- 8229,8238 ----
        return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value,
  			      ops[3].value, ops[4].value, ops[5].value,
  			      ops[6].value, ops[7].value);
+     case 9:
+       return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value,
+ 			      ops[3].value, ops[4].value, ops[5].value,
+ 			      ops[6].value, ops[7].value, ops[8].value);
      }
    gcc_unreachable ();
  }
Index: builtins.c
===================================================================
*** builtins.c	(revision 204945)
--- builtins.c	(working copy)
*************** builtin_memcpy_read_str (void *data, HOS
*** 3096,3107 ****
  }
  
  /* LEN specify length of the block of memcpy/memset operation.
!    Figure out its range and put it into MIN_SIZE/MAX_SIZE.  */
  
  static void
  determine_block_size (tree len, rtx len_rtx,
  		      unsigned HOST_WIDE_INT *min_size,
! 		      unsigned HOST_WIDE_INT *max_size)
  {
    if (CONST_INT_P (len_rtx))
      {
--- 3096,3110 ----
  }
  
  /* LEN specify length of the block of memcpy/memset operation.
!    Figure out its range and put it into MIN_SIZE/MAX_SIZE. 
!    In some cases we can make very likely guess on max size, then we
!    set it into PROBABLE_MAX_SIZE.  */
  
  static void
  determine_block_size (tree len, rtx len_rtx,
  		      unsigned HOST_WIDE_INT *min_size,
! 		      unsigned HOST_WIDE_INT *max_size,
! 		      unsigned HOST_WIDE_INT *probable_max_size)
  {
    if (CONST_INT_P (len_rtx))
      {
*************** determine_block_size (tree len, rtx len_
*** 3111,3138 ****
    else
      {
        double_int min, max;
!       if (TREE_CODE (len) == SSA_NAME 
! 	  && get_range_info (len, &min, &max) == VR_RANGE)
  	{
! 	  if (min.fits_uhwi ())
  	    *min_size = min.to_uhwi ();
! 	  else
! 	    *min_size = 0;
! 	  if (max.fits_uhwi ())
! 	    *max_size = max.to_uhwi ();
! 	  else
! 	    *max_size = (HOST_WIDE_INT)-1;
  	}
!       else
  	{
! 	  if (host_integerp (TYPE_MIN_VALUE (TREE_TYPE (len)), 1))
! 	    *min_size = tree_low_cst (TYPE_MIN_VALUE (TREE_TYPE (len)), 1);
! 	  else
! 	    *min_size = 0;
! 	  if (host_integerp (TYPE_MAX_VALUE (TREE_TYPE (len)), 1))
! 	    *max_size = tree_low_cst (TYPE_MAX_VALUE (TREE_TYPE (len)), 1);
! 	  else
! 	    *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
  	}
      }
    gcc_checking_assert (*max_size <=
--- 3114,3160 ----
    else
      {
        double_int min, max;
!       enum value_range_type range_type = VR_UNDEFINED;
! 
!       /* Determine bounds from the type.  */
!       if (host_integerp (TYPE_MIN_VALUE (TREE_TYPE (len)), 1))
! 	*min_size = tree_low_cst (TYPE_MIN_VALUE (TREE_TYPE (len)), 1);
!       else
! 	*min_size = 0;
!       if (host_integerp (TYPE_MAX_VALUE (TREE_TYPE (len)), 1))
! 	*probable_max_size = *max_size = tree_low_cst (TYPE_MAX_VALUE (TREE_TYPE (len)), 1);
!       else
! 	*probable_max_size = *max_size = GET_MODE_MASK (GET_MODE (len_rtx));
! 
!       if (TREE_CODE (len) == SSA_NAME)
! 	range_type = get_range_info (len, &min, &max);
!       if (range_type == VR_RANGE)
  	{
! 	  if (min.fits_uhwi () && *min_size < min.to_uhwi ())
  	    *min_size = min.to_uhwi ();
! 	  if (max.fits_uhwi () && *max_size > max.to_uhwi ())
! 	    *probable_max_size = *max_size = max.to_uhwi ();
  	}
!       else if (range_type == VR_ANTI_RANGE)
  	{
! 	  /* Anti range 0...N lets us to determine minmal size to N+1.  */
! 	  if (min.is_zero ())
! 	    {
! 	      if ((max + double_int_one).fits_uhwi ())
! 		*min_size = (max + double_int_one).to_uhwi ();
! 	    }
! 	  /* Code like
! 
! 	     int n;
! 	     if (n < 100)
! 	       memcpy (a,b, n)
! 
! 	     Produce anti range allowing negative values of N.  We still
! 	     can use the information and make a guess that N is not negative.
! 	     */
! 	   else if (!max.ule (double_int_one.lshift (31))
! 	            && min.fits_uhwi ())
! 	     *probable_max_size = min.to_uhwi () - 1;
  	}
      }
    gcc_checking_assert (*max_size <=
*************** expand_builtin_memcpy (tree exp, rtx tar
*** 3164,3169 ****
--- 3186,3192 ----
        unsigned int expected_align = 0;
        unsigned HOST_WIDE_INT min_size;
        unsigned HOST_WIDE_INT max_size;
+       unsigned HOST_WIDE_INT probable_max_size;
  
        /* If DEST is not a pointer type, call the normal function.  */
        if (dest_align == 0)
*************** expand_builtin_memcpy (tree exp, rtx tar
*** 3183,3189 ****
        dest_mem = get_memory_rtx (dest, len);
        set_mem_align (dest_mem, dest_align);
        len_rtx = expand_normal (len);
!       determine_block_size (len, len_rtx, &min_size, &max_size);
        src_str = c_getstr (src);
  
        /* If SRC is a string constant and block move would be done
--- 3206,3213 ----
        dest_mem = get_memory_rtx (dest, len);
        set_mem_align (dest_mem, dest_align);
        len_rtx = expand_normal (len);
!       determine_block_size (len, len_rtx, &min_size, &max_size,
! 			    &probable_max_size);
        src_str = c_getstr (src);
  
        /* If SRC is a string constant and block move would be done
*************** expand_builtin_memcpy (tree exp, rtx tar
*** 3213,3219 ****
  				         CALL_EXPR_TAILCALL (exp)
  				         ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
  					 expected_align, expected_size,
! 					 min_size, max_size);
  
        if (dest_addr == 0)
  	{
--- 3237,3243 ----
  				         CALL_EXPR_TAILCALL (exp)
  				         ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
  					 expected_align, expected_size,
! 					 min_size, max_size, probable_max_size);
  
        if (dest_addr == 0)
  	{
*************** expand_builtin_memset_args (tree dest, t
*** 3629,3634 ****
--- 3653,3659 ----
    unsigned int expected_align = 0;
    unsigned HOST_WIDE_INT min_size;
    unsigned HOST_WIDE_INT max_size;
+   unsigned HOST_WIDE_INT probable_max_size;
  
    dest_align = get_pointer_alignment (dest);
  
*************** expand_builtin_memset_args (tree dest, t
*** 3657,3663 ****
    len = builtin_save_expr (len);
  
    len_rtx = expand_normal (len);
!   determine_block_size (len, len_rtx, &min_size, &max_size);
    dest_mem = get_memory_rtx (dest, len);
    val_mode = TYPE_MODE (unsigned_char_type_node);
  
--- 3682,3689 ----
    len = builtin_save_expr (len);
  
    len_rtx = expand_normal (len);
!   determine_block_size (len, len_rtx, &min_size, &max_size,
! 			&probable_max_size);
    dest_mem = get_memory_rtx (dest, len);
    val_mode = TYPE_MODE (unsigned_char_type_node);
  
*************** expand_builtin_memset_args (tree dest, t
*** 3684,3690 ****
  	}
        else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
  					dest_align, expected_align,
! 					expected_size, min_size, max_size))
  	goto do_libcall;
  
        dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
--- 3710,3717 ----
  	}
        else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
  					dest_align, expected_align,
! 					expected_size, min_size, max_size,
! 					probable_max_size))
  	goto do_libcall;
  
        dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
*************** expand_builtin_memset_args (tree dest, t
*** 3706,3712 ****
        else if (!set_storage_via_setmem (dest_mem, len_rtx,
  					gen_int_mode (c, val_mode),
  					dest_align, expected_align,
! 					expected_size, min_size, max_size))
  	goto do_libcall;
  
        dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
--- 3733,3740 ----
        else if (!set_storage_via_setmem (dest_mem, len_rtx,
  					gen_int_mode (c, val_mode),
  					dest_align, expected_align,
! 					expected_size, min_size, max_size,
! 					probable_max_size))
  	goto do_libcall;
  
        dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
*************** expand_builtin_memset_args (tree dest, t
*** 3719,3725 ****
  				   CALL_EXPR_TAILCALL (orig_exp)
  				   ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
  				   expected_align, expected_size,
! 				   min_size, max_size);
  
    if (dest_addr == 0)
      {
--- 3747,3754 ----
  				   CALL_EXPR_TAILCALL (orig_exp)
  				   ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
  				   expected_align, expected_size,
! 				   min_size, max_size,
! 				   probable_max_size);
  
    if (dest_addr == 0)
      {
Index: testsuite/gcc.target/i386/memcpy-3.c
===================================================================
*** testsuite/gcc.target/i386/memcpy-3.c	(revision 0)
--- testsuite/gcc.target/i386/memcpy-3.c	(revision 0)
***************
*** 0 ****
--- 1,11 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2" } */
+ /* Memcpy should be inlined because block size is known.  */
+ /* { dg-final { scan-assembler-not "memcpy" } } */
+ void *a;
+ void *b;
+ t(int c)
+ {
+   if (c<10)
+     memcpy (a,b,c);
+ }
Index: expr.c
===================================================================
*** expr.c	(revision 204945)
--- expr.c	(working copy)
*************** static void move_by_pieces_1 (insn_gen_f
*** 129,135 ****
  			      struct move_by_pieces_d *);
  static bool block_move_libcall_safe_for_call_parm (void);
  static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT,
! 					unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
  static tree emit_block_move_libcall_fn (int);
  static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
  static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
--- 129,136 ----
  			      struct move_by_pieces_d *);
  static bool block_move_libcall_safe_for_call_parm (void);
  static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT,
! 					unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
! 					unsigned HOST_WIDE_INT);
  static tree emit_block_move_libcall_fn (int);
  static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
  static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
*************** rtx
*** 1131,1137 ****
  emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
  		       unsigned int expected_align, HOST_WIDE_INT expected_size,
  		       unsigned HOST_WIDE_INT min_size,
! 		       unsigned HOST_WIDE_INT max_size)
  {
    bool may_use_call;
    rtx retval = 0;
--- 1132,1139 ----
  emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
  		       unsigned int expected_align, HOST_WIDE_INT expected_size,
  		       unsigned HOST_WIDE_INT min_size,
! 		       unsigned HOST_WIDE_INT max_size,
! 		       unsigned HOST_WIDE_INT probable_max_size)
  {
    bool may_use_call;
    rtx retval = 0;
*************** emit_block_move_hints (rtx x, rtx y, rtx
*** 1188,1194 ****
      move_by_pieces (x, y, INTVAL (size), align, 0);
    else if (emit_block_move_via_movmem (x, y, size, align,
  				       expected_align, expected_size,
! 				       min_size, max_size))
      ;
    else if (may_use_call
  	   && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))
--- 1190,1196 ----
      move_by_pieces (x, y, INTVAL (size), align, 0);
    else if (emit_block_move_via_movmem (x, y, size, align,
  				       expected_align, expected_size,
! 				       min_size, max_size, probable_max_size))
      ;
    else if (may_use_call
  	   && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))
*************** emit_block_move (rtx x, rtx y, rtx size,
*** 1224,1230 ****
    else
      max = GET_MODE_MASK (GET_MODE (size));
    return emit_block_move_hints (x, y, size, method, 0, -1,
! 				min, max);
  }
  
  /* A subroutine of emit_block_move.  Returns true if calling the
--- 1226,1232 ----
    else
      max = GET_MODE_MASK (GET_MODE (size));
    return emit_block_move_hints (x, y, size, method, 0, -1,
! 				min, max, max);
  }
  
  /* A subroutine of emit_block_move.  Returns true if calling the
*************** static bool
*** 1289,1295 ****
  emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
  			    unsigned int expected_align, HOST_WIDE_INT expected_size,
  			    unsigned HOST_WIDE_INT min_size,
! 			    unsigned HOST_WIDE_INT max_size)
  {
    int save_volatile_ok = volatile_ok;
    enum machine_mode mode;
--- 1291,1298 ----
  emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
  			    unsigned int expected_align, HOST_WIDE_INT expected_size,
  			    unsigned HOST_WIDE_INT min_size,
! 			    unsigned HOST_WIDE_INT max_size,
! 			    unsigned HOST_WIDE_INT probable_max_size)
  {
    int save_volatile_ok = volatile_ok;
    enum machine_mode mode;
*************** emit_block_move_via_movmem (rtx x, rtx y
*** 1298,1305 ****
      expected_align = align;
    if (expected_size != -1)
      {
!       if ((unsigned HOST_WIDE_INT)expected_size > max_size)
! 	expected_size = max_size;
        if ((unsigned HOST_WIDE_INT)expected_size < min_size)
  	expected_size = min_size;
      }
--- 1301,1308 ----
      expected_align = align;
    if (expected_size != -1)
      {
!       if ((unsigned HOST_WIDE_INT)expected_size > probable_max_size)
! 	expected_size = probable_max_size;
        if ((unsigned HOST_WIDE_INT)expected_size < min_size)
  	expected_size = min_size;
      }
*************** emit_block_move_via_movmem (rtx x, rtx y
*** 1328,1334 ****
  	      || max_size <= (GET_MODE_MASK (mode) >> 1)
  	      || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
  	{
! 	  struct expand_operand ops[8];
  	  unsigned int nops;
  
  	  /* ??? When called via emit_block_move_for_call, it'd be
--- 1331,1337 ----
  	      || max_size <= (GET_MODE_MASK (mode) >> 1)
  	      || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
  	{
! 	  struct expand_operand ops[9];
  	  unsigned int nops;
  
  	  /* ??? When called via emit_block_move_for_call, it'd be
*************** emit_block_move_via_movmem (rtx x, rtx y
*** 1336,1342 ****
  	     that it doesn't fail the expansion because it thinks
  	     emitting the libcall would be more efficient.  */
  	  nops = insn_data[(int) code].n_generator_args;
! 	  gcc_assert (nops == 4 || nops == 6 || nops == 8);
  
  	  create_fixed_operand (&ops[0], x);
  	  create_fixed_operand (&ops[1], y);
--- 1339,1345 ----
  	     that it doesn't fail the expansion because it thinks
  	     emitting the libcall would be more efficient.  */
  	  nops = insn_data[(int) code].n_generator_args;
! 	  gcc_assert (nops == 4 || nops == 6 || nops == 8 || nops == 9);
  
  	  create_fixed_operand (&ops[0], x);
  	  create_fixed_operand (&ops[1], y);
*************** emit_block_move_via_movmem (rtx x, rtx y
*** 1348,1354 ****
  	      create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT);
  	      create_integer_operand (&ops[5], expected_size);
  	    }
! 	  if (nops == 8)
  	    {
  	      create_integer_operand (&ops[6], min_size);
  	      /* If we can not represent the maximal size,
--- 1351,1357 ----
  	      create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT);
  	      create_integer_operand (&ops[5], expected_size);
  	    }
! 	  if (nops >= 8)
  	    {
  	      create_integer_operand (&ops[6], min_size);
  	      /* If we can not represent the maximal size,
*************** emit_block_move_via_movmem (rtx x, rtx y
*** 1358,1363 ****
--- 1361,1375 ----
  	      else
  		create_fixed_operand (&ops[7], NULL);
  	    }
+ 	  if (nops == 9)
+ 	    {
+ 	      /* If we can not represent the maximal size,
+ 		 make parameter NULL.  */
+ 	      if ((HOST_WIDE_INT) probable_max_size != -1)
+ 	        create_integer_operand (&ops[8], probable_max_size);
+ 	      else
+ 		create_fixed_operand (&ops[8], NULL);
+ 	    }
  	  if (maybe_expand_insn (code, nops, ops))
  	    {
  	      volatile_ok = save_volatile_ok;
*************** rtx
*** 2747,2753 ****
  clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
  		     unsigned int expected_align, HOST_WIDE_INT expected_size,
  		     unsigned HOST_WIDE_INT min_size,
! 		     unsigned HOST_WIDE_INT max_size)
  {
    enum machine_mode mode = GET_MODE (object);
    unsigned int align;
--- 2759,2766 ----
  clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
  		     unsigned int expected_align, HOST_WIDE_INT expected_size,
  		     unsigned HOST_WIDE_INT min_size,
! 		     unsigned HOST_WIDE_INT max_size,
! 		     unsigned HOST_WIDE_INT probable_max_size)
  {
    enum machine_mode mode = GET_MODE (object);
    unsigned int align;
*************** clear_storage_hints (rtx object, rtx siz
*** 2789,2795 ****
      clear_by_pieces (object, INTVAL (size), align);
    else if (set_storage_via_setmem (object, size, const0_rtx, align,
  				   expected_align, expected_size,
! 				   min_size, max_size))
      ;
    else if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (object)))
      return set_storage_via_libcall (object, size, const0_rtx,
--- 2802,2808 ----
      clear_by_pieces (object, INTVAL (size), align);
    else if (set_storage_via_setmem (object, size, const0_rtx, align,
  				   expected_align, expected_size,
! 				   min_size, max_size, probable_max_size))
      ;
    else if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (object)))
      return set_storage_via_libcall (object, size, const0_rtx,
*************** clear_storage (rtx object, rtx size, enu
*** 2808,2814 ****
      min = max = UINTVAL (size);
    else
      max = GET_MODE_MASK (GET_MODE (size));
!   return clear_storage_hints (object, size, method, 0, -1, min, max);
  }
  
  
--- 2821,2827 ----
      min = max = UINTVAL (size);
    else
      max = GET_MODE_MASK (GET_MODE (size));
!   return clear_storage_hints (object, size, method, 0, -1, min, max, max);
  }
  
  
*************** bool
*** 2907,2913 ****
  set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
  			unsigned int expected_align, HOST_WIDE_INT expected_size,
  			unsigned HOST_WIDE_INT min_size,
! 			unsigned HOST_WIDE_INT max_size)
  {
    /* Try the most limited insn first, because there's no point
       including more than one in the machine description unless
--- 2920,2927 ----
  set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
  			unsigned int expected_align, HOST_WIDE_INT expected_size,
  			unsigned HOST_WIDE_INT min_size,
! 			unsigned HOST_WIDE_INT max_size,
! 			unsigned HOST_WIDE_INT probable_max_size)
  {
    /* Try the most limited insn first, because there's no point
       including more than one in the machine description unless
*************** set_storage_via_setmem (rtx object, rtx
*** 2942,2952 ****
  	      || max_size <= (GET_MODE_MASK (mode) >> 1)
  	      || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
  	{
! 	  struct expand_operand ops[8];
  	  unsigned int nops;
  
  	  nops = insn_data[(int) code].n_generator_args;
! 	  gcc_assert (nops == 4 || nops == 6 || nops == 8);
  
  	  create_fixed_operand (&ops[0], object);
  	  /* The check above guarantees that this size conversion is valid.  */
--- 2956,2966 ----
  	      || max_size <= (GET_MODE_MASK (mode) >> 1)
  	      || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
  	{
! 	  struct expand_operand ops[9];
  	  unsigned int nops;
  
  	  nops = insn_data[(int) code].n_generator_args;
! 	  gcc_assert (nops == 4 || nops == 6 || nops == 8 || nops == 9);
  
  	  create_fixed_operand (&ops[0], object);
  	  /* The check above guarantees that this size conversion is valid.  */
*************** set_storage_via_setmem (rtx object, rtx
*** 2958,2964 ****
  	      create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT);
  	      create_integer_operand (&ops[5], expected_size);
  	    }
! 	  if (nops == 8)
  	    {
  	      create_integer_operand (&ops[6], min_size);
  	      /* If we can not represent the maximal size,
--- 2972,2978 ----
  	      create_integer_operand (&ops[4], expected_align / BITS_PER_UNIT);
  	      create_integer_operand (&ops[5], expected_size);
  	    }
! 	  if (nops >= 8)
  	    {
  	      create_integer_operand (&ops[6], min_size);
  	      /* If we can not represent the maximal size,
*************** set_storage_via_setmem (rtx object, rtx
*** 2968,2973 ****
--- 2982,2996 ----
  	      else
  		create_fixed_operand (&ops[7], NULL);
  	    }
+ 	  if (nops == 9)
+ 	    {
+ 	      /* If we can not represent the maximal size,
+ 		 make parameter NULL.  */
+ 	      if ((HOST_WIDE_INT) probable_max_size != -1)
+ 	        create_integer_operand (&ops[8], probable_max_size);
+ 	      else
+ 		create_fixed_operand (&ops[8], NULL);
+ 	    }
  	  if (maybe_expand_insn (code, nops, ops))
  	    return true;
  	}
Index: expr.h
===================================================================
*** expr.h	(revision 204945)
--- expr.h	(working copy)
*************** extern rtx emit_block_move_via_libcall (
*** 302,307 ****
--- 302,308 ----
  extern rtx emit_block_move_hints (rtx, rtx, rtx, enum block_op_methods,
  			          unsigned int, HOST_WIDE_INT,
  				  unsigned HOST_WIDE_INT,
+ 				  unsigned HOST_WIDE_INT,
  				  unsigned HOST_WIDE_INT);
  extern bool emit_storent_insn (rtx to, rtx from);
  
*************** extern rtx clear_storage (rtx, rtx, enum
*** 365,370 ****
--- 366,372 ----
  extern rtx clear_storage_hints (rtx, rtx, enum block_op_methods,
  			        unsigned int, HOST_WIDE_INT,
  				unsigned HOST_WIDE_INT,
+ 				unsigned HOST_WIDE_INT,
  				unsigned HOST_WIDE_INT);
  /* The same, but always output an library call.  */
  rtx set_storage_via_libcall (rtx, rtx, rtx, bool);
*************** rtx set_storage_via_libcall (rtx, rtx, r
*** 373,378 ****
--- 375,381 ----
  extern bool set_storage_via_setmem (rtx, rtx, rtx, unsigned int,
  				    unsigned int, HOST_WIDE_INT,
  				    unsigned HOST_WIDE_INT,
+ 				    unsigned HOST_WIDE_INT,
  				    unsigned HOST_WIDE_INT);
  
  extern unsigned HOST_WIDE_INT move_by_pieces_ninsns (unsigned HOST_WIDE_INT,
Index: config/i386/i386.md
===================================================================
*** config/i386/i386.md	(revision 204945)
--- config/i386/i386.md	(working copy)
***************
*** 15506,15518 ****
     (use (match_operand:SI 4 "const_int_operand"))
     (use (match_operand:SI 5 "const_int_operand"))
     (use (match_operand:SI 6 ""))
!    (use (match_operand:SI 7 ""))]
    ""
  {
   if (ix86_expand_set_or_movmem (operands[0], operands[1],
  			        operands[2], NULL, operands[3],
  			        operands[4], operands[5],
! 				operands[6], operands[7], false))
     DONE;
   else
     FAIL;
--- 15506,15520 ----
     (use (match_operand:SI 4 "const_int_operand"))
     (use (match_operand:SI 5 "const_int_operand"))
     (use (match_operand:SI 6 ""))
!    (use (match_operand:SI 7 ""))
!    (use (match_operand:SI 8 ""))]
    ""
  {
   if (ix86_expand_set_or_movmem (operands[0], operands[1],
  			        operands[2], NULL, operands[3],
  			        operands[4], operands[5],
! 				operands[6], operands[7],
! 				operands[8], false))
     DONE;
   else
     FAIL;
***************
*** 15702,15715 ****
      (use (match_operand:SI 4 "const_int_operand"))
      (use (match_operand:SI 5 "const_int_operand"))
      (use (match_operand:SI 6 ""))
!     (use (match_operand:SI 7 ""))]
    ""
  {
   if (ix86_expand_set_or_movmem (operands[0], NULL,
  			        operands[1], operands[2],
  				operands[3], operands[4],
  			        operands[5], operands[6],
! 				operands[7], true))
     DONE;
   else
     FAIL;
--- 15704,15718 ----
      (use (match_operand:SI 4 "const_int_operand"))
      (use (match_operand:SI 5 "const_int_operand"))
      (use (match_operand:SI 6 ""))
!     (use (match_operand:SI 7 ""))
!     (use (match_operand:SI 8 ""))]
    ""
  {
   if (ix86_expand_set_or_movmem (operands[0], NULL,
  			        operands[1], operands[2],
  				operands[3], operands[4],
  			        operands[5], operands[6],
! 				operands[7], operands[8], true))
     DONE;
   else
     FAIL;
Index: config/i386/i386-protos.h
===================================================================
*** config/i386/i386-protos.h	(revision 204945)
--- config/i386/i386-protos.h	(working copy)
*************** extern int avx_vperm2f128_parallel (rtx
*** 60,66 ****
  
  extern bool ix86_expand_strlen (rtx, rtx, rtx, rtx);
  extern bool ix86_expand_set_or_movmem (rtx, rtx, rtx, rtx, rtx, rtx,
! 				       rtx, rtx, rtx, bool);
  
  extern bool constant_address_p (rtx);
  extern bool legitimate_pic_operand_p (rtx);
--- 60,66 ----
  
  extern bool ix86_expand_strlen (rtx, rtx, rtx, rtx);
  extern bool ix86_expand_set_or_movmem (rtx, rtx, rtx, rtx, rtx, rtx,
! 				       rtx, rtx, rtx, rtx, bool);
  
  extern bool constant_address_p (rtx);
  extern bool legitimate_pic_operand_p (rtx);
Index: config/i386/i386.c
===================================================================
*** config/i386/i386.c	(revision 204945)
--- config/i386/i386.c	(working copy)
*************** bool
*** 23711,23717 ****
  ix86_expand_set_or_movmem (rtx dst, rtx src, rtx count_exp, rtx val_exp,
  			   rtx align_exp, rtx expected_align_exp,
  			   rtx expected_size_exp, rtx min_size_exp,
! 			   rtx max_size_exp, bool issetmem)
  {
    rtx destreg;
    rtx srcreg = NULL;
--- 23711,23718 ----
  ix86_expand_set_or_movmem (rtx dst, rtx src, rtx count_exp, rtx val_exp,
  			   rtx align_exp, rtx expected_align_exp,
  			   rtx expected_size_exp, rtx min_size_exp,
! 			   rtx max_size_exp, rtx probable_max_size_exp,
! 			   bool issetmem)
  {
    rtx destreg;
    rtx srcreg = NULL;
*************** ix86_expand_set_or_movmem (rtx dst, rtx
*** 23735,23740 ****
--- 23736,23742 ----
    /* TODO: Once vlaue ranges are available, fill in proper data.  */
    unsigned HOST_WIDE_INT min_size = 0;
    unsigned HOST_WIDE_INT max_size = -1;
+   unsigned HOST_WIDE_INT probable_max_size = -1;
    bool misaligned_prologue_used = false;
  
    if (CONST_INT_P (align_exp))
*************** ix86_expand_set_or_movmem (rtx dst, rtx
*** 23750,23762 ****
      align = MEM_ALIGN (dst) / BITS_PER_UNIT;
  
    if (CONST_INT_P (count_exp))
!     min_size = max_size = count = expected_size = INTVAL (count_exp);
!   if (min_size_exp)
!     min_size = INTVAL (min_size_exp);
!   if (max_size_exp)
!     max_size = INTVAL (max_size_exp);
!   if (CONST_INT_P (expected_size_exp) && count == 0)
!     expected_size = INTVAL (expected_size_exp);
  
    /* Make sure we don't need to care about overflow later on.  */
    if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
--- 23752,23770 ----
      align = MEM_ALIGN (dst) / BITS_PER_UNIT;
  
    if (CONST_INT_P (count_exp))
!     min_size = max_size = probable_max_size = count = expected_size
!       = INTVAL (count_exp);
!   else
!     {
!       if (min_size_exp)
! 	min_size = INTVAL (min_size_exp);
!       if (max_size_exp)
! 	max_size = INTVAL (max_size_exp);
!       if (probable_max_size_exp)
! 	probable_max_size = INTVAL (probable_max_size_exp);
!       if (CONST_INT_P (expected_size_exp) && count == 0)
! 	expected_size = INTVAL (expected_size_exp);
!      }
  
    /* Make sure we don't need to care about overflow later on.  */
    if (count > ((unsigned HOST_WIDE_INT) 1 << 30))
*************** ix86_expand_set_or_movmem (rtx dst, rtx
*** 23764,23770 ****
  
    /* Step 0: Decide on preferred algorithm, desired alignment and
       size of chunks to be copied by main loop.  */
!   alg = decide_alg (count, expected_size, min_size, max_size, issetmem,
  		    issetmem && val_exp == const0_rtx,
  		    &dynamic_check, &noalign);
    if (alg == libcall)
--- 23772,23779 ----
  
    /* Step 0: Decide on preferred algorithm, desired alignment and
       size of chunks to be copied by main loop.  */
!   alg = decide_alg (count, expected_size, min_size, probable_max_size,
! 		    issetmem,
  		    issetmem && val_exp == const0_rtx,
  		    &dynamic_check, &noalign);
    if (alg == libcall)


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