#include "insn-config.h"
#include "rtl.h"
#include "tree.h"
+#include "tm_p.h"
#include "flags.h"
#include "insn-flags.h"
#include "insn-codes.h"
#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 *));
\f
&& binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) binoptab->handlers[(int) mode].insn_code;
- enum machine_mode mode0 = insn_operand_mode[icode][1];
- enum machine_mode mode1 = insn_operand_mode[icode][2];
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+ enum machine_mode mode1 = insn_data[icode].operand[2].mode;
rtx pat;
rtx xop0 = op0, xop1 = op1;
/* Now, if insn's predicates don't allow our operands, put them into
pseudo regs. */
- if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)
+ if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)
&& mode0 != VOIDmode)
xop0 = copy_to_mode_reg (mode0, xop0);
- if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)
+ if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
&& mode1 != VOIDmode)
xop1 = copy_to_mode_reg (mode1, xop1);
- if (! (*insn_operand_predicate[icode][0]) (temp, mode))
+ if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
temp = gen_reg_rtx (mode);
pat = GEN_FCN (icode) (temp, xop0, xop1);
if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) binoptab->handlers[(int) mode].insn_code;
- enum machine_mode mode0 = insn_operand_mode[icode][1];
- enum machine_mode mode1 = insn_operand_mode[icode][2];
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+ enum machine_mode mode1 = insn_data[icode].operand[2].mode;
rtx pat;
rtx xop0 = op0, xop1 = op1;
xop1 = convert_to_mode (mode1, xop1, unsignedp);
/* Now, if insn doesn't accept these operands, put them into pseudos. */
- if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
+ if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
xop0 = copy_to_mode_reg (mode0, xop0);
- if (! (*insn_operand_predicate[icode][2]) (xop1, mode1))
+ if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1))
xop1 = copy_to_mode_reg (mode1, xop1);
/* We could handle this, but we should always be called with a pseudo
for our targets and all insns should take them as outputs. */
- if (! (*insn_operand_predicate[icode][0]) (targ0, mode)
- || ! (*insn_operand_predicate[icode][3]) (targ1, mode))
+ if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
+ || ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
abort ();
pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) unoptab->handlers[(int) mode].insn_code;
- enum machine_mode mode0 = insn_operand_mode[icode][1];
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
rtx xop0 = op0;
if (target)
/* Now, if insn doesn't accept our operand, put it into a pseudo. */
- if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
+ if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
xop0 = copy_to_mode_reg (mode0, xop0);
- if (! (*insn_operand_predicate[icode][0]) (temp, mode))
+ if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
temp = gen_reg_rtx (mode);
pat = GEN_FCN (icode) (temp, xop0);
if (temp != 0)
return temp;
+ /* If we have a MAX insn, we can do this as MAX (x, -x). */
+ if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ {
+ rtx last = get_last_insn ();
+
+ temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
+ if (temp != 0)
+ temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
+ OPTAB_WIDEN);
+
+ if (temp != 0)
+ return temp;
+
+ delete_insns_since (last);
+ }
+
/* If this machine has expensive jumps, we can do integer absolute
value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
- where W is the width of MODE. */
+ where W is the width of MODE. But don't do this if the machine has
+ conditional arithmetic since the branches will be converted into
+ a conditional negation insn. */
+#ifndef HAVE_conditional_arithmetic
if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
{
rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
if (temp != 0)
return temp;
}
+#endif
/* If that does not win, use conditional jump and negate. */
/* 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
if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
int icode = (int) abs_optab->handlers[(int) mode].insn_code;
- enum machine_mode mode0 = insn_operand_mode[icode][1];
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
rtx xop0 = op0;
if (target)
/* Now, if insn doesn't accept our operand, put it into a pseudo. */
- if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
+ if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
xop0 = copy_to_mode_reg (mode0, xop0);
- if (! (*insn_operand_predicate[icode][0]) (temp, submode))
+ if (! (*insn_data[icode].operand[0].predicate) (temp, submode))
temp = gen_reg_rtx (submode);
pat = GEN_FCN (icode) (temp, xop0);
enum rtx_code code;
{
register rtx temp;
- enum machine_mode mode0 = insn_operand_mode[icode][1];
+ enum machine_mode mode0 = insn_data[icode].operand[1].mode;
rtx pat;
temp = target = protect_from_queue (target, 1);
/* Now, if insn does not accept our operands, put them into pseudos. */
- if (! (*insn_operand_predicate[icode][1]) (op0, mode0))
+ if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
- if (! (*insn_operand_predicate[icode][0]) (temp, GET_MODE (temp))
+ if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp))
|| (flag_force_mem && GET_CODE (temp) == MEM))
temp = gen_reg_rtx (GET_MODE (temp));
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;
}
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;
&& GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
{
- result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
+ result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode;
result = gen_reg_rtx (result_mode);
emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align)));
}
&& GET_CODE (size) == CONST_INT
&& INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
{
- result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
+ result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode;
result = gen_reg_rtx (result_mode);
emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align)));
}
#ifdef HAVE_cmpstrsi
if (HAVE_cmpstrsi)
{
- result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
+ result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
result = gen_reg_rtx (result_mode);
size = protect_from_queue (size, 0);
emit_insn (gen_cmpstrsi (result, x, y,
*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. */
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;
if (mode != wider_mode)
x = convert_modes (wider_mode, mode, x, unsignedp);
- if (! (*insn_operand_predicate[icode][opnum])
- (x, insn_operand_mode[icode][opnum]))
- x = copy_to_mode_reg (insn_operand_mode[icode][opnum], x);
+ if (! (*insn_data[icode].operand[opnum].predicate)
+ (x, insn_data[icode].operand[opnum].mode))
+ x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
return x;
}
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)
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);
}
{
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;
-}
\f
/* Emit a library call comparison between floating point X and Y.
COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.). */
emit_indirect_jump (loc)
rtx loc;
{
- if (! ((*insn_operand_predicate[(int)CODE_FOR_indirect_jump][0])
+ if (! ((*insn_data[(int)CODE_FOR_indirect_jump].operand[0].predicate)
(loc, Pmode)))
loc = copy_to_mode_reg (Pmode, loc);
/* If the insn doesn't accept these operands, put them in pseudos. */
- if (! (*insn_operand_predicate[icode][0])
- (subtarget, insn_operand_mode[icode][0]))
- subtarget = gen_reg_rtx (insn_operand_mode[icode][0]);
+ 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_operand_predicate[icode][2])
- (op2, insn_operand_mode[icode][2]))
- op2 = copy_to_mode_reg (insn_operand_mode[icode][2], op2);
+ 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_operand_predicate[icode][3])
- (op3, insn_operand_mode[icode][3]))
- op3 = copy_to_mode_reg (insn_operand_mode[icode][3], op3);
+ 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. */
{
int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
- if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
- || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
- || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2]))
+ if (! ((*insn_data[icode].operand[0].predicate)
+ (x, insn_data[icode].operand[0].mode))
+ || ! ((*insn_data[icode].operand[1].predicate)
+ (x, insn_data[icode].operand[1].mode))
+ || ! ((*insn_data[icode].operand[2].predicate)
+ (y, insn_data[icode].operand[2].mode)))
abort ();
return (GEN_FCN (icode) (x, x, y));
{
int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
- if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
- || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
- || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2]))
+ if (! ((*insn_data[icode].operand[0].predicate)
+ (x, insn_data[icode].operand[0].mode))
+ || ! ((*insn_data[icode].operand[1].predicate)
+ (x, insn_data[icode].operand[1].mode))
+ || ! ((*insn_data[icode].operand[2].predicate)
+ (y, insn_data[icode].operand[2].mode)))
abort ();
return (GEN_FCN (icode) (x, x, y));
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);
for (q = opname; *q; )
*p++ = *q++;
for (q = mname; *q; q++)
- *p++ = tolower ((unsigned char)*q);
+ *p++ = TOLOWER (*q);
*p++ = suffix;
*p++ = '\0';
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++)
{
/* The insn generating function can not take an rtx_code argument.
TRAP_RTX is used as an rtx argument. Its code is replaced with
the code to be used in the trap insn and all other fields are
- ignored.
-
- ??? Will need to change to support garbage collection. */
+ ignored. */
static rtx trap_rtx;
static void
init_traps ()
{
if (HAVE_conditional_trap)
- trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
+ {
+ trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
+ ggc_add_rtx_root (&trap_rtx, 1);
+ }
}
#endif