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]

Add conditional addition patterns


Hi,
We define inccc/deccc patterns but have no way to generate them.  i386 has
limited support for conditional increment and decrement and it is dificult to
set it up in combine from setcc patterns.  This patch adds new named pattern
addMcc that can be used to define generic conditional add.

Bootstrapped/regtested BIB branch with conditional add implemented.
Honza

Fri Nov 22 01:25:59 CET 2002  Jan Hubicka  <jh@suse.cz>
	* genopinit.c (optabs): Add addc_optab.
	* ifcvt.c (noce_try_store_flag): Rename to ...
	(noce_try_addcc): ... this one; handle generic conditional increment.
	(noce_process_if_block): Update noce_try_addcc call.
	* optabs.c (emit_conditional_add): New.
	(init_obtabs): Initialize addc_optab.
	* optabs.h (optab_index): Add OTI_addcc.
	(addcc_optab): New macro.
	* md.texi: Document addMcc

*** genopinit.c.old	Fri Nov 22 00:51:24 2002
--- genopinit.c	Fri Nov 22 00:52:44 2002
*************** static const char * const optabs[] =
*** 128,133 ****
--- 128,134 ----
    "movstrict_optab->handlers[$A].insn_code = CODE_FOR_$(movstrict$a$)",
    "cmp_optab->handlers[$A].insn_code = CODE_FOR_$(cmp$a$)",
    "tst_optab->handlers[$A].insn_code = CODE_FOR_$(tst$a$)",
+   "addcc_optab->handlers[$A].insn_code = CODE_FOR_$(add$acc$)",
    "bcc_gen_fctn[$C] = gen_$(b$c$)",
    "setcc_gen_code[$C] = CODE_FOR_$(s$c$)",
    "movcc_gen_code[$A] = CODE_FOR_$(mov$acc$)",
*** ifcvt.c.old	Thu Nov 21 23:13:16 2002
--- ifcvt.c	Fri Nov 22 00:46:02 2002
*************** struct noce_if_info
*** 580,586 ****
  static rtx noce_emit_store_flag		PARAMS ((struct noce_if_info *,
  						 rtx, int, int));
  static int noce_try_store_flag		PARAMS ((struct noce_if_info *));
! static int noce_try_store_flag_inc	PARAMS ((struct noce_if_info *));
  static int noce_try_store_flag_constants PARAMS ((struct noce_if_info *));
  static int noce_try_store_flag_mask	PARAMS ((struct noce_if_info *));
  static rtx noce_emit_cmove		PARAMS ((struct noce_if_info *,
--- 580,586 ----
  static rtx noce_emit_store_flag		PARAMS ((struct noce_if_info *,
  						 rtx, int, int));
  static int noce_try_store_flag		PARAMS ((struct noce_if_info *));
! static int noce_try_addcc		PARAMS ((struct noce_if_info *));
  static int noce_try_store_flag_constants PARAMS ((struct noce_if_info *));
  static int noce_try_store_flag_mask	PARAMS ((struct noce_if_info *));
  static rtx noce_emit_cmove		PARAMS ((struct noce_if_info *,
*************** noce_try_store_flag_constants (if_info)
*** 862,904 ****
     similarly for "foo--".  */
  
  static int
! noce_try_store_flag_inc (if_info)
       struct noce_if_info *if_info;
  {
    rtx target, seq;
    int subtract, normalize;
  
    if (! no_new_pseudos
-       && (BRANCH_COST >= 2
- 	  || HAVE_incscc
- 	  || HAVE_decscc)
        /* Should be no `else' case to worry about.  */
        && if_info->b == if_info->x
        && GET_CODE (if_info->a) == PLUS
-       && (XEXP (if_info->a, 1) == const1_rtx
- 	  || XEXP (if_info->a, 1) == constm1_rtx)
        && rtx_equal_p (XEXP (if_info->a, 0), if_info->x)
        && (reversed_comparison_code (if_info->cond, if_info->jump)
  	  != UNKNOWN))
      {
!       if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
! 	subtract = 0, normalize = 0;
!       else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
! 	subtract = 1, normalize = 0;
!       else
! 	subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
!       
!       start_sequence ();
  
!       target = noce_emit_store_flag (if_info,
! 				     gen_reg_rtx (GET_MODE (if_info->x)),
! 				     1, normalize);
! 
!       if (target)
! 	target = expand_simple_binop (GET_MODE (if_info->x),
! 				      subtract ? MINUS : PLUS,
! 				      if_info->x, target, if_info->x,
! 				      0, OPTAB_WIDEN);
        if (target)
  	{
  	  if (target != if_info->x)
--- 862,893 ----
     similarly for "foo--".  */
  
  static int
! noce_try_addcc (if_info)
       struct noce_if_info *if_info;
  {
    rtx target, seq;
    int subtract, normalize;
  
    if (! no_new_pseudos
        /* Should be no `else' case to worry about.  */
        && if_info->b == if_info->x
        && GET_CODE (if_info->a) == PLUS
        && rtx_equal_p (XEXP (if_info->a, 0), if_info->x)
        && (reversed_comparison_code (if_info->cond, if_info->jump)
  	  != UNKNOWN))
      {
!       rtx cond = if_info->cond;
!       enum rtx_code code = reversed_comparison_code (cond, if_info->jump);
  
!       /* First try to use addcc pattern.  */
!       start_sequence ();
!       target = emit_conditional_add (if_info->x, code,
! 				     XEXP (cond, 0), XEXP (cond, 1),
! 				     VOIDmode,
! 				     if_info->b, XEXP (if_info->a, 1),
! 				     GET_MODE (if_info->x),
! 				     (code == LTU || code == GEU
! 				      || code == LEU || code == GTU));
        if (target)
  	{
  	  if (target != if_info->x)
*************** noce_try_store_flag_inc (if_info)
*** 906,922 ****
  
  	  seq = get_insns ();
  	  end_sequence ();
- 
- 	  if (seq_contains_jump (seq))
- 	    return FALSE;
- 
  	  emit_insn_before_scope (seq, if_info->jump,
  				  INSN_SCOPE (if_info->insn_a));
- 
  	  return TRUE;
  	}
- 
        end_sequence ();
      }
  
    return FALSE;
--- 895,948 ----
  
  	  seq = get_insns ();
  	  end_sequence ();
  	  emit_insn_before_scope (seq, if_info->jump,
  				  INSN_SCOPE (if_info->insn_a));
  	  return TRUE;
  	}
        end_sequence ();
+ 	
+       /* If that fails, construct conditional increment or decrement using
+ 	 setcc.  */
+       if (BRANCH_COST >= 2
+ 	  && (XEXP (if_info->a, 1) == const1_rtx
+ 	      || XEXP (if_info->a, 1) == constm1_rtx))
+         {
+ 	  start_sequence ();
+ 	  if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
+ 	    subtract = 0, normalize = 0;
+ 	  else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
+ 	    subtract = 1, normalize = 0;
+ 	  else
+ 	    subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
+ 
+ 
+ 	  target = noce_emit_store_flag (if_info,
+ 					 gen_reg_rtx (GET_MODE (if_info->x)),
+ 					 1, normalize);
+ 
+ 	  if (target)
+ 	    target = expand_simple_binop (GET_MODE (if_info->x),
+ 					  subtract ? MINUS : PLUS,
+ 					  if_info->x, target, if_info->x,
+ 					  0, OPTAB_WIDEN);
+ 	  if (target)
+ 	    {
+ 	      if (target != if_info->x)
+ 		noce_emit_move_insn (if_info->x, target);
+ 
+ 	      seq = get_insns ();
+ 	      end_sequence ();
+ 
+ 	      if (seq_contains_jump (seq))
+ 		return FALSE;
+ 
+ 	      emit_insn_before_scope (seq, if_info->jump,
+ 				      INSN_SCOPE (if_info->insn_a));
+ 
+ 	      return TRUE;
+ 	    }
+ 	  end_sequence ();
+ 	}
      }
  
    return FALSE;
*************** noce_process_if_block (ce_info)
*** 1858,1864 ****
      {
        if (noce_try_store_flag_constants (&if_info))
  	goto success;
!       if (noce_try_store_flag_inc (&if_info))
  	goto success;
        if (noce_try_store_flag_mask (&if_info))
  	goto success;
--- 1884,1890 ----
      {
        if (noce_try_store_flag_constants (&if_info))
  	goto success;
!       if (noce_try_addcc (&if_info))
  	goto success;
        if (noce_try_store_flag_mask (&if_info))
  	goto success;
*** optabs.c.old	Thu Nov 21 23:25:39 2002
--- optabs.c	Thu Nov 21 23:46:34 2002
*************** can_conditionally_move_p (mode)
*** 4171,4176 ****
--- 4171,4304 ----
  }
  
  #endif /* HAVE_conditional_move */
+ 
+ /* Emit a conditional addition instruction if the machine supports one for that
+    condition and machine mode.
+ 
+    OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
+    the mode to use should they be constants.  If it is VOIDmode, they cannot
+    both be constants.
+ 
+    OP2 should be stored in TARGET if the comparison is true, otherwise OP2+OP3
+    should be stored there.  MODE is the mode to use should they be constants.
+    If it is VOIDmode, they cannot both be constants.
+ 
+    The result is either TARGET (perhaps modified) or NULL_RTX if the operation
+    is not supported.  */
+ 
+ rtx
+ emit_conditional_add (target, code, op0, op1, cmode, op2, op3, mode,
+ 		      unsignedp)
+      rtx target;
+      enum rtx_code code;
+      rtx op0, op1;
+      enum machine_mode cmode;
+      rtx op2, op3;
+      enum machine_mode mode;
+      int unsignedp;
+ {
+   rtx tem, subtarget, comparison, insn;
+   enum insn_code icode;
+   enum rtx_code reversed;
+ 
+   /* If one operand is constant, make it the second one.  Only do this
+      if the other operand is not constant as well.  */
+ 
+   if (swap_commutative_operands_p (op0, op1))
+     {
+       tem = op0;
+       op0 = op1;
+       op1 = tem;
+       code = swap_condition (code);
+     }
+ 
+   /* get_condition will prefer to generate LT and GT even if the old
+      comparison was against zero, so undo that canonicalization here since
+      comparisons against zero are cheaper.  */
+   if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
+     code = LE, op1 = const0_rtx;
+   else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
+     code = GE, op1 = const0_rtx;
+ 
+   if (cmode == VOIDmode)
+     cmode = GET_MODE (op0);
+ 
+   if (swap_commutative_operands_p (op2, op3)
+       && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
+           != UNKNOWN))
+     {
+       tem = op2;
+       op2 = op3;
+       op3 = tem;
+       code = reversed;
+     }
+ 
+   if (mode == VOIDmode)
+     mode = GET_MODE (op2);
+ 
+   icode = addcc_optab->handlers[(int) mode].insn_code;
+ 
+   if (icode == CODE_FOR_nothing)
+     return 0;
+ 
+   if (flag_force_mem)
+     {
+       op2 = force_not_mem (op2);
+       op3 = force_not_mem (op3);
+     }
+ 
+   if (target)
+     target = protect_from_queue (target, 1);
+   else
+     target = gen_reg_rtx (mode);
+ 
+   subtarget = target;
+ 
+   emit_queue ();
+ 
+   op2 = protect_from_queue (op2, 0);
+   op3 = protect_from_queue (op3, 0);
+ 
+   /* If the insn doesn't accept these operands, put them in pseudos.  */
+ 
+   if (! (*insn_data[icode].operand[0].predicate)
+       (subtarget, insn_data[icode].operand[0].mode))
+     subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
+ 
+   if (! (*insn_data[icode].operand[2].predicate)
+       (op2, insn_data[icode].operand[2].mode))
+     op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
+ 
+   if (! (*insn_data[icode].operand[3].predicate)
+       (op3, insn_data[icode].operand[3].mode))
+     op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
+ 
+   /* Everything should now be in the suitable form, so emit the compare insn
+      and then the conditional move.  */
+ 
+   comparison 
+     = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
+ 
+   /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
+   /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
+      return NULL and let the caller figure out how best to deal with this
+      situation.  */
+   if (GET_CODE (comparison) != code)
+     return NULL_RTX;
+   
+   insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
+ 
+   /* If that failed, then give up.  */
+   if (insn == 0)
+     return 0;
+ 
+   emit_insn (insn);
+ 
+   if (subtarget != target)
+     convert_move (target, subtarget, 0);
+ 
+   return target;
+ }
  
  /* These functions generate an insn body and return it
     rather than emitting the insn.
*************** init_optabs ()
*** 5170,5175 ****
--- 5298,5304 ----
    negv_optab = init_optabv (NEG);
    abs_optab = init_optab (ABS);
    absv_optab = init_optabv (ABS);
+   addcc_optab = init_optab (UNKNOWN);
    one_cmpl_optab = init_optab (NOT);
    ffs_optab = init_optab (FFS);
    sqrt_optab = init_optab (SQRT);
*** optabs.h.old	Thu Nov 21 23:19:26 2002
--- optabs.h	Thu Nov 21 23:34:22 2002
*************** enum optab_index
*** 160,165 ****
--- 160,168 ----
    /* Push instruction.  */
    OTI_push,
  
+   /* Conditional add instruction.  */
+   OTI_addcc,
+ 
    OTI_MAX
  };
  
*************** extern GTY(()) optab optab_table[OTI_MAX
*** 226,231 ****
--- 229,235 ----
  #define cmov_optab (optab_table[OTI_cmov])
  #define cstore_optab (optab_table[OTI_cstore])
  #define push_optab (optab_table[OTI_push])
+ #define addcc_optab (optab_table[OTI_addcc])
  
  /* Tables of patterns for extending one integer mode to another.  */
  extern enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
*** doc/md.texi.old	Fri Nov 22 01:23:57 2002
--- doc/md.texi	Fri Nov 22 01:25:03 2002
*************** codes and vice versa.
*** 2816,2821 ****
--- 2816,2828 ----
  If the machine does not have conditional move instructions, do not
  define these patterns.
  
+ @cindex @code{add@var{mode}cc} instruction pattern
+ @item @samp{mov@var{mode}cc}
+ Similar to @samp{mov@var{mode}cc} but for conditional addition.  Conditionally
+ move operand 2 or (operands 2 + operand 3) into operand 0 according to the
+ comparison in operand 1.  If the comparison is true, operand 2 is moved into
+ operand 0, otherwise operand 3 is moved.
+ 
  @cindex @code{s@var{cond}} instruction pattern
  @item @samp{s@var{cond}}
  Store zero or nonzero in the operand according to the condition codes.


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