#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
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
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;
*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;
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.). */
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);
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
&& cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
rtx insn;
+ start_sequence();
emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
PUT_CODE (trap_rtx, code);
insn = gen_conditional_trap (trap_rtx, tcode);
if (insn)
- return insn;
+ {
+ emit_insn (insn);
+ insn = gen_sequence ();
+ }
+ end_sequence();
+ return insn;
}
#endif