mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-12 21:15:10 +08:00
Use cbranch patterns when available
From-SVN: r29613
This commit is contained in:
parent
708d3415cf
commit
1c0290eaac
@ -1,3 +1,27 @@
|
||||
Thu Sep 23 11:15:36 1999 Bernd Schmidt <bernds@cygnus.co.uk>
|
||||
|
||||
* expmed.c (do_cmp_and_jump): Pass ccp_jump to can_compare_p.
|
||||
* expr.c (expand_expr): Likewise.
|
||||
(do_jump): Likewise.
|
||||
(do_store_flag): Pass ccp_store_flag to can_compare_p.
|
||||
* expr.h (enum optab_index): Add cbranch, cmov, cstore optabs and
|
||||
accessor macros.
|
||||
(enum can_compare_purpose): New.
|
||||
(can_compare_p): Adjust prototype.
|
||||
(prepare_cmp_insn, prepare_operand): Declare.
|
||||
* genopinit.c (optabs): Add cbranch_optab, cmov_optab, cstore_optab.
|
||||
* optabs.c (cmp_available_p): Deleted.
|
||||
(expand_abs): Pass ccp_jump to can_compare_p.
|
||||
(can_compare_p): New arg PURPOSE. Check for combined optabs.
|
||||
(prepare_cmp_insn): No longer static. Add arg PURPOSE.
|
||||
Call can_compare_p rather than cmp_available_p.
|
||||
(prepare_operand): No longer static.
|
||||
(emit_cmp_and_jump_insn): Check for and use cbranch patterns.
|
||||
(emit_cmp_and_jump_insns): Pass ccp_jump to prepare_cmp_insn.
|
||||
(expand_float): Fix a slightly broken emit_cmp_insn/emit_jump_insn
|
||||
sequence to use emit_cmp_and_jump_insns.
|
||||
(init_optabs): Initialize cbranch_optab, cmov_optab, cstore_optab.
|
||||
|
||||
Wed Sep 22 17:58:01 1999 Stan Cox <scox@cygnus.com>
|
||||
|
||||
* mips.h (GO_IF_LEGITIMATE_ADDRESS): Don't accept large
|
||||
|
@ -4548,7 +4548,7 @@ do_cmp_and_jump (arg1, arg2, op, mode, label)
|
||||
/* If this mode is an integer too wide to compare properly,
|
||||
compare word by word. Rely on cse to optimize constant cases. */
|
||||
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode, ccp_jump))
|
||||
{
|
||||
rtx label2 = gen_label_rtx ();
|
||||
|
||||
|
34
gcc/expr.c
34
gcc/expr.c
@ -7388,7 +7388,7 @@ expand_expr (exp, target, tmode, modifier)
|
||||
|
||||
/* If this mode is an integer too wide to compare properly,
|
||||
compare word by word. Rely on cse to optimize constant cases. */
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode, ccp_jump))
|
||||
{
|
||||
if (code == MAX_EXPR)
|
||||
do_jump_by_parts_greater_rtx (mode, TREE_UNSIGNED (type),
|
||||
@ -8938,7 +8938,7 @@ do_jump (exp, if_false_label, if_true_label)
|
||||
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
|
||||
|
||||
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
|
||||
&& !can_compare_p (TYPE_MODE (inner_type)))
|
||||
&& !can_compare_p (TYPE_MODE (inner_type), ccp_jump))
|
||||
do_jump_by_parts_equality (exp, if_false_label, if_true_label);
|
||||
else
|
||||
do_compare_and_jump (exp, EQ, EQ, if_false_label, if_true_label);
|
||||
@ -8978,7 +8978,7 @@ do_jump (exp, if_false_label, if_true_label)
|
||||
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
|
||||
|
||||
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
|
||||
&& !can_compare_p (TYPE_MODE (inner_type)))
|
||||
&& !can_compare_p (TYPE_MODE (inner_type), ccp_jump))
|
||||
do_jump_by_parts_equality (exp, if_true_label, if_false_label);
|
||||
else
|
||||
do_compare_and_jump (exp, NE, NE, if_false_label, if_true_label);
|
||||
@ -8986,36 +8986,36 @@ do_jump (exp, if_false_label, if_true_label)
|
||||
}
|
||||
|
||||
case LT_EXPR:
|
||||
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
|
||||
== MODE_INT)
|
||||
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
|
||||
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& ! can_compare_p (mode, ccp_jump))
|
||||
do_jump_by_parts_greater (exp, 1, if_false_label, if_true_label);
|
||||
else
|
||||
do_compare_and_jump (exp, LT, LTU, if_false_label, if_true_label);
|
||||
break;
|
||||
|
||||
case LE_EXPR:
|
||||
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
|
||||
== MODE_INT)
|
||||
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
|
||||
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& ! can_compare_p (mode, ccp_jump))
|
||||
do_jump_by_parts_greater (exp, 0, if_true_label, if_false_label);
|
||||
else
|
||||
do_compare_and_jump (exp, LE, LEU, if_false_label, if_true_label);
|
||||
break;
|
||||
|
||||
case GT_EXPR:
|
||||
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
|
||||
== MODE_INT)
|
||||
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
|
||||
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& ! can_compare_p (mode, ccp_jump))
|
||||
do_jump_by_parts_greater (exp, 0, if_false_label, if_true_label);
|
||||
else
|
||||
do_compare_and_jump (exp, GT, GTU, if_false_label, if_true_label);
|
||||
break;
|
||||
|
||||
case GE_EXPR:
|
||||
if ((GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
|
||||
== MODE_INT)
|
||||
&& !can_compare_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
|
||||
mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT
|
||||
&& ! can_compare_p (mode, ccp_jump))
|
||||
do_jump_by_parts_greater (exp, 1, if_true_label, if_false_label);
|
||||
else
|
||||
do_compare_and_jump (exp, GE, GEU, if_false_label, if_true_label);
|
||||
@ -9044,7 +9044,7 @@ do_jump (exp, if_false_label, if_true_label)
|
||||
emit_jump (target);
|
||||
}
|
||||
else if (GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
|
||||
&& ! can_compare_p (GET_MODE (temp)))
|
||||
&& ! can_compare_p (GET_MODE (temp), ccp_jump))
|
||||
/* Note swapping the labels gives us not-equal. */
|
||||
do_jump_by_parts_equality_rtx (temp, if_true_label, if_false_label);
|
||||
else if (GET_MODE (temp) != VOIDmode)
|
||||
@ -9658,7 +9658,7 @@ do_store_flag (exp, target, mode, only_cheap)
|
||||
}
|
||||
|
||||
/* Now see if we are likely to be able to do this. Return if not. */
|
||||
if (! can_compare_p (operand_mode))
|
||||
if (! can_compare_p (operand_mode, ccp_store_flag))
|
||||
return 0;
|
||||
icode = setcc_gen_code[(int) code];
|
||||
if (icode == CODE_FOR_nothing
|
||||
|
26
gcc/expr.h
26
gcc/expr.h
@ -377,6 +377,11 @@ enum optab_index
|
||||
/* String length */
|
||||
OTI_strlen,
|
||||
|
||||
/* Combined compare & jump/store flags/move operations. */
|
||||
OTI_cbranch,
|
||||
OTI_cmov,
|
||||
OTI_cstore,
|
||||
|
||||
OTI_MAX
|
||||
};
|
||||
|
||||
@ -427,6 +432,10 @@ extern optab optab_table[OTI_MAX];
|
||||
|
||||
#define strlen_optab (optab_table[OTI_strlen])
|
||||
|
||||
#define cbranch_optab (optab_table[OTI_cbranch])
|
||||
#define cmov_optab (optab_table[OTI_cmov])
|
||||
#define cstore_optab (optab_table[OTI_cstore])
|
||||
|
||||
/* Tables of patterns for extending one integer mode to another. */
|
||||
extern enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
|
||||
|
||||
@ -778,9 +787,24 @@ extern void emit_cmp_insn PROTO((rtx, rtx, enum rtx_code, rtx,
|
||||
extern void emit_cmp_and_jump_insns PROTO((rtx, rtx, enum rtx_code, rtx,
|
||||
enum machine_mode, int, int, rtx));
|
||||
|
||||
/* The various uses that a comparison can have; used by can_compare_p:
|
||||
jumps, conditional moves, store flag operations. */
|
||||
enum can_compare_purpose
|
||||
{
|
||||
ccp_jump,
|
||||
ccp_cmov,
|
||||
ccp_store_flag
|
||||
};
|
||||
/* Nonzero if a compare of mode MODE can be done straightforwardly
|
||||
(without splitting it into pieces). */
|
||||
extern int can_compare_p PROTO((enum machine_mode));
|
||||
extern int can_compare_p PROTO((enum machine_mode, enum can_compare_purpose));
|
||||
|
||||
extern void prepare_cmp_insn PROTO((rtx *, rtx *, enum rtx_code *, rtx,
|
||||
enum machine_mode *, int *, int,
|
||||
enum can_compare_purpose));
|
||||
|
||||
extern rtx prepare_operand PROTO((int, rtx, int, enum machine_mode,
|
||||
enum machine_mode, int));
|
||||
|
||||
/* Generate code to indirectly jump to a location given in the rtx LOC. */
|
||||
extern void emit_indirect_jump PROTO((rtx));
|
||||
|
@ -113,6 +113,9 @@ const char * const optabs[] =
|
||||
"bcc_gen_fctn[(int) %C] = gen_%(b%c%)",
|
||||
"setcc_gen_code[(int) %C] = CODE_FOR_%(s%c%)",
|
||||
"movcc_gen_code[(int) %A] = CODE_FOR_%(mov%acc%)",
|
||||
"cbranch_optab->handlers[(int) %A].insn_code = CODE_FOR_%(cbranch%a4%)",
|
||||
"cmov_optab->handlers[(int) %A].insn_code = CODE_FOR_%(cmov%a6%)",
|
||||
"cstore_optab->handlers[(int) %A].insn_code = CODE_FOR_%(cstore%a4%)",
|
||||
"reload_in_optab[(int) %A] = CODE_FOR_%(reload_in%a%)",
|
||||
"reload_out_optab[(int) %A] = CODE_FOR_%(reload_out%a%)",
|
||||
"movstr_optab[(int) %A] = CODE_FOR_%(movstr%a%)",
|
||||
|
89
gcc/optabs.c
89
gcc/optabs.c
@ -105,13 +105,8 @@ static void init_floating_libfuncs PROTO((optab, const char *, int));
|
||||
#ifdef HAVE_conditional_trap
|
||||
static void init_traps PROTO((void));
|
||||
#endif
|
||||
static int cmp_available_p PROTO((enum machine_mode, int));
|
||||
static void emit_cmp_and_jump_insn_1 PROTO((rtx, rtx, enum machine_mode,
|
||||
enum rtx_code, int, rtx));
|
||||
static void prepare_cmp_insn PROTO((rtx *, rtx *, enum rtx_code *, rtx,
|
||||
enum machine_mode *, int *, int));
|
||||
static rtx prepare_operand PROTO((int, rtx, int, enum machine_mode,
|
||||
enum machine_mode, int));
|
||||
static void prepare_float_lib_cmp PROTO((rtx *, rtx *, enum rtx_code *,
|
||||
enum machine_mode *, int *));
|
||||
|
||||
@ -2309,7 +2304,7 @@ expand_abs (mode, op0, target, safe)
|
||||
|
||||
/* If this mode is an integer too wide to compare properly,
|
||||
compare word by word. Rely on CSE to optimize constant cases. */
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
|
||||
if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode, ccp_jump))
|
||||
do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
|
||||
NULL_RTX, op1);
|
||||
else
|
||||
@ -2823,22 +2818,32 @@ emit_0_to_1_insn (x)
|
||||
emit_move_insn (x, const1_rtx);
|
||||
}
|
||||
|
||||
/* Nonzero if we can perform a comparison of mode MODE for a conditional jump
|
||||
straightforwardly. */
|
||||
|
||||
static int
|
||||
cmp_available_p (mode, can_use_tst_p)
|
||||
/* Nonzero if we can perform a comparison of mode MODE straightforwardly.
|
||||
If FOR_JUMP is nonzero, we will be generating a jump based on this
|
||||
comparison, otherwise a store-flags operation. */
|
||||
|
||||
int
|
||||
can_compare_p (mode, purpose)
|
||||
enum machine_mode mode;
|
||||
int can_use_tst_p;
|
||||
enum can_compare_purpose purpose;
|
||||
{
|
||||
do
|
||||
{
|
||||
if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing
|
||||
|| (can_use_tst_p
|
||||
&& tst_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing))
|
||||
if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
|
||||
return 1;
|
||||
if (purpose == ccp_jump
|
||||
&& cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
|
||||
return 1;
|
||||
if (purpose == ccp_cmov
|
||||
&& cmov_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
|
||||
return 1;
|
||||
if (purpose == ccp_store_flag
|
||||
&& cstore_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
|
||||
return 1;
|
||||
|
||||
mode = GET_MODE_WIDER_MODE (mode);
|
||||
} while (mode != VOIDmode);
|
||||
}
|
||||
while (mode != VOIDmode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2860,14 +2865,16 @@ cmp_available_p (mode, can_use_tst_p)
|
||||
The values which are passed in through pointers can be modified; the caller
|
||||
should perform the comparison on the modified values. */
|
||||
|
||||
static void
|
||||
prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align)
|
||||
void
|
||||
prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align,
|
||||
purpose)
|
||||
rtx *px, *py;
|
||||
enum rtx_code *pcomparison;
|
||||
rtx size;
|
||||
enum machine_mode *pmode;
|
||||
int *punsignedp;
|
||||
int align;
|
||||
enum can_compare_purpose purpose;
|
||||
{
|
||||
enum machine_mode mode = *pmode;
|
||||
rtx x = *px, y = *py;
|
||||
@ -2988,7 +2995,7 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align)
|
||||
|
||||
*px = x;
|
||||
*py = y;
|
||||
if (cmp_available_p (mode, y == CONST0_RTX (mode)))
|
||||
if (can_compare_p (mode, purpose))
|
||||
return;
|
||||
|
||||
/* Handle a lib call just for the mode we are using. */
|
||||
@ -3032,7 +3039,7 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align)
|
||||
to be used for operand OPNUM of the insn, is converted from mode MODE to
|
||||
WIDER_MODE (UNSIGNEDP determines whether it is a unsigned conversion), and
|
||||
that it is accepted by the operand predicate. Return the new value. */
|
||||
static rtx
|
||||
rtx
|
||||
prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
|
||||
int icode;
|
||||
rtx x;
|
||||
@ -3074,6 +3081,20 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
|
||||
enum insn_code icode;
|
||||
PUT_MODE (test, wider_mode);
|
||||
|
||||
if (label)
|
||||
{
|
||||
icode = cbranch_optab->handlers[(int)wider_mode].insn_code;
|
||||
|
||||
if (icode != CODE_FOR_nothing
|
||||
&& (*insn_data[icode].operand[0].predicate) (test, wider_mode))
|
||||
{
|
||||
x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
|
||||
y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
|
||||
emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle some compares against zero. */
|
||||
icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
|
||||
if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
|
||||
@ -3164,7 +3185,8 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
|
||||
emit_queue ();
|
||||
if (unsignedp)
|
||||
comparison = unsigned_condition (comparison);
|
||||
prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, align);
|
||||
prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, align,
|
||||
ccp_jump);
|
||||
emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
|
||||
}
|
||||
|
||||
@ -3180,24 +3202,6 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
|
||||
{
|
||||
emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Nonzero if a compare of mode MODE can be done straightforwardly
|
||||
(without splitting it into pieces). */
|
||||
|
||||
int
|
||||
can_compare_p (mode)
|
||||
enum machine_mode mode;
|
||||
{
|
||||
do
|
||||
{
|
||||
if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
|
||||
return 1;
|
||||
mode = GET_MODE_WIDER_MODE (mode);
|
||||
} while (mode != VOIDmode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Emit a library call comparison between floating point X and Y.
|
||||
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */
|
||||
@ -3876,8 +3880,8 @@ expand_float (to, from, unsignedp)
|
||||
do_pending_stack_adjust ();
|
||||
|
||||
/* Test whether the sign bit is set. */
|
||||
emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, imode, 0, 0);
|
||||
emit_jump_insn (gen_blt (neglabel));
|
||||
emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode,
|
||||
0, 0, neglabel);
|
||||
|
||||
/* The sign bit is not set. Convert as signed. */
|
||||
expand_float (target, from, 0);
|
||||
@ -4467,6 +4471,9 @@ init_optabs ()
|
||||
sin_optab = init_optab (UNKNOWN);
|
||||
cos_optab = init_optab (UNKNOWN);
|
||||
strlen_optab = init_optab (UNKNOWN);
|
||||
cbranch_optab = init_optab (UNKNOWN);
|
||||
cmov_optab = init_optab (UNKNOWN);
|
||||
cstore_optab = init_optab (UNKNOWN);
|
||||
|
||||
for (i = 0; i < NUM_MACHINE_MODES; i++)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user