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]

fix target/19518


This is one of those "how was this ever working" bugs.  While the
PR talks about vectors, I couldn't prove the same thing wouldn't
happen with plain integers.

The main problem is that we said that all integers (and all 
integral vectors) were LEGITIMATE_CONSTANT_P, but then we only
match a subset of them in the insn constraints.  Which would lead
to an invalid insn before we'd get a chance to split them.

Doh.  I just now noticed why this wouldn't happen for integers.
In gen_reload,

  /* If IN is a simple operand, use gen_move_insn.  */
  else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
    emit_insn (gen_move_insn (out, in));
...
  /* Otherwise, just write (set OUT IN) and hope for the best.  */
  else
    emit_insn (gen_rtx_SET (VOIDmode, out, in));

Unfortunately, my eye couldn't make the connection across the span
contained with the ellipsis last night.  But for some inexplicable
reason, CONST_VECTOR doesn't satisfy OBJECT_P.  I'll fix that in a bit.

Oh well.  This is a good change anyway, because previously we were
lying and saying that "hard" integers like "0x123456789012345" were
legitimate, and then having movdi immediately spill them to memory.
Claiming they were legitimate would cause reload, cse, and everyone
else extra work pulling them out of memory only to be dumped back again.


r~


        * config/alpha/alpha.c (alpha_rtx_costs): Handle HIGH.
        (alpha_preferred_reload_class): Handle CONST_VECTOR.
        (alpha_emit_set_const_1): Add no_output parameter; don't emit
        rtl if true.
        (alpha_emit_set_const): Likewise.  Make static.
        (alpha_emit_set_long_const): Make static.
        (alpha_extract_integer): Split out from alpha_expand_mov.
        (alpha_split_const_mov): Likewise.
        (alpha_expand_mov): Use them.  Handle CONST_VECTOR.
        (alpha_legitimate_constant_p): New.
        * config/alpha/alpha-protos.h: Update.
        * config/alpha/alpha.h (REGISTER_MOVE_COST): Correct fp<->gp cost.
        (LEGITIMATE_CONSTANT_P): Re-implement with a function.
        * config/alpha/alpha.md (movsi): Add n alternative.
        (movsi_nt_vms, movdi_er_nofix, movdi_er_fix, movdi_fix): Likewise.
        (mov<VEC>_fix, mov<VEC>_nofix): Add i alternative.
        (splitters for all of the above): Use alpha_split_const_mov.
        * config/alpha/predicates.md (non_add_const_operand): New.
        (non_zero_const_operand): New.
        (input_operand): Use alpha_legitimate_constant_p after reload.

Index: config/alpha/alpha-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha-protos.h,v
retrieving revision 1.59
diff -c -p -d -r1.59 alpha-protos.h
*** config/alpha/alpha-protos.h	23 Dec 2004 08:08:56 -0000	1.59
--- config/alpha/alpha-protos.h	20 Jan 2005 03:49:36 -0000
*************** extern bool alpha_extra_constraint (rtx,
*** 42,47 ****
--- 42,48 ----
  extern rtx alpha_tablejump_addr_vec (rtx);
  extern rtx alpha_tablejump_best_label (rtx);
  
+ extern bool alpha_legitimate_constant_p (rtx);
  extern bool alpha_legitimate_address_p (enum machine_mode, rtx, int);
  extern rtx alpha_legitimize_address (rtx, rtx, enum machine_mode);
  extern rtx alpha_legitimize_reload_address (rtx, enum machine_mode,
*************** extern enum reg_class secondary_reload_c
*** 56,63 ****
  					      enum machine_mode, rtx, int);
  
  extern void alpha_set_memflags (rtx, rtx);
! extern rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT, int);
! extern rtx alpha_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
  extern bool alpha_expand_mov (enum machine_mode, rtx *);
  extern bool alpha_expand_mov_nobwx (enum machine_mode, rtx *);
  extern void alpha_expand_movmisalign (enum machine_mode, rtx *);
--- 57,63 ----
  					      enum machine_mode, rtx, int);
  
  extern void alpha_set_memflags (rtx, rtx);
! extern bool alpha_split_const_mov (enum machine_mode, rtx *);
  extern bool alpha_expand_mov (enum machine_mode, rtx *);
  extern bool alpha_expand_mov_nobwx (enum machine_mode, rtx *);
  extern void alpha_expand_movmisalign (enum machine_mode, rtx *);
Index: config/alpha/alpha.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.c,v
retrieving revision 1.407
diff -c -p -d -r1.407 alpha.c
*** config/alpha/alpha.c	18 Jan 2005 12:01:22 -0000	1.407
--- config/alpha/alpha.c	20 Jan 2005 03:49:39 -0000
*************** alpha_rtx_costs (rtx x, int code, int ou
*** 1384,1389 ****
--- 1384,1394 ----
  	*total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency);
        return true;
  
+     case HIGH:
+       /* This is effectively an add_operand.  */
+       *total = 2;
+       return true;
+ 
      case PLUS:
      case MINUS:
        if (float_mode_p)
*************** alpha_preferred_reload_class(rtx x, enum
*** 1557,1563 ****
      return class;
  
    /* These sorts of constants we can easily drop to memory.  */
!   if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
      {
        if (class == FLOAT_REGS)
  	return NO_REGS;
--- 1562,1570 ----
      return class;
  
    /* These sorts of constants we can easily drop to memory.  */
!   if (GET_CODE (x) == CONST_INT
!       || GET_CODE (x) == CONST_DOUBLE
!       || GET_CODE (x) == CONST_VECTOR)
      {
        if (class == FLOAT_REGS)
  	return NO_REGS;
*************** alpha_set_memflags (rtx insn, rtx ref)
*** 1679,1689 ****
    for_each_rtx (base_ptr, alpha_set_memflags_1, (void *) ref);
  }
  
! /* Internal routine for alpha_emit_set_const to check for N or below insns.  */
  
  static rtx
  alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
! 			HOST_WIDE_INT c, int n)
  {
    HOST_WIDE_INT new;
    int i, bits;
--- 1686,1701 ----
    for_each_rtx (base_ptr, alpha_set_memflags_1, (void *) ref);
  }
  
! static rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT,
! 				 int, bool);
! 
! /* Internal routine for alpha_emit_set_const to check for N or below insns.
!    If NO_OUTPUT is true, then we only check to see if N insns are possible,
!    and return pc_rtx if successful.  */
  
  static rtx
  alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
! 			HOST_WIDE_INT c, int n, bool no_output)
  {
    HOST_WIDE_INT new;
    int i, bits;
*************** alpha_emit_set_const_1 (rtx target, enum
*** 1722,1727 ****
--- 1734,1741 ----
  	     emit_move_insn to gen_movdi.  So instead, since we know exactly
  	     what we want, create it explicitly.  */
  
+ 	  if (no_output)
+ 	    return pc_rtx;
  	  if (target == NULL)
  	    target = gen_reg_rtx (mode);
  	  emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (c)));
*************** alpha_emit_set_const_1 (rtx target, enum
*** 1729,1734 ****
--- 1743,1750 ----
  	}
        else if (n >= 2 + (extra != 0))
  	{
+ 	  if (no_output)
+ 	    return pc_rtx;
  	  if (no_new_pseudos)
  	    {
  	      emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (high << 16)));
*************** alpha_emit_set_const_1 (rtx target, enum
*** 1781,1794 ****
  	 high bits.  */
  
        new = ((c & 0xffff) ^ 0x8000) - 0x8000;
!       if (new != 0
!           && (temp = alpha_emit_set_const (subtarget, mode, c - new, i)) != 0)
! 	return expand_binop (mode, add_optab, temp, GEN_INT (new),
! 			     target, 0, OPTAB_WIDEN);
  
        /* Next try complementing.  */
!       if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0)
! 	return expand_unop (mode, one_cmpl_optab, temp, target, 0);
  
        /* Next try to form a constant and do a left shift.  We can do this
  	 if some low-order bits are zero; the exact_log2 call below tells
--- 1797,1822 ----
  	 high bits.  */
  
        new = ((c & 0xffff) ^ 0x8000) - 0x8000;
!       if (new != 0)
! 	{
!           temp = alpha_emit_set_const (subtarget, mode, c - new, i, no_output);
! 	  if (temp)
! 	    {
! 	      if (no_output)
! 		return temp;
! 	      return expand_binop (mode, add_optab, temp, GEN_INT (new),
! 				   target, 0, OPTAB_WIDEN);
! 	    }
! 	}
  
        /* Next try complementing.  */
!       temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output);
!       if (temp)
! 	{
! 	  if (no_output)
! 	    return temp;
! 	  return expand_unop (mode, one_cmpl_optab, temp, target, 0);
! 	}
  
        /* Next try to form a constant and do a left shift.  We can do this
  	 if some low-order bits are zero; the exact_log2 call below tells
*************** alpha_emit_set_const_1 (rtx target, enum
*** 1799,1814 ****
  	 bits to shift, but try all possibilities in case a ZAPNOT will
  	 be useful.  */
  
!       if ((bits = exact_log2 (c & - c)) > 0)
  	for (; bits > 0; bits--)
! 	  if ((temp = (alpha_emit_set_const
! 		       (subtarget, mode, c >> bits, i))) != 0
! 	      || ((temp = (alpha_emit_set_const
! 			  (subtarget, mode,
! 			   ((unsigned HOST_WIDE_INT) c) >> bits, i)))
! 		  != 0))
! 	    return expand_binop (mode, ashl_optab, temp, GEN_INT (bits),
! 				 target, 0, OPTAB_WIDEN);
  
        /* Now try high-order zero bits.  Here we try the shifted-in bits as
  	 all zero and all ones.  Be careful to avoid shifting outside the
--- 1827,1852 ----
  	 bits to shift, but try all possibilities in case a ZAPNOT will
  	 be useful.  */
  
!       bits = exact_log2 (c & -c);
!       if (bits > 0)
  	for (; bits > 0; bits--)
! 	  {
! 	    new = c >> bits;
! 	    temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
! 	    if (!temp && c < 0)
! 	      {
! 		new = (unsigned HOST_WIDE_INT)c >> bits;
! 		temp = alpha_emit_set_const (subtarget, mode, new,
! 					     i, no_output);
! 	      }
! 	    if (temp)
! 	      {
! 		if (no_output)
! 		  return temp;
! 	        return expand_binop (mode, ashl_optab, temp, GEN_INT (bits),
! 				     target, 0, OPTAB_WIDEN);
! 	      }
! 	  }
  
        /* Now try high-order zero bits.  Here we try the shifted-in bits as
  	 all zero and all ones.  Be careful to avoid shifting outside the
*************** alpha_emit_set_const_1 (rtx target, enum
*** 1816,1850 ****
        /* On narrow hosts, don't shift a 1 into the high bit, since we'll
  	 confuse the recursive call and set all of the high 32 bits.  */
  
!       if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
! 		   - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64))) > 0)
  	for (; bits > 0; bits--)
! 	  if ((temp = alpha_emit_set_const (subtarget, mode,
! 					    c << bits, i)) != 0
! 	      || ((temp = (alpha_emit_set_const
! 			   (subtarget, mode,
! 			    ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)),
! 			    i)))
! 		  != 0))
! 	    return expand_binop (mode, lshr_optab, temp, GEN_INT (bits),
! 				 target, 1, OPTAB_WIDEN);
  
        /* Now try high-order 1 bits.  We get that with a sign-extension.
  	 But one bit isn't enough here.  Be careful to avoid shifting outside
  	 the mode and to avoid shifting outside the host wide int size.  */
  
!       if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
! 		   - floor_log2 (~ c) - 2)) > 0)
  	for (; bits > 0; bits--)
! 	  if ((temp = alpha_emit_set_const (subtarget, mode,
! 					    c << bits, i)) != 0
! 	      || ((temp = (alpha_emit_set_const
! 			   (subtarget, mode,
! 			    ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)),
! 			    i)))
! 		  != 0))
! 	    return expand_binop (mode, ashr_optab, temp, GEN_INT (bits),
! 				 target, 0, OPTAB_WIDEN);
      }
  
  #if HOST_BITS_PER_WIDE_INT == 64
--- 1854,1906 ----
        /* On narrow hosts, don't shift a 1 into the high bit, since we'll
  	 confuse the recursive call and set all of the high 32 bits.  */
  
!       bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
! 	      - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64));
!       if (bits > 0)
  	for (; bits > 0; bits--)
! 	  {
! 	    new = c << bits;
! 	    temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
! 	    if (!temp)
! 	      {
! 		new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1);
! 	        temp = alpha_emit_set_const (subtarget, mode, new,
! 					     i, no_output);
! 	      }
! 	    if (temp)
! 	      {
! 		if (no_output)
! 		  return temp;
! 		return expand_binop (mode, lshr_optab, temp, GEN_INT (bits),
! 				     target, 1, OPTAB_WIDEN);
! 	      }
! 	  }
  
        /* Now try high-order 1 bits.  We get that with a sign-extension.
  	 But one bit isn't enough here.  Be careful to avoid shifting outside
  	 the mode and to avoid shifting outside the host wide int size.  */
  
!       bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
! 	      - floor_log2 (~ c) - 2);
!       if (bits > 0)
  	for (; bits > 0; bits--)
! 	  {
! 	    new = c << bits;
! 	    temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
! 	    if (!temp)
! 	      {
! 		new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1);
! 	        temp = alpha_emit_set_const (subtarget, mode, new,
! 					     i, no_output);
! 	      }
! 	    if (temp)
! 	      {
! 		if (no_output)
! 		  return temp;
! 		return expand_binop (mode, ashr_optab, temp, GEN_INT (bits),
! 				     target, 0, OPTAB_WIDEN);
! 	      }
! 	  }
      }
  
  #if HOST_BITS_PER_WIDE_INT == 64
*************** alpha_emit_set_const_1 (rtx target, enum
*** 1863,1872 ****
    if (mode == SImode)
      new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000;
  
!   if (new != c && new != -1
!       && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0)
!     return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
! 			 target, 0, OPTAB_WIDEN);
  #endif
  
    return 0;
--- 1919,1935 ----
    if (mode == SImode)
      new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000;
  
!   if (new != c)
!     {
!       temp = alpha_emit_set_const (subtarget, mode, new, n - 1, no_output);
!       if (temp)
! 	{
! 	  if (no_output)
! 	    return temp;
! 	  return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
! 			       target, 0, OPTAB_WIDEN);
! 	}
!     }
  #endif
  
    return 0;
*************** alpha_emit_set_const_1 (rtx target, enum
*** 1878,1909 ****
     emitted.  If it would take more than N insns, zero is returned and no
     insns and emitted.  */
  
! rtx
  alpha_emit_set_const (rtx target, enum machine_mode mode,
! 		      HOST_WIDE_INT c, int n)
  {
!   rtx result = 0;
    rtx orig_target = target;
    int i;
  
    /* If we can't make any pseudos, TARGET is an SImode hard register, we
       can't load this constant in one insn, do this in DImode.  */
    if (no_new_pseudos && mode == SImode
!       && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER
!       && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0)
      {
!       target = gen_lowpart (DImode, target);
        mode = DImode;
      }
  
    /* Try 1 insn, then 2, then up to N.  */
    for (i = 1; i <= n; i++)
      {
!       result = alpha_emit_set_const_1 (target, mode, c, i);
        if (result)
  	{
! 	  rtx insn = get_last_insn ();
! 	  rtx set = single_set (insn);
  	  if (! CONSTANT_P (SET_SRC (set)))
  	    set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c));
  	  break;
--- 1941,1986 ----
     emitted.  If it would take more than N insns, zero is returned and no
     insns and emitted.  */
  
! static rtx
  alpha_emit_set_const (rtx target, enum machine_mode mode,
! 		      HOST_WIDE_INT c, int n, bool no_output)
  {
!   enum machine_mode orig_mode = mode;
    rtx orig_target = target;
+   rtx result = 0;
    int i;
  
    /* If we can't make any pseudos, TARGET is an SImode hard register, we
       can't load this constant in one insn, do this in DImode.  */
    if (no_new_pseudos && mode == SImode
!       && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
      {
!       result = alpha_emit_set_const_1 (target, mode, c, 1, no_output);
!       if (result)
! 	return result;
! 
!       target = no_output ? NULL : gen_lowpart (DImode, target);
!       mode = DImode;
!     }
!   else if (mode == V8QImode || mode == V4HImode || mode == V2SImode)
!     {
!       target = no_output ? NULL : gen_lowpart (DImode, target);
        mode = DImode;
      }
  
    /* Try 1 insn, then 2, then up to N.  */
    for (i = 1; i <= n; i++)
      {
!       result = alpha_emit_set_const_1 (target, mode, c, i, no_output);
        if (result)
  	{
! 	  rtx insn, set;
! 
! 	  if (no_output)
! 	    return result;
! 
! 	  insn = get_last_insn ();
! 	  set = single_set (insn);
  	  if (! CONSTANT_P (SET_SRC (set)))
  	    set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c));
  	  break;
*************** alpha_emit_set_const (rtx target, enum m
*** 1911,1918 ****
      }
  
    /* Allow for the case where we changed the mode of TARGET.  */
!   if (result == target)
!     result = orig_target;
  
    return result;
  }
--- 1988,2000 ----
      }
  
    /* Allow for the case where we changed the mode of TARGET.  */
!   if (result)
!     {
!       if (result == target)
! 	result = orig_target;
!       else if (mode != orig_mode)
! 	result = gen_lowpart (orig_mode, result);
!     }
  
    return result;
  }
*************** alpha_emit_set_const (rtx target, enum m
*** 1922,1928 ****
     exponential run times encountered when looking for longer sequences
     with alpha_emit_set_const.  */
  
! rtx
  alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
  {
    HOST_WIDE_INT d1, d2, d3, d4;
--- 2004,2010 ----
     exponential run times encountered when looking for longer sequences
     with alpha_emit_set_const.  */
  
! static rtx
  alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
  {
    HOST_WIDE_INT d1, d2, d3, d4;
*************** alpha_emit_set_long_const (rtx target, H
*** 1976,1981 ****
--- 2058,2171 ----
    return target;
  }
  
+ /* Given an integral CONST_INT, CONST_DOUBLE, or CONST_VECTOR, return 
+    the low 64 bits.  */
+ 
+ static void
+ alpha_extract_integer (rtx x, HOST_WIDE_INT *p0, HOST_WIDE_INT *p1)
+ {
+   HOST_WIDE_INT i0, i1;
+ 
+   if (GET_CODE (x) == CONST_VECTOR)
+     x = simplify_subreg (DImode, x, GET_MODE (x), 0);
+ 
+ 
+   if (GET_CODE (x) == CONST_INT)
+     {
+       i0 = INTVAL (x);
+       i1 = -(i0 < 0);
+     }
+   else if (HOST_BITS_PER_WIDE_INT >= 64)
+     {
+       i0 = CONST_DOUBLE_LOW (x);
+       i1 = -(i0 < 0);
+     }
+   else
+     {
+       i0 = CONST_DOUBLE_LOW (x);
+       i1 = CONST_DOUBLE_HIGH (x);
+     }
+ 
+   *p0 = i0;
+   *p1 = i1;
+ }
+ 
+ /* Implement LEGITIMATE_CONSTANT_P.  This is all constants for which we
+    are willing to load the value into a register via a move pattern.
+    Normally this is all symbolic constants, integral constants that
+    take three or fewer instructions, and floating-point zero.  */
+ 
+ bool
+ alpha_legitimate_constant_p (rtx x)
+ {
+   enum machine_mode mode = GET_MODE (x);
+   HOST_WIDE_INT i0, i1;
+ 
+   switch (GET_CODE (x))
+     {
+     case CONST:
+     case LABEL_REF:
+     case SYMBOL_REF:
+     case HIGH:
+       return true;
+ 
+     case CONST_DOUBLE:
+       if (x == CONST0_RTX (mode))
+ 	return true;
+       if (FLOAT_MODE_P (mode))
+ 	return false;
+       goto do_integer;
+ 
+     case CONST_VECTOR:
+       if (x == CONST0_RTX (mode))
+ 	return true;
+       if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
+ 	return false;
+       if (GET_MODE_SIZE (mode) != 8)
+ 	return false;
+       goto do_integer;
+ 
+     case CONST_INT:
+     do_integer:
+       if (TARGET_BUILD_CONSTANTS)
+ 	return true;
+       alpha_extract_integer (x, &i0, &i1);
+       if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == (-i0 < 0))
+         return alpha_emit_set_const_1 (x, mode, i0, 3, true) != NULL;
+       return false;
+ 
+     default:
+       return false;
+     }
+ }
+ 
+ /* Operand 1 is known to be a constant, and should require more than one
+    instruction to load.  Emit that multi-part load.  */
+ 
+ bool
+ alpha_split_const_mov (enum machine_mode mode, rtx *operands)
+ {
+   HOST_WIDE_INT i0, i1;
+   rtx temp = NULL_RTX;
+ 
+   alpha_extract_integer (operands[1], &i0, &i1);
+ 
+   if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
+     temp = alpha_emit_set_const (operands[0], mode, i0, 3, false);
+ 
+   if (!temp && TARGET_BUILD_CONSTANTS)
+     temp = alpha_emit_set_long_const (operands[0], i0, i1);
+ 
+   if (temp)
+     {
+       if (!rtx_equal_p (operands[0], temp))
+ 	emit_move_insn (operands[0], temp);
+       return true;
+     }
+ 
+   return false;
+ }
+ 
  /* Expand a move instruction; return true if all work is done.
     We don't handle non-bwx subword loads here.  */
  
*************** alpha_expand_mov (enum machine_mode mode
*** 2008,2047 ****
  
    /* Split large integers.  */
    if (GET_CODE (operands[1]) == CONST_INT
!       || GET_CODE (operands[1]) == CONST_DOUBLE)
      {
!       HOST_WIDE_INT i0, i1;
!       rtx temp = NULL_RTX;
! 
!       if (GET_CODE (operands[1]) == CONST_INT)
! 	{
! 	  i0 = INTVAL (operands[1]);
! 	  i1 = -(i0 < 0);
! 	}
!       else if (HOST_BITS_PER_WIDE_INT >= 64)
! 	{
! 	  i0 = CONST_DOUBLE_LOW (operands[1]);
! 	  i1 = -(i0 < 0);
! 	}
!       else
! 	{
! 	  i0 = CONST_DOUBLE_LOW (operands[1]);
! 	  i1 = CONST_DOUBLE_HIGH (operands[1]);
! 	}
! 
!       if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
! 	temp = alpha_emit_set_const (operands[0], mode, i0, 3);
! 
!       if (!temp && TARGET_BUILD_CONSTANTS)
! 	temp = alpha_emit_set_long_const (operands[0], i0, i1);
! 
!       if (temp)
! 	{
! 	  if (rtx_equal_p (operands[0], temp))
! 	    return true;
! 	  operands[1] = temp;
! 	  return false;
! 	}
      }
  
    /* Otherwise we've nothing left but to drop the thing to memory.  */
--- 2198,2208 ----
  
    /* Split large integers.  */
    if (GET_CODE (operands[1]) == CONST_INT
!       || GET_CODE (operands[1]) == CONST_DOUBLE
!       || GET_CODE (operands[1]) == CONST_VECTOR)
      {
!       if (alpha_split_const_mov (mode, operands))
! 	return true;
      }
  
    /* Otherwise we've nothing left but to drop the thing to memory.  */
*************** alpha_expand_epilogue (void)
*** 7029,7035 ****
        else
  	{
  	  rtx tmp = gen_rtx_REG (DImode, 23);
! 	  FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3));
  	  if (!sp_adj2)
  	    {
  	      /* We can't drop new things to memory this late, afaik,
--- 7190,7197 ----
        else
  	{
  	  rtx tmp = gen_rtx_REG (DImode, 23);
! 	  FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size,
! 					       3, false));
  	  if (!sp_adj2)
  	    {
  	      /* We can't drop new things to memory this late, afaik,
Index: config/alpha/alpha.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.h,v
retrieving revision 1.236
diff -c -p -d -r1.236 alpha.h
*** config/alpha/alpha.h	30 Dec 2004 03:07:39 -0000	1.236
--- config/alpha/alpha.h	20 Jan 2005 03:49:40 -0000
*************** enum reg_class {
*** 884,893 ****
     reduce the impact of not being able to allocate a pseudo to a
     hard register.  */
  
! #define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2)	\
!   (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS)	\
!    ? 2							\
!    : TARGET_FIX ? 3 : 4+2*alpha_memory_latency)
  
  /* A C expressions returning the cost of moving data of MODE from a register to
     or from memory.
--- 884,893 ----
     reduce the impact of not being able to allocate a pseudo to a
     hard register.  */
  
! #define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2)		\
!   (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS)	? 2	\
!    : TARGET_FIX ? ((CLASS1) == FLOAT_REGS ? 6 : 8)		\
!    : 4+2*alpha_memory_latency)
  
  /* A C expressions returning the cost of moving data of MODE from a register to
     or from memory.
*************** do {						\
*** 1213,1221 ****
  /* Include all constant integers and constant doubles, but not
     floating-point, except for floating-point zero.  */
  
! #define LEGITIMATE_CONSTANT_P(X)  		\
!   (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT	\
!    || (X) == CONST0_RTX (GET_MODE (X)))
  
  /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
     and check its validity for a certain class.
--- 1213,1219 ----
  /* Include all constant integers and constant doubles, but not
     floating-point, except for floating-point zero.  */
  
! #define LEGITIMATE_CONSTANT_P  alpha_legitimate_constant_p
  
  /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
     and check its validity for a certain class.
Index: config/alpha/alpha.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.md,v
retrieving revision 1.231
diff -c -p -d -r1.231 alpha.md
*** config/alpha/alpha.md	23 Dec 2004 10:32:42 -0000	1.231
--- config/alpha/alpha.md	20 Jan 2005 03:49:43 -0000
***************
*** 5128,5135 ****
  })
  
  (define_insn "*movsi"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m")
! 	(match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ"))]
    "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK)
     && (register_operand (operands[0], SImode)
         || reg_or_0_operand (operands[1], SImode))"
--- 5128,5135 ----
  })
  
  (define_insn "*movsi"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m")
! 	(match_operand:SI 1 "input_operand" "rJ,K,L,n,m,rJ"))]
    "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK)
     && (register_operand (operands[0], SImode)
         || reg_or_0_operand (operands[1], SImode))"
***************
*** 5137,5149 ****
     bis $31,%r1,%0
     lda %0,%1($31)
     ldah %0,%h1($31)
     ldl %0,%1
     stl %r1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,ild,ist")])
  
  (define_insn "*movsi_nt_vms"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m")
! 	(match_operand:SI 1 "input_operand" "rJ,K,L,s,m,rJ"))]
    "(TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS)
      && (register_operand (operands[0], SImode)
          || reg_or_0_operand (operands[1], SImode))"
--- 5137,5150 ----
     bis $31,%r1,%0
     lda %0,%1($31)
     ldah %0,%h1($31)
+    #
     ldl %0,%1
     stl %r1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,multi,ild,ist")])
  
  (define_insn "*movsi_nt_vms"
!   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m")
! 	(match_operand:SI 1 "input_operand" "rJ,K,L,s,n,m,rJ"))]
    "(TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS)
      && (register_operand (operands[0], SImode)
          || reg_or_0_operand (operands[1], SImode))"
***************
*** 5152,5160 ****
     lda %0,%1
     ldah %0,%h1
     lda %0,%1
     ldl %0,%1
     stl %r1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist")])
  
  (define_insn "*movhi_nobwx"
    [(set (match_operand:HI 0 "register_operand" "=r,r")
--- 5153,5162 ----
     lda %0,%1
     ldah %0,%h1
     lda %0,%1
+    #
     ldl %0,%1
     stl %r1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist")])
  
  (define_insn "*movhi_nobwx"
    [(set (match_operand:HI 0 "register_operand" "=r,r")
***************
*** 5221,5235 ****
  
  (define_split
    [(set (match_operand:SI 0 "register_operand" "")
! 	(match_operand:SI 1 "const_int_operand" ""))]
!   "! add_operand (operands[1], SImode)"
!   [(set (match_dup 0) (match_dup 2))
!    (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))]
  {
!   rtx tem
!     = alpha_emit_set_const (operands[0], SImode, INTVAL (operands[1]), 2);
! 
!   if (tem == operands[0])
      DONE;
    else
      FAIL;
--- 5223,5233 ----
  
  (define_split
    [(set (match_operand:SI 0 "register_operand" "")
! 	(match_operand:SI 1 "non_add_const_operand" ""))]
!   ""
!   [(const_int 0)]
  {
!   if (alpha_split_const_mov (SImode, operands))
      DONE;
    else
      FAIL;
***************
*** 5452,5459 ****
  })
  
  (define_insn "*movdi_er_nofix"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
! 	(match_operand:DI 1 "input_operand" "rJ,K,L,T,s,m,rJ,*fJ,Q,*f"))]
    "TARGET_EXPLICIT_RELOCS && ! TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
--- 5450,5457 ----
  })
  
  (define_insn "*movdi_er_nofix"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q")
! 	(match_operand:DI 1 "input_operand" "rJ,K,L,T,s,n,m,rJ,*fJ,Q,*f"))]
    "TARGET_EXPLICIT_RELOCS && ! TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
***************
*** 5463,5483 ****
     ldah %0,%h1($31)
     #
     #
     ldq%A1 %0,%1
     stq%A0 %r1,%0
     fmov %R1,%0
     ldt %0,%1
     stt %R1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")
!    (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*")])
  
  ;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should
  ;; have been split up by the rules above but we shouldn't reject the
  ;; possibility of them getting through.
  
  (define_insn "*movdi_nofix"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
! 	(match_operand:DI 1 "input_operand" "rJ,K,L,U,s,m,rJ,*fJ,Q,*f"))]
    "! TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
--- 5461,5482 ----
     ldah %0,%h1($31)
     #
     #
+    #
     ldq%A1 %0,%1
     stq%A0 %r1,%0
     fmov %R1,%0
     ldt %0,%1
     stt %R1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst")
!    (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*")])
  
  ;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should
  ;; have been split up by the rules above but we shouldn't reject the
  ;; possibility of them getting through.
  
  (define_insn "*movdi_nofix"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q")
! 	(match_operand:DI 1 "input_operand" "rJ,K,L,U,s,n,m,rJ,*fJ,Q,*f"))]
    "! TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
***************
*** 5487,5505 ****
     ldah %0,%h1($31)
     laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0)
     lda %0,%1
     ldq%A1 %0,%1
     stq%A0 %r1,%0
     cpys %R1,%R1,%0
     ldt %0,%1
     stt %R1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,ild,ist,fcpys,fld,fst")
!    (set_attr "length" "*,*,*,16,*,*,*,*,*,*")])
  
  (define_insn "*movdi_er_fix"
    [(set (match_operand:DI 0 "nonimmediate_operand"
! 				"=r,r,r,r,r,r, m, *f,*f, Q, r,*f")
  	(match_operand:DI 1 "input_operand"
! 				"rJ,K,L,T,s,m,rJ,*fJ, Q,*f,*f, r"))]
    "TARGET_EXPLICIT_RELOCS && TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
--- 5486,5505 ----
     ldah %0,%h1($31)
     laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0)
     lda %0,%1
+    #
     ldq%A1 %0,%1
     stq%A0 %r1,%0
     cpys %R1,%R1,%0
     ldt %0,%1
     stt %R1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,multi,ild,ist,fcpys,fld,fst")
!    (set_attr "length" "*,*,*,16,*,*,*,*,*,*,*")])
  
  (define_insn "*movdi_er_fix"
    [(set (match_operand:DI 0 "nonimmediate_operand"
! 				"=r,r,r,r,r,r,r, m, *f,*f, Q, r,*f")
  	(match_operand:DI 1 "input_operand"
! 				"rJ,K,L,T,s,n,m,rJ,*fJ, Q,*f,*f, r"))]
    "TARGET_EXPLICIT_RELOCS && TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
***************
*** 5509,5514 ****
--- 5509,5515 ----
     ldah %0,%h1($31)
     #
     #
+    #
     ldq%A1 %0,%1
     stq%A0 %r1,%0
     fmov %R1,%0
***************
*** 5516,5527 ****
     stt %R1,%0
     ftoit %1,%0
     itoft %1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")
!    (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*,*")])
  
  (define_insn "*movdi_fix"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q,r,*f")
! 	(match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f,*f,r"))]
    "! TARGET_EXPLICIT_RELOCS && TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
--- 5517,5528 ----
     stt %R1,%0
     ftoit %1,%0
     itoft %1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof")
!    (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*,*,*")])
  
  (define_insn "*movdi_fix"
!   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q,r,*f")
! 	(match_operand:DI 1 "input_operand" "rJ,K,L,s,n,m,rJ,*fJ,Q,*f,*f,r"))]
    "! TARGET_EXPLICIT_RELOCS && TARGET_FIX
     && (register_operand (operands[0], DImode)
         || reg_or_0_operand (operands[1], DImode))"
***************
*** 5530,5535 ****
--- 5531,5537 ----
     lda %0,%1($31)
     ldah %0,%h1($31)
     lda %0,%1
+    #
     ldq%A1 %0,%1
     stq%A0 %r1,%0
     cpys %R1,%R1,%0
***************
*** 5537,5543 ****
     stt %R1,%0
     ftoit %1,%0
     itoft %1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")])
  
  ;; VMS needs to set up "vms_base_regno" for unwinding.  This move
  ;; often appears dead to the life analysis code, at which point we
--- 5539,5545 ----
     stt %R1,%0
     ftoit %1,%0
     itoft %1,%0"
!   [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof")])
  
  ;; VMS needs to set up "vms_base_regno" for unwinding.  This move
  ;; often appears dead to the life analysis code, at which point we
***************
*** 5568,5582 ****
  
  (define_split
    [(set (match_operand:DI 0 "register_operand" "")
! 	(match_operand:DI 1 "const_int_operand" ""))]
!   "! add_operand (operands[1], DImode)"
!   [(set (match_dup 0) (match_dup 2))
!    (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))]
  {
!   rtx tem
!     = alpha_emit_set_const (operands[0], DImode, INTVAL (operands[1]), 2);
! 
!   if (tem == operands[0])
      DONE;
    else
      FAIL;
--- 5570,5580 ----
  
  (define_split
    [(set (match_operand:DI 0 "register_operand" "")
! 	(match_operand:DI 1 "non_add_const_operand" ""))]
!   ""
!   [(const_int 0)]
  {
!   if (alpha_split_const_mov (DImode, operands))
      DONE;
    else
      FAIL;
***************
*** 6103,6108 ****
--- 6101,6119 ----
      DONE;
  })
  
+ (define_split
+   [(set (match_operand:VEC 0 "register_operand" "")
+ 	(match_operand:VEC 1 "non_zero_const_operand" ""))]
+   ""
+   [(const_int 0)]
+ {
+   if (alpha_split_const_mov (<MODE>mode, operands))
+     DONE;
+   else
+     FAIL;
+ })
+ 
+ 
  (define_expand "movmisalign<mode>"
    [(set (match_operand:VEC 0 "nonimmediate_operand" "")
          (match_operand:VEC 1 "general_operand" ""))]
***************
*** 6113,6125 ****
  })
  
  (define_insn "*mov<mode>_fix"
!   [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,m,*f,*f,m,r,*f")
! 	(match_operand:VEC 1 "input_operand" "rW,m,rW,*fW,m,*f,*f,r"))]
    "TARGET_FIX
     && (register_operand (operands[0], <MODE>mode)
         || reg_or_0_operand (operands[1], <MODE>mode))"
    "@
     bis $31,%r1,%0
     ldq %0,%1
     stq %r1,%0
     cpys %R1,%R1,%0
--- 6124,6137 ----
  })
  
  (define_insn "*mov<mode>_fix"
!   [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m,r,*f")
! 	(match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f,*f,r"))]
    "TARGET_FIX
     && (register_operand (operands[0], <MODE>mode)
         || reg_or_0_operand (operands[1], <MODE>mode))"
    "@
     bis $31,%r1,%0
+    #
     ldq %0,%1
     stq %r1,%0
     cpys %R1,%R1,%0
***************
*** 6127,6148 ****
     stt %R1,%0
     ftoit %1,%0
     itoft %1,%0"
!   [(set_attr "type" "ilog,ild,ist,fcpys,fld,fst,ftoi,itof")])
  
  (define_insn "*mov<mode>_nofix"
!   [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,m,*f,*f,m")
! 	(match_operand:VEC 1 "input_operand" "rW,m,rW,*fW,m,*f"))]
    "! TARGET_FIX
     && (register_operand (operands[0], <MODE>mode)
         || reg_or_0_operand (operands[1], <MODE>mode))"
    "@
     bis $31,%r1,%0
     ldq %0,%1
     stq %r1,%0
     cpys %R1,%R1,%0
     ldt %0,%1
     stt %R1,%0"
!   [(set_attr "type" "ilog,ild,ist,fcpys,fld,fst")])
  
  (define_insn "uminv8qi3"
    [(set (match_operand:V8QI 0 "register_operand" "=r")
--- 6139,6161 ----
     stt %R1,%0
     ftoit %1,%0
     itoft %1,%0"
!   [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst,ftoi,itof")])
  
  (define_insn "*mov<mode>_nofix"
!   [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m")
! 	(match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f"))]
    "! TARGET_FIX
     && (register_operand (operands[0], <MODE>mode)
         || reg_or_0_operand (operands[1], <MODE>mode))"
    "@
     bis $31,%r1,%0
+    #
     ldq %0,%1
     stq %r1,%0
     cpys %R1,%R1,%0
     ldt %0,%1
     stt %R1,%0"
!   [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst")])
  
  (define_insn "uminv8qi3"
    [(set (match_operand:V8QI 0 "register_operand" "=r")
Index: config/alpha/predicates.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/predicates.md,v
retrieving revision 1.2
diff -c -p -d -r1.2 predicates.md
*** config/alpha/predicates.md	20 Sep 2004 20:13:39 -0000	1.2
--- config/alpha/predicates.md	20 Jan 2005 03:49:43 -0000
***************
*** 66,71 ****
--- 66,82 ----
  		 || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O')")
      (match_operand 0 "register_operand")))
  
+ ;; Return 1 if the operand is a non-symbolic constant operand that
+ ;; does not satisfy add_operand.
+ (define_predicate "non_add_const_operand"
+   (and (match_code "const_int,const_double,const_vector")
+        (not (match_operand 0 "add_operand"))))
+ 
+ ;; Return 1 if the operand is a non-symbolic, non-zero constant operand.
+ (define_predicate "non_zero_const_operand"
+   (and (match_code "const_int,const_double,const_vector")
+        (match_test "op != CONST0_RTX (mode)")))
+ 
  ;; Return 1 if OP is the constant 4 or 8.
  (define_predicate "const48_operand"
    (and (match_code "const_int")
***************
*** 205,215 ****
  	      && general_operand (op, mode));
  
      case CONST_DOUBLE:
      case CONST_VECTOR:
        return op == CONST0_RTX (mode);
  
      case CONST_INT:
!       return mode == QImode || mode == HImode || add_operand (op, mode);
  
      default:
        abort ();
--- 216,234 ----
  	      && general_operand (op, mode));
  
      case CONST_DOUBLE:
+       return op == CONST0_RTX (mode);
+ 
      case CONST_VECTOR:
+       if (reload_in_progress || reload_completed)
+ 	return alpha_legitimate_constant_p (op);
        return op == CONST0_RTX (mode);
  
      case CONST_INT:
!       if (mode == QImode || mode == HImode)
! 	return true;
!       if (reload_in_progress || reload_completed)
! 	return alpha_legitimate_constant_p (op);
!       return add_operand (op, mode);
  
      default:
        abort ();


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