This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Add conditional addition patterns
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org, rth at cygnus dot com
- Date: Thu, 21 Nov 2002 23:39:58 +0100
- Subject: 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.